Repository navigation
fix(cli): snapshot waits for the image layers a seek reveals before capturing - #6161
Conversation
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important · 0 nits · head b97262a7
The optional Comments check fails: the comment share in captureCompositionFrame.ts went from 7.1% to 7.3% (5 comment lines added). It isn't a required check, but trimming those lines turns it green.
Scope
I read every changed source file and every consumer of waitForImagesMs / SCREENSHOT_SEEK_OPTIONS: snapshot.ts, compare.ts, checkBrowser.ts:514,792. warnings is already declared at snapshot.ts:537, so the early return and the envelope are safe. I didn't run the browser test locally. CI was still running at the time of review.
| const absolute = (href: string): string => new URL(href, document.baseURI).href; | ||
| for (const element of document.querySelectorAll("*")) { | ||
| const style = getComputedStyle(element); | ||
| if (style.display === "none" || style.visibility === "hidden") continue; |
There was a problem hiding this comment.
important: this check only looks at the element's own display, and a child of a display: none ancestor keeps its own display value. So images inside a hidden container are still scanned. Example: a scene that GSAP toggles with display: none holds a large <img> that isn't in the frame at the seek time. The snapshot waits up to 3 s for it, then warns that the frame "may be missing" an image that was never supposed to be there. A loading="lazy" image in that subtree never loads, so every frame pays the full 3 s. element.checkVisibility({ visibilityProperty: true }) (Chromium 121+) covers ancestors and visibility in one call:
| if (style.display === "none" || style.visibility === "hidden") continue; | |
| if (!element.checkVisibility({ visibilityProperty: true })) continue; | |
| const style = getComputedStyle(element); |
If you take this, remove the const style line just above.
Edit accuracy: accurate 271 (base branch 271), smooth 138 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
What
hyperframes snapshotnow waits, after each seek, for every visible image layer (<img>, SVG<image>, CSSbackground-image: url(...)) to finish decoding, for up to 3 seconds. A layer that is still loading, or broken, when the wait ends is named in a console warning and in awarningsarray of the--jsonenvelope.Why
snapshotscreenshotted as soon as the seek settled and never waited for images. A layer that appears at the seek time and is still loading (large PNGs, slow or remote assets, a cold cache) came out blank or half drawn. The frame looked complete, so anyone reading it to judge the video was sent to fix things that were fine. The failure depends on load timing, so it varies from run to run.Related work
The 120 ms image wait in
SCREENSHOT_SEEK_OPTIONSwas only used bycheck's screenshots;snapshotpassed{ exactTime: true }and had no image wait at all.How
captureCompositionFrame.ts:waitForCompositionImagesscans visible elements for the three layer kinds and decodes each (CSS and SVG sources through anImageof the same URL), racing one cap. It returns the layers stillpendingorfailed;settleCompositionSeekpasses that on.SCREENSHOT_IMAGE_WAIT_MS(3 s) replaces the 120 ms and is shared bysnapshot,checkscreenshots andcompare. A wait only costs time while an image is loading.snapshot.ts: opts in to the wait, and collects the report intowarnings, printed as a warning and added to the--jsonenvelope when non-empty.mask-imageandborder-image.checkandcomparewait but do not report.Test plan
New
snapshot.lateImages.browser.test.tsruns the realsnapshotcommand against a project whose seek reveals a layer served over an 800 ms connection: one test each for an<img>, a CSS background and an SVG<image>, plus one for an image that never loads (named inwarnings).On
mainall 4 fail; with the change all 4 pass, 3 runs in a row.Breaking each layer kind in the scan fails exactly its own test.
packages/cli: typecheck, lint and format clean; the snapshot, capture, compare and check test files pass (668 tests).Unit tests added/updated
Manual testing performed
Documentation updated (if applicable)
Comments follow CONTRIBUTING.md "Comments"
Before and after
hyperframes snapshot --at 1.5on a project whose seek at 1 s reveals three image layers, each served after 800 ms.