
The holographic card
Cards, 3D, Hover
Free
The Pre-order button of a shop printed like a lenticular postcard: its face is a row of thin lenses, three-sided prisms with one picture on each face. From the left it says Pre-order, from the right Ships Nov 14, and as the pointer goes by the lenses turn over in a wave, with the stripy flicker and the light running along the crests; pressed, every lens turns on to Reserved, with a tick that draws itself.
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 lenticular button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/bricolage-grotesque@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the lenticular button: the Pre-order button of a shop, printed like a lenticular postcard. Its face is a row of
thin ribbed lenses, each a little prism with three pictures on it, one per face: seen from the left the card
says Pre-order, from the right Ships Nov 14, and a press turns every lens over to Reserved. The lenses and
their light are drawn by the script on the canvas -->
<div class="lenti" data-lenti>
<button class="lenti__card" type="button" data-card data-autoclic>
<canvas class="lenti__lenses" aria-hidden="true" data-lenses></canvas>
<span class="lenti__sheet" aria-hidden="true"></span>
<span class="sr" data-name></span>
</button>
<p class="sr" aria-live="polite" data-live></p>
</div>
</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.
20 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 lenticular button” from Animorio and fit it into my siteEach picture (background, icon, words) is painted once on a canvas of its own, at the screen's density, and cut into strips as wide as a lens (LENS pixels, adjusted so a whole number fits). Each lens is a three-sided prism with an upright axis: face k shows its strip of picture k, with drawImage from the right piece. With all the lenses turned to the eye the picture is whole again; halfway round each lens shows two, squeezed, and the pictures alternate in stripes.
For a lens turned by φ degrees, face k has its normal at θ = φ − 120·k (brought between −180 and 180) and shows if cos θ is positive. Its middle moves by a·sin θ (a is the triangle's apothem, width / 2√3) and its width becomes width · cos θ: the strip is drawn on those measures. Between one lens and the next, while they turn, the dark back of the card shows.
Each face bulges a little: its normal goes from θ − 14° to θ + 14° from one edge to the other. At three points of the face the soft light of the sky, coming from the left, gives ambient + diffuse · cos(θ − sky), divided by that of the face turned straight: below 1 it is a black veil, above 1 a white one, in a gradient along the face. So at rest the ribs show, and a lens that turns darkens as it turns away.
For each lens the vector halfway between the direction of the lamp and that of the eye, which sits where the pointer is, is worked out (Blinn's half vector). A face glints where its bulge turns the normal along that vector: if the two angles are within 9°, a thin white line falls at the right point of the face, strongest in the middle, with a halo and a soft veil round it. As the angle changes slowly along the card, the lines make a band that follows the pointer and jumps from lens to lens as they turn.
Each lens has its spring (stiffness SPRING, damping from BOUNCE, two half steps a frame, never longer than a thirtieth of a second) and a move waiting with its time on GSAP's clock: a lens starts when its time comes, later the farther it is from the pointer or the point pressed, plus a delay of its own up to 0.07 seconds, so the front of the wave is ragged like a real print's. The press takes every lens to 240 degrees by way of 120, and the way back takes them on to 360 (or back to 120, if the pointer is on the right): at the end 360 degrees are taken off all of them, which is the same angle.
The pointer leans the lenses by TILT degrees at most and moves the eye; the picture changes only 6 per cent past the middle, so a hand resting in the middle does not make it flicker. A finger dragged across does the same (touch-action: pan-y), and the click that follows a drag is not a press. The focus from the Tab key shows the second picture; Enter and Space press the button, and squash it by themselves because there is nothing to let go of.
| Name | File | Default | What it changes |
|---|---|---|---|
FIRST | script.js | Pre-order | The first picture's words: at rest, and seen from the left. |
SECOND | script.js | Ships Nov 14 | The second picture's words: seen from the right, or reached with the Tab key. |
THIRD | script.js | Reserved | The third picture's words, after a press, with the tick. |
LENS | script.js | 5 | How wide a lens is, in pixels: the pictures are cut into strips this wide. |
TILT | script.js | 16 | How far the lenses lean following the pointer, in degrees. |
WAVE | script.js | 0.5 | The seconds a press takes to turn the lenses from one end of the card to the other. |
SPRING | script.js | 240 | How stiff each lens's spring is: higher, snappier turns. |
BOUNCE | script.js | 0.42 | How far a lens swings past its picture before it settles: 0 not at all. |
GLINT | script.js | 1 | The light on the lens crests: 0 none, 2 twice as bright. |
HOLD | script.js | 1.8 | The seconds Reserved stays before the card turns back. |
For the button of a pre-order or a release on a set date: a record, a book, a print, a pair of shoes, a limited run. It belongs where printing, souvenirs and collectables belong, and where two short pieces of information (the action and the date) are better in the same place than one under the other. Short words, up to about fifteen letters: the type shrinks by itself to fit. It is a button to show off, one to a page.
The card is 60 pixels tall like the other buttons and 300 wide, or the screen minus 48; the lenses are counted again for the real size. With no mouse a finger dragged across leans the card and turns it like the pointer (touch-action: pan-y, so up and down the page still scrolls), and a moment after it lifts the card goes back to Pre-order; a short tap is the press, and the wave starts from where the finger touched.
The lenses do not turn or lean, and the band of light stays still. The pictures go from one to the other in a fade (a third of a second), with the pointer on the right or the focus as with the press; Reserved arrives with the tick already drawn and when the page opens Pre-order is already there. Pressed, the card darkens a little instead of squashing.
GSAP 3.15.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 10.0 KB; the libraries: GSAP 28 KB.
Tested on 12 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.