Skip to content
animorio
IT
All components

The punched tape build

Loading, Physics, TransitionsCanvas, GSAPAdvancedCompressed weight: Demo 17 KBGSAP 28 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

On a black background, alone in the middle, a dark panel with round corners: at the top Production build and 1,204 modules · last built 2 h ago, on the right v2.8; in the middle a paper tape punch seen from the front and a little from above, enamelled in warm grey, with the roll of cream tape on the left, the head, two steel rollers, the cutter and a tray below; a piece of leader with only feed holes sticks out of the rollers. Below, in a monospaced face, main · 3f9c2a1 and the cream Build button. Pressed, the head starts to beat (it dips a hair at every column) and the tape comes out punched: the holes are the real bytes of the compiled file, in columns of eight bits with parity. The tape sticks out stiff, curves, falls to the floor and there folds and piles up in layers that lie on each other, with the light changing at every fold and its shadow on the floor; the chads flutter down into the tray and make a little heap. The roll gets thinner and its hub turns. The percentage climbs, the line says how many modules are compiled and the file names run along the bottom; the button becomes Cancel, pale and outlined. At the end the cutter drops and snips, the last length falls on the pile, a green tick is drawn in place of the percentage and the title says Build succeeded with the seconds and the kilobytes; Build again clears the pile and the chads away, changes the roll and starts over. One time in two, in the demo, the tape jams at the exit halfway and crumples like an accordion under the rollers: Build failed in red, the file with the error at the bottom, the Retry button. Retry drops the cutter, the crumpled length falls keeping its folds and the punch goes on from the same module.

How it works

A verlet chain seen from the side

The 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 rollers push the tape

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.

A strip in oblique projection

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 holes are the bytes

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.

Jam, cut and finish

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.

For those who cannot see and those who want no motion

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.

Values to change

NameFileDefaultWhat it changes
SECONDSscript.js6.5How long a build takes in the demo, in seconds (a real one follows its modules).
MODULESscript.js1204The modules to compile.
FAIL_EVERYscript.js2In the demo, one build in how many jams (0 never).
FAIL_ATscript.js0.56How far the build that jams gets, from 0 to 1.
TAPEscript.js100How much tape a second comes out of the punch, in pixels.
STIFFNESSscript.js0.5How stiff the paper is: 0 limp as cloth, 1 stiff as card.
GRAVITYscript.js1500How hard the tape falls, in pixels a second squared.
CHADSscript.js0.4How many of the punched chads are seen falling: 0 none, 1 all.
PAYLOADscript.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.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The chads built a tower: each one raised the heap where it fell, and they all fell in the same few millimetres. Now they roll off like sand towards the lower side until the slope is gentle, and raise the heap only a little.
  • The jam did not show: the new points, shut in a box under the rollers, folded in front of the hanging tape and looked like the same tape. Now they are pulled into an accordion with slanted folds, which turn their face towards the light and away, one in two.
  • After Retry a long blank length came out: during the jam the head stopped punching while the rollers still pushed tape under the punches. Now it punches as long as the tape moves.
  • With paper too limp the tape fell right next to the machine and piled up in a corner, leaving half the floor empty: a higher stiffness makes it stick out and lays it in wide folds.
  • Drawn as a filled ellipse, the pool of light on the floor had a visible edge; now it is a squashed radial gradient that fades to nothing.

Libraries

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.

Testing

Tested on 8 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All components