
The needle gauge
Counters, Physics, SVG
NewFree
The RSVP of a birthday party, Count me in, with a string of cloth pennants hanging slack under the raspberry pill: coral, sun, mint, pink and cream triangles with a line of stitches along the hem. Under the pointer a breeze ruffles them; at a click the string is hoisted in three heaves while the answer goes, then a last pull snaps it taut, the snap runs along the string and every pennant whips. The string is a chain of 36 points worked out every frame and each pennant has its own two swings. A moment later the string is let down again.
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 bunting button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the bunting button: the RSVP of a birthday party, with a string of cloth pennants hanging in a slack swag from
under the pill. Under the pointer a breeze ruffles them; a click hoists the string in a few heaves while the
answer goes, it snaps taut and every pennant whips and flaps, and the pill says you are on the list. A moment
later the string is let down again -->
<div class="bunting" data-bunting>
<div class="bunting__unit">
<!-- the string and its pennants, drawn by script.js behind the pill, so the string comes out from under it -->
<svg class="bunting__art" aria-hidden="true" data-art></svg>
<button class="bunting__btn" type="button" data-btn data-autoclic>
<span class="bunting__fill" aria-hidden="true"></span>
<span class="bunting__faces">
<span class="bunting__face" data-face="rest">
<span class="bunting__word" data-wide="Count me in" data-rest-text>Count me in</span>
<span class="bunting__date" data-rest-date>Sat 8 pm</span>
</span>
<span class="bunting__face bunting__face--two" data-face="busy" aria-hidden="true">
<span class="bunting__small" data-busy-small>Mia turns 30</span>
<span class="bunting__big" data-busy-text>Sending your RSVP</span>
</span>
<span class="bunting__face bunting__face--two" data-face="done" aria-hidden="true">
<span class="bunting__big" data-done-text>You’re on the list</span>
<span class="bunting__small" data-done-small>Sat 8 pm · bring a song</span>
</span>
</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.
22 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 bunting button” from Animorio and fit it into my siteThe string is a chain of 36 points tied behind the pill's two ends, worked out with Verlet integration: each point keeps its speed as the difference between where it is and where it was, gravity pulls it down, a little air holds it back, and twenty passes of constraints put each link back at its length. The links' length comes from how slack the string is (SLACK, its length over the distance between the knots): changing it, the string slackens or tightens by itself, with its own inertia. An SVG behind the pill draws it as a smooth curve of quadratics through the midpoints.
Each pennant hangs from three links: its hem follows the string's curve and its tip hangs at right angles to the hem. It has two swings of its own: sideways, a pendulum pushed the other way when the string jerks sideways (θ'' = −(g / l) sin θ − c θ' − a / l); to and fro on its hem, a flap pushed by the string's vertical jolts and by the breeze. The flap shows as perspective: turned away, the pennant looks shorter, darkens and its fold shows more. Each point's acceleration is measured every step from the change in its speed.
At a click a GSAP timeline shortens the string in three heaves of 0.16 seconds every 0.38: at each heave the string rises and bounces on its own. Then a last pull takes it a hair past its taut length and lets it back: that is the snap. At the same moment each pennant gets a kick of flapping, one after the other 35 thousandths apart, alternating its way, so the snap runs along the string. Going back is the same in reverse: the string lengthens in 0.9 seconds and drops back into its swag, swinging.
Under the pointer a breeze rises and falls slowly: on the string it is a sideways push in slow waves along its length, on the pennants two waves of different periods and a different phase for each, so they never flap all together. When the breeze dies and nothing moves any more, GSAP's loop stops drawing.
Three faces on top of each other, as wide as their words (at rest, answering, on the list); the pill is measured once on the widest and the string's drawing takes its width. The button is a real button with aria-disabled while the string is up, an aria-live region that says Sending your RSVP… and then You're on the list. Mia turns 30, Sat 8 pm, bring a song., and an aria-label that changes with the state.
| Name | File | Default | What it changes |
|---|---|---|---|
LABEL | script.js | Count me in | The words at rest. |
WHEN | script.js | Sat 8 pm | The date beside the words, and again underneath once you are on the list. |
PARTY | script.js | Mia turns 30 | The small line while the answer goes: whose party it is. |
SENDING | script.js | Sending your RSVP | The words while the string is hoisted; the aria-live region says them too. |
DONE | script.js | You’re on the list | The words once the string is taut. |
NOTE | script.js | bring a song | The small line under them, after the date: a note for the party. |
FLAGS | script.js | 7 | How many pennants hang from the string. |
SLACK | script.js | 1.07 | How slack the string hangs at rest: its length over the distance between the knots. 1.03 nearly taut, 1.14 a deep swag. |
HOLD | script.js | 2.8 | The seconds the string stays taut before it is let down. |
BREEZE | script.js | 1 | How hard the breeze under the pointer ruffles the pennants: 0 they stay still. |
For the RSVP of an invitation to a party, a birthday, a wedding, a dinner with friends or a shop opening, for an event's I'm going or a community's Join the party. The button fakes the answer: in a real site the click sends the answer and the string snaps taut when the server confirms.
The pill is about 250 pixels wide and the swag hangs some forty pixels under it at most: at 390 pixels it fits. A tap tugs the string, squashes the fill and answers. The pennants keep their size.
The string does not move and the pennants do not flap: when the answer is confirmed the bunting fades and comes back taut, and when it is let down it fades and comes back in its swag. The words fade in, the pill does not swell and the words do not widen (under the mouse the fill only lightens a little).
GSAP 3.15.0, Anybody (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.2 KB; the libraries: GSAP 28 KB.
Tested on 19 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.