fix(cli): a snapshot still shows what playback shows, whatever other times are asked for (#6720)

* fix(cli): a snapshot still shows what playback shows, whatever other times are asked for

* test(cli): pin that still-capture pages ask for the skipped-frame replay
This commit is contained in:
Miguel Ángel
2026-10-29 06:44:51 +00:00
committed by GitHub
parent 98a28cc4b2
commit cf15892425
5 changed files with 45 additions and 1 deletions
@@ -269,4 +269,13 @@ describe("openSettledCompositionPage when nothing may listen", () => {
expect(launched().args).toEqual(["--headless", HYPERFRAMES_BROWSER_MARKER_ARG]);
expect(opened.page.setRequestInterception).not.toHaveBeenCalled();
});
it("asks the page to replay skipped frames, so a still shows what playback shows", async () => {
const opened = fakeBrowser();
mocks.launch.mockResolvedValue(opened.browser);
await openSettledCompositionPage(HTML, "http://127.0.0.1:3000", OPTIONS);
expect(opened.page.evaluateOnNewDocument).toHaveBeenCalledWith(
"window.__HF_REPLAY_SKIPPED_FRAMES = true",
);
});
});
@@ -340,6 +340,7 @@ export async function openSettledCompositionPage(
await import("@hyperframes/engine");
await installMediaRenderIdBridge(page);
await page.evaluateOnNewDocument(forcePreservedDrawingBuffer);
await page.evaluateOnNewDocument("window.__HF_REPLAY_SKIPPED_FRAMES = true");
await page.setViewport(viewport);
if (answer) await answerPageInProcess(page, url, answer);
await options.beforeNavigate?.(page);
+31
View File
@@ -263,6 +263,7 @@ describe("initSandboxRuntimeModular", () => {
delete window.__playerReady;
delete window.__renderReady;
delete (window as { __HF_EXPORT_RENDER_SEEK_CONFIG?: unknown }).__HF_EXPORT_RENDER_SEEK_CONFIG;
delete window.__HF_REPLAY_SKIPPED_FRAMES;
delete window.__hfTimelinesBuilding;
delete (window as { THREE?: unknown }).THREE;
delete (window as { __hfAutoNoopRegistered?: boolean }).__hfAutoNoopRegistered;
@@ -1200,6 +1201,36 @@ describe("initSandboxRuntimeModular", () => {
});
});
it("gives a still the value playback shows when its capture page asks to replay skipped frames", () => {
const zoomFilm = () => {
const params = { z: 1 };
const timeline = gsap.timeline({ paused: true });
timeline.to(params, { z: 1.45, duration: 0.3, ease: "power4.out" }, 0.573);
timeline.set(params, { z: 1.04 }, 0.8);
timeline.to(params, { z: 1.12, duration: 1.39, ease: "power1.in" }, 0.869);
return { params, timeline };
};
const played = zoomFilm();
for (let frame = 0; frame <= 56; frame++) played.timeline.totalTime(frame / 60, true);
const root = document.createElement("div");
root.setAttribute("data-composition-id", "main");
root.setAttribute("data-root", "true");
root.setAttribute("data-start", "0");
root.setAttribute("data-duration", "3");
root.setAttribute("data-fps", "60");
root.setAttribute("data-width", "640");
root.setAttribute("data-height", "360");
document.body.appendChild(root);
const still = zoomFilm();
window.__timelines = { main: still.timeline as unknown as RuntimeTimelineLike };
window.__HF_REPLAY_SKIPPED_FRAMES = true;
initSandboxRuntimeModular();
window.__player?.renderSeek(56 / 60);
expect(still.params.z).toBeCloseTo(played.params.z, 9);
});
it("activates a nested outro on frame 584 when its authored start rounds just above it", () => {
const root = document.createElement("div");
root.setAttribute("data-composition-id", "main");
+2 -1
View File
@@ -549,8 +549,9 @@ export function initSandboxRuntimeModular(): void {
ensureAudioGroupInertStyle(document);
ensureColorGroupInertStyle(document);
const exportRenderFps = resolveExportRenderFps();
const renderFps = exportRenderFps.fps ?? undefined;
state.canonicalFps = exportRenderFps.fps ?? compositionFps() ?? state.canonicalFps;
const renderFps =
exportRenderFps.fps ?? (window.__HF_REPLAY_SKIPPED_FRAMES ? state.canonicalFps : undefined);
setRuntimeProtocolFps(state.canonicalFps);
if (window.__HF_EXPORT_RENDER_SEEK_CONFIG) {
const fpsDetail = JSON.stringify({
+2
View File
@@ -115,6 +115,8 @@ declare global {
owner?: string;
};
__HF_PARITY_MODE?: boolean;
/** Set by still-capture pages: seeks replay skipped frames at the composition fps, as a render does. */
__HF_REPLAY_SKIPPED_FRAMES?: boolean;
/** Legacy debug-only fps hint. Render-mode runtime fps uses __HF_EXPORT_RENDER_SEEK_CONFIG.fps. */
__HF_FPS?: number;
__HF_MAX_DURATION_SEC?: number;