
The layered button
Buttons, Hover, Physics
Free
The Activate wristband button of a festival app is a glow stick: inside the frosted plastic tube a thin glass vial lies on the bottom and slides when the pointer tips the stick. Pressed, the stick bends and the vial snaps; let go, it springs straight and gets shaken. The two liquids only make light where they meet: the light is born at the crack, runs along the broken vial and rises in almost white curls as the shaking stirs them, then spreads out to both ends until the whole tube glows: Wristband active.
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 glow stick button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/unbounded@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the glow stick button: the Activate wristband button of a festival app is a glow stick. Inside the frosted
tube a thin glass vial lies loose in the liquid. Pressed, the stick bends and the vial snaps; then it is
shaken, the two liquids meet and light up where they mix, in curls that run along the tube, until the whole
stick glows: Wristband active -->
<div class="stick" data-stick>
<div class="stick__rig" data-rig>
<canvas class="stick__halo" aria-hidden="true" data-halo></canvas>
<button class="stick__btn" type="button" data-btn data-autoclic>
<canvas class="stick__tube" aria-hidden="true" data-tube></canvas>
<span class="stick__window" data-window>
<span class="stick__label" data-label>
<svg class="stick__tick" viewBox="0 0 16 16" aria-hidden="true" data-tick>
<path d="M3.2 8.6 6.5 11.7 12.9 4.6" data-tick-path/>
</svg>
<span class="stick__words" data-words>Activate wristband</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.
16 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 glow stick button” from Animorio and fit it into my siteThe liquid in the tube is a grid of 192 by 30 cells holding two concentrations: A, the activator kept in the vial, and B, the dye that fills the tube. While the vial is whole they are apart; when it snaps, the cells inside the vial become A = 1 and B = 0, all the others the other way round. A cell's light is the product A × B, that is how fast the reaction runs, over the value it will have once the liquid is mixed all through: so where the two meet hardest the light goes past 1 and turns almost white, and at the end the whole tube sits at 1, lime green.
The liquid moves by a stream function ψ, and the velocity is u = ∂ψ/∂y, v = −∂ψ/∂x: so it is never squeezed and, with ψ multiplied by sin(πy) and faded at the two ends, it never flows through the walls. ψ is the sum of three things: the slosh (the top and the bottom of the liquid going opposite ways while the tube moves), five rolls along the tube that turn with the shaking, and gaussian vortices born near the ends of the pieces of glass, dying out in half a second. At every turn of the shaking the rolls move to a random place along the tube: a blinking cell flow, which mixes chaotically instead of winding back.
Every frame each cell takes what was upstream of it (semi-Lagrangian advection with bilinear sampling), then the two liquids blend a little between neighbouring cells. The light is uncovered starting from the crack, with a front that runs along the vial in little more than a tenth of a second. Towards the end of MIX every cell moves towards the mixed value, starting later the further it is from the crack (and a little later high than low): the light spreads out to the ends and the tube is lit all through right on time.
At rest the vial is loose on the bottom: its acceleration follows the sine of the stick's tilt, with the drag of the liquid and a bounce against the end of the liquid. At a click it breaks near the middle with a zigzag edge shared by the two pieces, and a pair of opposite vortices pushes the liquid up between them, the small mushroom. At every turn of the shaking the longest piece breaks again; every piece slides with the tube's inertia, does not pass through its neighbours and comes to rest a little crooked on a spring. The slivers follow the flow and sink.
The whole stick is drawn straight on a canvas of its own (the plastic, the liquid, the glass, the shading of its round and the highlights), then copied onto the visible one a column of pixels at a time, each moved down by bend × (u² − 1/3), where u runs from −1 to 1 along the tube: the middle rises and the ends drop. Every letter of the words is a box of its own, moved by the same parabola and turned by its slope.
The words change by rolling inside a window with soft edges (a mask): the old line goes up and away while the new one comes up into its place, always a line apart, so they never sit on each other and there are always words. The light on the page is a second canvas at half resolution, blurred with CSS: only the light is drawn on it, with an empty border so it fades without corners, and faint light counts for less (to the power of 2.2), so while only one curl is lit there is no murky haze.
| Name | File | Default | What it changes |
|---|---|---|---|
BUSY | script.js | Activating… | The words while the stick is shaken and the light spreads. |
DONE | script.js | Wristband active | The words once the whole stick glows. If they are too long for the tube, the type gets smaller. |
BEND | script.js | 6 | How far the stick bends before the vial snaps, in pixels: 0 it does not bend. |
SHAKES | script.js | 3 | How many times it is shaken to mix the two liquids: 0, the light is born at the crack and spreads by itself. |
MIX | script.js | 1.9 | The seconds from the crack to the stick glowing all through: how long the activation takes. |
SWIRL | script.js | 1 | How hard the liquids curl as they mix: 0 they only seep into each other. |
HOLD | script.js | 1.8 | The seconds the stick stays lit, saying Wristband active, before it is ready again. |
HALO | script.js | 1 | How much light spills onto the page around the stick: 0 none. |
For the action that switches something on and makes it valid: activating a wristband, a pass, a ticket, an eSIM, a licence, a card that has just arrived. The stick that bends and then lights up tells the short wait of an activation, so it belongs where the action truly takes a couple of seconds. It is a button to show off, one to a page, in apps for festivals, concerts, nights out, outdoor sports and travel.
The stick is 56 pixels tall and 304 wide, or the screen less 32. With no pointer it does not lean and the vial stays where it is; the finger does all the rest: pressed it bends the stick, lifted it snaps the vial. If the finger slides away to scroll the page, the stick goes straight again without snapping. The light on the page reaches past the sides but never makes the page scroll.
No bending, no shaking, no curls and the stick does not lean. At a click the whole vial fades into its two broken pieces and the light fades in, even all along the tube, over the time of MIX; then Wristband active with the tick already drawn, and at the end the light dies and the vial is whole again, always in a fade. The words change by fading into one another in their place.
GSAP 3.15.0, Unbounded (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.