
The needle gauge
Counters, Physics, SVG
NewFree
A pill of honey with a drop hanging under it: a glint of light slides over its surface after the pointer, the drop swells and stretches as you come near, and on the click the thread thins and snaps, the drop falls, splashes and spreads into a small pool. Then a new drop grows back out of the pill.
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 honey button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the honey button: an amber pill of real-looking honey with a drop hanging under it. A light glides over its
surface after the pointer, the drop swells and stretches when you come near, and pressing lets it go: the
thread thins and snaps, the drop falls, splashes and settles into a small pool, the words say "Added to
cart", and a moment later a new drop grows back out of the pill -->
<div class="honey" data-honey>
<svg class="honey__svg" aria-hidden="true" data-svg>
<defs>
<linearGradient id="honey-fill" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="260" data-fill></linearGradient>
<filter id="honey-goo" filterUnits="userSpaceOnUse" x="-64" y="-24" width="360" height="340" color-interpolation-filters="sRGB" data-filter>
<feGaussianBlur in="SourceGraphic" stdDeviation="3.4" result="blur"/>
<feColorMatrix in="blur" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -9" result="goo"/>
<feGaussianBlur in="goo" stdDeviation="1.7" result="bump"/>
<feDiffuseLighting in="bump" surfaceScale="5" diffuseConstant="1.3" lighting-color="#ffffff" result="shade">
<fePointLight x="116" y="-60" z="140" data-light-a/>
</feDiffuseLighting>
<feComponentTransfer in="shade" result="soft">
<feFuncR type="linear" slope="0.5" intercept="0.55"/>
<feFuncG type="linear" slope="0.5" intercept="0.55"/>
<feFuncB type="linear" slope="0.5" intercept="0.55"/>
</feComponentTransfer>
<feComposite in="goo" in2="soft" operator="arithmetic" k1="1" k2="0" k3="0" k4="0" result="lit"/>
<feSpecularLighting in="bump" surfaceScale="5" specularConstant="1.1" specularExponent="26" lighting-color="#fff4cf" result="glint" data-glint>
<fePointLight x="116" y="-60" z="140" data-light-b/>
</feSpecularLighting>
<feComposite in="glint" in2="goo" operator="in" result="glint-in"/>
<feComposite in="lit" in2="glint-in" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="honey"/>
<feDropShadow in="honey" dx="0" dy="10" stdDeviation="7" flood-color="#a35a00" flood-opacity="0.28"/>
</filter>
</defs>
<g filter="url(#honey-goo)" data-goo>
<rect data-pill x="0" y="0" width="232" height="60" rx="30" fill="url(#honey-fill)"/>
</g>
</svg>
<button class="honey__btn" type="button" aria-label="Order a jar" data-btn data-autoclic>
<span class="honey__word" aria-hidden="true" data-word>Order a jar</span>
<span class="honey__word honey__word--done" aria-hidden="true" data-done>
<svg class="honey__tick" viewBox="0 0 20 20"><path data-tick d="M4.5 10.5l3.6 3.6 7.4-8.2"/></svg>
<span data-done-text>Added to cart</span>
</span>
</button>
<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.
20 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 honey button” from Animorio and fit it into my siteA rounded rectangle, an ellipse for the drop, a row of twelve circles for the thread, the pool and the droplets all sit in one group. The filter blurs the group by 3.4 pixels and then cuts the edge hard with a colour matrix on the alpha (times 20, minus 9): shapes that touch melt together like metaballs and the edges come back sharp.
The result of that filter, blurred a little more, is the height map for two lights from the same point: a diffuse one that gives the volume (raised by a floor with a feComponentTransfer, or the far side goes black) and a specular one, the glossy glint. The script moves the light point towards the pointer and returns it to the top at rest.
At rest the drop follows a spring to the wanted length (longer when the pointer is near) and another one sideways, which bends it towards the pointer. On the click the springs are switched off and gravity and speed take over. The ellipse stretches with speed while keeping the same area.
Twelve circles between the foot of the pill and the drop, bigger at both ends and thinner in the middle. The middle radius falls with the length (a stand-in for volume being kept); when it falls below 1.3 the thread snaps: a stub folds back into the pill and a tiny drop leaves from the middle.
The pool is an ellipse with two under-damped springs, one for the width and one for the height, so it rings on contact. The droplets are bodies with a lighter gravity; when they reach the ground they nudge the pool’s spring. After HOLD seconds the pool is taken to zero and the new drop grows from the pill, with the spring bouncing it.
| Name | File | Default | What it changes |
|---|---|---|---|
LABEL | script.js | 'Order a jar' | The words at rest. |
DONE | script.js | 'Added to cart' | The words after the drop has landed. |
DRIP | script.js | [32, 50] | The length of the hanging drop at rest and with the pointer near, in pixels. |
GRAVITY | script.js | 2600 | How hard the drop falls. |
HOLD | script.js | 2.6 | The seconds the pool stays before the honey is taken back. |
PUDDLE | script.js | 30 | The half-width of the pool, in pixels. |
SPLASH | script.js | 6 | How many droplets the landing throws. |
GROUND | script.js | 230 | How far below the pill the pool forms, in pixels. |
SHINE | script.js | [0.85, 30] | The glossy glint: how strong and how sharp. |
COLORS | script.js | ['#ffcb3d', '#f39a00', '#c9700a'] | The honey, from the top to the foot. |
For a purchase, an order or an “add” where the product is something to eat, cook or give, and the button can have a material and a gesture.
Taps work like clicks. With a finger there is no glint following the pointer and no drop that stretches as you come near; the fall and the pool are there. The low part of the scene (about 230 pixels under the pill) must fit on the screen.
No springs, no fall, no splashes and no moving glint. On the click the drop is gone, the pool is already in place and the words swap with a fade; then the drop comes back.
GSAP 3.15.0, Geist (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.0 KB; the libraries: GSAP 28 KB.
Tested on 6 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.