Code — how this page is built

Under the hood

The actual source of the components on this page, read straight from the repo. Copy it, read it, or open it on GitHub.


Keeps a rolling window of tap timestamps and converts the average inter-tap interval to BPM; resets after a 2s gap.

'use client';

import * as React from 'react';

import { Win98Button } from '@/components/ui/win-98-button';

export function BpmGame() {
  const taps = React.useRef<number[]>([]);
  const [bpm, setBpm] = React.useState<number | null>(null);
  const [count, setCount] = React.useState(0);
  const [pulse, setPulse] = React.useState(0);

  const tap = () => {
    const now = performance.now();
    const last = taps.current[taps.current.length - 1];
    if (last && now - last > 2000) taps.current = []; // restart after a pause
    taps.current.push(now);
    if (taps.current.length > 8) taps.current.shift();
    setCount((c) => c + 1);
    setPulse((p) => p + 1);
    if (taps.current.length >= 2) {
      const intervals = taps.current.slice(1).map((t, i) => t - taps.current[i]);
      const avg = intervals.reduce((a, b) => a + b, 0) / intervals.length;
      setBpm(Math.round(60000 / avg));
    }
  };

  const reset = () => {
    taps.current = [];
    setBpm(null);
    setCount(0);
  };

  return (
    <div className="flex w-full max-w-sm flex-col items-center gap-6">
      <div className="text-center">
        <div key={pulse} className="text-7xl font-bold leading-none tracking-tight animate-[bump_.12s_ease-out]">
          {bpm ?? '—'}
        </div>
        <div className="mt-2 font-mono text-[11px] uppercase tracking-[0.18em] opacity-55">bpm</div>
      </div>

      <Win98Button onClick={tap} className="h-28 w-28 rounded-full text-base">
        Tap
      </Win98Button>

      <div className="flex items-center gap-3 font-mono text-[11px] uppercase tracking-[0.12em] opacity-50">
        <span>{count} taps</span>
        <button onClick={reset} className="underline underline-offset-2">
          reset
        </button>
      </div>
      <style>{`@keyframes bump{from{transform:scale(1.12)}to{transform:scale(1)}}`}</style>
    </div>
  );
}
↖ kaspirius