Polylion

The following is a guest post by Dennis Gaebel. Dennis created some pretty captivating polygon SVG effects on CodePen, and here he'll share how he did it.

Sometimes the things you least expect, gain the most attention as the case was with the Polylion I posted on CodePen. I figured the simplicity of the animation effect was easy enough to grok since I wasn't doing anything super crazy code wise, but I guess the end result was that cool. I'd like to share with all of you how and why this animation went down.

The Polylion Effect

If you don't follow me on Twitter then let me fill you in. I'm writing an entire series of articles for Tuts+ focusing on TimelineMax by GreenSock. Essentially it flows from beginner to advanced and provides working examples for readers to put to the test themselves. The study with polygon animations also began as practice with a project I did for Jonno Riekwel at Polyon so it was basically a win-win for everyone.

The Polyman

I started my research by examining the Polyman SVG I found on CodePen. Originally it was accomplished with CSS (also explodes on hover \o/), but I wanted to investigate the abilities of finer control with each polygon shape. The result is what you see below using TimelineMax to display the polygons at once.

The Polyman SVG using TimelineMax

Since the SVG contained portions of the man (ears, face, etc.) within <g> tags it made hooking to each one a cinch with JavaScript. Since SVG is XML everything that creates it is simply a node. In jQuery land the selector would be like this: $('svg g#shirt path').

Polylion Setup

For the lion I wanted to grab each polygon element individually $('svg.polylion > polygon') for maximum control and give each one a cascading effect as you saw. Obviously the result is super dope and frankly not terrible at all to make move. Let me explain how the lion got it's mojo.

Since I meander around frequently on CodePen I caught a glimpse of the lion posted by Dmytro Batarin's Pen SVG Low Poly Lion which appeared to have been originally posted on Dribbble by Breno Bitencourt who also wrote about the process of making polygon vector work here. In case you don't have time to read the article Breno wrote; the entire SVG is made by hand. There is no smoke and mirrors behind it at all and apparently it's the only way to get the best results at this time.

Making A Polygon SVG The Old Fashioned Way…By Hand!

Since the design part was already done for me the only thing I really needed to do was integrate TimelineMax and adjust my config as such in order to achieve the effect I was after.

Polylion Code

See the Pen SVG Low PolyLion: Animated Polygons by Dennis Gaebel (@grayghostvisuals) on CodePen.

Before we get to the really fun stuff lets take a look at our SVG's XML output.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600" class="polylion">
  <polygon points="392,85 380,128 339,98" style="fill: #FADFAA" />
  <polygon points="392,85 380,128 412,111" style="fill: #EABA8C" />
  <polygon points="339,98 380,128 340,140" style="fill: #FAD398" />
  <polygon points="339,98 340,140 309,142" style="fill: #DFA387" />
  <polygon points="339,98 309,142 286,133" style="fill: #F9D8AD" />
  <polygon points="392,85 412,111 443,101" style="fill: #DBB08E" />
  <polygon points="443,101 412,111 434,126" style="fill: #D59F7D" />
  <polygon points="443,101 434,126 475,122" style="fill: #FACC91" />
  <polygon points="412,111 380,128 402,132" style="fill: #CE8670" />
  <!-- and so on -->
</svg>

Not too much to this SVG. Besides the fact we know it was difficult to make, the output is pretty straight forward. If you're not familiar with the polygon element you can read more about it here. The polygon element defines a closed shape consisting of a set of connected straight line segments.

JavaScript was the only way to count the polygons in order to avoid using fingers and toes. As I mentioned earlier, GreenSock's TimelineMax was used in order to control each polygon shape.

I started with my initial setup for TimelineMax involving a few variables like the config (tmax_options) and the timeline constructor (TimelineMax()).

var tmax_options = {
  delay: 0.25, // init pause time
  repeat: -1, // make it repeat
  repeatDelay: 0.25, // delay this amount on repeat
  yoyo: true // also play sequence in reverse
};

var tmax_tl = new TimelineMax(tmax_options);

Based on the config represented as an object literal, the lion sequence is delaying the initial play state by 0.25 seconds, repeating the animation, delaying the sequence by 0.25 seconds on playback and finally setting the yoyo value to true so the polylion sequence animates in reverse.

Setup

For the remaining bits of my setup I define a few variables for reference at a later point in my code.

var svg_length  = $('svg.polylion > polygon').length,
    svg_shapes  = [],
    stagger_val = 0.00475,
    duration    = 1.5;

The only way to count the number of polygons dynamically was with JavaScript and that's exactly what we're using (we query for them all, then count the length of the set it returns). The svg_shapes variable is just an empty array that I'll explain in more detail momentarily. The rest is for easier config that defines how long the entire animation duration lasts in seconds and the amount I want each polygon to stagger by during playback.

Since the first argument of TimelineMax can be an array of elements I count each one within a loop and push the results into the empty array we created earlier. Also note we're grabbing each polygon individually using the :nth-of-type CSS selector.

for (var i = 1, l = svg_length; i <= l; i++) {
  svg_shapes.push($('svg.polylion > polygon:nth-of-type('+ i +')'));
}

The rest of the config is standard settings stuff, but this is where the magic happens. Our first object literal holds the CSS properties and values we'd like the object to animate from and the second object literal are the properties we're animating towards. What really makes this whole thing pop is the Elastic easing that gives the piece it's subtle bounce.

