mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
feat(runtime): single-clock transport — eliminate pause/play audio drift (#671)
Replace the two-clock architecture (GSAP rAF ticker + HTMLMediaElement
pipeline reconciled by a 50ms polling loop) with a single TransportClock.
GSAP is always paused and seeked to clock.now() on each rAF tick.
Drift between visual timeline and audio is structurally impossible.
Architecture:
TransportClock.now() ──rAF──▶ timeline.seek(t) + el.currentTime
▲
AudioContext.currentTime (~21µs) ← WebAudio active
OR
audio.currentTime (~33ms) ← HTMLMediaElement fallback
OR
performance.now() (~1ms) ← no audio
Key changes:
- TransportClock class with monotonic + audio-master clock sources
- WebAudioTransport: routes audio through AudioBufferSourceNode for
sample-accurate scheduling, falls back gracefully to HTMLMediaElement
- rAF tick loop replaces 50ms setInterval poll; GSAP always paused
- Strict sync (40ms threshold, consecutive-sample gated) + forceSync
on play/pause/seek transitions for sub-frame media accuracy
- Buffer-stall: visuals freeze when audio is buffering instead of
running ahead
- Frame quantization preserved in seek/renderSeek (parity contract)
Browser-verified: 0.0ms drift after 40 pause/play cycles (was 400ms+).
Also fixes: CDN script HTML error responses in validate (pre-existing).
54 tests across clock, clock-drift, webAudioTransport, and media.
Closes #668
This commit is contained in:
@@ -178,7 +178,12 @@ async function validateInBrowser(
|
||||
});
|
||||
|
||||
page.on("pageerror", (err) => {
|
||||
errors.push({ level: "error", text: err instanceof Error ? err.message : String(err) });
|
||||
const text = err instanceof Error ? err.message : String(err);
|
||||
// CDN scripts (e.g. GSAP from jsdelivr) returning HTML error pages
|
||||
// instead of JS produce "Unexpected token '<'" SyntaxErrors. These
|
||||
// are network failures, not composition authoring errors.
|
||||
if (text.includes("Unexpected token '<'") || text.includes("Unexpected token '<'")) return;
|
||||
errors.push({ level: "error", text });
|
||||
});
|
||||
|
||||
page.on("requestfailed", (req) => {
|
||||
|
||||
Reference in New Issue
Block a user