Today we’d like to show you a fancy little lettering animation made with SVG and anime.js. The idea is inspired by Jake Bartlett’s gorgeous opening animation for the “Shading Letters in Illustrator” Skillshare class by Jamie Bartlett. While we didn’t do any shading, we wanted to animate the stroke of each letter multiple times to achieve a similar effect.

Although this animation is nowhere near as beautiful as the Dribbble shot, we wanted to try to make the main concept work. And the trick for this effect is to have several layers of each letter. Every single stroke gets animated while adding a slight delay to each, creating the desired effect. Moreover, each letter has a little bouncy motion.

Attention: This is highly experimental and might not work as intended in older browsers.

Note that for this SVG lettering effect the type needs to be made of single strokes, hence our typographic construct cannot be made of shapes or normal “outline” letters (it can of course, but it will be a different effect). A great resource for single stroke glyphs is “Path Type” by Sivioco and Vintage Design Co.. Alternatively, you can get creative and draw your own type. However, keep in mind that there might be adjustments necessary depending on which stroke ending you are using (stroke-linecap).

Building the HTML

When looking at Jake’s opening animation, we can see that each letter gets drawn three times. Hence, for us technically, we need to have the same path tripled. In order to make things look nicely and not broken, we also need to consider that some letters should have their different parts animated separately. For example, the “L” in our Wilder Mind example is made of two parts, the vertical and the horizontal line. Given all these conditions, we come up with the following markup structure:

<svg width="100%" height="100%" viewBox="0 0 320 180" class="letters letters--effect-1"> <!--W--> <g class="letter letter--1"> <g class="letter__part"> <path class="letter__layer color-6" d="M25,39.7l22.4,51l7.9-32.2L76.2,84l1.3-61.2" /> <path class="letter__layer color-1" d="M25,39.7l22.4,51l7.9-32.2L76.2,84l1.3-61.2" /> <path class="letter__layer color-2" d="M25,39.7l22.4,51l7.9-32.2L76.2,84l1.3-61.2" /> </g> </g> <!--I--> <g class="letter letter--2"> <g class="letter__part"> <path class="letter__layer color-6" d="M100,20.3l8.4,58.4" /> <path class="letter__layer color-2" d="M100,20.3l8.4,58.4" /> <path class="letter__layer color-3" d="M100,20.3l8.4,58.4" /> </g> </g> <!--L--> <g class="letter letter--3"> <g class="letter__part"> <path class="letter__layer color-6" d="M126.4,70.8l27.6,0.5" /> <path class="letter__layer color-3" d="M126.4,70.8l27.6,0.5" /> <path class="letter__layer color-4" d="M126.4,70.8l27.6,0.5" /> </g> <g class="letter__part"> <path class="letter__layer color-6" d="M128.9,15.6l-2.3,60.2" /> <path class="letter__layer color-3" d="M128.9,15.6l-2.3,60.2" /> <path class="letter__layer color-4" d="M128.9,15.6l-2.3,60.2" /> </g> </g> <!-- ...and so on --> </svg>

We added some classes that will help us identify the SVG, each letter, the letter parts and the layers. Like this we can define colors and effects for each example.

Some styling

We just need a couple of styles for the SVG and the paths. It’s important to note that we are using the “butt” value for the stroke-linecap property so that our path lines start where the path starts and not before (as it would be the case with “square” or “round”).

/* Main SVG */ .letters { position: relative; display: block; min-height: 400px; max-height: 70vh; margin: 0 auto; } /* Letter path */ .letter__layer { fill: none; stroke-miterlimit: 3; stroke-linecap: butt; stroke-linejoin: bevel; } /* Styles for effect 1 */ .letters--effect-1 .letter__layer:first-child { stroke-width: 9px; } .letters--effect-1 .letter__layer:nth-child(2) { stroke-width: 9.5px; } .letters--effect-1 .letter__layer:nth-child(3) { stroke-width: 10px; } /* Effect 1 colors */ .color-1 { stroke: #dea521; } .color-2 { stroke: #f84242; } .color-3 { stroke: #3758a7; } .color-4 { stroke: #f79c8c; } .color-5 { stroke: #84b5bd; } .color-6 { stroke: #feefde; }

The strokes for each layer in our first example are set a bit fatter for each new layer so that we don’t see any ugly outline shining through.

The Action

For the animations we are using anime.js which allows us to easily set animation properties and handle the different types of animations that we have. Particularly, we have two main types of animations: the motion of each letter group (incoming and outgoing) and the stroke animation. The stroke animation is done as usual with setting the stroke-dasharray and the stroke-dashoffset to the length of the path in order to hide it and then setting the stroke-dashoffset to 0 in order to draw the path.

Another little trick that we do in order to have a smoother look of the layers, is the opacity animation of the lower layers. This ensures that once the lower layers get drawn, they disappear, leaving no jagged edges behind.

Phrase.prototype.options = { // If true, all the layers/paths of each letter part (except the last one) will animate the opacity to 0. // With this, we avoid any overlapping path behind the last one to be shown. pathOpacityAnim: false, // The animation settings for the ´out´ animation (when we click the button and the letters disappear). We are using the anime.js lib so the syntax is the same. outAnimation: { translateY: [0, 15], opacity: [1, 0], duration: 250, easing: 'easeInOutQuad' }, // The animation settings for the ´in´ animation (when the letters appear again). inAnimation: { properties: { translateY: { value: [-30, 0], duration: 900, elasticity: 600, easing: 'easeOutElastic' }, opacity: { value: [0, 1], duration: 500, easing: 'linear' }, }, delay: 40 // delay increment per letter. }, // Stroke animation settings pathAnimation: { duration: 800, easing: 'easeOutQuint', delay: 200 // delay increment per path. } };

We hope you enjoy this little experiment and find it inspiring!

References and Credits