mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
## Summary - Run `oxfmt .` across the entire codebase to establish formatted baseline - 299 files changed — mechanical formatting only, no logic changes - Double quotes, semicolons, 2-space indent, trailing commas, 100 print width Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits) ## Test plan - [x] `pnpm format:check` — all 426 files pass - [x] `pnpm -r typecheck` — all packages pass - [x] `pnpm build` — all packages build - [x] All 348 tests pass
111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
import type { RuntimePlayer, RuntimeTimelineLike } from "./types";
|
|
import { quantizeTimeToFrame } from "../inline-scripts/parityContract";
|
|
|
|
type PlayerDeps = {
|
|
getTimeline: () => RuntimeTimelineLike | null;
|
|
setTimeline: (timeline: RuntimeTimelineLike | null) => void;
|
|
getIsPlaying: () => boolean;
|
|
setIsPlaying: (playing: boolean) => void;
|
|
getPlaybackRate: () => number;
|
|
setPlaybackRate: (rate: number) => void;
|
|
getCanonicalFps: () => number;
|
|
onSyncMedia: (timeSeconds: number, playing: boolean) => void;
|
|
onStatePost: (force: boolean) => void;
|
|
onDeterministicSeek: (timeSeconds: number) => void;
|
|
onDeterministicPause: () => void;
|
|
onDeterministicPlay: () => void;
|
|
onRenderFrameSeek: (timeSeconds: number) => void;
|
|
onShowNativeVideos: () => void;
|
|
getSafeDuration?: () => number;
|
|
};
|
|
|
|
function seekTimelineDeterministically(
|
|
timeline: RuntimeTimelineLike,
|
|
timeSeconds: number,
|
|
canonicalFps: number,
|
|
): number {
|
|
const quantized = quantizeTimeToFrame(timeSeconds, canonicalFps);
|
|
timeline.pause();
|
|
if (typeof timeline.totalTime === "function") {
|
|
timeline.totalTime(quantized, false);
|
|
} else {
|
|
timeline.seek(quantized, false);
|
|
}
|
|
return quantized;
|
|
}
|
|
|
|
export function createRuntimePlayer(deps: PlayerDeps): RuntimePlayer {
|
|
return {
|
|
_timeline: null,
|
|
play: () => {
|
|
const timeline = deps.getTimeline();
|
|
if (!timeline || deps.getIsPlaying()) return;
|
|
const safeDuration = Math.max(
|
|
0,
|
|
Number(deps.getSafeDuration?.() ?? timeline.duration() ?? 0) || 0,
|
|
);
|
|
if (safeDuration > 0) {
|
|
const currentTime = Math.max(0, Number(timeline.time()) || 0);
|
|
if (currentTime >= safeDuration) {
|
|
timeline.pause();
|
|
timeline.seek(0, false);
|
|
deps.onDeterministicSeek(0);
|
|
deps.setIsPlaying(false);
|
|
deps.onSyncMedia(0, false);
|
|
deps.onRenderFrameSeek(0);
|
|
}
|
|
}
|
|
if (typeof timeline.timeScale === "function") {
|
|
timeline.timeScale(deps.getPlaybackRate());
|
|
}
|
|
timeline.play();
|
|
deps.onDeterministicPlay();
|
|
deps.setIsPlaying(true);
|
|
deps.onShowNativeVideos();
|
|
deps.onStatePost(true);
|
|
},
|
|
pause: () => {
|
|
const timeline = deps.getTimeline();
|
|
if (!timeline) return;
|
|
timeline.pause();
|
|
const time = Math.max(0, Number(timeline.time()) || 0);
|
|
deps.onDeterministicSeek(time);
|
|
deps.onDeterministicPause();
|
|
deps.setIsPlaying(false);
|
|
deps.onSyncMedia(time, false);
|
|
deps.onRenderFrameSeek(time);
|
|
deps.onStatePost(true);
|
|
},
|
|
seek: (timeSeconds: number) => {
|
|
const timeline = deps.getTimeline();
|
|
if (!timeline) return;
|
|
const safeTime = Math.max(0, Number(timeSeconds) || 0);
|
|
const quantized = seekTimelineDeterministically(timeline, safeTime, deps.getCanonicalFps());
|
|
deps.onDeterministicSeek(quantized);
|
|
deps.setIsPlaying(false);
|
|
deps.onSyncMedia(quantized, false);
|
|
deps.onRenderFrameSeek(quantized);
|
|
deps.onStatePost(true);
|
|
},
|
|
renderSeek: (timeSeconds: number) => {
|
|
const timeline = deps.getTimeline();
|
|
if (!timeline) return;
|
|
const quantized = seekTimelineDeterministically(
|
|
timeline,
|
|
timeSeconds,
|
|
deps.getCanonicalFps(),
|
|
);
|
|
deps.onDeterministicSeek(quantized);
|
|
deps.setIsPlaying(false);
|
|
deps.onSyncMedia(quantized, false);
|
|
deps.onRenderFrameSeek(quantized);
|
|
deps.onStatePost(true);
|
|
},
|
|
getTime: () => Number(deps.getTimeline()?.time() ?? 0),
|
|
getDuration: () => Number(deps.getTimeline()?.duration() ?? 0),
|
|
isPlaying: () => deps.getIsPlaying(),
|
|
setPlaybackRate: (rate: number) => deps.setPlaybackRate(rate),
|
|
getPlaybackRate: () => deps.getPlaybackRate(),
|
|
};
|
|
}
|