mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(core): a preview that is never seeked shows only the clips of its current time (#4422)
The visibility pass ran only on seek, pause, play and during playback, and at init for video and img alone, so a paused page published __renderReady with every caption and composition host visible until someone seeked. Readiness now runs that pass for non-media timed elements; media keeps its init pass and seeks, which own color grading and audio scheduling.
This commit is contained in:
@@ -2559,8 +2559,8 @@ describe("initSandboxRuntimeModular", () => {
|
||||
expect(getContextSpy).toHaveBeenCalledTimes(1);
|
||||
expect(document.getElementById("first")?.style.visibility).toBe("visible");
|
||||
expect(document.getElementById("second")?.style.visibility).toBe("hidden");
|
||||
expect(futureComposition.style.visibility).toBe("");
|
||||
expect(futureComposition.style.display).toBe("");
|
||||
expect(futureComposition.style.visibility).toBe("hidden");
|
||||
expect(futureComposition.style.display).toBe("none");
|
||||
|
||||
window.__player?.seek(3);
|
||||
|
||||
@@ -2805,6 +2805,59 @@ describe("initSandboxRuntimeModular", () => {
|
||||
expect(window.__player).toBeDefined();
|
||||
});
|
||||
|
||||
function mountRootWithClip(start: string): HTMLElement {
|
||||
const root = document.createElement("div");
|
||||
root.setAttribute("data-composition-id", "main");
|
||||
root.setAttribute("data-root", "true");
|
||||
root.setAttribute("data-start", "0");
|
||||
root.setAttribute("data-width", "1920");
|
||||
root.setAttribute("data-height", "1080");
|
||||
document.body.appendChild(root);
|
||||
return appendClip(root, start);
|
||||
}
|
||||
|
||||
function appendClip(parent: Element, start: string): HTMLElement {
|
||||
const clip = document.createElement("div");
|
||||
clip.className = "clip";
|
||||
clip.setAttribute("data-start", start);
|
||||
clip.setAttribute("data-duration", "2");
|
||||
clip.setAttribute("data-track-index", "1");
|
||||
parent.appendChild(clip);
|
||||
return clip;
|
||||
}
|
||||
|
||||
it("publishes render readiness with out-of-window clips already hidden, no seek needed", () => {
|
||||
const caption = mountRootWithClip("5");
|
||||
window.__timelines = { main: createMockTimeline(10) };
|
||||
|
||||
initSandboxRuntimeModular();
|
||||
|
||||
expect(window.__renderReady).toBe(true);
|
||||
expect(caption.style.visibility).toBe("hidden");
|
||||
});
|
||||
|
||||
it("paints clips mounted before readiness at the time sought before readiness", () => {
|
||||
mountRootWithClip("0");
|
||||
const root = document.querySelector("[data-composition-id='main']")!;
|
||||
window.__timelines = { main: createMockTimeline(10) };
|
||||
window.__hfTimelinesBuilding = true;
|
||||
|
||||
initSandboxRuntimeModular();
|
||||
expect(window.__renderReady).toBe(false);
|
||||
window.__player?.seek(6);
|
||||
const inWindow = appendClip(root, "5");
|
||||
const outOfWindow = appendClip(root, "0");
|
||||
window.__hfTimelinesBuilding = false;
|
||||
window.dispatchEvent(new CustomEvent("hf-timelines-built"));
|
||||
|
||||
expect(window.__renderReady).toBe(true);
|
||||
expect(window.__player?.getTime()).toBe(6);
|
||||
expect([inWindow.style.visibility, outOfWindow.style.visibility]).toEqual([
|
||||
"visible",
|
||||
"hidden",
|
||||
]);
|
||||
});
|
||||
|
||||
it("waits for GSAP batching to finish before publishing render readiness", () => {
|
||||
const root = document.createElement("div");
|
||||
root.setAttribute("data-composition-id", "main");
|
||||
|
||||
@@ -3341,6 +3341,12 @@ export function initSandboxRuntimeModular(): void {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Nothing else hides out-of-window clips on a paused page until someone seeks, so readiness does.
|
||||
// Media is left to init's media pass and to seeks: they own color grading and audio scheduling.
|
||||
syncTimedElementVisibility(
|
||||
state.currentTime,
|
||||
Array.from(document.querySelectorAll("[data-start]:not(video, audio, img)")),
|
||||
);
|
||||
// __renderReady = timeline binding attempted, safe for deterministic seeking.
|
||||
// Set after any GSAP batching has completed. renderSeek works with or
|
||||
// without a GSAP timeline (CSS/WAAPI/Lottie compositions use adapters only).
|
||||
|
||||
Reference in New Issue
Block a user