
Standing letters with a long shadow
Text, Scroll, 3D
NewFree
Scroll inside the preview
A minimal-style 3D scroll animation: the chapters of a made-up magazine climb a spiral staircase around an invisible axis. In front the words are wide and full, at the back narrow and pale; the one passing the reading line in front takes the blue accent, and at the end the spiral lays itself down into the contents page.
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 spiral staircase of words</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>
<!-- a made-up quarterly, Coil. The stage sticks while you scroll: the chapters of the issue climb a spiral staircase
around an invisible axis, the one passing the reading line in front takes the accent, and at the end the spiral
lays itself down into the contents page. The words are placed by the script -->
<main>
<section class="corsa" data-corsa>
<div class="palco" data-palco>
<header class="testa">
<a class="marchio" href="#" data-entra>Coil</a>
<p class="testa__nota" data-entra>Issue nine, autumn</p>
</header>
<div class="livello" data-livello aria-hidden="true">
<span class="livello__tacca livello__tacca--sx"></span>
<span class="livello__tacca livello__tacca--dx"></span>
</div>
<div class="scena" data-scena>
<div class="elica" data-elica role="list" aria-label="Chapters of the issue"></div>
</div>
<div class="indice" data-indice aria-hidden="true">
<p class="indice__titolo" data-indice-titolo>In this issue</p>
</div>
<p class="cenno" data-entra><span data-cenno>Scroll to climb</span></p>
</div>
</section>
<section class="dopo">
<p class="dopo__testo">Twelve chapters, one staircase. Read them in any order.</p>
</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="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.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.
33 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 spiral staircase of words” from Animorio and fit it into my siteEvery word is a span inside a 3D container (transform-style preserve-3d) in the middle of the stage, with the perspective on the stage. Word i sits at angle i times the step (360 over PER_TURN) and at height i times RISE: its transform is translate3d, rotateY by the angle, translateZ by the radius and translate(-50%, -50%), so the text is centred on its face and looks outwards.
The scroll moves a single number, giro, from 0 to 1, which becomes the angle phi: each word sits at i times the step minus phi, and its height at (i minus phi over the step) times RISE. So the word that comes to the front also comes to the reading line: the spiral is a screw. One function on GSAP’s ticker redraws the twelve words on every frame.
The cosine of the angle gives the depth, from 0 at the back to 1 in front. From it come the weight (between the two WEIGHT values), the width (font-stretch between the two WIDTH values; Archivo goes from 62 to 125) and the ink: no blur filters, which are costly and muddy. Words leaving at the top or the bottom fade within a margin.
The accent depends on how close the word is to the front (under 26 degrees) and to the line (under half a step): the colour is mixed between ink and blue, so it comes and goes gently. When the word in front changes, its spring (an object holding one number) starts at 1 and goes back to 0 with elastic.out: the word jolts by a tenth of its height and settles, up or down depending on the scroll direction.
A second number, piatto, takes every word from the staircase to the contents page, offset by STAGGER: angle and radius go to zero with power2.inOut, the text scales down to the contents size, the anchor moves from the centre to the left edge, and the vertical position arrives with back.out, a small overshoot and return. The opacity rises with the cube of the progress, so the words from the back stay pale until they are in place. Then the hairlines draw themselves and the page numbers appear.
| Name | File | Default | What it changes |
|---|---|---|---|
WORDS | script.js | ['Arrivals', 'Maps', 'Rooms', 'Weather', 'Letters', 'Gardens', 'Bridges', 'Night', 'Rivers', 'Kitchens', 'Islands', 'Endings'] | The chapters on the staircase, from the bottom up (they become the contents; up to 24). |
FIRST_PAGE | script.js | 6 | The page number of the first chapter in the contents. |
PER_TURN | script.js | 6 | How many words make one full turn of the spiral: fewer words, wider steps. |
RISE | script.js | 0.88 | How much the spiral climbs from one word to the next, in word heights. |
RADIUS | script.js | 1 | How far the words stand from the axis (1 = what fits the screen). |
SIZE | script.js | 1 | How big the words are (1 = what fits the screen). |
WEIGHT | script.js | [210, 720] | The weight of the words at the back and in front. |
WIDTH | script.js | [64, 122] | The width of the type (font-stretch, in percent) at the back and in front; Archivo goes from 62 to 125. |
STAGGER | script.js | 0.45 | How staggered the words are as they lie down into the contents (0 = all together). |
SMOOTH | script.js | 0.6 | How softly the spiral follows the scroll, in seconds (0 = glued to it). |
RIDE | script.js | 1 | How much scroll the whole thing takes: 2 is twice as long. |
--accento | style.css | #2b45ff | The only accent: the word on the reading line. |
For the contents of a magazine or a long read, the chapters of a book, the services of a studio, the sections of a site whose titles are worth showing all together before you start.
The same animation with the sizes adapted: smaller words, a narrower radius so the words in front fit the screen, and the final contents that fit the height.
No smoothed scroll and no rotation: the contents page fades in directly, with its hairlines and page numbers.
GSAP 3.15.0, ScrollTrigger 3.15.0, Lenis 1.3.26, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 6.1 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.
Tested on 21 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.