Leverage Branding Triangle Email Icon Map Marker Icon Twitter Icon Instagram Icon LinkedIn Icon Facebook Icon Pinterest Icon Brand Strategy + Planning Icon Print Icon Digital Marketing Icon Search Icon Events Icon Social Icon eCommerce Icon Design + Development Icon Video Icon

Handwriting Animation Tutorial

Headshot of the Author Drew Hagni

Demo: codepen.io/drewhagni/pen/wvQXKKW


  • GSAP (basic knowledge)
  • Adobe Illustrator (intermediate knowledge)

Required tools:


  • Text is not readable by bots as it is converted to SVG shapes
  • Illustrator is the only program I’ve successfully done this in. Figma should be able to do it, but it handles clipping masks differently, so it caused issues for me.

Handwriting animation for script style fonts is not only possible, but if given enough time and patience can add a new level of production quality to your next project. You only need a basic understanding of GSAP and (honestly, quite a bit of) patience to set everything up in Illustrator.

Surely someone has already made a plugin for this, right?

There are plenty of animation libraries out there for animating more traditional serif/sans-serif fonts. In that case, you’re most likely looking for some sort of typewriter effect, which essentially comes down to targeting individual characters and animating them each separately. But when it comes to animating script/handwriting style fonts, you may come up a bit short when it comes to ready-made tools.

If Googling has led you here, you may have encountered Vara during your exploration. On paper, this is the perfect solution, but for me, even after several hours of trial and error in the bizarro world of Inkscape (don’t ask me why… they recommend it for some reason), I simply couldn’t get it to work correctly. If you want to animate anything other than the 4 or so fonts that come out of the box with Vara, it involves a pretty wild process of setting up your font in ASCII format with a baseline, renaming layers, saving as SVG, and uploading to their proprietary web program to convert to JSON… And that’s where it broke down for me. No matter my configuration, the program was not detecting the characters in my font correctly.

My best guess is that the font I was attempting to use just didn’t play nice with what their program expects. I think it’s looking for basic line-like shapes that it can convert to paths and my stylized brush font probably didn’t fit the mold. Who knows.

Pull yourself up by your own boot sock-straps

Okay, so that’s not going to work; let’s go back to the drawing board. If you’re like me, the drawing board (at least when it comes to animation) is GSAP. You’ve likely already encountered the DrawSVGPlugin, but maybe wrote it off after learning it only can animate the stroke of a path, which makes sense if you think about what it’s doing under the hood. In execution, this means you can only animate the outline of a font—a pretty specific use-case.

What you may not have considered is that with a clever use of clipping-masks and some fat stroke widths you can still leverage the DrawSVGPlugin to give the illusion of animating any text to look like it’s being handwritten.

So without further ado, let’s dig in.


Step 1 – Set the stage

You’ll obviously need to have your font selected before you can do anything. Technically you can apply this effect to any font you’d like, but handwriting animation of this sort works best with—you guessed it—handwriting fonts. Generally any script font will look decent, but since we are attempting to give the illusion of handwriting the font families that are more “buttoned up” and formal may not look as convincing.

This isn’t a sponsored post, but I really like Creative Market’s handwriting font selection. I’ve always had a good experience finding and using fonts from their library. Their search is great and you can get really specific with the various tags attached to each font.

While you’re practicing though, you may want to grab a free font from Dafont’s handwriting or brush font libraries. Of course if you plan on using a font in production, please purchase a license through legitimate means.

We won’t need this for a while, but might as well set it up now. For small sandbox-type tests like this, I usually reach for Vite. You just need Node JS installed on your machine and then you can follow their Getting Started instructions to get up and running. It’s real simple and real fast.

I just set it up as Vanilla JS. No bells or whistles needed for this one.

You can install Sass, Tailwind or whatever else you like to improve your dev experience. The only real dependency here though is GSAP with bonus plugins. Check out their installation page to include it in your project. The bonus plugins are only available if you’re a Club Greensock member.

