mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 23:03:09 +00:00
fix(player): correct playback rate for direct-timeline and audio-clock paths (#849)
## Summary - **Direct-timeline path** (GSAP compositions with `window.__timelines`): The player drives these via `DirectTimelineAdapter`, bypassing postMessage entirely. Rate changes sent `set-playback-rate` to the iframe but had no receiver — GSAP's `timeScale()` was never called. Fix: add optional `timeScale?` to `DirectTimelineAdapter` and call `this._directTimelineAdapter?.timeScale?.(rate)` in `attributeChangedCallback`. GSAP timelines expose `timeScale` natively, no composition changes required. - **Audio-clock path** (compositions with audio): Three bugs caused `TransportClock` to always run at 1x when an audio element or WebAudio context drove the clock: 1. `schedulePlayback` was called without the `playbackRate` arg (defaulted to 1). 2. `onSetPlaybackRate` and `player.setPlaybackRate` didn't call `webAudio.setRate()`. 3. `TransportClock.attachAudioSource` divided by `this._rate` instead of `el.playbackRate`, cancelling the rate multiplier. - Adds 2 regression tests to `clock.test.ts` covering the corrected audio-clock formula. ## Test plan - [ ] Unit tests: `bun run --cwd packages/core test` — 861/861 pass - [ ] Browser verification (Playwright headless, GSAP direct-timeline composition): - 1x speed → ratio 0.972 ✓ - 2x speed → ratio 1.965 ✓ - 0.5x speed → ratio 0.490 ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -177,6 +177,7 @@ class HyperframesPlayer extends HTMLElement {
|
||||
const rate = parseFloat(val || "1");
|
||||
this._media.updatePlaybackRate(rate);
|
||||
this._sendControl("set-playback-rate", { playbackRate: rate });
|
||||
this._directTimelineAdapter?.timeScale?.(rate);
|
||||
this.controlsApi?.updateSpeed(rate);
|
||||
this.dispatchEvent(new Event("ratechange"));
|
||||
break;
|
||||
|
||||
@@ -24,6 +24,8 @@ export interface DirectTimelineAdapter {
|
||||
seek: (timeInSeconds: number) => unknown;
|
||||
play: () => unknown;
|
||||
pause: () => unknown;
|
||||
/** Optional: set playback rate (e.g. GSAP's timeScale). Called when the player's playbackRate changes. */
|
||||
timeScale?: (scale: number) => unknown;
|
||||
}
|
||||
|
||||
export type PlaybackDurationAdapter =
|
||||
|
||||
Reference in New Issue
Block a user