
The water button
Buttons, SVG, Physics, Hover
NewFree
A wine is rated with five glasses: moving over them, the glass pointed at and the ones before it are poured one after the other, and the wine inside sloshes for real, on the glass’s own movements. With the top rating the glasses are filled to the brim and the wine spills over in drops. Once the rating is picked, the full glasses are raised for a toast: they lean towards each other, touch where their bowls really meet, with a gold spark, and the knock sets the wine swinging.
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 wine glass rating</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/cormorant@5.3.0/wght.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/cormorant@5.3.0/wght-italic.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- a tasting note given with wine glasses: the glass under the pointer and the ones before it are poured, and the
wine in them sloshes for real, on the glasses' own movement; the top rating pours them to the brim and they
spill. Picked, the full glasses are raised and brought together for a toast: they clink, bounce apart and the
wine swings. Under the glasses there are five real radio buttons; the glasses are drawn by the script -->
<form class="taste" data-taste onsubmit="return false">
<p class="taste__ask" id="taste-ask">How was the 2019 Nebbiolo?</p>
<fieldset class="taste__row" aria-labelledby="taste-ask" data-row data-autoclic>
<svg class="taste__art" aria-hidden="true" data-art>
<defs>
<linearGradient id="taste-wine" x1="0" y1="-98" x2="0" y2="-38" gradientUnits="userSpaceOnUse">
<stop class="taste__stop-wine" offset="0"/>
<stop class="taste__stop-deep" offset="1"/>
</linearGradient>
<linearGradient id="taste-tint" x1="0" y1="0" x2="1" y2="0">
<stop class="taste__stop-tint" offset="0"/>
<stop class="taste__stop-clear" offset="0.45"/>
<stop class="taste__stop-tint" offset="1"/>
</linearGradient>
<clipPath id="taste-inside"><path data-inside/></clipPath>
</defs>
<g data-shadows></g>
<g data-glasses></g>
<g data-drops></g>
<g data-sparks></g>
</svg>
<div class="taste__choices" data-choices></div>
</fieldset>
<p class="taste__word" aria-hidden="true"><span data-word>Choose a glass</span></p>
<p class="taste__thanks" role="status" aria-live="polite" data-thanks></p>
</form>
</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.
26 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 wine glass rating” from Animorio and fit it into my siteOver the glasses lie five real radio buttons, see-through and with no pointer events, in a fieldset tied to the question (aria-labelledby): Tab goes into them, the arrows change the rating, screen readers read the number and the word (aria-label) and the form sends the value. The hand works on the glasses through pointer events; the arrows pour at once and log the rating after a 0.55 second pause (a gsap.delayedCall that every key restarts), Enter and Space log it straight away.
The bowl comes from one function: its half width at every height, a quarter ellipse from the bottom up to the widest point (BELLY), then a cosine curve going in towards the rim. From it come the outline, the light on the glass (a line parallel to the edge), the inside cut by the thickness of the glass and used as a clipPath for the wine, and the rim as two half ellipses, the far one paler. Each glass is a group with a translate and a rotate round its foot, redrawn only when something changes.
The wine’s surface is the sum of the first three sloshing modes of a bowl, cos(mπ(ξ+1)/2) across the width of the wine at its height, each a damped spring whose frequency grows as the square root of m (SLOSH). Every frame measures where the middle of the wine has got to and works out its acceleration: sideways it pushes the odd modes towards the slope a/g (the wine piles up away from where the glass goes), up and down it pushes the even one. In the glass’s own drawing the surface is tilted by −tan θ, so it stays level on the page however the glass leans. The sums run on GSAP’s ticker in steps of 1/240 of a second, with the frame capped at 1/30, and once everything is still the ticker is removed.
With the top rating the wine goes up to BRIM, near the rim. Every step checks the surface’s height at both sides of the mouth: whatever rises past the rim turns into drops, more the higher it goes, which leave the rim outwards with the glass’s speed, fall with gravity and vanish within half a second or on the table. They are tears drawn in SVG, pointed on the side they come from. The wine lost pays itself back: the level goes back to its spring.
For the toast each full glass has a pose: towards the middle of the full glasses by TOAST, leaning by TILT degrees for each place away, raised by 8 pixels. Before it starts, the share of the way at which two neighbouring bowls really touch is found: the points of one outline are taken into the other glass’s drawing and checked against its profile. A GSAP timeline takes the glasses there speeding up (power2.in), fires the spark at the point of contact, bounces them back by a tenth, holds them close and sets them down. The wine knows nothing of the timeline: it swings only because the glass stops short.
A finger slides sideways along the glasses (touch-action: pan-y) and the rating falls where it lifts; a mouse button let go away from the glasses picks nothing. The glass under the pointer is held by a soft spring that lifts it by 2.5 pixels and leans it up to 3 degrees towards the pointer, and the hand lets go when the toast starts. A click from a script (detail 0, the library’s preview) is a pretend hand: it runs to the rating and picks in turn Unforgettable, Pleasant, Elegant and Simple.
| Name | File | Default | What it changes |
|---|---|---|---|
LABELS | script.js | ['Not for me', 'Simple', 'Pleasant', 'Elegant', 'Unforgettable'] | The word for each rating, from the lowest to the highest (and how many glasses: 2 to 6). |
START | script.js | 0 | The rating picked when the page opens (0 = empty glasses). |
POUR | script.js | 0.4 | How much wine is poured in a glass, from the bottom of the bowl (0) to the rim (1). |
BRIM | script.js | 0.92 | How far they are poured for the top rating: so near the rim that the wine spills. |
SLOSH | script.js | [2.6, 0.055] | The wine’s slosh: how many times a second it swings and how quickly it calms down. |
TOAST | script.js | 0.62 | How far the glasses travel towards each other for the toast (with too little the bowls no longer touch and the toast goes without a spark). |
TILT | script.js | 8 | How far the glasses lean in for the toast, in degrees for each place away from the middle. |
STAGGER | script.js | 0.07 | The time between one glass and the next as they are poured or emptied, in seconds. |
For rating a wine in a winery’s or wine shop’s app, for a wine club’s tasting notes, for reviewing a bottle bought online, to ask how a dinner or an evening at a wine bar went: wherever a rating is about drinking and celebrating, and stars would feel anonymous.
The glasses narrow with the screen: 358 pixels at 390. A finger slides sideways along the glasses and the rating falls where it lifts; up and down the page still scrolls (touch-action: pan-y). A tap picks straight away and starts the toast.
No sloshing, no drops and no toast: the wine fades in already at its level and fades out the same way, the glasses stay still on the table; the word and the thanks change in a fade.
GSAP 3.15.0, Cormorant (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 13 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.