
The needle gauge
Counters, Physics, SVG
NewFree
The tempo slider of a music practice app, in the minimal style: above a thin bar a metronome drawn in hairlines swings at the chosen tempo, with the weight rising on the rod for slow tempos and sliding down for fast ones, a vermilion mark at every beat and a big figure that rolls its digits and grows wider with the tempo.
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 metronome slider</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/roboto-flex@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the tempo field of a practice app: a slider for the beats per minute, and above it a metronome drawn in
hairlines that swings at the tempo chosen. As in a real metronome the weight slides up the rod for a slow
tempo and down for a fast one. The real range input underneath carries the value, the keys and the screen
reader; a tap on the metronome stops it and starts it again -->
<div class="tempo" data-tempo>
<button class="tempo__metro" type="button" aria-pressed="true" aria-label="Pause the metronome" data-metro>
<svg class="metro" viewBox="0 0 200 220" aria-hidden="true">
<!-- the two ticks that light at the ends of the swing -->
<path class="metro__arc" data-arc />
<path class="metro__tick" data-tick-l />
<path class="metro__tick" data-tick-r />
<!-- the case: a tall pyramid in a hairline, with its foot and the face of the scale -->
<path class="metro__case" d="M74 18 h52 l38 176 h-128 z" />
<path class="metro__foot" d="M30 194 h140 l6 10 h-152 z" />
<path class="metro__face" d="M88 40 h24 l20 120 h-64 z" />
<g class="metro__marks" data-marks></g>
<!-- the pendulum: rod, weight and pivot; the script turns it round the pivot -->
<g class="metro__arm" data-arm>
<line class="metro__rod" x1="100" y1="172" x2="100" y2="26" />
<g data-weight>
<path class="metro__weight" d="M91 -7 h18 l3 14 h-24 z" />
<path class="metro__shine" d="M94 -4 h4 l1 8 h-5.5 z" />
</g>
</g>
<circle class="metro__pivot" cx="100" cy="172" r="3.2" />
</svg>
</button>
<div class="tempo__read" aria-hidden="true">
<p class="tempo__num" data-num></p>
<div class="tempo__side">
<span class="tempo__unit">BPM</span>
<span class="tempo__name"><span class="tempo__name-text" data-name>Andante</span></span>
</div>
</div>
<div class="tempo__track" data-track>
<svg class="track" aria-hidden="true" data-track-svg></svg>
<input class="tempo__range" type="range" id="tempo-range" min="40" max="208" step="1" value="92" aria-label="Tempo, beats per minute" data-range>
</div>
</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.
32 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 metronome slider” from Animorio and fit it into my siteThe pendulum does not follow a clock but a phase that grows at each step by 2π times the frequency (the tempo divided by 120, since a whole swing holds two beats) times the time elapsed. Changing the tempo only changes how fast the phase grows, so the pendulum speeds up or slows down where it is, without a jerk. The angle is SWING times the sine of the phase, times how far the metronome is switched on.
A beat is the moment the phase passes a quarter turn plus a whole half turn: the pendulum is then at its widest on one side. The vermilion mark on that side lights and fades in TICK seconds on a squared curve, and the rod jumps by KICK pixels and back: the knock of the mechanism.
As in a real metronome the weight sits higher for slow tempos and lower for fast ones: its distance from the pivot goes from 136 to 50 drawing units along the slider. A spring (WEIGHT_SPRING) takes it there and brings it in with a bounce; the marks on the face show where the weight stands for each named tempo.
The figure is made of three columns, each with the ten digits stacked in a one-line mask: when the number changes every column slides to its digit with back.out, and the hundreds column shrinks to nothing below 100. The figure’s width (Roboto Flex’s font-stretch) goes from WIDTH[0] to WIDTH[1] along the slider.
Knob, weight and the pendulum switching on are springs worked out on GSAP’s ticker in steps of 1/240 of a second, with the frame step capped at 1/30. When the metronome is stopped and nothing moves any more, the ticker is removed, and a touch puts it back.
Under the drawing there is a real, invisible range input that holds the value, the keys (arrows, Page Up and Down, Home, End) and the screen reader, with an aria-valuetext like 92 beats per minute, Andante. After IDLE seconds without a touch a GSAP timeline acts as a pretend hand and drags the knob between six tempos; the first real touch stops it.
| Name | File | Default | What it changes |
|---|---|---|---|
MIN_BPM | script.js | 40 | The slowest tempo. |
MAX_BPM | script.js | 208 | The fastest tempo. |
START_BPM | script.js | 92 | The tempo when the page opens. |
SWING | script.js | 24 | How far the pendulum swings to each side, in degrees. |
WEIGHT_SPRING | script.js | [140, 0.62] | The spring of the weight sliding on the rod: how stiff, and how much it is held back. |
KNOB_SPRING | script.js | [260, 0.82] | The spring of the knob following the hand: how stiff, and how much it is held back. |
TICK | script.js | 0.32 | How long the vermilion mark of each beat stays lit, in seconds. |
KICK | script.js | 1 | How far the pendulum jumps at each beat, in pixels of the drawing. |
WIDTH | script.js | [40, 140] | The figure’s width axis at the slowest and at the fastest tempo (25 to 151). |
IDLE | script.js | 2.6 | Seconds without a touch before the pretend hand moves the slider. |
TEMPI | script.js | [[60, 'Largo'], [76, 'Adagio'], [108, 'Andante'], [120, 'Moderato'], [168, 'Allegro'], [208, 'Presto']] | The tempo names: up to this tempo, this name. |
For the tempo of a metronome or a practice app, a player’s playback speed, the pace of a workout or any slider whose value is a rhythm and is better seen beating while it is chosen.
The metronome is sized on the height of the screen (30% at most) and the figure shrinks with it; the bar takes the width minus a margin. A finger drags it sideways while the page still scrolls up and down (touch-action: pan-y), and a tap on the metronome stops and restarts it.
The pendulum stands still in the middle and there are no beat marks; the weight is at once in its place, the digits change without sliding and the tempo’s name changes at once. The slider works as usual.
GSAP 3.15.0, Roboto Flex (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 8.7 KB; the libraries: GSAP 28 KB.
Tested on 24 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.