
Standing letters with a long shadow
Text, Scroll, 3D
NewFree
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.
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>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
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 siteThe 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.
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.
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.
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.
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.
| Name | File | Default | What it changes |
|---|---|---|---|
WORD | script.js | 'Margin' | The word to set: better short, with a letter that goes below the line. |
SIZES | script.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. |
WEIGHT | script.js | 400 | The weight of the word, from 100 to 1000. |
OPTICAL | script.js | true | The optical size follows the size; with false the word stays drawn for 14 points and you can see the difference. |
SNAP | script.js | 'back.out(1.4)' | The curve of every click: the number in brackets is how far it overshoots before settling. |
HOLD | script.js | 0.45 | The part of every step in which the size waits before the click, from 0 (it grows continuously) to 0.9. |
SCRUB | script.js | 0.6 | How many seconds the drawing takes to catch up with the scroll. |
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.
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.
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.
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.
Tested on 19 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.