
The cube stories
Stories, 3D, Transitions
NewFree
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.
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>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
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 siteThe 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.
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 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.
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.
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.
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.
| Name | File | Default | What it changes |
|---|---|---|---|
BOOKS | script.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. |
START | script.js | 3 | The book lying open in the middle when the page opens, counting from 0. |
FOLD | script.js | 86 | The steepest fold, in degrees: the one of the stacks at the two ends (90 would be shut flat). |
SPREAD | script.js | 0.72 | How quickly the paper folds up away from the middle, in cards: bigger, gentler folds and a wider strip. |
BREATHE | script.js | 0.15 | How much the folds open while the strip runs: 0 not at all. |
PEEK | script.js | 0.22 | How much a folded card opens under the pointer or a finger. |
GLIDE | script.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). |
THROW | script.js | 0.24 | The seconds a thrown strip runs on before it is caught (how far a flick goes). |
SHADE | script.js | 0.13 | How dark a card turned away from the light gets. |
--card-w | style.css | 232px | The width of a card (196 on a phone). |
--card-h | style.css | 318px | The height of a card (276 on a phone). |
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.
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.
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.
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.
Tested on 16 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.