diff --git a/packages/core/src/runtime/heldScenes.test.ts b/packages/core/src/runtime/heldScenes.test.ts index 062874af42..5f70390fbe 100644 --- a/packages/core/src/runtime/heldScenes.test.ts +++ b/packages/core/src/runtime/heldScenes.test.ts @@ -88,6 +88,21 @@ describe("scene scripts held until the playhead nears", () => { expect(ran()).toBe("near tied far "); }); + it("runs a far scene the playback reaches without pausing the clock", async () => { + await boot(true); + window.__player!.seek(19.5); + await window.__hfWaitForSeekCompletion?.(); + // The runtime's own copy: boot reset the module registry. + const { TransportClock } = await import("./clock"); + const pause = vi.spyOn(TransportClock.prototype, "pause"); + window.__player!.play(); + await vi.waitFor(() => expect(ran()).toContain("far"), { timeout: 3000 }); + await window.__hfWaitForSeekCompletion?.(); + expect(pause).not.toHaveBeenCalled(); + expect(window.__player!.isPlaying()).toBe(true); + window.__player!.pause(); + }); + it("runs every scene's scripts at boot outside a preview, as a capture does", async () => { await boot(false); expect(ran()).toBe("near far tied "); diff --git a/packages/core/src/runtime/init.ts b/packages/core/src/runtime/init.ts index bbb2a90af3..d9134a8461 100644 --- a/packages/core/src/runtime/init.ts +++ b/packages/core/src/runtime/init.ts @@ -3718,7 +3718,7 @@ export function initSandboxRuntimeModular(): void { // Swap edited scenes in place from a rebuilt preview document. Refuses before changing anything unless // the documents differ only inside existing scenes; a later failure is left to the caller's reload. // Nests the timelines a scene's scripts just made and redraws the current frame with them. - const nestRanScenes = (hosts: Element[]) => { + const nestRanScenes = (hosts: Element[], { drawnByTick = false } = {}) => { childrenBound = false; bindRootTimelineIfAvailable(); // Probed before the scene was nested, so the new media found no volume envelope. @@ -3737,7 +3737,9 @@ export function initSandboxRuntimeModular(): void { applyPositionEdits(document); // Redraw the current frame as a seek does; a playing film cut to end at or before it stops there, as at its end. const cutShort = clock.isPlaying() && duration > 0 && state.currentTime >= duration; - transport.seek(cutShort ? duration : state.currentTime, { keepPlaying: !cutShort }); + // Playing, the next tick draws the frame; a seek would pause and restart the clock and media. + if (!(drawnByTick && clock.isPlaying() && !cutShort)) + transport.seek(cutShort ? duration : state.currentTime, { keepPlaying: !cutShort }); syncTimedElementVisibility(state.currentTime); postTimeline(); }; @@ -3947,7 +3949,7 @@ export function initSandboxRuntimeModular(): void { for (const host of hosts) applyVariableBindings(document, host); bindMediaMetadataListeners(); initVfx(document.body, state.canonicalFps); - nestRanScenes(hosts); + nestRanScenes(hosts, { drawnByTick: true }); }); sceneMounts = mounted.catch(() => undefined); registerSeekCompletion(mounted);