
The slide-to-confirm button
Buttons, Physics, Transitions
NewFree
The button to sign up for a bike ride, Join the ride, made as a little swallowtail flag of red cloth on a short pole. The cloth is truly simulated, point by point, and the words are printed on it: at rest a breeze makes it wave gently, with the mouse over it the wind picks up where the pointer is, pressed it gathers in folds towards the pole. At a click a ruck runs down the flag to the tip, and behind it the flag has turned over: the other side is green and says You’re in with a tick. Then it turns back.
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 flag button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/saira@5.3.0/wght-italic.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the flag button: the sign-up of a club ride, made as a swallowtail pennant of cloth on a short pole. The cloth
is simulated (a grid of points in 3D, held by links, pushed by a breeze) and drawn on a canvas with the words
printed on it and the light on its folds. The pointer brings the wind up, a press gathers the cloth to the
pole, and the click sends a big wave down it that turns the flag over to You're in -->
<div class="flag" data-flag>
<div class="flag__spot" data-spot>
<canvas class="flag__shadow" aria-hidden="true" data-shadow></canvas>
<canvas class="flag__cloth" aria-hidden="true" data-cloth></canvas>
<button class="flag__btn" type="button" data-btn data-autoclic><span class="sr" data-name>Join the ride</span></button>
</div>
<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.
19 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 flag button” from Animorio and fit it into my siteThe flag is a grid of 33 by 7 points in space: the column on the pole is sewn on and does not move, the others move at every step by their speed (the distance from where they were before, damped by the air) plus the forces. Then, six times a step, the links bring each pair back to its distance: along and down (the cloth does not stretch), the two diagonals (it does not skew) and, softer, every other point (the folds stay round). The step is fixed, 1/120 of a second, and a frame never counts for more than 1/30. The forces: a light gravity, the wind blowing away from the pole and two trains of gusts, sin(2π(1.25u − 0.82t)) and a shorter, quicker one, pushing in and out of the page, stronger towards the tip: so the waves run from the pole to the tail.
The two sides of the flag are painted once on two off-screen canvases, at two or three times the resolution: the colour, the weave (fine threads both ways and a little grain), the darker hems with their dashed stitch, the bike or the tick and the letters one by one, with their kerning. Every frame the cloth is drawn triangle by triangle: for each triangle the affine that takes the flat triangle of the picture to where it is now comes from its three points, the triangle is clipped (a hair larger, so no gap is left between neighbours) and only the piece of the picture it needs is copied. The farthest triangles go first, and the whole cloth is clipped once to its own edge.
Each point’s normal is the cross product of its two neighbours along and its two neighbours down. Compared with a lamp at the upper left it gives how much darker or lighter that point is than if the cloth lay flat, plus a satin highlight where the fold faces between the lamp and the eye. The values go into two images of 33 by 7 pixels, one per point, stretched smoothly over the whole picture with source-atop before it is handed to the triangles: the light travels with the cloth and the folds have their light side and their dark one. The shadow on the page is the flag’s outline on a second canvas, moved in proportion to each point’s height and softened by the CSS.
With the pointer over it the wind grows by GUST, the gusts thicken in a bell round the pointer and the cloth is pushed away from its side. Pressed, every point is pulled towards a pole nearer by GATHER and every fourth column is pushed out of the page and the others in: the cloth gathers in even folds, and extra damping holds it still. At the click a burst of wind opens it and the ruck sets off: the points near it are pulled by a stiff spring towards a bell-shaped ridge 19 pixels high that runs from the pole to the tip in SNAP seconds, and behind it the cloth is smoothed flat. The two sides swap on the far slope of the ridge, where the cloth goes down to the page, in shadow and almost edge on, along a slightly slanting line with a thread of light and its shadow.
After the links, along each row every point stays at least a fifth of a cell to the right of the one before, and down each column a third of a cell lower: the cloth can fold in and out of the page as much as it likes, but never back over itself before the eye, and the tail never falls over the words. Enter, Space, a screen reader and the library’s preview make the same round: with no hand, the cloth gathers halfway by itself and then the ruck sets off. When the breeze is at zero and nothing moves any more, the flag is not redrawn; out of sight it stops.
| Name | File | Default | What it changes |
|---|---|---|---|
BREEZE | script.js | 1 | The breeze at rest: 0 the flag hangs almost still, 2 a fresh wind. |
GUST | script.js | 2.6 | How much the wind picks up with the pointer over the flag (1 = not at all). |
RIPPLE | script.js | 1 | How big the waves running along the cloth are. |
GATHER | script.js | 0.45 | How far the cloth gathers towards the pole while pressed, as a share of its length. |
SNAP | script.js | 0.75 | The seconds the ruck of the click takes to run from the pole to the tip. |
HOLD | script.js | 1.6 | The seconds the flag says You’re in before it turns back. |
NOTCH | script.js | 0.12 | How deep the swallowtail cut at the end of the flag is, as a share of its length (0 = a square flag). |
DONE_LABEL | script.js | You’re in | The words printed on the other side of the flag. |
For signing up to something done outdoors and together: a cycling club’s Saturday ride, a gran fondo, a running race, a regatta, an outing. It also suits event organisers or a bike shop. The colours of both sides and the words change in the CSS and in the script.
The flag is 284 pixels wide, or the screen minus 48, and 60 tall; the cloth and the words are redrawn to the real size. The finger touching it is the wind and the hand at once: the cloth waves and gathers, and letting go sets the ruck off. Up and down the page still scrolls (touch-action pan-y); the long-press menu is off.
The cloth stays still in a calm fold, with its light, and is not redrawn. No wind and no gathering: pressed, the flag only darkens a little. At the click the red side dims into the shade of the cloth and the green side comes up out of it, with nothing moving, and the same on the way back.
GSAP 3.15.0, Saira (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 15 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.