
The loader that becomes a logo
Transitions, SVG, Text
NewFree
A minimal page change: on a click every line of the page, the label, the title, the text and the link, shrinks and narrows into one column of small type in the middle of the screen, like the tape of a telex. The tape scrolls up past a thin vermilion head, carrying the old lines away and bringing up those of the new page, which open out into their places gaining width and weight on a spring, one after the other.
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 ticker-tape transition</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>
<main class="stage" data-stage>
<header class="bar">
<span class="brand">Wire</span>
<nav class="nav" aria-label="Pages">
<button type="button" data-go="notes" aria-current="page">Notes</button>
<button type="button" data-go="rooms">Rooms</button>
<button type="button" data-go="about">About</button>
</nav>
</header>
<!-- three pages of a made-up sound archive; on a change every line of the page runs into one narrow tape,
the tape scrolls past a thin head and the lines of the new page open out into their places -->
<section class="page" data-page="notes" aria-label="Notes">
<p class="ln ln--kicker" data-role="kicker">Field notes</p>
<h1 class="ln ln--title" data-role="title">Listen.</h1>
<p class="ln ln--body" data-role="body">Notes from a studio that</p>
<p class="ln ln--body" data-role="body">records the quiet parts</p>
<p class="ln ln--body" data-role="body">of cities at night.</p>
<a class="ln ln--go" data-role="go" href="#rooms" data-next="rooms" data-autoclic>Hear the rooms<svg viewBox="0 0 16 12" aria-hidden="true"><path d="M1 6h13M9 1.5 14 6l-5 4.5"/></svg></a>
</section>
<section class="page" data-page="rooms" aria-label="Rooms">
<p class="ln ln--kicker" data-role="kicker">Recordings</p>
<h2 class="ln ln--title" data-role="title">Rooms.</h2>
<p class="ln ln--body" data-role="body">Twelve rooms, one microphone,</p>
<p class="ln ln--body" data-role="body">the hum of every ceiling</p>
<p class="ln ln--body" data-role="body">kept exactly as it was.</p>
<a class="ln ln--go" data-role="go" href="#about" data-next="about" data-autoclic>Who we are<svg viewBox="0 0 16 12" aria-hidden="true"><path d="M1 6h13M9 1.5 14 6l-5 4.5"/></svg></a>
</section>
<section class="page" data-page="about" aria-label="About">
<p class="ln ln--kicker" data-role="kicker">About</p>
<h2 class="ln ln--title" data-role="title">Wire.</h2>
<p class="ln ln--body" data-role="body">A small sound archive</p>
<p class="ln ln--body" data-role="body">kept by two people</p>
<p class="ln ln--body" data-role="body">and one long cable.</p>
<a class="ln ln--go" data-role="go" href="#notes" data-next="notes" data-autoclic>Back to the notes<svg viewBox="0 0 16 12" aria-hidden="true"><path d="M1 6h13M9 1.5 14 6l-5 4.5"/></svg></a>
</section>
<!-- the head the tape runs past: a short hairline with a tick at each end -->
<div class="head" data-head aria-hidden="true"><span class="head__tick"></span><span class="head__tick"></span></div>
<footer class="foot">
<span>Wire sound archive</span>
<span>Listening room open on weekdays</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>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 ticker-tape transition” from Animorio and fit it into my siteEvery line of the page (label, title, text, link) is a block on a single row (white-space: nowrap), moved only with the x, y and scale transforms, with its origin at the top left. Its width and weight live in the --w and --g variables, tied in the CSS to font-stretch and font-weight through clamp, so GSAP animates them as numbers and the spring never carries the type past the axes of Archivo (62-125, 100-900).
The tape is a column in the middle of the screen with its rows TAPE_SIZE times 1.9 pixels apart, row zero on the head. To send a line onto the tape, the script measures where it sits at rest (getBoundingClientRect with the transform briefly removed) and works out the move to its place on the tape and the scale, TAPE_SIZE divided by its font size. The old lines gather around the head, the new ones right after them, two and a half rows further on, already small and invisible.
The scroll is a tween of one number, from zero to as far as it takes to bring the middle of the new lines onto the head, with power2.inOut; on every update each line is set back to its y from the same formula. Its opacity depends on its distance from the head (it fades above and below) and the line passing over the head turns vermilion. Everything comes from that number, so the editing bench can stop and rewind the scroll.
When the scroll ends, each new line goes back to x 0, y 0 and scale 1 with elastic.out(1, SPRING), and width and weight go back to its own with back.out, staggered by STAGGER: the title first, then the others from top to bottom. At the end transforms and variables are removed from the lines, so the page stays as the CSS has it and a resize finds nothing written by hand.
A click during a change waits in a queue; a resize takes the change straight to its end. On its own the site goes round the three pages with a gsap.delayedCall of HOLD seconds. On phones the sizes come down (the title with a min of vw and vh) and the tape stays in the middle. With reduced motion the new page fades in over the old one, with no tape.
| Name | File | Default | What it changes |
|---|---|---|---|
TAPE_SIZE | script.js | 15 | The size in pixels of the type on the tape. |
TAPE_WIDTH | script.js | 62 | The width of the type on the tape, 62 to 125 (the page goes back to its own). |
GATHER_TIME | script.js | 0.6 | The seconds the old lines take to run into the tape. |
SCROLL_TIME | script.js | 0.95 | The seconds the tape takes to scroll past the head. |
OPEN_TIME | script.js | 1.1 | The seconds the new lines take to open out into their places. |
STAGGER | script.js | 0.05 | The seconds between one line and the next. |
SPRING | script.js | 0.5 | The spring of the opening: lower wobbles more, 1 hardly wobbles. |
HOLD | script.js | 2.6 | The seconds each page stays before the next one comes by itself. |
To move from one page to another on a quiet site made of words: an archive, a magazine, a newspaper, a sound or design studio, a portfolio. The tape says that the new page is made of the same lines as the old one, only lined up again.
The same transition with the sizes adapted: the title is sized on both the width and the height of the screen, the tape stays in the middle and the head gets shorter. A tap on the link or the menu changes the page.
Nothing moves: the new page fades in over the old one with its lines already in place, and there is no tape.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 5.9 KB; the libraries: GSAP 28 KB.
Tested on 22 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.