Skip to content
animorio
IT
All components

The flag button

Buttons, Physics, TransitionsCanvas, GSAPAdvancedCompressed weight: Demo 15 KBGSAP 28 KBFreeDownload the zip

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.

The code

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>

Playground

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

Or ask Claude Code for it

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 site

What it does

On a white background a short dark pole, as tall as the button, with a brass cap on top and its foot showing below. From the pole runs a little swallowtail flag of red cloth, sewn round the pole with a sleeve: you see the weave of the fabric, the hems a little darker with a pale running stitch all round, along the cut of the tail too, and printed in cream a bicycle and JOIN THE RIDE in italics. A light breeze sends small waves from the pole to the tip: the folds have a lit side and a shaded one, the cloth has a satin sheen, the tail moves more than the rest and the flag’s soft shadow falls on the page, following the waves. On arrival the flag is gathered on its pole and the wind opens it. With the mouse over it the wind picks up: the waves grow deeper round the pointer and the cloth moves away from the side it comes from. Pressed, the cloth gathers towards the pole in even folds, like a drawn curtain. At the click a burst of wind opens it again and a ruck sets off from the pole and runs to the tip: where it has passed the flag has turned over, green, with a tick and YOU’RE IN; along the edge of the ruck there is a thread of light and its shadow falls on the side still red. At the end a gust pulls it taut. After a moment a slower ruck turns it back to the red side. With the keyboard the focus shows a dark ring round the flag and a breath of wind runs along it; Enter turns it, Space gathers it while held. On a phone the touching finger is wind and press at once.

How it works

A Verlet cloth in 3D

The 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 words printed on the cloth

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.

Light from the normals

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.

The wind, the hand and the ruck

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.

Never over the words

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.

Values to change

NameFileDefaultWhat it changes
BREEZEscript.js1The breeze at rest: 0 the flag hangs almost still, 2 a fresh wind.
GUSTscript.js2.6How much the wind picks up with the pointer over the flag (1 = not at all).
RIPPLEscript.js1How big the waves running along the cloth are.
GATHERscript.js0.45How far the cloth gathers towards the pole while pressed, as a share of its length.
SNAPscript.js0.75The seconds the ruck of the click takes to run from the pole to the tip.
HOLDscript.js1.6The seconds the flag says You’re in before it turns back.
NOTCHscript.js0.12How deep the swallowtail cut at the end of the flag is, as a share of its length (0 = a square flag).
DONE_LABELscript.jsYou’re inThe words printed on the other side of the flag.

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The two sides swapped where the push was fell on flat cloth and looked like a wipe: the cloth lags behind the push. Now the points near the ruck are pulled by a stiff spring towards a running ridge, and the swap sits on the far slope of the ridge, in shadow.
  • A slanting ridge turned the flag and left a skewed fold, like paper folded on a diagonal: the ridge stays upright and only the line of the swap slants.
  • A ruck drawing cloth in from both sides pulled the tail back, and the tail fell over it, covering the words; stopping it halfway gave back all the cloth it had taken at once, with the same result. The rule that along each row a point always stays to the right of the one before makes it impossible for the cloth to fold back over the words.
  • The folds left by the press were frozen behind the ruck: behind it the cloth is smoothed flat, and on release a burst of wind opens it before the ruck sets off.
  • The triangles a hair larger, which close the gaps between neighbours, overlapped along the edge and left a row of little dark dots: the whole cloth is clipped once to its outline.
  • With 24 columns the light of a ruck 40 pixels wide fell into a single cell and did not show: there are 32 columns.
  • With reduced motion the dissolve between red and green went through brown, with the two words on top of each other: now the old side dims into the shade of the cloth and the new one comes up out of it. For the same reason the sleeve on the pole changes colour at once.
  • The shadow on the page jumped above the flag when a fold went deeper than the page itself: a fold can reach the page, never go through it.
  • A corner of the tail left folded over never opened again: a very faint memory of the flat flag unrolls it by itself.

Libraries

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.

Testing

Tested on 12 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

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.

All components