
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
An app’s build as a vintage paper tape punch: the head punches the real bytes of the compiled bundle into the cream tape, eight holes a column plus the feed hole, the tape comes out between two rollers, bends and falls to the floor in folds with real physics, and the chads rain into a tray. At the end the cutter snips the tape; if it jams it crumples like an accordion until Retry cuts it away.
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 punched tape build</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/jetbrains-mono@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the build panel of a web app's deploy tool, with the build shown as a vintage paper tape punch: the head
punches the compiled bytes into the cream tape, eight bits a column with the feed hole, the punched tape comes
out of the machine and falls in folds on the floor, and the chads rain into a tray. Done, the cutter snips the
tape. The machine and the tape are drawn by script.js on the canvas; the words and the button are HTML -->
<section class="build" aria-labelledby="build-title" data-build>
<div class="build__head">
<div class="build__words">
<h2 class="build__title" id="build-title"><span class="build__swap" data-title>Production build</span></h2>
<p class="build__meta"><span class="build__swap" data-meta>1,204 modules · last built 2 h ago</span></p>
</div>
<p class="build__figure" aria-hidden="true">
<span class="build__pct" data-pct>v2.8</span>
<svg class="build__tick" viewBox="0 0 24 24" data-tick><path d="M5.5 12.6l4.1 4.1L18.6 7.4" pathLength="1"/></svg>
</p>
</div>
<div class="build__bay" role="progressbar" aria-labelledby="build-title" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-valuetext="Not building" data-bay>
<canvas class="build__paint" aria-hidden="true" data-paint></canvas>
<canvas class="build__paint build__ghost" aria-hidden="true" data-ghost></canvas>
</div>
<div class="build__foot">
<p class="build__file"><span class="build__swap" data-file>main · 3f9c2a1</span></p>
<button class="pill" type="button" data-action data-autoclic><span class="pill__label" data-label>Build</span></button>
</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 punched tape build” from Animorio and fit it into my siteThe tape that has left the machine is a row of points, one every 4 units of tape, moved by Verlet integration (the velocity is the difference between the position now and the one before) in three substeps a frame, with the step capped at 1/30 of a second. Six rounds of constraints keep the links’ length and pull every point towards the line through its neighbours: that is the paper’s stiffness, which makes the tape stick out before it bends. The floor has friction, and points more than three places apart push each other away under 3.3 units, so the layers of the pile lie on each other instead of passing through.
The last points, the ones still between the rollers, are not free: they sit on the exit line, as far out as they have come. The tape grows by adding a point every 4 units, and a point set free carries the rollers’ speed with it because its previous position is the one of the frame before. The punch runs at full speed while the compiler has modules ready and waits when it has none, in fits and starts like a real one.
The tape’s width runs back into the page: every link of the chain becomes a quad, its edge plus the same edge moved half the width to the right and four tenths of it up. The face we see takes the light by the angle of the link (lying on the floor it is bright, hanging it is darker), the near edge is a touch darker, and the links are painted from the farthest to the nearest, sorted by x ÷ 0.5 − y ÷ 0.4, so the upper layers of the pile cover the ones below. Their shadow falls on the floor, moved to the right the higher the link is.
The text of the compiled bundle becomes seven bit ASCII bytes with even parity on the eighth track: every column, a tenth of an inch as on real tape, has the holes of the one bits on eight tracks and the small feed hole between the third and the fourth. A column is recorded when it passes under the punches, and every hole is drawn at its place on the tape, interpolated along its link and turned with it: it follows every fold. The chads flutter down and, on reaching the heap, roll off it like sand until the slope is gentle; then they are painted once into the tray’s canvas.
When it jams the head stops but the rollers push 60 more units: the new points are pulled into an accordion under the exit, and at the cut every crumpled point remembers the span between its neighbours, so the piece falls keeping its folds. The cutter, a GSAP timeline with power3.in and an elastic return, breaks the link between two points: the tape past the blade becomes a piece of its own and falls, and a new one starts between the rollers.
The machine is a role=progressbar with aria-valuenow and an aria-valuetext in modules, the panel has aria-busy while it works and an aria-live line says when the build starts, fails and finishes. The button changes its word (Build, Cancel, Retry, Build again) and the pill takes the new width with a bounce; a click from a script, the preview’s, never cancels. With reduced motion the physics still runs, but the canvas updates every half second, dissolving from one still to the next, and the chads go straight into the tray.
| Name | File | Default | What it changes |
|---|---|---|---|
SECONDS | script.js | 6.5 | How long a build takes in the demo, in seconds (a real one follows its modules). |
MODULES | script.js | 1204 | The modules to compile. |
FAIL_EVERY | script.js | 2 | In the demo, one build in how many jams (0 never). |
FAIL_AT | script.js | 0.56 | How far the build that jams gets, from 0 to 1. |
TAPE | script.js | 100 | How much tape a second comes out of the punch, in pixels. |
STIFFNESS | script.js | 0.5 | How stiff the paper is: 0 limp as cloth, 1 stiff as card. |
GRAVITY | script.js | 1500 | How hard the tape falls, in pixels a second squared. |
CHADS | script.js | 0.4 | How many of the punched chads are seen falling: 0 none, 1 all. |
PAYLOAD | script.js | 'import{h as e,render as t}from"./vendor-9c1e.js";const n=[{path:"/",load:()=>import("./home-3a7f.js")},{path:"/checkout",load:()=>import("./checkout-b21d.js")}];t(e(App,{routes:n}),document.getElementById("app"));' | The bytes punched into the tape, one character a column. |
For a wait of a few seconds with an outcome: a build, a compile, a data export, a print, a backup in a developer tool or an app with a vintage taste. The tape piling up says «how much work has been done» well; for a half second load it is too much.
The panel takes the screen’s width less 32 pixels (358 on a 390 screen) and the drawing shrinks with it keeping its proportions; the canvas paints at the screen’s real density, up to twice. Under a finger the button squashes and springs back; its words widen on the width axis only under the mouse.
No tape running and no chads falling: the physics still runs, but the canvas changes every half second with a dissolve from one still to the next, the head does not beat, the chads go straight into the tray and the cutter cuts without dropping. The new words and the tick fade in.
GSAP 3.15.0, Instrument Sans (font variabile) 5.3.0, JetBrains Mono (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 17 KB; the libraries: GSAP 28 KB.
Tested on 8 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.