Skip to content
animorio
IT
Back to the library

The prints that go into the index

Images, ScrollGSAP, CSS onlyMediumCompressed weight: Demo 7.3 KBGSAP + ScrollTrigger 45 KBLenis 5.3 KBFreeDownload the zip

Scroll inside the preview

A minimal-style scroll animation for galleries: one print at a time opens in the middle inside a thin frame, a measuring line gives its height, then as you scroll it shrinks and travels down into its own slot in the index row at the bottom, where it lands a pixel too low and settles. When the row is full the title comes in.

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>Sable photo archive</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>
  <!-- a made-up photo archive, Sable. The stage sticks while you scroll: one print at a time opens in a thin frame,
       its size is measured on the side, then it shrinks along the page into its own slot in the index row at the
       bottom, lands a pixel too low and settles. When the row is full the title comes in. The prints are drawn in
       CSS, from the colours below -->
  <main>
    <section class="corsa" data-corsa>
      <div class="palco" data-palco>
        <header class="testa">
          <a class="marchio" href="#">Sable</a>
          <p class="testa__nota">Photo archive, 2019&ndash;2025</p>
        </header>

        <div class="quota" data-quota aria-hidden="true">
          <span class="quota__riga" data-quota-riga></span>
          <span class="quota__testo" data-quota-testo></span>
        </div>

        <p class="didascalia" data-didascalia aria-live="polite"><span data-did-titolo></span> <span class="didascalia__nota" data-did-nota></span></p>

        <div class="stampe" data-stampe></div>

        <ol class="indice" data-indice aria-label="Index"></ol>

        <div class="finale" data-finale>
          <h1 class="finale__titolo" data-finale-titolo>Five places, one light.</h1>
          <span class="finale__riga" data-finale-riga></span>
          <p class="finale__nota" data-finale-nota>The autumn index is complete.</p>
        </div>

        <p class="cenno" data-cenno><span>Scroll</span><svg viewBox="0 0 20 20" aria-hidden="true"><path d="M10 3v13M4.5 10.5 10 16l5.5-5.5"/></svg></p>
      </div>
    </section>

    <footer class="piede">
      <p>Sable keeps one print of every place it has stood in. Ask for the full index by letter.</p>
    </footer>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/ScrollTrigger.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/lenis@1.3.26/dist/lenis.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.

31 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 prints that go into the index” from Animorio and fit it into my site

What it does

A warm white page with the name of a made-up photo archive, Sable, at the top. In the middle a print, Dune, is already open in a thin frame, with a dimension line beside it giving its height (30 cm) and its title and size underneath; at the bottom of the page there is a row of five empty slots, each with its name, and a vermilion mark under Dune’s slot. As you scroll the stage stays still: the print shrinks and travels down the page into its slot in the row, lands a pixel too low and settles, and the slot’s name turns from grey to ink. Meanwhile the next print opens in the middle, from the bottom up, and its frame closes in around it; the dimension line draws itself again with the new measure and the vermilion mark runs under the slot it will go to. The same for all five, Dune, Shore, Salt, Quarry and Night. When the row is full the title ‘Five places, one light.’ comes in: it enters light and wide and gains weight as it narrows, then a vermilion rule draws itself under it and the note appears. Scrolling back up takes the prints out of the index in the same order backwards.

How it works

Measuring from the window

The script measures the stage and works everything out in pixels from it: the slots of the row (at most a fifth of the row wide and at most 13% of the screen tall, in 4:5), the open print (in the free space between the header and the row, with the caption below and the dimension line on the right) and the spot for the final title. On resize it measures again, even halfway, and ScrollTrigger refreshes.

One number for the whole ride

A ScrollTrigger without a timeline reads the section’s progress, Lenis smooths the scroll and an exponential average chases it once more (SMOOTH). The progress becomes a number u: each print has its own time t = u minus its place times 0.62, so the next one starts opening while the one before is leaving. From t come the opening (a clip-path from the bottom and a small zoom from 1.12 to 1, from 0 to 0.3), the dimension line (from 0.28) and the trip to the slot (from 0.55 to 0.95, with power3.inOut, a lerp of the position and a scale down to the slot’s size).

The landing

When a print crosses into its slot it gets a kick on a damped spring (LANDING and SPRING) that drops it a pixel or two and brings it back; the empty slot disappears under it and its name turns to ink. The vermilion mark under the row is a small GSAP tween, not tied to the scroll, which moves under the slot the open print is heading for.

The title

In the last stretch the title comes in with opacity and eight pixels of rise, and its Archivo axes go from weight 260 and width 118 to weight 620 and width 94; the vermilion rule widens with scaleX and the note arrives last.

Values to change

NameFileDefaultWhat it changes
PRINTSscript.js['Dune', 'Shore', 'Salt', 'Quarry', 'Night']The prints, in order (up to six). Short names: on a phone they sit under narrow slots.
SIZESscript.js['24 x 30 cm', '30 x 40 cm', '20 x 25 cm', '40 x 50 cm', '24 x 30 cm']The size written beside each print; the dimension line shows the second number.
OPENscript.js0.62How big the open print is, as a share of the free space.
SLOTscript.js0.13How tall a slot of the index can be, as a share of the screen height.
LANDINGscript.js30How hard a print lands in its slot: 0 sets it down without the extra pixel.
SPRINGscript.js300How stiff the landing spring is: more is quicker.
SMOOTHscript.js6How quickly the prints catch up with the scroll: less is softer.
RIDEscript.js1How much scroll the whole thing takes: 2 is twice as long.

Try them in the Playground

When to use it

For the gallery of a photographer, an archive, an exhibition or a catalogue: a page that shows the images one at a time and puts them in order as you scroll, ending with a headline above the full row.

On phones

The same animation with the sizes adapted: the row of slots takes the whole width, the open print fits in the space left above it and the dimension line stays beside it. Everything is worked out again if the window changes size, even halfway.

With reduced motion

Nothing moves and the scroll is not smoothed: the five prints are already in the row, with the title, the rule and the note above, and the page fades in.

Pitfalls

  • One print after the other, each with its own stretch of scroll, left the middle empty between one landing and the next opening: now the next one starts opening while the other leaves (a step of 0.62).
  • The frame sat on the element cut by the clip-path and vanished until the print was fully open: it moved to the outer element, which is not clipped.
  • The print going into the index passed behind the one opening: while it travels it is in front.
  • On a phone the long names (Salt flat, Night pool) touched under slots 55 pixels wide: short names.

Libraries

GSAP 3.15.0, ScrollTrigger 3.15.0, Lenis 1.3.26, Archivo (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 7.3 KB; the libraries: GSAP + ScrollTrigger 45 KB, Lenis 5.3 KB.

Testing

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