var stagger_opts_from = {
  css: {
    scale: 0,
    transformOrigin: 'center center',
    opacity: 0
  },
  ease: Elastic.easeInOut,
  force3D: true
};

var stagger_opts_to = {
  css: {
    scale: 1,
    opacity: 1,
  },
  ease: Elastic.easeInOut,
  force3D: true
};

Now we can attach the TimelineMax staggerFromTo method to our TimeLineMax constructor reference in order to give the lion it's life force.

tmax_tl.staggerFromTo(svg_shapes, duration, stagger_opts_from, stagger_opts_to, stagger_val, 0);

Literally one line gives this artwork life. The result is magical!

Yeah, but this is "CSS-Tricks" not "JS-Tricks"

I hear ya. We still would probably use JavaScript to count the polygons, but once we know that, we can create a loop using a pre-processor like Sass, LESS or Stylus to do the work. Let's try using the powers of Sass and this lion created by Jord Riekwel (@Larkef) for the Polyon project I previously mentioned.

Here's an example of the Polyman TimelineMax animation above using only CSS for the effect.

@keyframes polyonlion-animation {
  to {
    transform: scale(1);
    opacity: 1;
  }
}

svg.polyonlion > g polygon {
  animation: polyonlion-animation 400ms linear 1 forwards;
  transform: scale(0);
  transform-origin: center center;
  opacity: 0;
}

Here's another cool effect using the same approach above, but making use of different transformations on the polygons (a slight scaling and rotation).

After working through a few revisions, here's the final result we ended up with below.

See the Pen Polyon SVG Lion by Dennis Gaebel (@grayghostvisuals) on CodePen.

In order to obtain the numbers for my loops in Sass I used JavaScript to count the length of the polygons that existed. I also went through by hand to separate the mane from the face so we could control those sections independently. I took each polygon element relating to the face along with the mane and grouped them within a <g> tag. You can see for yourself in the HTML output of the haml in the pen above. As I was saying, in order to count the length of the polygons I used JavaScript which looked like this…

var polygon_mane = $('svg > g#polyonlion-face polygon').length;
console.log(polygon_mane);

Now that I have the count for the face I can do the same for the mane. My resulting values are 26 and 76 making the overall polygons total 102 (76 + 26 = 102).

$polyonlion-count: $polyonlion-count-mane + $polyonlion-count-face; // reports 102
$polyonlion-count-mane: 26;
$polyonlion-count-face: 76;

As outlined above, we define the count values as variables for reference. The next steps are defining a few properties for the SVG itself and setting up the animations @keyframes call.

@keyframes polyonlion-animation {
  to {
    transform: scale(1);
    opacity: 1;
  }
}

svg.polyonlion {
  width: 98px;
  height: 115px;
}

A few things like width and height are set and we also configure an animation that states "go from the currently set properties in the declaration to these property values indicated here."

The next steps are to remove the object entirely from view initially (i.e make invisible). The scale transformation and opacity values used in the code that follows are shrinking and hiding the polygons in order to make the lion invisible. We're also saying we'd like the point of origin to be the direct center of the polygons themselves when they transform. This essentially breaks down to the object animating from the center of themselves outwards.

.polyonlion {
  width: 98px;
  height: 115px;

  > g polygon {
    transform: scale(0);
    transform-origin: center center;
    opacity: 0;
  }
}

To make one final polish to the block above I'll add a couple more lines for a fallback in case JS is turned off or the animation property has no support. For this task I'm using Modernizr and it's feature classes placed on the HTML tag.

.polyonlion {
  width: 98px;
  height: 115px;

  > g polygon {
    transform: scale(0);
    transform-origin: center center;
    opacity: 0;

    .no-js &,
    .no-cssanimations & {
      transform: scale(1);
      opacity: 1;
    }
  }
}

Now we need to delay the polygons for the lion's face slightly from one another and also do the same for the mane. To do both tasks we need two loops since our count differs (76, 26). We also need to multiply the animation delay by the count of the polygons on each loop iteration giving the animation a bit of randomness.

@for $i from 1 through $polyonlion-count-face {
  .polyonloaded .polyonlion > g#polyonlion-face polygon:nth-of-type(#{$i}) {
    animation: polyonlion-animation 100ms linear 1 forwards;
    animation-delay: 0.0275s * $i; // 0.0275s * 1, 0.0275s * 2, etc.
  }
}

@for $i from 1 through $polyonlion-count-mane {
  .polyonloaded .polyonlion > g#polyonlion-mane polygon:nth-of-type(#{$i}) {
    animation: polyonlion-animation 100ms linear 1 forwards;
    animation-delay: 0.0475s * $i; // 0.0475s * 1, 0.0475s * 2, etc.
  }
}

You may have noticed I used a class called polyonloaded. This class controls the loading of the animation and execution once the DOM loads. Essentially I wait until the DOM is loaded then run a setTimeout for 900ms and finally place a class on the body that triggers my animation sequence. All that looks like this in jQuery:

$(document).ready(function() {
  setTimeout(function() {
    $('body').addClass('polyonloaded');
  }, 900);
});

Parting Thoughts

I can't stress enough how cool SVG is these days, but I'm sure you already know that. It's pretty crazy as the bar gets higher and higher in the community or on places like CodePen that really examine the powers of SVG in regards to animation. When you have some free time definitely checkout my collection on CodePen where I've been gathering my favorite SVG animations. You can always checkout the developers on CodePen as well that are creating mind-bending movements with SVG daily.

Other References

Here's some YouTube videos on creating poly art in Photoshop: