Repository navigation
perf(core): show the first frame without waiting on far scenes' fonts - #5722
Conversation
36df048 to
6422fcf
Compare
2146383 to
8ef62ad
Compare
6422fcf to
f81c0e6
Compare
94d30ea to
c9db90c
Compare
c9db90c to
525d817
Compare
terencecho
left a comment
There was a problem hiding this comment.
Request changes — one introduced P2
Reviewed HEAD 525d817b0d462ba2969900c08a03df2a56d32af0 against effective BASE 2ff895a6945a758103c0a645b25664d0f3e41d27.
The new boot/post-boot split can defer a provider that a boot-time reader needs: the compiler preserves the first eager reason, while the runtime now interprets that diagnostic string as scheduling priority. The inline comment gives a compiler-produced, provider-before-reader counterexample whose visible result differs from BASE. The follow-up repairs newly marked providers, but not providers already eager for another reason.
Source-only review: all seven changed BASE files read in full before all seven changed HEAD files (13,545 lines total), production compiler/preview/runner integration traced, both independent review reports considered, and all 21 unordered interactions among seven behavioral groups audited. No earlier-pin verdict transferred; pre-existing #5719 findings are not refiled here.
No repository/dependency code, browser, tests, builds, native/media tools, or CI was executed or queried. The ordering witness is source-derived, not an executed runtime reproduction; author performance/test claims remain unverified.
— Review by tai (pr-review)
| return { host, start, end: start + duration, scripts: [] }; | ||
| const eager = host.getAttribute(SCENE_EAGER_ATTR); | ||
| if (eager == null) return { host, start, end: start + duration, scripts: [] }; | ||
| if (eager.startsWith(REACHED_BY_ROOT_REASON) || eager.endsWith(READ_BY_SCENE_REASON)) return null; |
There was a problem hiding this comment.
[P2] Keep already-eager dependency providers in the boot batch
keepScenesReadAtBootEager still skips any provider already carrying SCENE_EAGER_ATTR, so the absence of these two reason strings does not mean the scene is safe to move after boot. A valid compiler-produced example has host/script order c, b, a, starts 40s, 30s, 0s, and distinct paused timelines: b reads window.__timelines.c during initialization, and a initializes its visible label from whether window.__timelines.b exists. The compiler emits c=b reads it, b=its script names c, a=its script names b. BASE runs c,b,a, so a displays ready; HEAD keeps c,a in the boot batch and queues b afterward, so a displays missing even with every font already ready. Mounting b does not rerun a's initialization.
The follow-up protects a newly marked provider but misses this already-eager case. Preserve boot-required dependency priority independently of the first diagnostic reason (or promote it safely), and cover the compiler-produced c,b,a chain rather than only a manually stamped a reads it host. This is a source-traced ordering counterexample, not an executed browser reproduction.
What
A preview's first frame no longer waits on web fonts that only far scenes use. The scripts that run before the first frame wait for the faces their own text uses. Everything else waits for every font, as before:
Renders and thumbnail captures are unchanged: with no preview mark nothing is held, and every script waits for every font at load.
Stacked on #5719.
Why
The after-fonts gate waited for
document.fonts.ready, which covers every face any laid-out text uses, hidden far scenes included. In a 9-minute film, two CJK faces of 18 MB and 25 MB are used only by scenes from 0:30 on. One of them took 5.5 s to download, so the first frame waited about 5 s for text nobody sees yet.How
waitForFonts(families)waits only for the loading faces of the given families. It uses the same 5 s cap and the same diagnostic.bootFontFamilies()(heldScenes.ts) collects the font families of the text outside the scenes that wait. It walks the DOM and skips their subtrees.holdFarSceneScriptsnow also holds an eager scene that starts past the lead. It runs right after boot, through perf(core): preserve boot dependencies while holding distant scenes #5719's mount path, after the full font wait, in document order. Two kinds of scene still run at boot: one that a root script selects into (its eager reason starts withREACHED_BY_ROOT_REASON, now one constant shared by the compiler and the runtime), and a caption scene.Test plan
Unit tests in
heldScenes.test.ts: the near scene's face loads and the far eager scene's face hangs. Boot finishes having run only the near scenes and the root-reached one, and the eager scene runs once its face loads. The existing tests are updated for the eager scene now running after boot. 3 runs in a row, withentry.afterFontsandinit.swapScenes(157 tests).Fails without the fix. Each break was checked separately:
expected undefined to be defined).expected 'near reached ' to be 'near reached tied ').Core: 211 test files, 4716 tests pass. Typecheck, oxlint, oxfmt, the comment ratchet and comment citations, and package cycles pass.
Manual: the 9-minute film in
hyperframes preview, headless Chrome driving Studio, same machine, cache cleared.Two after-runs paint the first frame 1 to 2 s after ready, and their longest task is 0.88 s, because the far eager scenes' scripts now run right after boot. Median seek was 0.95 to 0.97 s in two runs and 2.05 s in one. Every seek lands on its frame, and playback frame rates are within noise.
Comments follow CONTRIBUTING.md "Comments"