Ce qu’un métronome m’a appris sur le temps en JavaScript
Metrono est une app pour noter ses séances de pratique musicale, avec un métronome intégré. J’ai d’abord prototypé ce métronome dans le navigateur, avec un minuteur déclenché à chaque temps. À 60 BPM, tout allait bien. À 180 BPM, écran chargé, on l’entendait trébucher.
Deux horloges, un rôle chacune
Le minuteur JavaScript est une horloge pour l’interface. Il prend du retard dès que le fil principal est occupé. L’horloge audio, elle, est celle que suivent les haut-parleurs, et l’écran lui est indifférent.
Le minuteur ne joue donc plus aucun clic. Il se réveille toutes les 25 ms, regarde 100 ms devant lui et réserve sur l’horloge audio chaque temps qui tombe dans cette fenêtre.

const LOOKAHEAD = 0.1; // secondes réservées à l’avance
const TICK_MS = 25; // fréquence de vérification
let nextBeat = ctx.currentTime;
function scheduler(bpm: number) {
const step = 60 / bpm;
while (nextBeat < ctx.currentTime + LOOKAHEAD) {
playClick(nextBeat);
nextBeat += step;
}
}
setInterval(() => scheduler(tempo), TICK_MS);L’interface suit, elle ne mène pas
Le voyant qui clignote sur chaque temps lit le même planning et se dessine à l’image suivante. Si une image saute, le voyant est un peu en retard. Le son, jamais.
- Sortez le timing du fil de l’interface dès que la plateforme le permet.
- Planifiez par petites fenêtres, pour qu’un changement de tempo s’applique dans le temps qui suit.
- Testez les extrêmes : 30 BPM, 240 BPM, mode économie d’énergie.
On pardonne une animation en retard. Un musicien ne pardonne jamais un clic en retard.
La même règle revient plus souvent qu’on ne le croit en design : trouvez l’horloge à laquelle l’utilisateur fait vraiment confiance, et faites suivre tout le reste.
Vous construisez quelque chose et cherchez un designer qui sait aussi le livrer ? Écrivez-moi →