
Standing letters with a long shadow
Text, Scroll, 3D
NewFree
Scroll inside the preview
A coffee roaster’s story on a single thin vertical line: as you scroll, the ink runs down a ruler of ticks, the big year counts every year it passes and, at every year that matters, the line makes a vermilion notch and a sentence unrolls beside it, rolling back in when the next year comes. Minimal style.
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 of years</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- the story of a made-up coffee roaster on a single thin vertical line. Scrolling down, the ink runs down the line
like the hand of a ruler: the big year counts every year it passes, and at every year that matters the line
makes a notch and a sentence unrolls beside it, then rolls back in when the next year comes -->
<main>
<section class="apertura">
<p class="piccolo">Ashby Coffee Roasters</p>
<h1 class="titolo">Sixty-seven years,<br>one line.</h1>
<p class="piccolo piccolo--tenue">Scroll down</p>
</section>
<section class="racconto" data-racconto>
<div class="palco">
<header class="testa">
<p class="marchio">Ashby</p>
<p class="piccolo piccolo--tenue">Roasting since 1958</p>
</header>
<div class="scena" data-scena>
<div class="guida" data-guida aria-hidden="true"></div>
<div class="traccia" data-traccia aria-hidden="true"></div>
<div class="righello" data-righello aria-hidden="true"></div>
<ol class="tappe">
<li class="tappa" data-tappa data-anno="1958">
<i class="tappa__segno" aria-hidden="true"></i>
<i class="tappa__filo" aria-hidden="true"></i>
<span class="tappa__anno" aria-hidden="true">1958</span>
<p class="tappa__frase"><span class="nascosto">1958. </span>A second-hand drum roaster in a garage on Mill Lane.</p>
</li>
<li class="tappa" data-tappa data-anno="1971">
<i class="tappa__segno" aria-hidden="true"></i>
<i class="tappa__filo" aria-hidden="true"></i>
<span class="tappa__anno" aria-hidden="true">1971</span>
<p class="tappa__frase"><span class="nascosto">1971. </span>The corner shop opens. Twelve seats, one grinder.</p>
</li>
<li class="tappa" data-tappa data-anno="1986">
<i class="tappa__segno" aria-hidden="true"></i>
<i class="tappa__filo" aria-hidden="true"></i>
<span class="tappa__anno" aria-hidden="true">1986</span>
<p class="tappa__frase"><span class="nascosto">1986. </span>Nora takes the drum over from her father.</p>
</li>
<li class="tappa" data-tappa data-anno="2004">
<i class="tappa__segno" aria-hidden="true"></i>
<i class="tappa__filo" aria-hidden="true"></i>
<span class="tappa__anno" aria-hidden="true">2004</span>
<p class="tappa__frase"><span class="nascosto">2004. </span>The first beans bought straight from a farm.</p>
</li>
<li class="tappa" data-tappa data-anno="2025">
<i class="tappa__segno" aria-hidden="true"></i>
<i class="tappa__filo" aria-hidden="true"></i>
<span class="tappa__anno" aria-hidden="true">2025</span>
<p class="tappa__frase"><span class="nascosto">2025. </span>A new roastery by the river. The old drum came too.</p>
</li>
</ol>
<i class="ago" data-ago aria-hidden="true"></i>
<p class="anno" data-grande aria-hidden="true">1958</p>
</div>
</div>
</section>
<section class="apertura apertura--fine">
<h2 class="titolo titolo--medio">The drum is<br>still turning.</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.
37 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 line of years” from Animorio and fit it into my siteEvery year that matters is an item of a list with data-anno and its sentence: the script reads them, sorts them and gets the first and the last year. That gives the scale: a function turns a year into a height on the line, and everything (ticks, tip, sentences) is placed with it. The ruler has one tick per year, from four years before the first to four after the last.
The timeline, tied to the scroll with scrub SCRUB, mostly moves numbers: the year the ink has reached, the needle, the knock on the ticks, and for every year the notch, the hairline, the sentence, its way back and the small year. On every update of the timeline a single function redraws everything from those numbers: the height of the ink with scaleY, the length of the ticks with scaleX, the cut of the sentence with clip-path.
The big figure is the year reached, rounded: when a digit changes, its inner box makes a small jump with a timed tween (back.out), in the direction of the count. Two CSS variables, --wd and --wg, are Archivo’s wdth and wght axes: at the start of every run they drop to NARROW and THIN, on arrival they go back to WIDE and HEAVY along the LAND curve. Tabular digits keep the figure from dancing while it counts.
Each tick of the ruler grows with its distance from the tip, along a bell (Math.exp of the squared distance) WAVE high. On arrival at a year the knock variable jumps up and goes back to zero on an elastic: the bell swells and shivers. Ticks already passed turn black, the ones to come stay light. The final wave is another bell running from top to bottom.
The sentence sits beside the notch, centred on its height (under the year on a phone), and is cut with clip-path: an inset from the right at 100% that opens to 0 with power3.out while the words, one per box, slide in with a stagger. To roll it back a second number closes the cut again, the words leave from the last one, and the notch goes short again, from vermilion to black with gsap.utils.interpolate.
| Name | File | Default | What it changes |
|---|---|---|---|
NARROW | script.js | 64 | The width of the big year while it counts (62 is the narrowest). |
WIDE | script.js | 100 | The width it lands on (125 is the widest). |
THIN | script.js | 260 | The weight of the year while it counts. |
HEAVY | script.js | 780 | The weight it lands on. |
NOTCH | script.js | 30 | How far the vermilion notch springs out of the line, in pixels. |
WAVE | script.js | 1.6 | How much the ticks near the tip lean out. |
LAND | script.js | 'elastic.out(1, 0.55)' | The curve of the year landing and of the notch springing out: a smaller second number means more shiver. |
SCRUB | script.js | 0.8 | How many seconds the drawing takes to catch up with the scroll. |
For the story of a company, a shop, a studio or a family on an about page: four to six years that matter, one short sentence each. The years are changed in the HTML (data-anno and the sentence): the scale rebuilds itself. With more than six years the section must be made longer.
The same animations: the line moves to the left, the big year hangs under the notch instead of sitting left of the line, and the sentence goes under the year, on two lines if needed. This way the year going down never runs over the small years already written.
No movement: line and ruler are already drawn. Scrolling steps from one year to the next: the big year and the sentence fade out and back in at their new place, the years already told stay written small, the ones to come are not there yet.
GSAP 3.15.0, ScrollTrigger (GSAP) 3.15.0, Archivo (font variabile, asse wdth) 5.3.0.
Compressed with gzip, the three demo files weigh 8.3 KB; the libraries: GSAP + ScrollTrigger 45 KB.
Tested on 14 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.