Skip to content
animorio
IT
Back to the library

The line set by hand

Text, PhysicsGSAPMediumCompressed weight: Demo 9.6 KBGSAP 28 KBFreeDownload the zip

A sentence set as in a hand compositor’s stick, in the minimal style: the letters come in from the right one at a time, upside down, turn over in the air, touch down and slide home flush against the one before. The word spaces are thin red springs; at the end the springs let go one after the other and the line is justified exactly from edge to edge.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The line set by hand</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bodoni-moda@5.3.0/opsz.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage role="button" tabindex="0" aria-label="Good type takes time. Click to set the line again.">
    <!-- the composing stick seen from above: one hairline bracket (the knee on the left, the clamp on the right),
         the letters and the springs in the word spaces. One SVG, built by the script. -->
    <svg class="scene" data-scene aria-hidden="true">
      <g data-world>
        <path class="stick" data-stick d="" pathLength="1" />
        <g data-springs></g>
        <g data-letters></g>
      </g>
    </svg>

    <h1 class="sr-only" data-text>Good type takes time</h1>

    <p class="readout" data-readout aria-hidden="true">
      <span class="readout__label">Word space</span>
      <span class="readout__value" data-readout-value>0.25 em</span>
    </p>

    <p class="hint" data-hint aria-hidden="true">Click to set it again</p>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

15 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The line set by hand” from Animorio and fit it into my site

What it does

On ivory paper a thin line draws itself in the shape of a bracket: the left side, the bottom, the right side. It is the composing stick seen from above, and under it, on the right, a small caption says how wide the space between the words is (Word space 0.25 em). The letters of «Good type takes time», in a thin Bodoni, come in from the right one at a time upside down, turn over as they come down, touch down on the bottom a little past their place and a push sends them flush against the letter before. On the strike the letter squashes a hair, tips and straightens with a spring and gains weight for a moment; the letters of the same word feel the knock and give way by a pixel. The first letter strikes the left side, which shakes a little. When a word is done, a compressed red spring drops into the space, and the first letter of the next word strikes it: the spring gives and pushes it back. With all the letters home, a gap is left on the right: the springs let go one after the other, the words move apart and the last one reaches the right side, pushes it out a few pixels and comes back. The number below counts up to 0.90 em. Then the right side locks the line with a tap, the line tightens and a wave of weight runs from left to right. After a pause the letters lift and fade, the springs relax and the line is set again from the start. Pointing at a letter with the mouse makes it hop, turn over in the air and land back in its place; a click (or a tap) starts the setting again.

How it works

Flush letters, measured

Every letter is an SVG text with text-anchor middle: its origin is the middle of its advance, on the baseline. The advances are measured once with measureText on a canvas in the same face and weight, with kerning switched off both in the canvas (fontKerning) and in the SVG (font-kerning: none): added up, they put every letter exactly against the one before, like lead type in the stick. The word space is as wide as the face’s real space.

The strike is the metronome

The letters do not set off at fixed intervals: the moment of the strike keeps the beat, one letter every PACE seconds. Each letter’s flight is worked out backwards from there: the ones coming from far away leave earlier, the ones with a short way to go leave later. So the order of the strikes never breaks. The flight has two parts: the arc (power2.out across, power2.in down, the rotation from 180 to 0 degrees) and the final push, with power2.in, speeding up into the strike.

The strike and who feels it

On the strike the letter squashes sideways for 45 thousandths of a second and comes back with elastic.out, tips a few degrees and straightens, and its weight goes up by 140 and back. The letters of the same word give way by a pixel or two, more the ones nearer the strike, and spring back. The first letter of a word strikes the spring in the word space, which gives by a quarter and pushes it back; the first of the line makes the side of the stick shake.

Springs that justify

Every space is a number k from 0 to 1: its width is the real space plus k times its share of the gap left over. The words after a space move by the sum of the widths before them, so widening one spring moves everything to its right. The k values go to 1 one after the other with a damped spring written as an easing function (a dying cosine, corrected to end exactly on 1): GSAP’s elastic went a third past the edge. The spring drawn is an SVG zigzag, flatter as it widens.

One clock

Everything that moves is a number in an object: GSAP animates it inside one timeline per round, and a single function on the GSAP ticker turns it into transforms, weights, paths and opacities, writing to the DOM only what changes. The right side of the stick always stands where the longest line ends, if the line goes past it: that is why the last word pushes it out. On a phone, if the sentence on one line would be too small, it breaks into two or three lines of at least two words each.

Values to change

NameFileDefaultWhat it changes
TEXTscript.js'Good type takes time'The sentence set in the stick, letter by letter (up to 40 characters). It needs at least two words: the spaces are what justify the line.
MEASUREscript.js1.2How much wider the stick is than the line set tight: 1.05 leaves nearly normal spaces, 1.5 long springs and words far apart.
PACEscript.js0.13The seconds between one letter striking home and the next: lower is a burst, higher one letter at a time, calmly.
SPRINGscript.js1How springy the springs and the strikes are: 0.3 settles dead, 2 wobbles for longer and pushes the right side further out.
WEIGHTscript.js540The weight of the letters once home, from 400 to 900; in flight they are at 400, the lightest the face goes.
HOLDscript.js2.4How many seconds the justified line stays before the stick is emptied and set again.
LOOPscript.jstrueWhether the line is set again and again. With false it stays still, justified.

Try them in the Playground

When to use it

For the opening headline of a site about care and craft: a print shop, a bindery, a type foundry, a design studio, a magazine, a publisher, a maker. It works with short sentences of three or four words: the springs in the spaces say it on their own.

On phones

The same animation: if the sentence on a single line would be too small, it breaks into two lines (Good type, takes time) inside the same stick, and each line is set and justified before the next. A tap starts the setting again.

With reduced motion

Nothing flies and nothing bounces: the stick, the line already justified with its springs and the caption fade in and stay still. A click fades the line out and back in; no repeat and no hop of the letters under the pointer.

Pitfalls

  • With departures at fixed intervals, the letters near the right side, which have a short way to go, would arrive before the ones that left from far away and pass through them. The fixed beat has to be given to the strike, and the departure worked out backwards from the length of the flight.
  • GSAP’s elastic.out overshoots by 2 to the power of −5 × period: with a period of 0.3 that is more than a third, and the last word would leave the stick by tens of pixels. The springs in the spaces use an easing function of their own, a damped cosine corrected to end exactly on 1, which overshoots by about a tenth.
  • A letter flying to a fixed point would jump a few pixels on arrival if the spring before it is still swinging from the previous letter’s strike. Its target in flight follows the same shift as the letters already home, so the move from flight to line is seamless.
  • The hop under the pointer and the emptying of the stick would animate the same properties (y, weight) and get in each other’s way if the pointer passes just as the pause ends. The hop uses numbers of its own (hy, hr, hw, hq) that are added to the timeline’s.
  • The hop under the pointer only works once the line is still: while it is being set the letters belong to the timeline. An automated test that passes over the letters before the pause sees nothing, and that is not a bug.

Libraries

GSAP 3.15.0, Bodoni Moda (font variabile, assi opsz e wght) 5.3.0.

Compressed with gzip, the three demo files weigh 9.6 KB; the libraries: GSAP 28 KB.

Testing

Tested on 14 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All animations