
The inflatable button
Buttons, Physics, WebGL, 3D
NewFree
A seed company's spring catalogue, printed in four risograph inks, leafed through by taking its pages by the corner. The paper is drawn in WebGL and bends like the real thing: round a cone whose tip sits on the line of the spine, so the spine stays put, the paper never stretches and the corner you hold curls more than the rest. Let go, the page falls to the side it leans to, the air holds back its edge and the paper flutters as it lands; light, sheen and shadow come from the shape.
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 seed catalogue</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/caprasimo@5.3.0/index.css">
<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">
<!-- a seed catalogue printed in four risograph inks. The pages are drawn on a WebGL canvas: a page taken by a
corner bends round a cone whose tip sits on the line of the spine, so the spine stays put and the paper never
stretches; light, sheen and shadow come from the shape. The words below are the real pages: the script draws
them on the paper, and a screen reader reads them -->
<section class="catalogue" aria-label="Wrenfield Seed Co., spring catalogue" data-catalogue data-autoclic>
<div class="book" tabindex="0" role="group" aria-roledescription="catalogue" aria-label="Wrenfield Seed Co., spring catalogue" data-book>
<canvas class="book__paper" aria-hidden="true" data-paper></canvas>
<canvas class="book__ghost" aria-hidden="true" data-ghost></canvas>
<span class="book__ring" aria-hidden="true" data-ring></span>
<div class="book__text" data-pages>
<article data-art="cover" data-name="Cover">
<p data-kicker>Spring 2027</p>
<h2><span>Wrenfield</span> <span>Seed Co.</span></h2>
<p data-text>Heirloom vegetables, herbs and cutting flowers.</p>
<p data-text>Grown and saved on our own fields.</p>
</article>
<article data-art="note" data-name="From the field">
<h2>From the field</h2>
<p data-text>Every packet in here was grown on our farm, picked by hand and dried in the old barn. We sow what we sell, so we only sell what did well for us.</p>
<p data-sign>Mara and Teo, growers</p>
<h3>When to sow</h3>
<ul>
<li data-sow="3-4" data-pick="7-9">Tomatoes: sow in March and April, pick from July to September.</li>
<li data-sow="5-6" data-pick="7-9">Beans: sow in May and June, pick from July to September.</li>
<li data-sow="4-5" data-pick="9-10">Squash: sow in April and May, pick in September and October.</li>
<li data-sow="3-6" data-pick="5-10">Herbs: sow from March to June, pick from May to October.</li>
<li data-sow="4-5" data-pick="7-10">Flowers: sow in April and May, cut from July to October.</li>
</ul>
</article>
<article data-art="tomatoes" data-name="Tomatoes">
<p data-kicker>Tomatoes</p>
<h2>Sun on the vine</h2>
<ul>
<li><b>Brandywine</b> <span>Pink beefsteak, rich and old fashioned.</span> <span data-days>85 days</span> <span data-price>$3.80</span></li>
<li><b>Green Zebra</b> <span>Striped, sharp and very juicy.</span> <span data-days>75 days</span> <span data-price>$3.60</span></li>
<li><b>San Marzano</b> <span>Long and meaty, the one for sauce.</span> <span data-days>80 days</span> <span data-price>$3.40</span></li>
</ul>
</article>
<article data-art="beans" data-name="Beans and peas">
<p data-kicker>Beans and peas</p>
<h2>Up the poles</h2>
<ul>
<li><b>Borlotti</b> <span>Splashed pods, creamy beans.</span> <span data-days>65 days</span> <span data-price>$3.20</span></li>
<li><b>Blue Lake</b> <span>A stringless green climber.</span> <span data-days>60 days</span> <span data-price>$2.90</span></li>
<li><b>Scarlet Runner</b> <span>Red flowers first, then long pods.</span> <span data-days>70 days</span> <span data-price>$3.20</span></li>
</ul>
</article>
<article data-art="squash" data-name="Squash">
<p data-kicker>Squash</p>
<h2>Keeps till spring</h2>
<ul>
<li><b>Musquée de Provence</b> <span>Deep ribs and sweet orange flesh.</span> <span data-days>120 days</span> <span data-price>$4.10</span></li>
<li><b>Delicata</b> <span>Small and striped, no peeling.</span> <span data-days>100 days</span> <span data-price>$3.60</span></li>
<li><b>Crown Prince</b> <span>Blue grey skin, keeps for months.</span> <span data-days>110 days</span> <span data-price>$3.90</span></li>
</ul>
</article>
<article data-art="herbs" data-name="Herbs">
<p data-kicker>Herbs</p>
<h2>By the kitchen door</h2>
<ul>
<li><b>Genovese basil</b> <span>Big soft leaves for pesto.</span> <span data-days>60 days</span> <span data-price>$2.80</span></li>
<li><b>Dill</b> <span>Feathery, with flowers for pickles.</span> <span data-days>55 days</span> <span data-price>$2.40</span></li>
<li><b>Flat-leaf parsley</b> <span>Sow a little, and often.</span> <span data-days>75 days</span> <span data-price>$2.40</span></li>
</ul>
</article>
<article data-art="flowers" data-name="Cutting flowers">
<p data-kicker>Cutting flowers</p>
<h2>A bucket a week</h2>
<ul>
<li><b>Zinnia</b> <span>Hot colours from July to the frost.</span> <span data-days>75 days</span> <span data-price>$3.20</span></li>
<li><b>Cosmos</b> <span>Tall and airy, the more you cut.</span> <span data-days>90 days</span> <span data-price>$3.00</span></li>
<li><b>Sweet pea</b> <span>Scented, sow in autumn or spring.</span> <span data-days>100 days</span> <span data-price>$3.40</span></li>
</ul>
</article>
<article data-art="back" data-name="Back cover">
<h2>Order by post or at the farm gate</h2>
<p data-text>Packets leave the barn within two days.</p>
<p data-text>Every order over $25 comes with a free packet of marigolds.</p>
<p data-sign>Wrenfield Seed Co.</p>
</article>
</div>
</div>
<nav class="leaf" aria-label="Pages">
<button class="leaf__btn leaf__btn--prev" type="button" aria-label="Previous page" data-prev><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14.5 6l-6 6 6 6"/></svg></button>
<p class="leaf__where"><span class="leaf__roll" data-where></span></p>
<button class="leaf__btn leaf__btn--next" type="button" aria-label="Next page" data-next><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9.5 6l6 6-6 6"/></svg></button>
</nav>
<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.
108 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 seed catalogue” from Animorio and fit it into my siteThe page is a grid of 34 by 26 points on the flat sheet. Bent, every point lies on a line from the tip of a cone set on the line of the spine, past the top or bottom edge: the spine is one of those lines, so it does not move, and every point keeps its distance from the tip, so the paper never stretches (it is Hong, Card and Chen's model for electronic books, generalised). Going round the tip, the direction of the lines traces a curve on a sphere: it is built in steps, turning the direction of travel by as much as the bend wants (spread with a smoothstep over part of the page) and then walking on along the great circle; the first direction is the angle round the spine. Normals included, it is 40 rotations a page.
The cone's tip comes close to the corner you take: taken at the corner it sits a fifth of a page away, and the bend is tight and diagonal; taken halfway down the edge it goes very far, and the cone becomes a cylinder. The whole move is one number p from 0 to 1: at first it is nearly all bend (the corner lifts), then the page turns, and at the end it lies flat. To keep the spot you took under the finger, at every move the script works out where it would land on the screen, perspective included, for 40 values of p and takes the right one; moving the corner up or down brings the tip closer or further.
The hand pulls the page with a stiff spring, so when let go the page has the hand's speed. Free, it turns round the spine by its own weight (a torque that goes with the cosine of the angle and changes sign past the middle), slowed by the air linearly and quadratically, and lands with a little bounce; the bend is a second spring (FLUTTER) pulled towards −AIR times the speed, so the edge lags while it falls and flutters as it lands. The page cannot bend into the pile: the bend stays between −angle and 180° − angle. On release, where it will land is simulated ahead, and the words below change at once. The arrows are a pretend hand that lifts the bottom corner inside the same physics and lets the page go past the top.
The real pages are the articles in the HTML, hidden from sight and read by screen readers: the script reads them and prints them once onto 1024 canvases, in units of 300 by 414. Each ink (yellow, green, red, blue) is a layer of its own, pitted where the drum runs dry with a grain pattern, laid on the paper with multiply and shifted by a hair, like a risograph out of register: red on yellow makes the squash orange, green on yellow the leaf green, blue on yellow the dark green of the title. Type: Caprasimo for titles and names, Bricolage Grotesque for the rest.
In WebGL every page has two faces (gl_FrontFacing picks the print) and the light is worked out on the normal: Lambert, normalised so a page lying flat shows the right colours, a little light coming through from behind, a sheen only where the curve faces the light more than a flat page, the fold at the spine and the edge. In the air the paper lets the print of its back show through, reversed. The shadow: the pages in the air are cast along the light into a texture 256 wide, darker where they are low (MAX blending), blurred in two passes and read by the lying pages and the table; under the top page of each pile the edges of three sheets peek out.
Under 640 pixels each page sits on a sheet of its own, with a plain back and the print showing through; the turned page leaves the frame fading, and the one before is brought back by dragging from the left third. Closed, the catalogue sits in the middle, and goes back there only once every page has crossed the spine. Arrows, Page Up and Down, Home and End; aria-live says the open pages. A click from a script (the library's preview) turns the next page and, at the back cover, brings all the pages back in a fan.
| Name | File | Default | What it changes |
|---|---|---|---|
TURN | script.js | 0.5 | The seconds the arrows' hand takes to carry a page over the top. |
BEND | script.js | 1.15 | How far a page curls when taken by a corner, in radians. |
PEEK | script.js | 1.5 | How far the corner curls when the mouse comes near it, in radians. |
AIR | script.js | 0.1 | How much the air holds back the edge of a falling page. |
FLUTTER | script.js | [130, 6] | The paper's spring: stiffness and damping (lower, more flutter as it lands). |
GRAVITY | script.js | 24 | How quickly a page let go falls to the side it leans to. |
COVER | script.js | 2.2 | How many times stiffer the cover is than the pages. |
LIGHT | script.js | [-0.36, 0.3, 1] | Where the light comes from: left or right, up or down, and its height. |
SHADOW | script.js | 0.42 | How dark the shadow of a lifted page is. |
DEPTH | script.js | 2200 | The perspective in pixels: smaller brings a lifted page closer to you. |
For the catalogue of a nursery or a seed company, a magazine, a brochure, a lookbook, a restaurant's menu, a recipe book, the yearbook of a club or a school, a wedding booklet: anything printed that is worth leafing through.
Under 640 pixels the catalogue shows one page at a time, up to 360 pixels wide: the finger takes the page and turns it towards the spine on the left, and a third of the way is enough for it to fall; the page before is brought back by dragging from the left third to the right. The catalogue lets the page scroll vertically (touch-action pan-y) and only takes sideways gestures. The corners that turn down under the mouse are not there on a phone.
Pages turn at once, with the arrows, the keys, a tap or a sideways swipe: the old pages dissolve over the new ones. No bending under the hand, no corners under the mouse, no entrance, and the catalogue changes place without sliding.
GSAP 3.15.0, Caprasimo 5.3.0, Bricolage Grotesque (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 27 KB; the libraries: GSAP 28 KB.
Tested on 6 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.