Why the clicks do not drift
The naive way to build a metronome is a setInterval that plays a sound every beat. It sounds fine for ten seconds and then falls apart, because JavaScript timers are best-effort: a garbage collection pause, a layout, another tab doing work — any of it delays the callback by a few milliseconds, and those delays accumulate into audible drag.
This one separates the two jobs. A timer wakes up roughly every 25 milliseconds, but it does not play anything. It looks 100 milliseconds into the future on the Web Audio clock and schedules every click that falls inside that window, giving each one an exact start time. The audio hardware then plays them at those times regardless of what the main thread is doing. A late timer callback simply schedules the same notes slightly later in wall-clock terms; it cannot move a note that has already been handed to the audio system. The result is that the interval between clicks is sample-accurate rather than approximately right.
Each click is synthesised on the spot rather than loaded as a file: an oscillator and a gain envelope that ramps up over a millisecond and back down across 50, cut off at 60 milliseconds. The pitch encodes the beat's role — 1500 Hz for an accent, 1000 Hz for a plain beat, 880 Hz for a subdivision — with subdivisions also dropped to about a third of the main volume so they sit underneath rather than competing.
Latency, tabs, and the things it will not do
Steady is not the same as instant. Scheduling accuracy controls the spacing between clicks; it does nothing about output latency, which is the fixed delay between the audio system receiving a sample and you hearing it. Bluetooth headphones and speakers add a substantial one. The metronome will still be perfectly even, but everything arrives late relative to what you are playing, which matters enormously when you are recording to it or playing along with something else on a different output. Wired output, or the device's own speaker, removes the problem entirely.
Hidden tabs are a partial casualty. The flashing beat dots are driven by requestAnimationFrame, which browsers stop outright when a tab is not visible — so the visual indicator freezes even while the sound continues. The scheduler itself runs on a timer, and browsers throttle background timers, so for anything that matters keep the tab visible. On phones, locking the screen suspends audio altogether.
Known gaps. Tempo is clamped between 30 and 300 BPM in whole numbers, so no fractional tempos and no tempo above Prestissimo — for faster work, halve the number and use a subdivision. There is one click sound, not a choice of woodblock or cowbell samples. There is no programmable sequence of tempo changes, no accelerando and no saved setlist; each session starts at 120 BPM in 4/4. And muting a beat only silences its main click — that beat's subdivisions still sound, which is usually what you want but is worth knowing before you conclude the mute is broken.
Practising with it
The single most useful control here is the pair of arrow keys, which move the tempo one BPM at a time. The standard method for a passage you cannot play is to find the fastest tempo at which you can play it cleanly — usually much slower than feels dignified — then raise it by one or two clicks and repeat. One BPM steps are small enough that your hands do not notice the change, which is the entire point; jumping in fives reintroduces the tension you just spent twenty minutes removing.
Use the beat dots to make the metronome do less rather than more. Click a dot to cycle it through accent, normal and muted. Muting beats 2 and 4 forces you to hold the pulse across the gap; muting everything except beat 1 turns a bar into a single reference point and exposes exactly where your time slips. This is a far better test of internal timing than raising the volume.
Subdivisions solve a different problem. If your eighth notes rush, adding the eighth-note layer gives them something to land on. Once the passage is even, switch back to quarters — leaving the subdivision on permanently means you are following it rather than keeping time. Tap tempo averages the gaps between taps within the last two and a half seconds, so four or five steady taps give a much better reading than two, and pausing resets the window. Space starts and stops, T taps, and the fullscreen button enlarges the BPM readout for a music stand across the room. If you are working from a recording, the audio speed changer slows a track down without dropping its pitch, and the rest of the audio set — including MIDI tools — is grouped on the audio & video page.
Tempo markings and their BPM ranges
The name under the BPM readout updates from the thresholds below. Historical usage varied by composer and era, and a marking in a score is a character instruction as much as a speed — but these are the boundaries this tool uses.
| Marking | From | Typical use |
| Largo | 40 BPM | Broad and slow; also shown below 40, at the bottom of the tool's range. |
| Larghetto | 60 BPM | A little less broad than Largo. |
| Adagio | 66 BPM | Slow movements, ballads. |
| Andante | 76 BPM | Walking pace. |
| Moderato | 108 BPM | Moderate; a comfortable practice speed for most material. |
| Allegro | 120 BPM | Fast and bright. The tool's default tempo. |
| Vivace | 168 BPM | Lively. |
| Presto | 200 BPM | Very fast. |
| Prestissimo | 300 BPM | The top of the tool's range. |