
The layered button
Buttons, Hover, Physics
Free
In the minimal style, on white: the card of a chamber concert printed like a programme page, with its bottom right corner dog-eared. With the pointer near, the corner lifts towards it like a page about to be turned, with a real fold, a lengthening shadow and the paler back of the paper; a click turns the whole page and underneath is the inside, with the programme and the button to book.
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 card that turns like a page</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/instrument-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the card of an evening concert, printed like the page of a programme. Its bottom right corner is a little
dog-eared; with the pointer near it the corner lifts towards the pointer like a page you are about to turn,
and a click turns the whole page over: underneath is the inside, with the programme and the button to book.
The front is the page cut along the fold, the flap is the same page reflected across the fold and seen from
the back, and the inside waits underneath -->
<article class="card" aria-labelledby="ev-title" data-card>
<!-- the inside, revealed by the turn -->
<section class="inside" id="ev-inside" data-inside aria-hidden="true">
<p class="label" data-in>Programme</p>
<ol class="programme">
<li data-in><span class="who">Haydn</span><span class="what">Quartet in G, Op. 77</span></li>
<li data-in><span class="who">Janáček</span><span class="what">Intimate Letters</span></li>
<li data-in><span class="who">Ravel</span><span class="what">Quartet in F</span></li>
</ol>
<p class="note" data-in>About 95 minutes, with one interval. 38 seats left.</p>
<div class="actions" data-in>
<a class="pill" href="#book" data-book><span class="pill__fondo"></span><span class="pill__testo">Book a seat</span></a>
<button class="back" type="button" data-back tabindex="-1">
<svg viewBox="0 0 16 10" aria-hidden="true"><path d="M15 5H2M5.5 1.2 1.6 5l3.9 3.8" /></svg>
<span>Back</span>
</button>
</div>
<span class="inside__shade" data-inside-shade aria-hidden="true"></span>
</section>
<!-- the front page, clipped along the fold -->
<button class="front" type="button" data-front data-autoclic aria-expanded="false" aria-controls="ev-inside">
<span class="front__body">
<span class="label">Quillon Hall <span class="sep">/</span> Concerts</span>
<span class="title" id="ev-title" data-title>Late<br>Quartets</span>
<span class="rule" aria-hidden="true"></span>
<span class="meta">
<span class="date">Thu 12 Nov, 20:30</span>
<span class="place">Room B, second floor</span>
</span>
<span class="hint">Turn the page</span>
</span>
<span class="front__shade" data-front-shade aria-hidden="true"></span>
</button>
<!-- the back of the front page, folded over: the same paper reflected across the fold -->
<span class="flapwrap" aria-hidden="true">
<span class="flap" data-flap>
<span class="flap__ghost">
<span class="label">Quillon Hall <span class="sep">/</span> Concerts</span>
<span class="title">Late<br>Quartets</span>
</span>
<span class="flap__shade" data-flap-shade></span>
</span>
</span>
</article>
</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.
41 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 card that turns like a page” from Animorio and fit it into my siteThe corner of the page is a point M on a spring. The fold is the bisector between the real corner C and M: the midpoint and the direction from M to C. Everything else comes from there, at every frame.
The front is the card cut on the side of the fold away from the corner: the rectangle clipped against a half-plane (Sutherland-Hodgman), written as a clip-path in pixels. The piece on the other side is the flap.
The flap is a layer as big as the card, in the colour of the back of the paper, cut to the same piece and then reflected across the fold with a matrix: matrix(1 − 2nx², −2nxny, −2nxny, 1 − 2ny², 2(Q·n)nx, 2(Q·n)ny). So it lies exactly over the front, and the print showing through is reversed, as on thin paper.
Three linear gradients laid along the fold, with stops in pixels from the line: the shadow on the front, the flap’s shadow on the inside and the curl of the flap, dark at the fold, then a thread of light, then the paper colour. They grow with how far the corner is lifted. Over the flap a drop-shadow lifts it off the page.
The page is held on its left side: the corner can’t go further from the spine than the paper is wide, nor further from the top corner than the diagonal. M is put back inside these two circles at every step, so the fold stays paper-like and never tears.
The click carries M along an arc past the spine in TURN seconds with power2.inOut, raising it by ARC of the height halfway; the flap fades as it passes the spine, and halfway through the turn the inside’s lines rise one after another. Going back runs the same arc the other way and hands M to the spring with its speed, which settles it with a small bounce.
| Name | File | Default | What it changes |
|---|---|---|---|
REST | script.js | 18 | How big the dog-ear is at rest, in pixels. |
LIFT | script.js | 74 | How far the corner lifts with the pointer on the card, in pixels. |
REACH | script.js | 150 | How close to the corner the pointer must come for the corner to follow it, in pixels. |
TURN | script.js | 1.05 | How long a full turn of the page lasts, in seconds. |
ARC | script.js | 0.2 | How high the corner rises while the page turns, as a share of the card’s height. |
STIFFNESS | script.js | 190 | How quick the corner’s spring is. |
DAMPING | script.js | 0.58 | The damping of the spring: at 1 it lands without going past, lower it goes past more. |
SHADE | script.js | 0.2 | How dark the shadows along the fold are. |
WEIGHT | script.js | [380, 540] | The weight of the title at rest and with the corner lifted. |
For the card of an event, a course or a product with something to say on the back: the concert with its programme, the course with its lesson plan, the wine with its tasting notes. It works where one more click to see the details is a pleasure rather than a chore.
The card narrows to 82 hundredths of the screen and its height is measured on the window’s height too, so it fits the box. With no pointer the corner stays dog-eared; a tap turns the page and «Back» turns it again. The flap fades as it passes the spine, so it never leaves the screen.
The corner stays dog-eared and doesn’t move; a click goes from the front to the inside with a fade, and the lines appear without rising.
GSAP 3.15.0, Fraunces (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.4 KB; the libraries: GSAP 28 KB.
Tested on 24 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.