Skip to content
animorio
IT
Back to the library

The lone word that climbs back

TextGSAP, CSS onlyMediumCompressed weight: Demo 7.2 KBGSAP 28 KBFreeDownload the zip

A short ragged-right paragraph, in the minimal style, whose last word is left alone on the last line: the line above tightens by a hair on the width axis of the typeface, the word slides along under its place, climbs back to the end of the line and its full stop falls onto the edge of the column, in the accent colour.

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 lone word that climbs back</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-serif@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the column: two hairlines mark its edges; the script sets the paragraph inside, ragged right, with the last
         word left alone on its own line. Then the line above tightens on the width axis and the word climbs back -->
    <div class="measure" data-measure>
      <i class="guide" data-guide aria-hidden="true"></i>
      <i class="guide guide--right" data-guide aria-hidden="true"></i>
      <p class="para" data-para></p>
      <i class="span" data-span aria-hidden="true"></i>
      <p class="foot" data-foot>
        <span class="foot__brand">Quoin Press</span>
        <span class="foot__axis" aria-hidden="true">wdth <b data-wd>100</b></span>
      </p>
    </div>
  </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.

19 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 lone word that climbs back” from Animorio and fit it into my site

What it does

On ivory paper two very thin lines draw themselves from the top and mark the edges of a column. Inside, line after line, a ragged-right paragraph is set in a serif typeface: every word arrives narrow, rises a little and widens to its normal width on a spring, so the uneven right margin grows and settles. The last word, «alone.», is left by itself on the last line, and next to it a thin dimension line measures the empty run to the edge. Then the line above tightens, word after word, on the width axis (the space between the words stays the same), and below, on the right, the wdth value counts from 100 to 91. The lone word tightens too, slides along its empty line leaning a little into the run while the dimension line withdraws ahead of it, then hops up into the room left at the end of the line, lands one pixel past its place with a small squash and comes back; the words of the line feel the knock and give way by a pixel, from the last to the first. Last of all the full stop hops, turns red in the air and falls exactly onto the right edge of the column, which shakes by a pixel. The column gets a line shorter, the paragraph rests, then the words squeeze and leave in reading order, the edge lines withdraw and it all starts again.

How it works

A serif typeface that tightens

Roboto Serif has a width axis from 50 to 150 and weight from 100 to 900: the Fontsource «wdth» file keeps both and is light. Every word is an inline-block span with its own CSS variable --wd, and the CSS takes it to the axis with font-variation-settings: 'wdth' var(--wd), 'wght' var(--wg). GSAP tweens the variable directly ('--wd' in a tween), word by word.

The lines are set by the writer

The rag is not left to the browser: each line of the paragraph is an entry of LINES, a flex row that never wraps, with the word space measured once («n n» minus «nn»). So the last word is always left alone, at any window width, and on a phone the paragraph is the same, only smaller.

The column comes from the text

The width of the column is worked out from the lines: the longest one fills 95.5% of it, and the line above plus the lone word, at normal width, overrun it by 3.5%. Then the type grows until the column fits the window (40 px at most, 30 on a phone) and everything is measured again at the real size.

The width that mends the line

A binary search on the wdth axis (sixteen steps, measuring the real lines with getBoundingClientRect) finds the value that takes the line above plus the lone word exactly to the edge. What has to touch the edge is the ink of the full stop, not its box: the stop’s right side bearing is read on a canvas in the same typeface (measureText, width minus actualBoundingBoxRight) and left outside.

The direction

A single GSAP timeline that starts again: the words come in on a damped spring written as an easing function (BOUNCE), the line above tightens with a stagger, the lone word slides with power3.inOut and hops with power2.out and power2.in, then the one-pixel overshoot and the return; the full stop has its own tweens for the hop, the colour and the squash, and the right edge line a one-pixel knock. The edge lines and the note below get a line shorter on a soft spring.

Values to change

NameFileDefaultWhat it changes
LINESscript.js['Set the measure, mind the rag,', 'give each line the same quiet', 'colour, and when the text', 'runs short, never leave a word']The paragraph, line by line, ragged right. The longest line sets the column; the last one is where the lone word climbs back.
LASTscript.js'alone.'The word left alone on the last line: it climbs back to the line above and its last character falls into the accent colour.
WEIGHTscript.js380The weight of the paragraph, from 100 (a hairline) to 900 (black).
SQUEEZEscript.js62The width the words start from and go back to, on the wdth axis: 50 is the narrowest the typeface goes, 100 is normal.
BOUNCEscript.js0.35How springy the words are as they settle: 0 stops dead, 1 bounces a lot.
HOLDscript.js2.2The seconds the mended paragraph rests before it goes and starts again.
SPEEDscript.js1The speed of everything: 2 is twice as fast, 0.5 half as fast.
LOOPscript.jstrueWhether the paragraph goes and is set again from the start.
--accentstyle.css#e5432aThe colour of the full stop, once the word is back in its place.

Try them in the Playground

When to use it

For a page where writing and typography matter: the manifesto of a design studio or a publisher, the introduction of a personal blog or a magazine, the about page of a type foundry. It works with a short paragraph, four or five lines long, ending on a word worth looking at.

On phones

The same animation with the same lines: the column is as wide as the screen minus the margins and the type is measured again to fit (around 19 px on a common phone). The width that mends the line is searched again at the real size; if the window changes width the paragraph is set again from the start, if only the height changes (the address bar) it goes on.

With reduced motion

Nothing moves or widens: the edge lines and the paragraph fade in already at normal width, with the lone word on the last line. Then the last two lines fade out and fade back in already mended, with the word at the end of the line above and the full stop in red; at the end everything fades and starts again.

Pitfalls

  • The first version flew the word in an arc from its line to the end of the line above: halfway through it passed over «runs short» and the letters overlapped. Now it slides along its empty line, under its place, and hops up only once it is past the last word of the line.
  • With the width measured on the boxes of the letters the full stop stopped two and a half pixels short of the edge line: the box of a full stop has a blank margin on the right. The margin is read on a canvas (width minus actualBoundingBoxRight) and added to the measure to reach.
  • With the line above 6% longer than the column the mended line went down to wdth 83 and looked narrow next to the others; at 3.5% wdth 91 is enough, which barely shows and is what a real compositor would do.
  • A repeating timeline with fromTo tweens writes the starting values as soon as it is built: so the timeline has immediateRender: false in its defaults and a reset() at the start of every round, which puts every word back narrow and transparent.
  • The movement of the word goes on the line that holds it, not on the word: the word already has its entry and exit tweens on y and opacity, and two tweens on the same property of the same element would have trodden on each other. The lone line is as wide as the word (width: max-content), so the rotation turns about its middle.

Libraries

GSAP 3.15.0, Roboto Serif (font variabile, assi wght e wdth) 5.3.0.

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

Testing

Tested on 15 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