Next, we’ll need to jump into Adobe Illustrator. This is where we’ll spend the brunt of our time. Your artboard here can be whatever you want for your project, but to keep things simple, I just set it up as a standard 1920x1080px white canvas.


Step 2 – Yer a designer, ‘arry

I won’t spend long on this step as typography & design are outside the scope of this tutorial. By way of quick synopsis though, you’ll want to type out your phrase with your handwriting font selected and tweak it to your heart’s content.

And by “heart’s content” I mean pretty much anything. You can type on a curved path, adjust tracking and kerning, skew it, warp it, resize words or characters—whatever you want. We’ll be converting it all to paths and exporting as SVG in the end, so there aren’t really any limitations besides your own patience with prepping everything for the clipping masks. You’ll see what I mean in a minute.

Once you’re satisfied with your design, go ahead and duplicate it (just in case) and then convert your type to outlines (Object > Expand).


Step 3 – Wrap your head around it

Okay, so before we proceed, we have to fully grasp what we’re attempting to do here:

  • We are going to draw the path (line) of each letter, essentially trying to follow the center “spine” of each character because we know that GSAP can animate that path using the DrawSVGPlugin.
  • Obviously that path alone won’t look anything like our font, but what we can do is scale the stroke width up beyond the boundaries of our font’s shapes and then use our font as a clipping mask on top of the path.
  • Then we can import the SVG with all of its clipping magic intact and target just the paths we drew in our GSAP animations.


Step 4 (optional) – Divide and conquer

This step is technically optional. If you’re just curious about how this idea works conceptually and want to experiment a bit, feel free to skip this one—it’s definitely the most labor intensive. If, however, you are intending on including your completed piece into production, I would recommend taking the extra time with this step to make the animation as convincing as possible.
In order to prevent our animation from filling parts of the character mask prematurely, we need to start slicing up our lettering into separate pieces. There are a few things I consider when deciding where to break up a character shape:

  1. If I were writing this by hand, where would I lift my pen or brush? A lowercase “d” or “p” for instance has a natural stopping point after you finish the ascender/descender stroke, so I would break it into its ascender/descender and its bowl. Would you actually lift your pen when writing a “p” or a “d” normally? Probably not, but try to think like a calligrapher who is being extremely precise in where they are placing each stroke. Also, as a side note, you’re much more likely to have issues not having enough individual shapes rather than having too many.
  2. Does the stroke width change drastically within the character? With handwriting fonts, this tends to happen quite a bit; it’s what gives these fonts their unique handwriting quality. That’s all well and good except when we’ve scaled up our stroke width to 50pts so that it can expand beyond that fat downward stroke of our font and then it all of a sudden thins out to a few millimeters and double backs on itself. If you proceed as normal and have a single stroke width for the entire character you inevitably will fill parts of the mask unintentionally as it animates and break the illusion we’re trying to achieve.
  3. Speaking of doubling back, does the letter have any pesky loops? If you have a character with loops and therefore overlapping paths, you’ll likely need to make careful incisions to ensure that as we animate our stroke it doesn’t fill other parts of the shape prematurely.

If you’re worried that too many pieces will make the animation look choppy, fret not. We’ll be able to smooth all of it out with the right timing parameters in our code later. Rule of thumb: If in doubt, break up.

Okay, but quick question… how?

Well this is starting to tap into that “intermediate” part of Illustrator skills required. Don’t worry though, with enough patience anyone can pull this off.

What I typically do is clone the shape, then I’ll use the “Pen – subtraction” tool (shortcut: “P”, “-”) to delete each node one at a time. Once I’ve removed all of the unnecessary nodes.

Pro-tip: Clone anything you plan on changing first so you have a point of reference and you don’t have to CMD+Z ad nauseam if you mess up. Also, since you’re splitting shapes into multiple other shapes, you’ll need at least 2 objects to begin with.

