• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Breaking Boundaries: Constructing a Tangram Puzzle With (S)CSS

Admin by Admin
June 13, 2025
Home Coding
Share on FacebookShare on Twitter


, easy and efficient.

  • For rotation, we added eight radio buttons, every representing a 45-degree increment: 45°, 90°, 135°, all the way in which to 360°. These simulate rotation controls totally in CSS.
  • Each potential shadow place acquired its personal radio button too. (Sure, it’s so much, I do know.)
  • And to wrap all of it up, I included a traditional reset button inside a  utilizing 
  • Given the sheer variety of components required, I used Pug to generate the HTML extra effectively. It was purely a comfort selection. It doesn’t have an effect on the logic or habits of the puzzle in any method.

    Beneath is a pattern of the compiled HTML. It would look overwhelming at first look (and that is only a portion of it!), but it surely illustrates the structural complexity concerned. This part is collapsed to not nuke your display, however it may be expanded should you’d wish to discover it.

    Open HTML Code

    Creating maps for form information

    Now that HTML skeleton is prepared, it’s time to inject it with some actual energy. That’s the place our Sass maps are available in, and right here’s the place the puzzle logic begins to shine.

    Notice: Maps in Sass maintain pairs of keys and values, and make it straightforward to search for a worth by its corresponding key. Like objects in JavaScript, dictionaries in Python and, nicely, maps in C++.

    I’m mapping out all of the core information wanted to manage every tangram piece (tan): its coloration, form, place, and even interplay logic. These maps comprise:

    • the background-color for every tan,
    • the clip-path coordinates that outline their shapes,
    • the preliminary place for every tan,
    • the place of the blocking div (which disables interplay when a tan is chosen),
    • the shadow positions (coordinates for the tan’s silhouette displayed on the duty board),
    • the grid info, and
    • the profitable mixtures — the precise goal coordinates for every tan, marking the right resolution.
    $colours: ( blue-color: #53a0e0, yellow-color: #f7db4f, /* Colours for every tan */ );
    $nth-child-grid: ( 1: (2, 3, 1, 2, ), 2: ( 3, 4, 1, 2, ), 4: ( 1, 2, 2, 3, ), /* Extra entries to be added */);
    $bluePosiblePositions: ( 45: none, 90: ( (6.7, 11.2), ), 135: none, 180: none, /* Positions outlined as much as 360 levels */);
    /* Different tans */
    
    /* Knowledge outlined for every tan */
    $tansShapes: (
      blueTriangle: (
        coloration: map.get($colours, blue-color),
        clip-path: ( 0 0, 50 50, 0 100, ),
        rot-btn-position: ( -20, -25, ),
        exit-mode-btn-position: ( -20, -33, ),
        tan-position: ( -6, -37, ),
        diable-lab-position: ( -12, -38, ),
        poss-positions: $bluePosiblePositions,
        correct-position: ((4.7, 13.5), (18.8, 13.3), ),
        transform-origin: ( 4.17, 12.5,),
      ),
    );
    
    /* Remaining 7 mixtures */
    $winningCombinations: (
      combo1: (
        (blueTriangle, 1, 360),
        (yellowTriangle, 1, 225),
        (pinkTriangle, 1, 180),
        (redTriangle, 4, 360),
        (purpleTriangle, 2, 225),
        (sq., 1, 90),
        (polygon, 4, 90),
      ),
    );

    You possibly can see this in motion on CodePen, the place these maps drive the precise look and habits of every puzzle piece. At this level, there’s no seen change within the preview. We’ve merely ready and saved the information for later use.

    Utilizing mixins to learn from maps

    The principle concept is to create reusable mixins that may learn information from the maps and apply it to the corresponding CSS guidelines when wanted.

    However earlier than that, we’ve elevated issues to the next degree by making one key determination: We by no means hard-coded models straight contained in the maps. As an alternative, we constructed a reusable utility perform that dynamically provides the specified unit (e.g., vmin, px, and many others.) to any numeric worth when it’s getting used. This fashion, when can use our maps nonetheless we please.

    @perform get-coordinates($information, $key, $separator, $unit) {
      $coordinates: null;
    
      // Test if the primary argument is a map
      @if meta.type-of($information) == "map" {
        // If the map incorporates the desired key
        @if map.has-key($information, $key) {
          // Get the worth related to the important thing (anticipated to be an inventory of coordinates)
          $coordinates: map.get($information, $key);
        }
    
      //  If the primary argument is an inventory
      } @else if meta.type-of($information) == "listing" {
        // Guarantee the hot button is a sound index (1-based) throughout the listing
        @if meta.type-of($key) == "quantity" and $key > 0 and $key <= listing.size($information) {
          // Retrieve the merchandise on the specified index
          $coordinates: listing.nth($information, $key);
        }
    
      //  If neither map nor listing, throw an error
      } @else {
        @error "Invalid enter: First argument have to be a map or an inventory.";
      }
    
      // If no legitimate coordinates had been discovered, return null
      @if $coordinates == null {
        @return null;
      }
    
      //  Extract x and y values from the listing
      $x: listing.nth($coordinates, 1);
      $y: listing.nth($coordinates, -1); // -1 will get the final merchandise (y)
    
      //  Return the mixed x and y values with models and separator
      @return #{$x}#{$unit}#{$separator}#{$y}#{$unit};
    }

    Positive, nothing’s exhibiting up within the preview but, however the true magic begins now.

    Now we transfer on to writing mixins. I’ll clarify the strategy intimately for the primary mixin, and the remainder will likely be described by means of feedback.

    The primary mixin dynamically applies grid-column and grid-row placement guidelines to baby components based mostly on values saved in a map. Every entry within the map corresponds to a component index (1 by means of 8) and incorporates an inventory of 4 values: [start-col, end-col, start-row, end-row].

    @mixin tanagram-grid-positioning($nth-child-grid) {
      // Loop by means of numbers 1 to eight, similar to the tanam items
      @for $i from 1 by means of 8 {
    
        // Test if the map incorporates a key for the present piece (1-8)
        @if map.has-key($nth-child-grid, $i) {
    
          // Get the grid values for this piece: [start-column, end-column, start-row, end-row]
          $values: map.get($nth-child-grid, $i);
    
          // Goal the nth baby (piece) and set its grid positions
          &:nth-child(#{$i}) {
            // Set grid-column: begin and finish values based mostly on the primary two objects within the listing
            grid-column: #{listing.nth($values, 1)} / #{listing.nth($values, 2)};
    
            // Set grid-row: begin and finish values based mostly on the final two objects within the listing
            grid-row: #{listing.nth($values, 3)} / #{listing.nth($values, 4)};
          }
        }
      }
    }

    We are able to count on the next CSS to be generated:

    .tanagram-box:nth-child(1) {
      grid-column: 2 / 3;
      grid-row: 1 / 2;
    }
    
    .tanagram-box:nth-child(2) {
      grid-column: 3 / 4;
      grid-row: 1 / 2;
    }

    On this mixin, my aim was truly to create all of the shapes (tans). I'm utilizing clip-path. There have been concepts to make use of fancy SVG photographs, however this check mission is extra about testing the logic somewhat than specializing in lovely design. Because of this, the best resolution was to chop the weather in accordance with dimensions whereas they're nonetheless within the sq. (the preliminary place of all of the tans).

    So, on this case, by means of a static calculation, the $tansShapes map was up to date with the clip-path property:

    clip-path: (0 0, 50 50, 0 100);

    This incorporates the clip factors for all of the tans. In essence, this mixin shapes and colours every tan accordingly.

    @mixin set-tan-clip-path($tanName, $values) {
      //  Initialize an empty listing to carry the ultimate clip-path factors
      $clip-path-points: ();
    
      // Extract the 'clip-path' information from the map, which incorporates coordinate pairs
      $clip-path-key: map.get($values, clip-path);
    
      // Get the variety of coordinate pairs to loop by means of
      $depend: listing.size($clip-path-key);
    
      //  Loop by means of every coordinate level
      @for $i from 1 by means of $depend {
        //  Convert every pair of numbers right into a formatted coordinate string with models
        $current-point: get-coordinates($clip-path-key, $i, " ", "%");
    
        //  Add the formatted coordinate to the listing, separating every level with a comma
        $clip-path-points: listing.append($clip-path-points, #{$current-point}, comma);
      }
    
      //  Fashion for the preview aspect (lab model), utilizing the configured background coloration
      #tan#{$tanName}lab {
        background: map.get($values, coloration);
        clip-path: polygon(#{$clip-path-points}); // Apply the total listing of clip-path factors
      }
    
      //  Apply the identical clip-path to the precise tan aspect
      .#{$tanName} {
        clip-path: polygon(#{$clip-path-points});
      }
    }

    and output in CSS must be:

    .blueTriangle {
      clip-path: polygon(0% 0%, 50% 50%, 0% 100%);
    }
    /* different tans */

    Begin logic

    Alright, now I’d wish to make clear what ought to occur first when the sport hundreds.

    First, with a click on on the Begin button, all of the tans “go to their positions.” In actuality, we assign them a rework: translate() with particular coordinates and a rotation.

    .begin:checked ~ .shadow #tanblueTrianglelab {
      transform-origin: 4.17vmin 12.5vmin;
      rework: translate(-6vmin,-37vmin) rotate(360deg);
      cursor: pointer;
    }

    So, we nonetheless keep this sample. We use rework and easily change the positions or angles (within the maps) of each the tans and their shadows on the duty board.

    When any tan is clicked, the rotation button seems. By clicking on it, the tan ought to rotate round its heart, and this continues with every subsequent click on. There are literally eight radio buttons, and with every click on, one disappears and the following one seems. After we attain the final one, clicking it makes it disappear and the primary one reappears. This fashion, we get the impression of clicking the identical button (they're, after all, styled the identical) and having the ability to click on (rotate the tan) infinitely. That is precisely what the next mixin allows.

    @mixin set-tan-rotation-states($tanName, $values, $angles, $coloration) {
      // This mixin dynamically applies rotation UI kinds based mostly on a tan's configuration.
      // It controls the positioning and look of rotation buttons and visible suggestions when a rotation state is energetic.
      @every $angle in $angles{
        & ~ #rot#{$angle}{ rework: translate(get-coordinates($values,rot-btn-position,',',vmin )); background: $coloration;}
        & ~ #rotation-#{$angle}:checked{
          @every $key in map.keys($tansShapes){
            & ~ #tan#{$key}labRes{ visibility: seen; background:rgba(0,0,0,0.4); }
            & ~ #tan#{$key}lab{ opacity:.3; }
            & ~ #rotReset{ visibility: seen; }
          } 
        }
      }
    }

    And the generated CSS must be:

    #blueTriangle-tan:checked ~ #rotation-45:checked ~ #tanblueTrianglelab {
      rework: translate(-6vmin,-37vmin) rotate(45deg);
    }
    
    #blueTriangle-tan:checked ~ #rotation-45:checked ~ #tanblueTrianglelabRes {
      visibility: hidden;
    }

    OK, the next mixins use the set-clip-path and set-rotation mixins. They comprise all of the details about the tans and their habits in relation to which tan is clicked and which rotation is chosen, in addition to their positions (as outlined within the second mixin).

    @mixin generate-tan-shapes-and-interactions($tansShapes) {
    // Applies styling logic and UI interactions for every particular person tan form from the $tansShapes map.
      @every $tanName, $values in $tansShapes{
        $coloration: coloration.scale(map.get($values, coloration), $lightness: 10%); 
        $angles: (45, 90, 135, 180, 225, 270, 315, 360); 
        @embody set-tan-clip-path($tanName, $values);
    
        ##{$tanName}-tan:checked{
          & ~ #tan#{$tanName}Res{ visibility:hidden; }
          & ~ #tan#{$tanName}lab{opacity: 1 !vital;background: #{$coloration};cursor:auto;}
          @every $key in map.keys($tansShapes){
              & ~ #tan#{$tanName}Res:checked ~ #tan#{$key}labRes{visibility: seen;}
          }
          & ~  #rot45{show: flex;visibility: seen;}
          & ~ #rotReset{ rework: translate(get-coordinates($values, exit-mode-btn-position,',', vmin)); }
          @embody set-tan-rotation-states($tanName, $values, $angles, $coloration);
        }  
      }
    }
    @mixin set-initial-tan-position($tansShapes) {
    // This mixin units the preliminary place and transformation for each the interactive (`lab`) and shadow (`labRes`) variations
    // of every tan form, based mostly on coordinates offered within the $tansShapes map.
     @every $tanName, $values in $tansShapes{
        & ~ .shadow #tan#{$tanName}lab{
          transform-origin: get-coordinates($values, transform-origin,' ' ,vmin);
          rework: translate( get-coordinates($values,tan-position,',', vmin)) rotate(360deg) ;
          cursor: pointer;
        }
        & ~ .shadow #tan#{$tanName}labRes{
          visibility:hidden;
          rework: translate(get-coordinates($values,diable-lab-position,',',vmin)); 
        }
      }
    }

    As talked about earlier, when a tan is clicked, one of many issues that turns into seen is its shadow — a silhouette that seems on the duty board.

    These shadow positions (coordinates) are presently outlined statically. Every shadow has a particular place on the map, and a mixin reads this information and applies it to the shadow utilizing rework: translate().

    When the clicked tan is rotated, the variety of seen shadows on the duty board can change, in addition to their angles, which is anticipated.

    After all, particular care was taken with naming conventions. Every shadow aspect will get a novel ID, made out of the identify (inherited from its mum or dad tan) and a quantity that represents its sequence place for the given angle.

    Fairly cool, proper? That method, we keep away from sophisticated naming patterns totally!

    @mixin render-possible-tan-positions( $identify, $angle, $possiblePositions, $visibility, $coloration, $id, $transformOrigin ) {
        // This mixin generates kinds for attainable positions of a tan form based mostly on its identify, rotation angle, and configuration map.
        // It handles each squares and polygons, normalizing their rotation angles accordingly and making use of rework kinds if positions exist.}
      @if $identify == 'sq.' {
        $angle: normalize-angle($angle); // Normalizujemo ugao ako je u pitanju sq.
      } @else if $identify == 'polygon'{
        $angle: normalize-polygon-angle($angle);
      }
      @if map.has-key($possiblePositions, $angle) {
        $values: map.get($possiblePositions, $angle);
    
        @if $values != none {
          $depend: listing.size($values);
    
          @for $i from 1 by means of $depend {
            $place: get-coordinates($values, $i, ',', vmin);
            & ~ #tan#{$identify}lab-#{$i}-#{$angle} { 
              @if $visibility == seen {
                visibility: seen;
                background-color: $coloration;
                opacity: .2;
                z-index: 2;
                transform-origin: #{$transformOrigin};
                rework: translate(#{$place}) rotate(#{$angle}deg);
              } @else if $visibility == hidden { visibility: hidden; }
              &:hover{ opacity: 0.5; cursor: pointer; }
            }
          }
        }
      }
    }

    The generated CSS:

    #blueTriangle-tan:checked ~ #tanblueTrianglelab-1-360 {
      visibility: seen;
      background-color: #53a0e0;
      opacity: 0.2;
      z-index: 2;
      transform-origin: 4.17vmin 12.5vmin;
      rework: translate(4.7vmin,13.5vmin) rotate(360deg);
    }

    This subsequent mixin is tied to the earlier one and manages when and the way the tan shadows seem whereas their mum or dad tan is being rotated utilizing the button. It listens for the present rotation angle and checks whether or not there are any shadow positions outlined for that particular angle. If there are, it shows them; if not — no shadows!

    @mixin render-possible-positions-by-rotation {
       // This mixin applies rotation to every tan form. It loops by means of every tan, calculates its attainable positions for every angle, and handles visibility and transformation.
       // It ensures that rotation is utilized accurately, together with dealing with the transitions between numerous tan positions and visibility states.
     @every $tanName, $values in $tansShapes{
        $possiblePositions: map.get($values, poss-positions);
        $possibleTansColor: map.get($values, coloration);
        $validPosition: get-coordinates($values, correct-position,',' ,vmin);
        $transformOrigin: get-coordinates($values,transform-origin,' ' ,vmin); 
        $rotResPosition: get-coordinates($values,exit-mode-btn-position ,',' ,vmin );
        $angle: 0;
        @for $i from 1 by means of 8{
          $angle: $i * 45;
          $nextAngle: if($angle + 45 > 360, 45, $angle + 45);
          @embody render-position-feedback-on-task($tanName,$angle, $possiblePositions,$possibleTansColor, #{$tanName}-tan, $validPosition,$transformOrigin, $rotResPosition);   
            ##{$tanName}-tan{
            @embody render-possible-tan-positions($tanName,$angle, $possiblePositions,hidden, $possibleTansColor, #{$tanName}-tan,$transformOrigin)
          }
            ##{$tanName}-tan:checked{
              @embody render-possible-tan-positions($tanName,360, $possiblePositions,seen, $possibleTansColor, #{$tanName}-tan,$transformOrigin);
              & ~ #rotation-#{$angle}:checked {
                @embody render-possible-tan-positions($tanName,360, $possiblePositions,hidden, $possibleTansColor, #{$tanName}-tan,$transformOrigin);
                & ~ #tan#{$tanName}lab{rework:translate( get-coordinates($values,tan-position,',', vmin))  rotate(#{$angle}deg) ;}
                & ~ #tan#{$tanName}labRes{ visibility: hidden; }
                & ~ #rot#{$angle}{ visibility: hidden; }
                & ~ #rot#{$nextAngle}{ visibility: seen } 
                @embody render-possible-tan-positions($tanName,$angle, $possiblePositions,seen, $possibleTansColor, #{$tanName}-tan,$transformOrigin);
            }
          }
        }
      }
    }

    When a tan’s shadow is clicked, the corresponding tan ought to transfer to that shadow’s place. The following mixin then checks whether or not this new place is the right one for fixing the puzzle. Whether it is right, the tan will get a quick blinking impact and turns into unclickable, signaling it’s been positioned accurately. If it’s not right, the tan merely stays on the shadow’s location. There’s no impact and it stays draggable/clickable.

    After all, there’s an inventory of all the right positions for every tan. Since some tans share the identical dimension — and a few may even mix to kind bigger, current shapes — we've got a number of legitimate mixtures. For this Camel process, all of them had been taken into consideration. A devoted map with these mixtures was created, together with a mixin that reads and applies them.

    On the finish of the sport, when all tans are positioned of their right positions, we set off a “merging” impact — and the silhouette of the camel turns yellow. At that time, the one remaining motion is to click on the Restart button.

    Properly, that was lengthy, however that’s what you get once you decide the enjoyable (albeit arduous and prolonged) path. All as an ode to CSS-only magic!

    Tags: BoundariesBreakingBuildingPuzzleSCSSTangram
    Admin

    Admin

    Next Post
    Chatbots Have interaction, However Don’t Ship

    Chatbots Have interaction, However Don’t Ship

    Leave a Reply Cancel reply

    Your email address will not be published. Required fields are marked *

    Recommended.

    ESET APT Exercise Report This autumn 2024–Q1 2025

    ESET APT Exercise Report This autumn 2024–Q1 2025

    June 5, 2025
    Merging design and pc science in inventive methods | MIT Information

    Merging design and pc science in inventive methods | MIT Information

    May 27, 2025

    Trending.

    Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

    Industrial-strength April Patch Tuesday covers 135 CVEs – Sophos Information

    April 10, 2025
    Expedition 33 Guides, Codex, and Construct Planner

    Expedition 33 Guides, Codex, and Construct Planner

    April 26, 2025
    How you can open the Antechamber and all lever places in Blue Prince

    How you can open the Antechamber and all lever places in Blue Prince

    April 14, 2025
    Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

    Important SAP Exploit, AI-Powered Phishing, Main Breaches, New CVEs & Extra

    April 28, 2025
    Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

    Wormable AirPlay Flaws Allow Zero-Click on RCE on Apple Units by way of Public Wi-Fi

    May 5, 2025

    AimactGrow

    Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

    Categories

    • AI
    • Coding
    • Cybersecurity
    • Digital marketing
    • Gaming
    • SEO
    • Technology

    Recent News

    The Obtain: tackling tech-facilitated abuse, and opening up AI {hardware}

    The Obtain: tackling tech-facilitated abuse, and opening up AI {hardware}

    June 18, 2025
    Why Media Coaching is Vital for Danger Administration and Model Status

    Why Media Coaching is Vital for Danger Administration and Model Status

    June 18, 2025
    • About Us
    • Privacy Policy
    • Disclaimer
    • Contact Us

    © 2025 https://blog.aimactgrow.com/ - All Rights Reserved

    No Result
    View All Result
    • Home
    • Technology
    • AI
    • SEO
    • Coding
    • Gaming
    • Cybersecurity
    • Digital marketing

    © 2025 https://blog.aimactgrow.com/ - All Rights Reserved