Web frontend

This commit is contained in:
2026-08-27 12:32:20 +02:00
parent d44c24ec97
commit edb6e5e027
97 changed files with 9535 additions and 195 deletions

View File

@@ -0,0 +1,33 @@
/** A smooth playback position, from a position that only arrives twice a second.
Driving a progress bar straight off the websocket visibly steps. This interpolates
between frames on every animation frame and re-seeds whenever a real one lands, which
also gives beat-synced animation the frame-accurate clock it will need later.
*/
import { useEffect, useRef, useState } from "react";
export function usePlaybackClock(position: number, playing: boolean): number {
const [interpolated, setInterpolated] = useState(position);
const anchor = useRef({ position, at: performance.now() });
// A new server frame is the truth; restart the interpolation from it.
useEffect(() => {
anchor.current = { position, at: performance.now() };
setInterpolated(position);
}, [position]);
useEffect(() => {
if (!playing) return;
let frame = 0;
const tick = () => {
const { position: base, at } = anchor.current;
setInterpolated(base + (performance.now() - at) / 1000);
frame = requestAnimationFrame(tick);
};
frame = requestAnimationFrame(tick);
return () => cancelAnimationFrame(frame);
}, [playing]);
return playing ? interpolated : position;
}