Skip to content
animorio
IT
All components

The export reels

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

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.

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 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>

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 export reels” from Animorio and fit it into my site

What it does

On a black background, alone in the middle, the export panel of an editing program: two reels with dark metal flanges with three windows and, between them, a strip of film that comes down from the inside of the left reel, turns under a roller, runs straight under a small steel gate and climbs over the other roller to the right reel. On the left is the orange negative, wound in brown rings; on the right only the grey of the head of the film. Above the gate, large, 1.4 GB, then Ready to export and About 12 s to export; below, Harbour at dusk.mp4 with 4K · 24 fps · 1:12 and the Export button. Pressed, the lamp behind the gate warms up like a filament, from dull red to warm white, and the reels take up the slack with a little tug (Preparing). Then the film runs: every frame arrives as a negative and, passing under the lit gate, comes out printed in its colours: a pier in the afternoon, boats at golden hour, the sunset, the blue hour, the lights of the town. The right reel grows ring by ring in those colours and the left one shrinks; each turns at the right speed for its radius, the left one faster and faster as it empties, the right one slower and slower as it fills, and when they run the flanges’ windows blur. The number climbs (37%), below it the phase (Rendering frames, Mixing audio, Writing file) and the time left change, and next to the file’s name the megabytes already written; the encoder moves in fits and starts and sometimes stalls for a moment, and the film slows down and starts again with it. Pause stops the reels with a little inertia and dims the lamp; Cancel winds the film back fast, the printed frames pass back under the gate and turn back into negative, and Export canceled, Nothing was saved is left. At the end the tail of the film leaves the left reel, passes under the gate, climbs onto the right one and flaps there as the reel spins: it lifts with the speed, slaps against the roller at every turn, then the reel slows down, winds the end in and a piece of tape holds it on the roll; a glint runs across the rings and the number becomes Saved, with In Movies · 1.4 GB and the time it took, while the empty reel spins down. Export again winds back and starts over. One time in two, in the demo, at about 60% a clip goes offline: the film snaps in the gate, the right reel winds its end in and the left one pulls its own back, both ends flap and settle, the lamp is left bare and cools until it goes out, and in red Boats.mov is offline appears, with Reconnect it and retry. Retry brings both ends back to the gate, joins them with a piece of splicing tape and the export goes on: the splice stays on the film, and in the finished reel it is a pale ring.

How it works

The radius comes from the film

A 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 tangents, every frame

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.

The film is a texture in slices

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.

A lamp that warms up

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.

The end that flaps

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.

Snap, splice and those who cannot see

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.

Values to change

NameFileDefaultWhat it changes
SECONDSscript.js8How long an export takes in the demo, in seconds (a real one follows the encoder).
SIZEscript.js1.4The size of the exported file, in gigabytes.
FAIL_EVERYscript.js2In the demo, one export in how many goes wrong (0 never).
FAIL_ATscript.js0.62How far the export that goes wrong gets, from 0 to 1.
OFFLINEscript.js'Boats.mov'The clip that goes offline then.
STALLSscript.js1How often the encoder stalls for a moment: 0 never, 1 now and then, 2 often.
FOLLOWscript.js0.3How long the film takes to catch up with the encoder, in seconds.
REWINDscript.js0.9The seconds the reels take to wind the film back when the export is canceled.
FLAPscript.js1How long the end of the film flaps on the spinning reel: 0 not at all, 1 a lot.
LAMPscript.js1How bright the light in the gate is: 0 off, 1 full.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The film went round the outside of the reels, like a belt on their outer edge, and on the right it crossed the flange at a slant: it now comes down and climbs up on the inside, with both reels turning clockwise, and the tangents are worked out with signed radii, because the rollers turn the other way.
  • When the reel stopped, the free end lay across the coloured rings like a grey patch: the reel now winds it in until 13 pixels are left, and a piece of tape holds it down.
  • A ring’s colour was the average of the whole frame, and a golden sky with a dark sea made a dull olive green: the sky now weighs more than the sea and the colour is pushed a little, so that the shots read as bands.
  • On the printed film the perforations were black holes on an almost black edge and could not be seen: the edge is a little lighter.
  • The hub, a pale circle with a notch, looked like a letter: it is now a spindle with a square drive, on a core with three slots.
  • The Mixing audio and Writing file phases went by in three tenths of a second, unreadable: the demo’s encoder now goes slower on the sound and the file, and each stays in view for about a second.
  • Saved waited for the empty reel to stop too, and it spins freely for four seconds: it now waits only for the right one, and the left one finishes spinning on its own.
  • At rewinding speed the frames jumped three or four at a time and the film flickered: above 650 pixels a second they fade into a band of their colour, and the flanges’ windows are drawn several times along the turn.
  • When all three lines changed together (at the start, at Saved) for a moment nothing was written over the gate: they now change one after another, eight hundredths of a second apart.

Libraries

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.

Testing

Tested on 6 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