Skip to content
animorio
IT
Back to the library

The photo from the slit

ImagesGSAP, CanvasMediumCompressed weight: Demo 8.1 KBGSAP 28 KBFreeDownload the zip

In the minimal style: a thin red line draws itself down the middle of the page and opens like a slit. The photo comes out in columns, the middle one first and then the others in pairs towards the sides, each on a spring that goes one pixel too far and comes back; when the last one lands, the caption takes its weight letter by letter.

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>The photo from the slit</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage" data-stage>
    <p class="mark" data-mark>Lumen</p>

    <!-- the plate: the script places it, cuts the photo into columns and opens them from one slit in the middle -->
    <figure class="plate" data-plate role="img">
      <div class="cols" data-cols aria-hidden="true"></div>
      <i class="edge" data-edge aria-hidden="true"></i>
      <i class="edge" data-edge aria-hidden="true"></i>
      <figcaption class="cap" aria-hidden="true">
        <span class="cap__title" data-title></span>
        <span class="cap__meta" data-meta></span>
      </figcaption>
    </figure>
  </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.

13 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 photo from the slit” from Animorio and fit it into my site

What it does

A paper-coloured page, with the name of a made-up photography studio, Lumen, at the top left. Below the spot where the photo will be the caption rises, Stairs at noon, thin and grey, as if waiting. In the middle a one-pixel red line draws itself from the centre upwards and downwards: it is a slit. It opens: the middle column of the photo widens from the line, and the two red lines part, following its edges. Then the other columns open in pairs, one on the left and one on the right, outwards: each column starts from the edge of its neighbour and widens on a spring that goes one pixel past its place and comes back, while the photo inside is dragged towards the slit and settles a moment later; when a column lands, the one next to it feels the knock and shifts by a pixel. For a moment a thread of paper stays between one column and the next, so the photo arrives in strips. The red lines reach the edges of the photo and fade, and the caption takes its weight from left to right: every letter goes from thin to semibold with a small elastic, narrows a little and turns black; on the right a small line with the shot's details appears. The photo, made by the script on a canvas, is a white wall in the noon sun with a stair and its shadow, a blue sky and an arched door in the shade. After a few seconds everything goes back into the slit: the caption turns thin again, the columns close from the outside towards the middle, the line closes and it starts again. With the mouse over the still photo, the columns near the pointer move aside by a few pixels, as if the slit wanted to open again there; a click on the photo closes it and opens it again.

How it works

One photo, many columns

The photo is split into COLUMNS columns, always an odd number so that one sits on the slit. Every column is a div with its own window (clip-path: inset()) and inside it a child with the whole photo as its background, moved left by the column's distance from the edge: so the open columns meet to the pixel. The column edges sit on whole pixels, and the photo inside is a little wider (MARGIN on each side), so dragging it never shows the paper.

The window that opens

Every column has two numbers, l and r, the edges of its window in pixels from its left side. Closed, the window sits on the edge that faces the slit (the middle one is a line on its centre). Opening, the outer edge runs with power3.out to OVERSHOOT pixels past its place, then comes back with sine.inOut: inset() takes negative values, so the window really goes one pixel outside the column and shows the actual photo, not a gap.

The staggered columns

The middle column goes first; then the others, in pairs, STAGGER seconds apart. Each one starts from its neighbour's finishing edge before the neighbour is done, and for a moment a thread of paper stays between them: the photo arrives in strips. Meanwhile the photo inside the column starts DRAG pixels towards the slit and settles with expo.out, and when a column lands the one further in moves one pixel outwards and comes back with an elastic.

The two lines of the slit

The red lines are two one-pixel elements. On every frame the GSAP ticker looks among the open columns for the leftmost and the rightmost edge and puts the lines just outside them, so they never cover the photo. When the windows are closed the two lines coincide and are the slit; at the start they draw themselves with scaleY from the centre, and at the end they close the same way.

The caption that takes its weight

The caption is a row of separate letters in Archivo, a variable typeface with the wght and wdth axes. Every letter has two CSS variables, --g and --w, read by font-variation-settings. While the photo opens they sit at 220 and 112 (thin and wide, in grey); when the last column lands GSAP takes --g to 640 with elastic.out and --w to 100, one letter after another, and the colour to black.

Values to change

NameFileDefaultWhat it changes
IMAGEscript.js''The photo: an address, or a file loaded in the Playground. Empty, the script draws the photo. The frame takes the photo's proportions.
CAPTIONscript.js'Stairs at noon'The short caption under the photo: it takes its weight when the last column lands.
METAscript.js'f/11, 1/250 s'The small line on the right of the caption.
COLUMNSscript.js9How many columns the photo opens in (an even number gets one more, so that one sits on the slit).
STAGGERscript.js0.17The seconds between one pair of columns and the next.
OVERSHOOTscript.js1How many pixels every column goes past its place before coming back (0 = it stops dead).
HOLDscript.js3How many seconds the whole photo stays before going back into the slit.
LOOPscript.jstrueWhether the photo closes and opens again and again. With false it opens once and stays (a click opens it again).

Try them in the Playground

When to use it

To present a single photo properly: the opening of a photographer's or an architect's portfolio, the cover of a photo story, an exhibition page, the photo of a hotel room or a dish on a carefully made page. It works with any photo, including one loaded in the Playground.

On phones

The same animation with the sizes adapted: the photo is almost as wide as the screen, the columns are narrower and the caption smaller. A tap on the still photo closes it and opens it again.

With reduced motion

Nothing moves: the whole photo and the caption, already at its weight, fade in and stay, with no slit, columns or springs.

Pitfalls

  • With overflow: hidden on the columns the one-pixel overshoot did not show: the window could not leave the column. The columns do not cut anything themselves, the window is only the clip-path, and inset() with a negative value really goes past the edge.
  • Dragged inside its column, the photo of the first and last column uncovered a strip of paper at the edge: the photo inside every column is MARGIN pixels wider on each side, the same for all, so they still meet.
  • Placed on the edge of the window, the red lines covered the last pixel of the photo: they sit just outside, one pixel left of the left edge and on the first pixel after the right one; when the slit is closed the two coincide, otherwise a two-pixel line showed in the middle.
  • The lines followed an 'open column' flag written by a function in the timeline: jumping in the timeline (the Playground, the video) that function did not run and the lines stayed in the middle. Now a column is open if its window is wider than a twentieth of a pixel, read on every frame.
  • A photo loaded from another site cannot be redrawn on a canvas without locking it: the photo goes in as the columns' CSS background, and only the one made by the script goes through the canvas.

Libraries

GSAP 3.15.0, Archivo (font variabile) 5.3.0.

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

Testing

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