Skip to content
animorio
IT
Back to the library

The type scale

Scroll, TextGSAPMediumCompressed weight: Demo 7.0 KBGSAP + ScrollTrigger 45 KBFreeDownload the zip

Scroll inside the preview

A type foundry’s specimen, in the minimal style: as you scroll, a single word climbs the classical scale of type sizes, from 6 to 144 points, one click at a time with a hint of bounce. The optical size follows the size, so the letters are redrawn at every step, wide and open when small, tight and fine when large; a ruler measures the cap height and a vermilion dimension line counts the points.

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 type scale</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/full.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- the specimen of a made-up type foundry. Scrolling, one word climbs the classical scale of type sizes, from 6 to
       144 points, one click at a time; its optical size follows, so the letters are drawn again for every size: wide
       and open when small, tight and fine when large. A ruler on the left measures the cap height of every size -->
  <main>
    <section class="apertura">
      <p class="piccolo">Norrow Type, specimen</p>
      <h1 class="titolo">One word,<br>sixteen sizes.</h1>
      <p class="piccolo piccolo--tenue">Scroll to set it.</p>
    </section>

    <section class="racconto" data-racconto>
      <div class="palco" data-palco>
        <header class="testa">
          <p class="marchio">Norrow</p>
          <p class="piccolo piccolo--tenue">Optical sizes</p>
        </header>

        <h2 class="nascosto" data-nome>Margin, from 6 to 144 points</h2>
        <svg class="tavola" data-tavola aria-hidden="true"></svg>

        <p class="didascalia" aria-hidden="true">
          <span class="didascalia__riga" data-dida>Small: wide, open, loose.</span>
          <span class="didascalia__riga" data-dida>Text: steady and even.</span>
          <span class="didascalia__riga" data-dida>Headings: closing in.</span>
          <span class="didascalia__riga" data-dida>Display: tight and fine.</span>
        </p>
      </div>
    </section>

    <section class="apertura apertura--fine">
      <h2 class="titolo titolo--medio">Every size,<br>drawn for its size.</h2>
    </section>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/ScrollTrigger.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.

40 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 type scale” from Animorio and fit it into my site

What it does

The specimen of a made-up type foundry, Norrow, on a warm white with black ink and a single vermilion. After the opening the screen stops: on the black baseline, on the left, sits the word Margin at 6 points, tiny. On the left a thin ruler has one mark for every size of the classical scale (6, 8, 9, 10, 12, 14, 18, 24, 30, 36, 48, 60, 72, 96, 120, 144), set at that size’s cap height, with the numbers where there is room. As you scroll, the word rests for a moment on every size and then clicks to the next, goes a hair too far and settles; the mark just reached kicks out and back, the ones already passed turn grey. The optical size of the typeface follows the size: when small the word is wide, open and loosely spaced, with a tall x-height; when large it tightens, the x-height drops and the strokes get finer. Two grey guides, the x-height and the cap height, rise with the word; beside the word a vertical vermilion dimension line, with a tick at each end, runs from the baseline to the top of the capitals and the number of points counts between one size and the next. At the bottom a single line changes its sentence when the sizes change family: small, text, headings, display. At 144 points the word lands with a small elastic squash. Everything follows the scroll, forwards and backwards.

How it works

One SVG as big as the stage

The word, the three guides, the ruler and the dimension line sit in one SVG whose viewBox matches the pixels of the pinned stage (position: sticky, 100lvh tall). The word is a text element: x and y are its start on the baseline, so growing only means changing font-size, with no sums on the ascender. Its width, which also changes with the optical size, is read every frame with getComputedTextLength and puts the dimension line right after the last letter.

How many pixels a point is

On every ScrollTrigger refresh the script measures the word at 144 points on a hidden copy and decides how many pixels a point is worth: the biggest word must fit beside the ruler with room for the dimension line, and its capitals under the header. The ruler’s marks sit at the cap height of every size (0.708 of the size, measured on the typeface); a number is written only if it is at least 15 pixels from the one above, and marks closer than 3 pixels to their neighbour are left out.

Still, then the click

The timeline, tied to the scroll with scrub SCRUB, takes a single number s from 0 to 15: the whole part is the size reached, the rest how far into the step you are. For the first part of the step (HOLD) the size stays still, then it moves to the next one with the SNAP curve, a back.out that goes a hair too far and comes back. The number of points beside the dimension line counts between the two sizes but never goes past them, even when the word does.

The optical size and the x-height

Roboto Flex has an opsz axis from 8 to 144: the script sets it equal to the size in font-variation-settings, and the word redraws itself. The x-height, though, changes with opsz (from 0.53 of the size at 8 to 0.445 at 144): the x-height guide uses a small table measured on the typeface and interpolated, so it stays on top of the x at every size. The guides’ labels fade out when the guides get too close or when the dimension line reaches them.

Captions and landing

The caption at the bottom changes its sentence when the size passes 10, 18 and 48 points: the old one leaves upwards through an overflow hidden window, widening on the wdth axis, the new one rises from below narrow and opens up. At the top of the scale the timeline squashes the word from the baseline with an SVG transform and lets it come back with elastic.out.

Values to change

NameFileDefaultWhat it changes
WORDscript.js'Margin'The word to set: better short, with a letter that goes below the line.
SIZESscript.js[6, 8, 9, 10, 12, 14, 18, 24, 30, 36, 48, 60, 72, 96, 120, 144]The scale of sizes in points, smallest first: one step of the scroll per size.
WEIGHTscript.js400The weight of the word, from 100 to 1000.
OPTICALscript.jstrueThe optical size follows the size; with false the word stays drawn for 14 points and you can see the difference.
SNAPscript.js'back.out(1.4)'The curve of every click: the number in brackets is how far it overshoots before settling.
HOLDscript.js0.45The part of every step in which the size waits before the click, from 0 (it grows continuously) to 0.9.
SCRUBscript.js0.6How many seconds the drawing takes to catch up with the scroll.

Try them in the Playground

When to use it

For a typeface specimen, a foundry’s page, an article about typography or the presentation of a design system: wherever you want to show that a typeface works from footnote size to poster size. It works with any short word and any scale.

On phones

The same, with adapted measures: a point is worth fewer pixels, the ruler is narrower, marks that are too close are left out and the number of points sits above the dimension line instead of beside it. The guides’ labels make way for the word when it reaches the edge.

With reduced motion

No clicks and no bounces: at every step the word fades out and comes back already at the new size, with the guides and the dimension line; the captions take turns with a cross-fade and there is no squash at the end.

Pitfalls

  • The x-height guide with a fixed value (0.528, Roboto’s) sat above the x in the big sizes: with the opsz axis the x-height drops. It was measured on the typeface at six optical sizes and the guide uses that table.
  • The ruler’s numbers written from the bottom covered each other in the small sizes; written from the top with a minimum gap of 15 pixels they all read, and on a phone marks closer than 3 pixels to their neighbour made a grey smudge and are left out.
  • The caption line leaving upwards with yPercent -112 let the tails of the g and the comma show under the window: it leaves and enters by 135.
  • On a phone the number of points on the right of the dimension line went off screen at 144: there it is written above the line, aligned to its end.
  • The word must be measured again after the font has arrived (document.fonts.load, then ScrollTrigger.refresh): measured with the fallback font, at 144 points it ran past the margin.

Libraries

GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Roboto Flex (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 7.0 KB; the libraries: GSAP + ScrollTrigger 45 KB.

Testing

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