Skip to content
animorio
IT
Back to the library

The leading transition

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

A minimal page change: every line of the page stands on its own thin baseline. On a click the leading closes, the lines slide one after another onto a single vermilion baseline and flatten into it; out of the same line the lines of the new page open again, set with more room, and settle on a spring. Then the line runs back to the left margin, like a carriage return.

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 leading transition</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/standard.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <!-- the bar and the foot stay put: only the lines of the page change -->
    <header class="bar">
      <span class="brand">Reglet</span>
      <nav class="nav" aria-label="Pages">
        <a href="#essays" data-go="a" data-nav="a" aria-current="page">Essays</a>
        <a href="#about" data-go="b" data-nav="b">About</a>
      </nav>
    </header>

    <!-- the first page, set close: every line stands on its own baseline (the script draws the guides) -->
    <section class="page page--a is-on" data-page="a" aria-label="Essays">
      <div class="col" data-col>
        <div class="row row--kicker" data-row><span class="ink">Essays on type</span></div>
        <div class="row row--title" data-row><span class="ink">Set close,</span></div>
        <div class="row row--title" data-row data-anchor><span class="ink">read slow.</span></div>
        <p class="row--text" data-lines>Short pieces on type, paper and the space between the lines.</p>
        <div class="row row--link" data-row>
          <a class="go ink" href="#about" data-go="b" data-autoclic>
            <span class="go__text">Read about Reglet</span>
            <span class="go__arrow" aria-hidden="true"><span class="go__shaft"></span><svg class="go__head" viewBox="0 0 8 12"><path d="M1.5 1.5 6.5 6l-5 4.5"/></svg></span>
          </a>
        </div>
      </div>
    </section>

    <!-- the second page, set with room: its lines open out of the same baseline -->
    <section class="page page--b" data-page="b" aria-label="About" aria-hidden="true" inert>
      <div class="col" data-col>
        <div class="row row--kicker" data-row><span class="ink">About Reglet</span></div>
        <div class="row row--title" data-row><span class="ink">Room to</span></div>
        <div class="row row--title" data-row data-anchor><span class="ink">breathe.</span></div>
        <p class="row--text" data-lines>A small press for slow readers. Four essays a year, printed on paper that takes the ink well.</p>
        <div class="row row--link" data-row>
          <a class="go go--back ink" href="#essays" data-go="a" data-autoclic>
            <span class="go__arrow" aria-hidden="true"><svg class="go__head" viewBox="0 0 8 12"><path d="M6.5 1.5 1.5 6l5 4.5"/></svg><span class="go__shaft"></span></span>
            <span class="go__text">Back to the essays</span>
          </a>
        </div>
      </div>
    </section>

    <!-- the one baseline every line falls onto -->
    <div class="rule" data-rule aria-hidden="true"></div>

    <footer class="foot">
      <span>A small press</span>
      <span>Printed in short runs</span>
    </footer>
  </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.

29 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 leading transition” from Animorio and fit it into my site

What it does

The site of a made-up small press, Reglet (a reglet is the strip of wood a printer puts between one line of type and the next), in two pages and almost nothing else: a paper-coloured background, a big title on two lines, a line of text, a link, and under every line its own thin grey baseline. The first page is set close, Set close, read slow.; the second with room, Room to breathe. On load a vermilion line widens out from the middle and the lines of the first page open out of it. A click on Read about Reglet starts the vermilion line at the point you clicked and runs it out to the margins, on the baseline of the title's last line; the baselines darken and the leading closes: first the title's last line squashes onto its baseline, then the others come down or up one after another, speeding up, and just before they touch the line they flatten, turning wide and light. Each line that lands knocks the vermilion line down a pixel and back, and makes it a touch heavier. It stays alone for a moment. Then out of the same line the lines of the new page open, the farthest first: they run to their place, pass it by two pixels and come back, and meanwhile rise from flat to full height, wide and light, tightening on a spring into their own width and weight. The last to appear is the title line standing on the baseline, breathe.; then the vermilion line runs back to the left margin like a typewriter carriage and only the grey baseline is left. A click on Back to the essays does the same the other way round.

How it works

One line, one baseline