Technically, you can do this faster using the “Direct Selection” tool (shortcut: “A”) to delete multiple nodes simultaneously. Keep in mind though, that this method will actually break the path of the shape in question and you’ll need to rejoin the path at the end using the normal “Pen” tool.
Occasionally, you’ll need to “massage” the shape a bit to get it to match the original font shape better. This means using the “Pen”, “Direct Selection”, and “Anchor Point” tools to modify the shape path as needed. Keep in mind that where the shapes will connect again, feel free to allow them to overlap a bit. An overlap is always preferable to a gap.

Rinse and repeat for each piece of your letter and then put them back together to form the original shape. And on to the next letter—isn’t this fun?


Step 5 – Line it up

Alright, we’re really getting into it now. Now we need to draw our paths that GSAP will animate.
Go ahead and lock all of the shapes on your artboard (shortcut: “CMD + A”, “CMD” + “2”), grab your pen tool, set your stroke to 1pt, red (or whatever width/color works best for you) and start drawing.

You’ll generally want to try to stay in the center “spine” of each character as you draw. Don’t worry about being exact though, we’ll adjust things as we go. Remember, each piece you sliced should have exactly one path drawn on top of it.

Pro-tip: If you’re not familiar with the “Pen” tool, don’t worry about getting it right the first time. Use the add/subtraction modifiers to modify nodes as you go. You can also use the “Anchor point” and “Direct Selection” tools to create/modify curves as needed.

Repeat until you’ve got a path laid for each piece of each letter. Now select all of your paths and change the stroke width to like 30pts, adjust to taste depending on your chosen font. We want the minimum stroke width to cover up every shape in its entirety. You’re probably seeing some sharp corners and even the widest stroke still will have trouble covering the start of many characters. Go ahead and add rounded caps and curves to smooth things out a bit.

Lovely, right?

If you can see through your blob, and identify which strokes can be scaled down, feel free to do so to your liking. Just make sure the underlying artwork is still completely concealed.


Step 6 – The Masquerade

Okay, this is where it can get a bit tricky to keep track of everything because everything is stacked on top of everything else. I would recommend tackling each piece one at a time. Use your “Layers” panel to lock or hide things you’re not working on to keep things in focus.

First unlock all items in your workspace (shortcut: “CMD A”, “Option” + “CMD” + “2”). To create the clipping mask correctly, we need our artwork on top of the stroke.

To do this, find a way to select the piece you want to use as a mask. Either temporarily lock the stroke on top or sometimes if you move your mouse to the right position you’ll be able to select the shape outline. Then use the “Layers” panel or keyboard shortcut to move it to the front (shortcut: “CMD” + “Shift” + “]”)

Now, select both the shape and the path we drew. If you used the temporary lock method, make sure to unlock it again before trying to select both objects. With both selected, create a clipping mask of the two objects (shortcut: “CMD” + “7”).

The result should look exactly like your original slice of lettering except red (or whatever color you chose when we were drawing our paths in the previous step).

Repeat this process for each piece of each letter until it’s complete.

Lastly, go ahead and select all of your paths and change their color back to something sensible, like black or gray. If you need the artwork to be white, you can change your view to outlines to be able to keep working on it without switching back and forth (shortcut: “CMD” + “Y”). This is likely unnecessary, however, as you can modify the colors in the code later.


Step 7 – It’s a naming convention

Okay, one more quick step in Illustrator. We need to group our elements and name them so we can get really specific with our animations if needed.

Click and drag to select each character as a whole (all pieces together) and group them together (shortcut: “CMD + G”).

Now open up your “Layers” panel and rename each group according to its letter. Something like: “character-T”. If you have more than one of the same character in a word, you’ll want to throw some numbers in there or something to keep everything distinct.

You’ll also want to drill down into each of these groups to rename their containing mask groups. Something like “character-T-2”.

Pro-tip: Are your layers in the exact opposite order? Perfect! Keep it that way. When you export as SVG these layers will flip their order—don’t ask me why.

At this point you can “Save As…” and select “SVG” as the filetype (I always just keep the default SVG parameters). I would recommend saving into your project folder where your site files are stored in case you need to iterate on your artwork after the fact.

Take a break and celebrate the fact that we’re done with Illustrator (mostly).


Step 8 – Get in the code

