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.

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.

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.

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:
Great article! Love your work Dennis!
Thanks Evan. Go forth and make awesome things :)
Great post! Just a heads up, this sentence “As I mentioned earlier, GreenSock’s TimelineMax was used in order to control each polygon shape and frankly” is cut off- just wondering what you were going to say.
I love working with GSAP and SVG as well- the timeline and stagger become really powerful and you showcased this well in the article. Nice work!
Thanks Sarah. Yeah…it’s pretty amazing what can be done w/a few lines of GSAP \o/
That is super awesome! Thanks for sharing Dennis!
You got it Tony \m/
In your original Codepen example, looping through the jQuery array is unnecessary. You can feed the native jQuery object to TimelineMax and save yourself some work.
Here’s a simplified example below.
Hey Colin. Nice spot. Yeah, it’s funny you say that because I was pouring myself a coffee this morning and thought the same thing. I don’t do it for Polyman so not sure why I did it here? Anyways…thanks again. Awesome catch!
So freakin cool – I get all the code parts, that all makes sense… I just have to teach myself how to do the art part… c’est la vie.
P.S. I really hate doing this, but there are quite a few “it’s” in the article. “It’s” is always “It is”, not the possessive “its”.
Killlller! There goes the talk I was going to have you give at the CodePen Chicago meetup…;)
lol! I actually have a ton more to add to this (development and creation of the artwork itself). I’m finishing up some final touches with the Polyon project plus Jack at GreenSock gave me some tips for improvements that are noteworthy for discussion. There’s still much to say about performance and animations in regards to these demos \o/
This is incredible. Fantastic job and thank you for the links! I hope this catches on more often in modern web design :)
I guess I need to make more :) Thanks for the kind words \m/ The linked videos are even super fun just to watch. Enjoy!
This is so cool! A friend of mine actually has this style of drawing. Time to wrap my head around this timeline max thingy and scan some of his drawings! Thnx for this great article/tut!
You got it…um…Dennis ;)
Fantabulous. keep it coming.
You got Arun! Here you go! http://codepen.io/grayghostvisuals/full/radeqX
You totally inspired me with this post! I spent last night drawing a low poly portrait of myself to use with the effect.
Whoops here is the CodePen
Wow! So awesome! You’ve inspired me to start a polygon animations collection. You should check it out…might recognize one in there ;)
Sick that’s Awesome!
Awesome! I really like it & thanks for sharing
Wow! Can you imagine my surprise when i saw my name on css-tricks? :D
Great article, dude :)
I’ve found that using some Delaunay triangulations tools can help make generating the polygonal version of the images easier. They don’t generate SVG, but can be used to create an SVG version a bit easier.
Or someone could modify the tools to generate an SVG output which would be awesome!
Bad. Ass.
Thanks for sharing.
http://www.vacib.info/
Thanks for the article – love it!
Check out this project og Github:
https://github.com/snorpey/triangulation
Thanks Thomas. I’ve never seen that project b4…so cool! Thanks for sharing it :)