Every line is a .row div holding an .ink span (the text) and a one-pixel .guide line, which the script places exactly at the baseline: the baseline is measured with an empty span sitting on it. The paragraph is only a source: the script wraps each word in a span, groups them by offsetTop and builds one .row for every line the browser set, again on every resize. The column moves so the baseline of the title's last line falls exactly at RULE_AT of the height.

Squashing onto the baseline

The .ink span is an inline-block whose transform-origin sits on its own baseline (worked out in pixels for each line): so scaleY towards zero squashes it onto its baseline, not towards its middle. Two variables change with it, --w for font-stretch (Roboto Flex runs from 25 to 151) and --t for the weight, with font-weight: calc(var(--wt) - (var(--wt) - 110) * var(--t)): lying flat, the line is WIDE and light.

The leading closes

For every line the script knows dy, the distance between its baseline and the shared line. The lines leave nearest first, GAP seconds apart, and travel to dy with power3.in, so they speed up into the knock; the second half of the trip squashes them with power2.in. Leaving earlier, the near ones land earlier and none overtakes another. At each landing the vermilion line drops KNOCK pixels in 0.05 seconds and comes back with elastic.out(1, 0.35), and scaleY makes it a little heavier.

The leading opens

The new page is already underneath, its lines squashed onto the line. They open farthest first: that way a rising line never passes through one already standing, and the title line sitting on the baseline is born last. Each line runs OVERSHOOT pixels past its place with expo.out and comes back on an elastic; scaleY reaches 1 with back.out(1.5), --w and --t come back with elastic.out(1, 0.6), and the line tightens and gains weight with a small bounce. The grey baselines light up, then cool down.

Direction, phone and reduced motion

Each change is one timeline: the line is drawn from the click with x and scaleX (left end and length), then fold, then open, then the run back to the margin with expo.inOut; timeScale is SPEED. A click that comes while the page is changing waits in a queue. The hidden page carries inert and aria-hidden. The measures are taken again on every resize and the title fits the width. With reduced motion the pages swap with a fade, with no line and nothing moving.

Values to change

NameFileDefaultWhat it changes
RULE_ATscript.js0.56Where the shared baseline runs, from the top: 0.5 is the middle, 0.45 higher, 0.65 lower.
FOLDscript.js0.62The seconds each line takes to slide onto the baseline and flatten.
OPENscript.js0.9The seconds each line of the new page takes to open out of the baseline.
GAPscript.js0.055The seconds between one line and the next, closing and opening: 0 = all together.
WIDEscript.js140How wide a line is when it lies flat (font-stretch in %): 100 = no change in width.
OVERSHOOTscript.js2How many pixels a line runs past its place before it settles back: 0 = it just stops.
KNOCKscript.js1How many pixels the baseline dips each time a line lands on it: 0 = it stays still.
SPEEDscript.js1The speed of everything: 2 is twice as fast, 0.5 half as fast.

Try them in the Playground

When to use it

To move from one page to another on a site where the type does all the work: a magazine, an essay blog, a small publisher, a type foundry, a design studio, a portfolio. It suits pages made of text best, where the lines themselves become the transition.

On phones

The same transition with the sizes adapted: the title shrinks to fit the width of the screen, the text wraps onto more lines and each line closes and opens on its own. A tap on the link sends the page back and forth.

With reduced motion

Nothing moves and nothing squashes: the old page fades out and the new one fades in with its lines already in place; the vermilion line does not appear.

Pitfalls

  • Opening the new page nearest line first, the lines rising out of the baseline passed squashed through the title already standing and left a grey streak across its letters: they open farthest first, and the title line sitting on the baseline is born last.
  • The baselines are absolutely positioned and the browser paints them over the text in normal flow, cutting through the descenders (the p, the comma): the .ink span has position: relative and the line is the row's first child, so it sits underneath.
  • A paragraph that wraps cannot be squashed line by line: it has to be split into real lines by measuring where each word falls, and rebuilt on every resize because the lines change.
  • Lying flat and WIDE, a long line runs out of the column and could widen the page: the stage has overflow: hidden, and at that moment the line is less than a pixel tall anyway.
  • A click that comes halfway through the change (the previews' autopilot clicks every 2.8 seconds) would start on top of a timeline still running: it waits in a queue and goes as soon as the timeline ends.

Libraries

GSAP 3.15.0, Roboto Flex (font variabile) 5.3.0.

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

Testing

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