Alright, now for the fun part. Open up your favorite text editor and pull up that monstrosity of an SVG file. Copy everything except the <?xml> tag & comment and paste it into whichever page you’d like. Check your browser to ensure your artwork is showing up correctly.

Now hop over to your main javascript file and make sure you’ve imported GSAP and imported/registered DrawSVGPlugin.

import { gsap } from 'gsap'
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin'

To see our hard work pay off quickly, you can run a simple stagger animation on the SVG paths. It might look something like this:

gsap.from('svg path', {duration: 0.2, drawSVG: 0, stagger: 0.1})

Look at that!

You’ll likely want to adjust the timing a bit. I’ve noticed that a stagger of about half of the duration feels about right for most scenarios.You can also try adding some different easing functions and see if it feels more natural.

Now, if you want to get even more granular you can set up a timeline and start targeting those IDs we set up in the previous step. From here we can get super specific on every single stroke and get closer to mimicking something similar to a calligrapher’s timing.

let animateTextTL = gsap.timeline({
defaults: {
duration: 0.25,
ease: 'power2.out'
.to('figure', {duration: 1, delay: 0.5, autoAlpha: 1})
.from('svg #character-W-1 path', {duration: 0.4, drawSVG: 0, ease: 'power2.in'})
.from('svg #character-W-2 path', {duration: 0.15, drawSVG: 0})
.from('svg #character-W-3 path', {duration: 0.3, drawSVG: 0, ease: 'power2.in'})
.from('svg #character-W-4 path', {duration: 0.15, drawSVG: 0, ease: 'power3.inOut'})
.from('svg #character-A path', {duration: 0.15, drawSVG: 0, stagger: 0.05})
.from('svg #character-N-1 path', {duration: 0.3, drawSVG: 0}, '-=0.1')
.from('svg #character-N-2 path', {duration: 0.15, drawSVG: 0}, '-=0.1')
.from('svg #character-N-3 path', {duration: 0.3, drawSVG: 0})
.from('svg #character-D path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #character-E path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #character-R path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #character-L path', {duration: 0.15, drawSVG: 0}, '-=0.1')
.from('svg #character-U path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #character-S path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #character-T path', {duration: 0.15, drawSVG: 0, stagger: 0.05}, '-=0.1')
.from('svg #underline path', {duration: 1, ease: 'expo.out', drawSVG: 0}, '+=0.5')
const restartBtn = document.querySelector('#restart')
restartBtn.addEventListener('mousedown', (e) => {

At this point it’s all finesse and feel. If you see something that feels off, slow everything down and zoom in and try to catch what’s going on. You may also want to hide all other characters except the one you’re looking at.

You may also notice an issue or two once you start animating. For me, I had a few problems:

  1. One of my strokes wasn’t animating. I realized it was because the path wasn’t a , it was a . This was due to me not including any curves or anything when I drew it in Illustrator originally. Rather than try to target both paths and lines in GSAP, I just went back into Illustrator and modified that path to have a slight curve.
  2. I somehow had one of my strokes animating the wrong direction. So I went back into Illustrator, drilled down into that clip-mask group and redrew the underlying path.
  3. My underline wasn’t animating, but I figured out that it got converted to a regular path (not a clip mask group), so I redid it in Illustrator.

You might notice all of my mistakes originated in Illustrator. If you have to make changes to your Illustrator file, as long as you saved to your site working directory, you can just click save again and copy over the code again from my SVG file. You can automate this process further using a tool like inline-svg if you’d like.

All in all, it’s a fairly simple process just a bit tedious—especially if Illustrator isn’t necessarily your forte. I hope this tutorial is helpful though if this is something you’ve been curious about or are attempting for your next project. Happy animating!

Full video timelapse: https://www.youtube.com/watch?v=TH2frl8VwhY

How can we help?

Start A Project

Beer Institute Demo

I looove a cold beer, so when the Beer Institute came calling for some support in building an interactive website, I was all in. Sneak Peek Here’s what we ultimately built…  The Ask Build an interactive beer glass where...

Read More
laptop with beer institute website on screen