
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
Delete project comes apart into thousands of grains: from left to right the button crumbles and a wind full of eddies carries the red dust away, while in its place the dark note Project deleted with Undo gathers out of the wind. Undo runs it all backwards, and the grains fly home into the button.
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 crumbling button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the crumbling button: pressed, the button is painted on a canvas, its pixels become grains and a wind full of
eddies carries them off from left to right; in its place "Project deleted" gathers out of the same wind, and
Undo plays the whole film backwards until the button is whole again -->
<!-- the button and the note that takes its place share one cell; their shadows stand apart, so that they can fade
while the grains fly -->
<div class="action" tabindex="-1" data-action data-autoclic>
<div class="action__item" data-del-wrap>
<span class="action__shadow action__shadow--del" aria-hidden="true" data-del-shadow></span>
<button class="del" type="button" data-del>
<svg class="del__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M4 6.5h16M9.5 6.5V5a1.5 1.5 0 0 1 1.5-1.5h2A1.5 1.5 0 0 1 14.5 5v1.5" data-lid/>
<path d="M6 6.5l.9 12.6A2 2 0 0 0 8.9 21h6.2a2 2 0 0 0 2-1.9L18 6.5M10 10.5v6.5M14 10.5v6.5"/>
</svg>
<span class="del__label">Delete project</span>
</button>
</div>
<div class="action__item" data-toast-wrap>
<span class="action__shadow action__shadow--toast" aria-hidden="true" data-toast-shadow></span>
<div class="toast is-gone" role="group" aria-label="Project deleted" data-toast>
<svg class="toast__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20.5a8.5 8.5 0 1 0 0-17a8.5 8.5 0 0 0 0 17z"/><path d="M8.6 12.2l2.3 2.3 4.6-4.7"/></svg>
<span class="toast__text">Project deleted</span>
<span class="toast__rule" aria-hidden="true"></span>
<button class="undo" type="button" data-undo>
<svg class="undo__icon" viewBox="0 0 24 24" aria-hidden="true"><g data-undo-turn><path d="M8.5 14.5L4 10l4.5-4.5"/><path d="M4 10h10.5a5 5 0 0 1 0 10H11"/></g></svg>
<span class="undo__label">Undo</span>
</button>
</div>
</div>
<p class="sr" aria-live="polite" data-live></p>
</div>
</main>
<!-- the grains in the wind, over the whole page -->
<canvas class="dust" aria-hidden="true" data-dust></canvas>
<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 crumbling button” from Animorio and fit it into my siteOn the click the button (and the note that will take its place) is painted again on a canvas at the screen's resolution, from the computed styles: the gradient, the two inner lines of light, the SVG icon stroked with Path2D and the label on the page's own baseline (an empty element put into the line for a moment tells where it is). The painting starts from the same whole pixel as the page, so swapping the real button for its painting does not show.
The painting's pixels are read with getImageData in square cells of GRAIN pixels (about 1,700 grains for the button, 3,000 for the note). Each grain has its home, the average colour of its cell, a moment it sets off (its x along the button times SWEEP, plus a noise that makes the ragged front) and a flight time. They are drawn grouped by colour, one fillRect each, on a fixed canvas over the page.
The wind is WIND to the right, lifted by LIFT, plus the eddies: the curl of a noise field at two scales, worked out once on a grid every 8 pixels. The velocity is the noise's slope turned a quarter of a turn, so the air swirls without ever piling the grains up or tearing them apart; the eddies are carried by the wind at a little over half its speed, and CURL sets their strength.
Every grain's path is integrated ahead with the midpoint method, 32 steps, and kept in a Float32Array; it is worked out as soon as the page is still, and again after a resize, so the click only has to paint. The whole film is a function of a single time that GSAP moves. The note gathers by integrating backwards from its place against the same breeze: played forwards, each grain arrives with the wind and slows as it lands.
Undo brings the time back to zero in REWIND seconds with power2.inOut: the note comes apart into the wind and the button's grains fly home the same way they left. An image of what is whole is updated cell by cell, cleared when a grain leaves and painted back when it returns; the shadows under the button and the note follow the same time, with a soft mask that moves with the front.
| Name | File | Default | What it changes |
|---|---|---|---|
WIND | script.js | 300 | The speed of the wind, in pixels a second. |
CURL | script.js | 130 | How hard the eddies in the wind turn the grains, in pixels a second. |
LIFT | script.js | 0.16 | How much the wind lifts the grains, as a share of its speed. |
SWEEP | script.js | 0.75 | The seconds the crumbling takes to cross the button from left to right. |
FLIGHT | script.js | 1.3 | The seconds a grain flies before it is gone. |
GRAIN | script.js | 1.5 | The size of a grain, in pixels. |
REWIND | script.js | 1.15 | The seconds Undo takes to put the button back together. |
For the action that deletes something and can be undone: a project, a file, a conversation, an item in a list. The button coming apart says the thing is gone, and the film running backwards says that Undo truly brings it back. Best on a rare action: it is a show, not a gesture to repeat a hundred times a day.
The button and the note sit in the middle of the page, in the same place; the grains are painted at the screen's density (up to 2) and the cells grow on their own if there would be too many. The wind carries the grains past the edge of the screen without making it scroll sideways. A tap works like a click, and the bin's hover is not there.
No grains and no wind: the button fades out and the note fades in in its place, and Undo does the same the other way round. The bin does not open its lid, the press shows in the light alone and the button does not come up on arrival.
GSAP 3.15.0, Geist (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 13 KB; the libraries: GSAP 28 KB.
Tested on 4 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.