
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
A video export as film running from one reel to the other: the orange negative unwinds from the left reel, every frame is printed in colour under a lit gate and the right reel fills ring by ring in the colours of the video, like the barcode of a film. At the end the tail of the film slaps round the reel as it spins down; if a clip goes offline the film snaps, and Retry joins the two ends with a piece of splicing tape.
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, viewport-fit=cover">
<title>The export reels</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/encode-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the export panel of a video editor: the video is a strip of film running from a reel of orange negative,
through a lit gate where every frame is printed in colour, onto a take-up reel whose pack grows ring by ring
in the colours of the video. The reels, the film and the light are painted on the canvas; the words and the
buttons are HTML -->
<section class="export" aria-labelledby="export-title" data-export>
<div class="export__deck" role="progressbar" aria-labelledby="export-title" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" data-bar>
<canvas class="export__paint" aria-hidden="true" data-paint></canvas>
<div class="export__readout" aria-hidden="true">
<p class="export__big"><span class="export__swap" data-big>1.4 GB</span></p>
<p class="export__phase"><span class="export__swap" data-phase>Ready to export</span></p>
<p class="export__note"><span class="export__swap" data-note>About 12 s to export</span></p>
</div>
</div>
<div class="export__foot">
<div class="export__file">
<h2 class="export__title" id="export-title">Harbour at dusk.mp4</h2>
<p class="export__meta">4K · 24 fps · 1:12</p>
</div>
<div class="export__buttons">
<button class="export__btn export__btn--ghost" type="button" data-cancel hidden><span class="export__label">Cancel</span></button>
<button class="export__btn" type="button" data-action data-autoclic><span class="export__label" data-label>Export</span></button>
</div>
</div>
<p class="sr" role="status" aria-live="polite" data-live></p>
</section>
</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.
32 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 export reels” from Animorio and fit it into my siteA reel is a spiral of film, so its area grows with the length wound on it: r² = r₀² + k·L, with k chosen so that the whole film makes a reel of 41 pixels on a core of 12. So the left reel shrinks and the right one grows, and each turns by ΔL ÷ r: for the same step of film the reel that empties spins faster and faster. A turn adds π·k to the radius, and every turn is drawn as a circle of its own in the colour of the film there, taken from the frame at that point: the barcode of the film, rolled up. On the left the same colours in negative.
The path is a belt round four circles: the two reels, turning clockwise, and the two rollers, turning the other way. The tangent between two circles is worked out with signed radii: sin β = (s₂·r₂ − s₁·r₁) ÷ d, and the points of contact lie s·r from the line. As the reels’ radii change, the segments, the arcs, the length of the path and the place of the gate are worked out again every frame (twice, because the length on the path changes in turn how much film is on the reels). Every point of the film has its material coordinate: m = m_gate + s_gate − s.
Every frame is painted once only in a small canvas, printed and in negative (the colours turned over pixel by pixel through the orange base, with getImageData), and the perforations are holes made with destination-out. Along the straight stretches a frame is a single drawImage, turned like the line; on the arcs the film is laid in slices 1.6 pixels long, each widened on the outer edge as much as the curve needs. Half a frame before the middle of the gate the frames are taken from the printed set. Above 650 pixels a second, when rewinding, the frames fade into a band of their colour and the flanges’ windows are drawn several times along the turn, as if blurred.
The light follows a filament’s ramp, from dull red to orange to warm white: switching on it goes through all of them, switching off it goes back. It is added (lighter) under the film, on it round the gate and in the gate; with the film in it the lit frame shows, with no film the bare lamp. The perforations are real holes, so near the gate the light comes through them.
When the end of the film gets within 34 pixels of a reel it becomes a free end, attached to the roll where it leaves it and carried round by the turn: a curve with a lift (a damped spring pushed by ω², plus a random flutter), the curl of the roll (which goes back to 1 ÷ r as the reel slows down) and a bend set off by the slaps. When the tip meets the roller it is knocked back and the roller shakes. The reel slows down by friction; below 1.8 radians a second it winds the end in to 13 pixels and, at the end of an export, a piece of tape is laid on it. To rewind, the reel turns back to the angle where the end started flapping (within a turn) while the end straightens: from there it is a piece of the path again.
At the snap the film becomes two pieces, each with its own material at the gate: the right motor, with no load any more, speeds up and winds its end in, the left brake pulls the other one back; the ends are ragged. Retry brings both ends back to the gate and joins them; the splice keeps its material, so it travels with the film and in the reel it becomes a pale ring. The panel is a role=progressbar with aria-valuenow and aria-valuetext («37 percent, rendering frames, about 6 seconds left»), aria-busy while it works and an aria-live line for the start, the pause, the error, the cancel and the end; a click from a script, the library preview’s, never pauses.
| Name | File | Default | What it changes |
|---|---|---|---|
SECONDS | script.js | 8 | How long an export takes in the demo, in seconds (a real one follows the encoder). |
SIZE | script.js | 1.4 | The size of the exported file, in gigabytes. |
FAIL_EVERY | script.js | 2 | In the demo, one export in how many goes wrong (0 never). |
FAIL_AT | script.js | 0.62 | How far the export that goes wrong gets, from 0 to 1. |
OFFLINE | script.js | 'Boats.mov' | The clip that goes offline then. |
STALLS | script.js | 1 | How often the encoder stalls for a moment: 0 never, 1 now and then, 2 often. |
FOLLOW | script.js | 0.3 | How long the film takes to catch up with the encoder, in seconds. |
REWIND | script.js | 0.9 | The seconds the reels take to wind the film back when the export is canceled. |
FLAP | script.js | 1 | How long the end of the film flaps on the spinning reel: 0 not at all, 1 a lot. |
LAMP | script.js | 1 | How bright the light in the gate is: 0 off, 1 full. |
For a wait of a few seconds or a few minutes in an app that works with pictures: exporting a video or an animation, rendering a scene, converting a photo archive, uploading a film. The film says «I am making something frame by frame» well, and the snap says at once that something broke; for a short wait without an outcome, like a page loading, it is too much.
The panel takes the screen’s width less 32 pixels (358 on a 390 screen) and stays 172 tall; the reels keep their size at the sides, the film between them gets shorter and the words over the gate narrow to 166 pixels (a long clip name ends in an ellipsis). The canvas paints at the screen’s real density, up to twice, and spills 15 pixels over each side for the light and the flapping end, without scrolling the page sideways. The buttons are pills 36 tall: under a finger they squash and spring back, and their words widen on the width axis only under the mouse.
The film stands still and the reels do not turn: they still grow and shrink, because they are what says how far along things are, and the gate shows the frame being printed. No flapping end, no ends flying off at the snap, no rewinding: every change (the end, the snap, the splice, the cancel) arrives as a fade from the picture before, and new words fade in.
GSAP 3.15.0, Encode Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 23 KB; the libraries: GSAP 28 KB.
Tested on 6 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.