Skip to content
animorio
IT
Back to the library

The frame that leaves the film

Images, TransitionsGSAP, CanvasMediumCompressed weight: Demo 10 KBGSAP 28 KBFreeDownload the zip

In the minimal style: a film strip drawn with thin lines, perforations and all, runs sideways and stops on a spring with one frame between two red ticks. The frame unhooks and comes out of the strip until it is a large print, with its title and a frame number that widens and gains weight; then it goes back into its slot with a small knock and the strip runs on.

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">
  <title>Halide</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- a hairline film strip runs through the room; the frame that stops at the gate comes out of the strip as a print -->
  <main class="stage" data-stage tabindex="0" role="region" aria-roledescription="film strip" aria-label="Halide, a roll of film. Click, tap or press Enter to move on.">
    <header class="top">
      <p class="mark" data-mark aria-hidden="true">Halide</p>
      <p class="hint" data-hint aria-hidden="true">Click to move on</p>
    </header>

    <canvas class="film" data-film aria-hidden="true"></canvas>

    <div class="caption" data-caption aria-hidden="true">
      <p class="caption__title"><span class="slot" data-title></span></p>
      <p class="caption__frame"><span class="caption__label" data-label>Frame</span><span class="slot slot--num" data-num></span></p>
    </div>

    <p class="sr" data-live aria-live="polite"></p>
  </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.

27 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 frame that leaves the film” from Animorio and fit it into my site

What it does

A paper-coloured room, with the name of a made-up photo lab, Halide, at the top left and a small line on the right. The two lines of the film draw themselves across the whole page, the top one from the left and the bottom one from the right, and the perforations appear behind them; then the frames open one after another from a horizontal line, with a little bounce. They are five black and white photographs drawn by the script, with the grain and the slightly darker corners of silver prints: the sun on the line of the sea, a stair at noon, an open door in a dark room, a dune, the moon on water. In the middle, above and below the strip, two red ticks mark the place where the film stops. The strip takes a step back of a few pixels, then runs to the left and brakes on a spring: it goes a couple of pixels past and comes back, and when the frame reaches the ticks the ticks twitch and the strip jolts by a pixel and a half. The frame unhooks, rising five pixels, and comes out of the strip, growing into a large print in the middle of the room, while the strip slides down and its frames fade; where the frame was, its empty slot stays, a thin outline. Under the print the title rises letter by letter, its width axis opening on an elastic, and on the right the frame number arrives in red, narrow and light first, then wide and heavy. After a couple of seconds the letters escape upwards, the print goes back down shrinking, stops a few pixels above its slot and drops in with a knock, and the strip runs on to the next frame, two further along. With a mouse the frame of the strip under the pointer lifts a few pixels, and over the large print the print stays out until the pointer leaves. A click, a tap or Enter sends the print back at once and moves on.

How it works

One canvas

The film, the perforations, the frames, the ticks and the large print are drawn on every frame by the GSAP ticker on a canvas as big as the room, at the screen's pixel density. One-pixel lines sit on whole screen pixels (the hp function), so they stay sharp while the strip moves. Only the texts are in the DOM, so the variable typeface can work with its axes.

An endless strip

The state is a single number, pos: the frame standing at the gate, even halfway. Every frame k sits (k minus pos) times the pitch from the centre and shows picture k modulo the number of pictures; the perforations, six per frame, follow the same number. Only the visible ones are drawn, and after a full round pos goes back by as many pictures as there are: nothing changes on screen.

The run on a real spring

The ease of the run is the position of a damped spring let go from rest, 1 minus e to the minus dt times (cos wt plus d/w sin wt). The first overshoot is e to the minus d pi over w, so w is chosen to make the strip go past by exactly OVERSHOOT pixels, whatever the distance. The moment it first reaches the gate is (pi minus the arctangent of w/d) over w: that is where the timeline puts the knock, the ticks twitching and the strip jolting on an elastic.out.

The print coming out

The print is a number p from 0 to 1: its rectangle is part way between its slot in the strip (worked out again on every frame, because meanwhile the strip moves down) and its large place. So it always leaves from and returns exactly to its empty slot. While it is small it is drawn from the copy already scaled down, when large from the full picture. Before leaving it rises five pixels (it unhooks); coming back it arrives five pixels above and then drops in.

The title and the number

Every text sits in a slot with hidden overflow and every letter is a span. The letters of the title rise from below while the --w variable takes Anybody's wdth axis from 66 to 100 with an elastic; those of the number start narrow and light (wdth 52, wght 220) and widen and gain weight up to 100 and 640. Leaving, they escape upwards and the slot is emptied.

Values to change

NameFileDefaultWhat it changes
FRAMESscript.js[{ title: 'Tide line', code: '14A' }, …]The frames of the strip, in order: the title under the print and the frame number. There are five drawings, repeated if there are more entries.
IMAGEscript.js''Your photo in the first frame: an address, or a file loaded in the Playground. It is cropped to 3:2 like a cover. Empty, the script draws the first frame.
RUNscript.js1.5How many seconds the strip takes to run from one stop to the next.
SKIPscript.js2How many frames the strip moves on at every stop.
OVERSHOOTscript.js2How many pixels the strip goes past the gate before the spring brings it back (0 = it stops smoothly).
HOLDscript.js2.3How many seconds the print stays out of the strip.
SIZEscript.js0.86How much of the free room the large print takes up.
AUTOPLAYscript.jstrueWhether the strip moves on by itself. With false it moves only with a click, a tap or Enter.

Try them in the Playground

When to use it

To show work made of pictures like a roll of film: a photographer's or a director's portfolio, the page of a film lab, a film or photography festival, a travel story, a project gallery. It also works at the top of a page, as an opening that plays by itself.

On phones

The same animation with the sizes adapted: the strip is lower, the large print takes up almost the whole width and the title and number are smaller. A tap sends the print back and moves on.

With reduced motion

Nothing runs or moves: the strip stands still, and at every stop the room fades out and back in with the large print and its caption already in place, then fades again and the strip comes back with the new frame at the gate.

Pitfalls

  • A print starting from the place worked out at the beginning came away from its empty slot, because meanwhile the strip moves down: its rectangle is worked out on every frame between its slot in the strip at that moment and its large place.
  • The letters of the title, hidden just below the slot, peeked out for a pixel under the strip even before the print came out (the slot has a bottom margin for descenders): they start lower, at 140%.
  • Leaving upwards, the dot of the i stayed peeking over the edge of the slot: once the exit is over the slot is emptied.
  • A spring with the same overshoot as a percentage went past by one pixel on short runs and by ten on long ones: the overshoot is asked in pixels and becomes a percentage by dividing by the distance of each run.
  • Drawing many small frames from the large picture on every frame makes them grainy: the strip has a scaled-down copy of each picture, made again when the window changes size.

Libraries

GSAP 3.15.0, Anybody (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 10 KB; the libraries: GSAP 28 KB.

Testing

Tested on 16 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 animations