From e704a33c69dc078ed15bed59e24c115d604ba336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 11 May 2026 21:21:35 -0700 Subject: [PATCH] fix(core): preserve per-element preload ordering in render mode The lazy media preloading refactor split bindMediaMetadataListeners into two loops: bind all listeners first, then preload all elements. This changed when metadata listeners fire relative to .load(), shifting timeline duration hydration and causing 3 transition frames to render at a slightly different state in the style-9-prod regression test. Move eager preload back inside the per-element binding loop so listener attachment and .load() happen in the same iteration, matching the original ordering. Lazy-mode demotion stays in a separate block after mediaPreloader.refresh() since it needs the full clip list. --- packages/core/src/runtime/init.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/core/src/runtime/init.ts b/packages/core/src/runtime/init.ts index f10e3fd485..8316d8b53c 100644 --- a/packages/core/src/runtime/init.ts +++ b/packages/core/src/runtime/init.ts @@ -1233,6 +1233,7 @@ export function initSandboxRuntimeModular(): void { const bindMediaMetadataListeners = () => { if (state.tornDown) return; const mediaEls = Array.from(document.querySelectorAll("video, audio")) as HTMLMediaElement[]; + const isLazy = mediaPreloader.isLazy(); let newElementsBound = false; for (const mediaEl of mediaEls) { @@ -1241,22 +1242,20 @@ export function initSandboxRuntimeModular(): void { newElementsBound = true; mediaEl.addEventListener("loadedmetadata", scheduleMetadataDurationHydration); mediaEl.addEventListener("durationchange", scheduleMetadataDurationHydration); + + // In eager mode, preload inline (same ordering as before lazy preloading) + if (!isLazy || isRenderMode) { + if (mediaEl.preload !== "auto") mediaEl.preload = "auto"; + if (mediaEl.readyState < HTMLMediaElement.HAVE_FUTURE_DATA) mediaEl.load(); + } } if (newElementsBound && !isRenderMode) { mediaPreloader.refresh(); } - if (!mediaPreloader.isLazy() || isRenderMode) { - for (const mediaEl of mediaEls) { - if (mediaEl.preload !== "auto") { - mediaEl.preload = "auto"; - } - if (mediaEl.readyState < HTMLMediaElement.HAVE_FUTURE_DATA) { - mediaEl.load(); - } - } - } else { + // Lazy-mode demotion runs separately after refresh updates the clip list + if (mediaPreloader.isLazy() && !isRenderMode) { // Only demote timed media (elements with data-start) to metadata preload. // Untimed media (background audio, ambient loops, decorative video) must // keep their original preload state — the mediaPreloader only manages