Skip to content
animorio
IT
All components

The leporello carousel

Carousels, 3D, TransitionsGSAP, CSS onlyAdvancedCompressed weight: Demo 11 KBGSAP 28 KBFreeDownload the zip

The books of a small publisher's pocket series, in the minimal style: one strip of paper folded like a leporello, the accordion book. The card in the middle lies open and flat, the ones towards the ends fold up in a zigzag, tighter and tighter, until they are a stack of thin slivers marked by the hairlines of the folds. Dragged or thrown, the paper runs through: the cards open as they reach the middle and fold back into the stack on the other side, and the strip stops with a measured snap on the nearest card.

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 leporello carousel</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/fraunces@5.3.0/full.css">
  <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">
    <!-- the books of a small publisher's pocket series on one long strip of paper folded like a leporello: the card in
         the middle lies open and flat, the ones towards the ends fold up in a zigzag, tighter and tighter, until they
         are a stack of thin slivers. Dragged, thrown, the arrows or the keys pull the paper through: the cards open
         as they reach the middle and fold back into the stack on the other side. The cards are made by the script -->
    <section class="lep" role="region" aria-roledescription="carousel" aria-labelledby="lep-title" data-lep>
      <header class="lep__head">
        <h2 class="lep__title" id="lep-title">Tidelow Pocket Series</h2>
        <div class="lep__arrows">
          <button class="arrow" type="button" aria-label="Previous book" data-prev>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14.5 6 8.5 12l6 6"/></svg>
          </button>
          <button class="arrow" type="button" aria-label="Next book" data-next data-autoclic>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9.5 6l6 6-6 6"/></svg>
          </button>
        </div>
      </header>

      <div class="lep__view" tabindex="0" aria-describedby="lep-help" data-view>
        <span class="lep__shadow" aria-hidden="true" data-shadow></span>
        <div class="lep__strip" data-strip></div>
      </div>
      <p class="sr" id="lep-help">Arrow keys to move along the series, Home and End for the first and the last book.</p>
      <p class="sr" 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.

67 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 leporello carousel” from Animorio and fit it into my site

What it does

On a white background, alone in the middle, the carousel of the Tidelow Pocket Series: at the top the name of the series in Fraunces and two round buttons with arrows, made of a thin hairline; under it, nine paper-coloured cards 232 pixels wide and 318 tall, printed on one folded strip. Every card has the author in grey small capitals, the title large in Fraunces on two lines, a few words about the book, a hairline and under it the year and the kind of book. The card in the middle, Paper Harbour by Elif Demir, lies open and flat, its title full and its year, 1979, in vermilion; the others fold in a zigzag, one towards you and one away, tighter and tighter towards the ends, until the last ones are thin slivers where the title barely shows at a slant and, above, the white corner of the back of the paper. The folds are marked by hairlines, the cards turned away from the light are a little darker and the paper casts a soft shadow on the table. On arrival the strip is a shut packet and opens from the middle out, one fold after the other, a touch past its place and back. The next arrow takes the paper to the left: the card in the middle folds and goes into the stack, the next one opens and lies flat, its title takes weight and loses its softness on the typeface's axes and its year lights up. The strip is dragged with the mouse or a finger, thrown, and runs on by inertia; while it runs the folds open a little, like an accordion being pulled, and close again when it stops. Past the ends it pulls like a rubber band. With the mouse over a folded card it opens a little and pushes the stack aside; a click goes there. With the strip focused the arrow keys, Home and End work, and a thin frame marks the open card.

How it works

A fold for every card

The strip is a single number, p: the card in the middle as a fraction. Each card takes its fold from its distance d = i − p, on an upside-down bell: FOLD · (1 − e^(−(d/SPREAD)²)). In the middle it is zero, halfway between two cards the two neighbours stand at about thirty degrees each, one card away already past 70 and further on almost shut at FOLD. The sign alternates with the card, like the real folds of paper: a mountain and a valley, and they never change while the strip runs.

The chain: the paper never tears

Every card is an element with its transform-origin on its left edge, the fold it shares with the one before. Every frame the script builds the chain: card i starts where card i − 1 ends, and ends W·cos φ further right and W·sin φ further back. Then it moves everything so that the middle of the card at p stands in the middle of the view at its true depth: translate3d(x, 0, z) rotateY(φ) on sibling elements inside a preserve-3d container, so the browser sorts them by depth on its own.

The light and the back

The normal of a card turned by φ is (sin φ, cos φ): its product with the direction of the light, in front and a little to the left, says how much to darken the front (SHADE), and the opposite the back, a second face turned by 180 degrees with backface-visibility hidden. The camera looks a little from above (perspective-origin over the strip): cards coming towards you go down, the ones going away go up, and the zigzag reads along the top edges. The shadow on the table is as wide as the paper projected with the perspective.

Springs, inertia and a measured snap

