From 13ea8349597bbcb874402d1771aea65766fd7ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Fri, 16 Oct 2026 23:16:13 +0000 Subject: [PATCH] perf(core): hold a clip at 0 inside a later scene until it is due (#5716) --- packages/core/src/runtime/entry.test.ts | 15 +++++++++++++++ packages/core/src/runtime/preloadMedia.ts | 10 ++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/core/src/runtime/entry.test.ts b/packages/core/src/runtime/entry.test.ts index 5d0c54c257..d54f98505f 100644 --- a/packages/core/src/runtime/entry.test.ts +++ b/packages/core/src/runtime/entry.test.ts @@ -680,6 +680,21 @@ describe("runtime entry", () => { expect([first.preload, later.preload, untrimmed.preload]).toEqual(["", "none", ""]); }); + it("defers a clip at 0 inside a later scene, by its start in the film", async () => { + servePreview(); + const root = mountRoot(); + const opening = timed(root, "div", "0"); + const later = timed(root, "div", "5"); + for (const scene of [opening, later]) { + scene.setAttribute("data-composition-id", "scene"); + timed(scene, "div", "0"); + } + await evaluateRuntime(); + const [now, due] = [timed(opening, "video", "0"), timed(later, "video", "0")]; + await Promise.resolve(); + expect([now.preload, due.preload]).toEqual(["", "none"]); + }); + it("keeps a render loading every media element at bind", async () => { spyLoad(); const [now, soon, later] = videos(mountRoot(), "0", "1.5", "5"); diff --git a/packages/core/src/runtime/preloadMedia.ts b/packages/core/src/runtime/preloadMedia.ts index 2d98cd8798..43ac5ccf54 100644 --- a/packages/core/src/runtime/preloadMedia.ts +++ b/packages/core/src/runtime/preloadMedia.ts @@ -1,4 +1,5 @@ import { parseStrictFiniteTimingNumber } from "./playbackRate"; +import { createRuntimeStartTimeResolver } from "./startResolver"; import { skipsHiddenImages } from "./timedClipHide"; type PreloadableMedia = Pick< @@ -40,18 +41,19 @@ export function deferMediaUntilDue(): void { win.__hfMediaDeferral?.disconnect(); win.__hfMediaDeferral = undefined; if (!skipsHiddenImages()) return; - const defer = (el: Element) => { + const defer = (el: Element, startInFilm: (el: Element) => number) => { const start = parseStrictFiniteTimingNumber(el.getAttribute("data-start")); - if (start != null && start > 0 && lengthIsAuthored(el)) + if (start != null && lengthIsAuthored(el) && startInFilm(el) > 0) (el as HTMLMediaElement).preload = "none"; }; win.__hfMediaDeferral = new MutationObserver((records) => { + const startInFilm = createRuntimeStartTimeResolver({}).resolveMediaStartForElement; for (const record of records) for (const node of record.addedNodes) { if (node.nodeType !== 1) continue; const el = node as Element; - if (el.matches("video, audio")) defer(el); - for (const media of el.querySelectorAll("video, audio")) defer(media); + if (el.matches("video, audio")) defer(el, startInFilm); + for (const media of el.querySelectorAll("video, audio")) defer(media, startInFilm); } }); win.__hfMediaDeferral.observe(document.documentElement, { childList: true, subtree: true });