
The holographic card
Cards, 3D, Hover
Free
In the rich style: the Menu button of a letterpress studio opens a rotary desk card file, with a walnut base, chrome legs, knurled knobs and twenty-one cards hanging on the rails. Every coloured divider with its tab is a menu item: turning the drum the cards flip over the rails one after another, each on a spring of its own, and the chosen item rises out of the file with a brass paper clip.
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 rotary card file menu</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/courier-prime@5.3.0/400.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the menu of a letterpress studio: the Menu button opens a rotary card file under it. The drum turns, the
cards flip over the rails one after another, and every coloured divider with its tab is a menu item. Drag the
cards, roll the wheel, use the arrows or point at a tab; choosing a divider lifts it out of the file. -->
<nav class="rolo-menu" aria-label="Main" data-rolo-menu>
<button class="rolo-btn" type="button" aria-expanded="false" aria-controls="rolo-file" data-toggle>
<svg class="rolo-btn__icon" viewBox="0 0 44 44" aria-hidden="true">
<path class="rolo-btn__base" d="M6 37.5 H 38 L 36 41 H 8 Z"/>
<path class="rolo-btn__leg" d="M10 37.5 L 13 27 M34 37.5 L 31 27"/>
<g class="rolo-btn__cards">
<rect class="rolo-btn__card rolo-btn__card--back" data-icon-card x="14" y="11" width="16" height="16" rx="1.6"/>
<rect class="rolo-btn__card rolo-btn__card--mid" data-icon-card x="14" y="11" width="16" height="16" rx="1.6"/>
<rect class="rolo-btn__card rolo-btn__card--front" data-icon-card x="14" y="11" width="16" height="16" rx="1.6"/>
</g>
<rect class="rolo-btn__tab" x="16.5" y="8.4" width="6" height="3.2" rx="0.8"/>
<path class="rolo-btn__rod" d="M9 27 H 35"/>
<circle class="rolo-btn__knob" cx="8.4" cy="27" r="2.6"/>
<circle class="rolo-btn__knob" cx="35.6" cy="27" r="2.6"/>
</svg>
<span class="rolo-btn__word" data-word>Menu</span>
</button>
<div class="rolo" id="rolo-file" inert data-rolo>
<div class="rolo__shadow" aria-hidden="true"></div>
<!-- the frame: walnut base, chrome legs, the hubs and the knurled knobs -->
<div class="rolo__base" aria-hidden="true">
<span class="rolo__base-top"></span>
<span class="rolo__base-front"></span>
</div>
<span class="rolo__leg rolo__leg--l" aria-hidden="true"></span>
<span class="rolo__leg rolo__leg--r" aria-hidden="true"></span>
<!-- the drum: the cards are made by the script around the dividers below -->
<div class="rolo__drum" data-drum>
<ul class="rolo__cards" data-cards role="list">
<li class="rolo__rail" aria-hidden="true" data-rail></li>
<li><a class="card card--divider" href="#work" data-item style="--tone: var(--coral)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Work</span></span><span class="card__word">Work</span><span class="card__note">Posters, books, invitations</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#printing" data-item style="--tone: var(--mustard)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Printing</span></span><span class="card__word">Printing</span><span class="card__note">Letterpress and foil</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#papers" data-item style="--tone: var(--teal)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Papers</span></span><span class="card__word">Papers</span><span class="card__note">Cotton, kraft, deckle edges</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#workshops" data-item style="--tone: var(--sky)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Workshops</span></span><span class="card__word">Workshops</span><span class="card__note">Saturday classes at the press</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#journal" data-item style="--tone: var(--olive)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Journal</span></span><span class="card__word">Journal</span><span class="card__note">Notes from the press room</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#studio" data-item style="--tone: var(--plum)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Studio</span></span><span class="card__word">Studio</span><span class="card__note">Who sets the type</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
<li><a class="card card--divider" href="#contact" data-item style="--tone: var(--rose)"><span class="card__front"><span class="card__tab"><span class="card__tab-word">Contact</span></span><span class="card__word">Contact</span><span class="card__note">Say hello, order a proof</span></span><span class="card__back"><span class="card__tab"></span></span></a></li>
</ul>
</div>
<!-- the hubs on the ends of the rails (the rails sit among the cards: in front of the cards behind them,
behind the cards in front) -->
<span class="rolo__hub rolo__hub--l" aria-hidden="true"></span>
<span class="rolo__hub rolo__hub--r" aria-hidden="true"></span>
<span class="rolo__knob rolo__knob--l" aria-hidden="true" data-knob><span class="rolo__knob-mark" data-knob-mark></span></span>
<span class="rolo__knob rolo__knob--r" aria-hidden="true" data-knob><span class="rolo__knob-mark" data-knob-mark></span></span>
<span class="rolo__pawl" aria-hidden="true" data-pawl></span>
<!-- the brass plate on the base: it says which divider is at the front -->
<span class="rolo__plate">
<span class="rolo__brand" aria-hidden="true">Kardwell</span>
<span class="rolo__now" aria-live="polite"><span class="rolo__now-word" data-now>Work</span></span>
</span>
</div>
</nav>
</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.
42 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 rotary card file menu” from Animorio and fit it into my siteThe whole card file moves from a single number, the angle of the drum. Every card has its place on the circle, twenty-one places 360 divided by 21 degrees apart; on every frame the script works out how far the card is from the front, between minus 180 and 180 degrees, and from that how far it should lean. The drum follows the chosen item on a spring that overshoots a little; dragging, the angle follows the finger and on release it runs on with its speed and stops on the nearest divider.
The wanted lean comes from two hyperbolic tangents: the cards behind open slowly up to 56 degrees, the ones that went past the rails fall fast up to 72. No card goes straight there though: each one has a spring of its own, with a slightly different stiffness and little damping, so every card arrives a moment late, overshoots and settles. That is what makes the cascade when the drum turns.
Every card is a list item turned with rotateX around its bottom edge, which sits on the rails; inside it has two faces, the front and the back turned by 180 degrees, with backface-visibility hidden, so the cards that fell forward show their backs. The perspective sits on the list with the point of view high above the file, and the order of drawing is decided by the script with z-index: behind, the card nearest the front is on top; in front, the most upright covers the one lying flatter, and the rails sit in between.
The knobs are cylinders seen from the side: the knurling is a repeating gradient that runs vertically with the angle of the drum, and the white mark goes round the cylinder with a sine, squashed by the cosine and hidden when it goes round the back. Every time a card goes past the rails the pawl ticks and comes back with an elastic; when the divider at the front changes the brass plate sends the old name up and bounces the new one in from below.
The dividers are the links of the menu, in the right order and reachable with the Tab key: when one takes the focus the drum brings it to the front, the arrows go to the previous and the next, Home and End go to the ends, Esc closes and gives the focus back to the button. The chosen item has aria-current, the plate speaks in an aria-live region, the typewritten cards are hidden from screen readers and the closed file is inert.
| Name | File | Default | What it changes |
|---|---|---|---|
SPRING | script.js | 1 | How lively the cards are when they flip over the rails (1 is normal). |
FAN | script.js | 56 | The degrees the cards behind lean back. |
FLOP | script.js | 72 | The degrees the cards in front fall forward. |
DRAG | script.js | 0.5 | The degrees the drum turns for every pixel dragged. |
LIFT | script.js | 18 | How far the chosen divider rises out of the file. |
SPIN | script.js | 1 | How fast the drum turns to an item (1 is normal). |
For the menu of the site of a print studio, a graphic design studio, a stationery shop, an archive, a professional office or a contact book: the items are the dividers, from five to eight, with short names like on real tabs.
The card file is as wide as the screen and at most as tall as the room left under the button; the cards, the type and the plate are measured on the box with container units. It turns by dragging the cards up or down with a finger, and a tap on a tab brings its item to the front and chooses it.
The card file fades in already still on the item at the front; turning, the cards go straight to their places with no springs or cascade, the chosen item stays a little higher with no elastic and the paper clip appears. No ticking pawl, no gleam on the plate.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0, Courier Prime 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 23 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.