
The loader that becomes a logo
Transitions, SVG, Text
NewFree
A minimal click page change: one thin vermilion line crosses the screen like the head of a scanner. Above it the new page is already there, below it the old one is still left; the new title comes in thin and condensed and, as soon as the line has passed it, settles into width and weight on a spring, one letter after another. On the next page the line scans back up from the bottom.
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 scan-line 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>
<!-- three pages of a made-up print room; the line scans each new one over the old -->
<section class="page page--paper" data-page="prints" aria-label="Prints" aria-hidden="true">
<header class="bar">
<span class="brand">Plano</span>
<nav class="nav" aria-label="Pages">
<a href="#prints" aria-current="page">Prints</a>
<a href="#archive" data-go="archive">Archive</a>
<a href="#visit" data-go="visit">Visit</a>
</nav>
</header>
<div class="hero">
<p class="kicker">Risograph print room</p>
<h1 class="title" data-title>Prints</h1>
<p class="lede">Two drums, eleven inks and a great deal of paper. Small runs, printed by hand.</p>
<a class="go" href="#archive" data-go="archive" data-autoclic>
<span class="go__text">See the archive</span>
<span class="go__arrow" aria-hidden="true"><span class="go__shaft"></span><svg class="go__head" viewBox="0 0 8 12"><path d="M1.5 1.5 6.5 6l-5 4.5"/></svg></span>
</a>
</div>
<footer class="foot">
<span>Plano print room</span>
<span>Open Thursday to Saturday</span>
</footer>
</section>
<section class="page page--night" data-page="archive" aria-label="Archive" aria-hidden="true">
<header class="bar">
<span class="brand">Plano</span>
<nav class="nav" aria-label="Pages">
<a href="#prints" data-go="prints">Prints</a>
<a href="#archive" aria-current="page">Archive</a>
<a href="#visit" data-go="visit">Visit</a>
</nav>
</header>
<div class="hero">
<p class="kicker">Since 2014</p>
<h2 class="title" data-title>Archive</h2>
<p class="lede">Every run we have printed, one copy of each, kept flat in wide drawers.</p>
<a class="go" href="#visit" data-go="visit" data-autoclic>
<span class="go__text">Plan a visit</span>
<span class="go__arrow" aria-hidden="true"><span class="go__shaft"></span><svg class="go__head" viewBox="0 0 8 12"><path d="M1.5 1.5 6.5 6l-5 4.5"/></svg></span>
</a>
</div>
<footer class="foot">
<span>Plano print room</span>
<span>Open Thursday to Saturday</span>
</footer>
</section>
<section class="page page--stone" data-page="visit" aria-label="Visit" aria-hidden="true">
<header class="bar">
<span class="brand">Plano</span>
<nav class="nav" aria-label="Pages">
<a href="#prints" data-go="prints">Prints</a>
<a href="#archive" data-go="archive">Archive</a>
<a href="#visit" aria-current="page">Visit</a>
</nav>
</header>
<div class="hero">
<p class="kicker">Thursday to Saturday</p>
<h2 class="title" data-title>Visit</h2>
<p class="lede">Bring a file on a stick, leave with a warm stack of paper. The coffee is on us.</p>
<a class="go" href="#prints" data-go="prints" data-autoclic>
<span class="go__text">Back to prints</span>
<span class="go__arrow" aria-hidden="true"><span class="go__shaft"></span><svg class="go__head" viewBox="0 0 8 12"><path d="M1.5 1.5 6.5 6l-5 4.5"/></svg></span>
</a>
</div>
<footer class="foot">
<span>Plano print room</span>
<span>Open Thursday to Saturday</span>
</footer>
</section>
<!-- the scan line: a hairline, a faint wash behind it that grows with its speed, a tick at each end -->
<div class="scan" data-scan aria-hidden="true">
<div class="scan__trail" data-trail></div>
<div class="scan__rule" data-rule></div>
<div class="scan__tick scan__tick--l" data-tick></div>
<div class="scan__tick scan__tick--r" data-tick></div>
</div>
</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/CustomEase.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.
45 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 scan-line transition” from Animorio and fit it into my siteThe new page sits on top of the old one (higher z-index) and is clipped with clip-path: going down inset(0 0 calc(height - y) 0), going up inset(y 0 0 0), where y is the line's position. The line is a zero-height div holding the one-and-a-half-pixel rule, the two ticks and the wash: it only moves in y, and on every frame the line and the clip are written together from the same y, so they never come apart.
The run is a tween of a number from 0 to 1 with a linear ease; y is worked out by passing that number through the SWEEP curve, a CustomEase (0.66, 0, 0.16, 1: starts slowly, runs, brakes for a long time). So the speed comes from the same curve: its slope at that point, divided by the highest speed, gives a number from 0 to 1 that stretches the wash behind the line (scaleY) while it runs and fades it as it brakes.
Each title is split into letters, inline-blocks whose font-stretch and font-weight are tied to the --w and --g variables (Archivo runs from 62 to 125 in width and from 100 to 900 in weight; clamp in the CSS keeps them inside even when the spring carries them past). Before the run the letters go to FROM_WIDTH and FROM_WEIGHT; then a tween with elastic.out(1, SPRING) takes them to 100 and 620, staggered by STAGGER, while they sink a pixel and a half and come back.
The title does not wait for a check on every frame: the moment the line passes it is worked out beforehand, by bisecting the curve for the point where the line reaches the title's baseline (going down) or the top of its capitals (going up), and the tween is placed there in the timeline. So the editing bench can slow it, stop it and rewind it without missing the beat.
The line always starts from the edge it rests on: after a run down it stays at the bottom and the next page comes up, like a scanner head (with BACK_AND_FORTH set to false it fades back to the top and always runs down). The three titles share one size, the one that fits the longest in the width, and sit at the same height on every page. A click during a change waits in a queue. With reduced motion the new page fades in with its title already in place and the line changes edge in a fade.
| Name | File | Default | What it changes |
|---|---|---|---|
SWEEP_TIME | script.js | 1.35 | The seconds the line takes to cross the page. |
SWEEP | script.js | 0.66, 0, 0.16, 1 | The curve of the run: how the line starts, runs and brakes. |
FROM_WIDTH | script.js | 62 | The title's width before the line passes it, 62 to 125 (it settles at 100): above 100 it comes in wide and narrows. |
FROM_WEIGHT | script.js | 160 | The title's weight before the line passes it, 100 to 900 (it settles at 620). |
SPRING | script.js | 0.42 | The spring of the settle: lower wobbles more, 1 hardly wobbles. |
STAGGER | script.js | 0.04 | The seconds between one letter settling and the next: 0 = all together. |
TRAIL | script.js | 90 | The pixels of the wash behind the line at full speed: 0 = no wash. |
BACK_AND_FORTH | script.js | true | On, the next page is scanned back up from the bottom; off, the line always runs down from the top. |
To move from one page to another on a quiet site where the type does all the work: a print shop, a design studio, an archive, a portfolio, a magazine, an agency's about page. The line reading the page suits anything about paper, print, scans and documents.
The same transition with the sizes adapted: the titles shrink to fit the width of the screen, sit a little lower on the tall page and the text wraps. A tap on the link sends the line back and forth.
Nothing moves: the new page fades in over the old one with its title already settled, and the line fades out at one edge and back in at the other.
GSAP 3.15.0, CustomEase (GSAP) 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.1 KB; the libraries: GSAP + CustomEase 31 KB.
Tested on 15 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.