A spring takes p to the chosen card, a = ω²·(goal − p) − 2ζω·v with ω and ζ from GLIDE, divided by the square root of the distance for long jumps. With a finger the strip chases the pointer on a stiff spring; let go, it takes the speed of the last 90 milliseconds, looks at where it would get in THROW seconds and is caught there. Paper thrown hard would fly past its card: it keeps only the speed the spring can stop in time, so it always lands with the same pixel too far. Speed opens the folds by BREATHE on a spring of its own, and the mouse over a folded card opens it by PEEK.

The typeface at work

Fraunces has axes for weight, softness (SOFT) and optical size. How flat each card is, 1 − |φ| / FOLD, cubed, gives the title its weight (330 to 560) and takes its softness away: shut in the stack the title is light and round, open in the middle it is full and crisp. The lines of the titles are set by hand and never wrap, so the changing weight moves nothing. The year goes from grey to vermilion with color-mix and a --lit variable.

The packet that opens, the phone

On arrival every card has an opening from 0 to 1, a GSAP spring with back.out: the fold goes from FOLD to the one of its place, the middle card first and then its neighbours, 70 milliseconds apart. When nothing moves the loop switches off. On a phone the cards go down to 196 by 276 and the strip runs to the edges of the screen; a finger drags and throws (up and down scrolls the page), and a finger on a folded card opens it as the mouse does.

Values to change

NameFileDefaultWhat it changes
BOOKSscript.js[['Small|Weathers', 'Ada Linwood', '1987', 'Poems for the hour before the rain.', 'Poems'], …]The books of the series: title (the bar | breaks the line), author, year, a few words, kind.
STARTscript.js3The book lying open in the middle when the page opens, counting from 0.
FOLDscript.js86The steepest fold, in degrees: the one of the stacks at the two ends (90 would be shut flat).
SPREADscript.js0.72How quickly the paper folds up away from the middle, in cards: bigger, gentler folds and a wider strip.
BREATHEscript.js0.15How much the folds open while the strip runs: 0 not at all.
PEEKscript.js0.22How much a folded card opens under the pointer or a finger.
GLIDEscript.js[7, 0.8]The strip's spring: how quickly it reaches a card and how much it is held back (below 0.7 it goes further past).
THROWscript.js0.24The seconds a thrown strip runs on before it is caught (how far a flick goes).
SHADEscript.js0.13How dark a card turned away from the light gets.
--card-wstyle.css232pxThe width of a card (196 on a phone).
--card-hstyle.css318pxThe height of a card (276 on a phone).

Try them in the Playground

When to use it

For a publisher's or a bookshop's series, a gallery's exhibitions, the issues of a magazine, a restaurant's seasonal menus, the rooms of a small hotel or the projects of a portfolio: wherever each thing is a sheet with a title and a few lines, and the gesture of leafing through an accordion book already says something about the site. It suits six to twelve cards on a light background; colours, sizes and words change in the variables.

On phones

The cards go down to 196 by 276 pixels and the strip runs to the edges of the screen, fading only in the margins: the open card in the middle, the folds and the start of the stacks at the sides. A finger drags and throws the strip (up and down scrolls the page), a finger on a folded card opens it a little as the mouse does and a tap goes there; the buttons are 42 pixels.

With reduced motion

The paper does not run: the view fades out and back in already on the new card, the folds already in place. No packet opening on arrival (the component fades in), no breathing folds and no cards opening under the mouse; dragged, the strip does not follow the hand, and let go it moves one card on or back with a fade. The title of the open card stays full and its year vermilion.

Pitfalls

  • With the camera at the height of the strip the chain looked like any coverflow: the zigzag did not read. Looking a little from above (perspective-origin at -30%) the cards coming forward go down and the ones going away go up, and the top edges draw the folds.
  • With the first curve the cards one away from the middle stayed at 50 degrees, and the one coming towards you, enlarged by the perspective, looked as open as the middle one. The curve is steeper now (past 70 degrees one card away) and the perspective longer (nine times a card's width).
  • The reduced-motion fade, done on the strip, flattened it for a moment: opacity on a preserve-3d element switches the 3D off. The view fades instead, which only has the perspective.
  • Thrown hard towards the last card, the strip flew past the end and came back: a spring with a large starting speed goes far past. On release the speed towards the goal is cut to what the spring can stop (ω times the distance), so it lands with the same pixel too far as a single step.
  • The speed that opened the folds threw them wide at every step, and for a moment there were two flat cards in the middle: BREATHE went down to 0.15 and counts the speed up to 5 cards a second.
  • The shadow on the table was as wide as the chain without perspective and stuck out past the paper: now the ends are projected with x · P / (P − z).

Libraries

GSAP 3.15.0, Fraunces (font variabile, con gli assi del peso, della morbidezza e della misura ottica) 5.3.0, Archivo (font variabile, con l'asse della larghezza) 5.3.0.

Compressed with gzip, the three demo files weigh 11 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 components