
The needle gauge
Counters, Physics, SVG
NewFree
The inks of a small ink maker, each in its glass bottle, on a shelf that slides: when the shelf sets off the ink is left behind and climbs the glass, when it brakes it runs to the other side, and when it stops it rocks until it lies flat again. Where the wave went the glass stays stained, and the stain runs back down in streaks. Each bottle rocks at its own pace: the wide ones slowly, the narrow ones quickly.
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 sloshing inks</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/alegreya@5.3.0/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the inks of a small ink maker, each in its glass bottle on a shelf that moves. The ink feels the shelf: it
is left behind when the shelf sets off, runs up the glass when it brakes, rocks when it stops, and the glass
stays stained where the wave went until the film drains back down. The bottles are drawn by the script -->
<section class="shelf" role="region" aria-roledescription="carousel" aria-labelledby="shelf-title" data-shelf>
<header class="shelf__head">
<h2 class="shelf__title" id="shelf-title">Fountain pen inks</h2>
<div class="shelf__arrows">
<button class="arrow" type="button" aria-label="Previous inks" aria-controls="shelf-track" data-prev>
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 6.5 8.5 12l5.5 5.5"/></svg>
</button>
<button class="arrow" type="button" aria-label="Next inks" aria-controls="shelf-track" data-next data-autoclic>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path class="arrow__step" d="M10 6.5 15.5 12 10 17.5"/>
<path class="arrow__back" d="M18.5 12H9M13 7.5 8.5 12l4.5 4.5M5.5 6.5v11"/>
</svg>
</button>
</div>
</header>
<div class="shelf__view" tabindex="0" aria-describedby="shelf-help" data-view>
<div class="shelf__track" id="shelf-track" data-track></div>
</div>
<p class="sr" id="shelf-help">Arrow keys to move along the inks, Home and End for the first and the last.</p>
<p class="sr" aria-live="polite" data-live></p>
</section>
</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.
53 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 sloshing inks” from Animorio and fit it into my siteThe shelf is a single number, x, the pixels it has gone. A spring takes it to the chosen stop, a = ω²·(goal − x) − 2ζω·v, with ω and ζ from GLIDE; the stiffness is divided by the square root of the distance in tiles, so the long run back to the start sets off with the same push as a single step. The stops are the tiles lined up with the title, the last one with the last tile against the right edge. That a, worked out by the spring at every step, is the bottles’ acceleration (the other way), already smooth: no differences between two frames.
The ink’s surface is the sum of the first three modes a push sideways can start in a tank W wide: z(u) = Σ ηₙ·cos(nπu) for n = 1, 3, 5, with u from 0 to 1 between the two walls. Each ηₙ is a spring with the true frequency of a liquid h deep, ωₙ² = g·k·tanh(k·h) with k = nπ/W, and the push moves it towards the height it would have under a steady push, (a/g)·4W/(n²π²): added up, they are the surface tilted by a/g. The g is chosen so that a bottle 100 wide and 60 deep rocks WAVE[0] times a second; ζ grows with the square root of n, so the ripples die before the big wave.
The push is held softly under two g with a hyperbolic tangent, because a flick of the hand would give four or five g and the ink would go straight up to the cap. A big wave sharpens as at the second order of a standing wave, KAPPA·η₁²/W·cos(2πu), higher at the crest and flat in the trough; and it does not climb past the bottle’s shoulder: the height is squeezed with tanh near the ceiling and the bottom.
Each bottle is an SVG with its outline and its inside. The ink is a path made again at every frame: everything under the far edge of the surface, cut by the inside with a clipPath. The surface seen a little from above is the band between the far edge and the near one, an ellipse in the round bottles and an even band in the square ones, with a thread of light on the near edge. The same path, cut by the outside outline and paler, colours the thick glass of the walls; the white reflections stay still on top, like a lamp.
For each of the 33 points of the surface the script remembers the highest the far edge has reached: there the glass is wet. The wet line runs down at 26/FILM units a second, each point at a slightly different pace (two slow sines), so the stain runs in soft streaks; its edge is drawn smoothed over five points, in the ink’s colour at 20 per cent. When the surface rises again the line rises with it.
With the mouse or a finger the shelf chases the pointer on a stiff spring, so the push is smooth there too, and past the ends on a rubber band; let go, it takes the speed of the last 90 milliseconds, looks at where it would get in THROW seconds and is caught on the nearest stop. The sideways wheel does the same. A tap on a bottle in full view gives it a push on a spring of the shelf, and its acceleration adds to the shelf’s. On a phone the shelf runs to the edges of the screen with the first tile lined up with the title. When everything is still the loop switches off.
| Name | File | Default | What it changes |
|---|---|---|---|
SLOSH | script.js | 0.3 | How much the ink feels the shelf moving: 0 not at all. |
WAVE | script.js | [1.5, 0.15] | The ink in a bottle about 110 pixels wide: how many times a second it rocks and how much it is held back. Wider bottles rock more slowly, narrower ones more quickly. |
FILM | script.js | 0.9 | The seconds the ink left on the glass takes to run back down. |
GLIDE | script.js | [7, 0.85] | The shelf’s spring: how quickly it gets to a tile and how much it is held back. |
THROW | script.js | 0.24 | The seconds a thrown shelf runs on before it is caught (how far a flick goes). |
INKS | script.js | [['Kingfisher', 'Teal blue', '50 ml', '€16', '#0f7f8a', 'pot'], …] | The inks: name, colour, size, price, the ink’s colour and the bottle (pot, square, flask, cone, tall, classic). |
--card | style.css | 280px | The width of a tile (264 on a phone). |
--gap | style.css | 16px | The space between two tiles (12 on a phone). |
For the products of a shop that sells liquid things in glass: inks, perfumes, oils, syrups, sauces, cosmetics, a bar’s cocktail list. Wherever the product is looked at before buying it, and a little life in the row makes people want to scroll it.
The tiles go down to 264 pixels and the shelf reaches the edges of the screen: the first tile lines up with the title, 16 pixels from the edge, and about 90 pixels of the second one show. A finger drags and throws the shelf (up and down scrolls the page), the ink sloshes as with the mouse, the buttons are 44 pixels and a tap on a cut tile brings it in.
The shelf does not run: it fades out and back in already at the new stop, and the ink stays flat, with no waves or stains; a tap on a bottle does not move it. Dragged, the shelf follows the hand, and let go it fades onto the nearest stop. The component comes in with a fade only.
GSAP 3.15.0, Alegreya (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 13 KB; the libraries: GSAP 28 KB.
Tested on 7 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.