
The needle gauge
Counters, Physics, SVG
NewFree
How many guests at a table, counted on one row of an abacus: ten lacquered beads on a brass rod, and the ones pushed to the right are the guests. Plus and minus give one end of the rod a little knock: it runs through the beads like a Newton’s cradle, the last one shoots off, slides, knocks into the others and bounces back a hair, and the number rolls on its reels as it lands. The beads can also be dragged and thrown.
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 abacus stepper</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/newsreader@5.3.0/opsz.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- how many guests at a table, as one row of an abacus: lacquered beads on a brass rod in a black lacquer frame,
and the beads pushed to the right are the guests. Plus and minus fire a little hammer at one end of the rod:
the knock runs through the beads like a Newton's cradle and the last one shoots across. The beads can also be
dragged and thrown. The number's reels, the beads and the rod are made by the script -->
<div class="guests" data-guests>
<div class="guests__head" aria-hidden="true">
<span class="guests__count" data-count></span>
<span class="guests__note" data-note></span>
</div>
<div class="abacus" data-abacus>
<button class="abacus__btn" type="button" aria-label="Remove a guest" data-less>
<span class="abacus__disc" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M6.5 12h11"/></svg>
</span>
</button>
<div class="abacus__track" role="spinbutton" tabindex="0" aria-label="Guests" aria-valuemin="1" aria-valuemax="10" aria-valuenow="2" aria-valuetext="2 guests" data-track>
<div class="abacus__groove" data-groove>
<span class="abacus__layer" data-shades></span>
<svg class="abacus__rod" aria-hidden="true" data-rod></svg>
<span class="abacus__layer" data-beads></span>
</div>
</div>
<button class="abacus__btn" type="button" aria-label="Add a guest" data-more data-autoclic>
<span class="abacus__disc" aria-hidden="true">
<svg viewBox="0 0 24 24"><path d="M6.5 12h11M12 6.5v11"/></svg>
</span>
</button>
</div>
<p class="sr" aria-live="polite" data-said></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.
34 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 abacus stepper” from Animorio and fit it into my siteEach bead has a position and a speed along the rod, in pixels. The sums run on GSAP’s ticker in steps of 1/600 of a second at most (and a slow frame counts as 1/30): a viscous friction (FRICTION) takes speed away, a constant pull of 650 pixels per second squared brings each bead back towards its pile, as if the rod sloped down a little towards both ends, and the washers are damped springs (RUBBER) with brass behind them, which stops a bead once the rubber is fully squashed. When nothing moves the loop stops and draws nothing.
Two beads that touch and close in on each other knock: the impulse between them takes away their closing speed and gives back BOUNCE of it, half to each (below 24 pixels a second they no longer bounce, so they come to rest). The pairs are solved one at a time, going over the row again until none closes in: that is how a knock walks along a row of touching beads and comes out of the last one, which is the Newton’s cradle. A bead held in a hand has infinite mass: it pushes the others and does not give way.
Plus knocks the first bead of the left pile, minus the last bead of the right one. Along a row of n beads the knock keeps (1 + BOUNCE) / 2 of itself at every pair, so the bead that leaves gets V · ((1 + BOUNCE) / 2)^(n − 1): the script picks V so that it reaches the other pile at ARRIVE pixels a second, adding FRICTION times the distance to travel, because viscous friction takes away speed in proportion to the way covered.
Every bead has two places, in the left pile and in the right one, and belongs to the side whose place is nearer: the border is half way between the two. The beads cannot pass each other, so this always gives a run on the left and a run on the right. With the buttons and the keys the side is decided by the command; with hands it is read from the positions, and the number only changes once everything has stopped.
Tens and units are two strips of eleven figures in a window that fades out at the top and the bottom. One number moves them, going from the old count to the new one: the units turn with it, the tens only while the units go from 9 to 0, like an odometer. The number arrives with back.out, and its strength is picked for each jump so that it goes past by a fifth of a figure, however far it travels.
At a limit the hammer knocks dully: the frame is kicked to the left and comes back on a fully damped spring; the beads inside feel its acceleration the other way round and are thrown against the stop on the right. The rod is a damped oscillator that every knock pushes a little, a pixel at most: the beads follow it along a parabola, more in the middle than at the ends.
| Name | File | Default | What it changes |
|---|---|---|---|
MIN | script.js | 1 | The fewest guests. |
MAX | script.js | 10 | The most guests, which is also the number of beads on the rod (3 to 12). |
START | script.js | 2 | The guests when the page opens. |
ARRIVE | script.js | 380 | How fast a bead reaches the other pile, in pixels a second: how hard it knocks. |
BOUNCE | script.js | 0.9 | How much of a knock passes from one bead to the next (1 = all of it, like a Newton’s cradle). |
FRICTION | script.js | 3.2 | How quickly a bead sliding along the rod slows down. |
RUBBER | script.js | [9000, 0.36] | The rubber washers at the ends of the rod: how stiff they are and how much they hold back (1 = no bounce). |
FLEX | script.js | 1 | How much the rod flexes when the beads knock (0 = a rigid rod). |
HOLD | script.js | [0.42, 0.17, 0.07] | Holding a button: how long before it starts repeating, the first gap and the shortest, in seconds. |
WORD | script.js | ['guest', 'guests'] | The word under the number, for one and for more than one. |
For choosing how many people or things when the number is small and it matters: guests at a table, seats in a booking, nights, portions, tickets, items in a cart. It suits places that want a calm, physical gesture, like a real object, such as booking a restaurant or a wine bar, and where five beads of one colour help to read the number at a glance.
Below 520 pixels the number moves above the rod and the frame takes the whole width, so the beads stay large and have room to run; at 390 pixels nothing overflows. A finger works like the mouse: a tap on a button counts one, held down it repeats faster and faster, a bead can be dragged and thrown (the page still scrolls up and down) and a tap on a bead sends it to the other side. A long press opens no menu and two quick taps do not zoom the page.
No flights, bounces, frame knocks, rod flexing or cocking hammers: the bead that changes side fades out where it was and appears in its place in the other pile, and the number changes with a fade instead of rolling. The beads can still be dragged; let go, they reach their places with a fade.
GSAP 3.15.0, Newsreader (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 15 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.