Repository navigation
feat(core): capture blur falls back to per-element filters where capture cannot run - #6107
Conversation
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 0 important · 1 nit · 09d41cce
The hand-off holds. start() returns before wrapping when the scan disables capture, and settleTier tears capture down before the filter tier paints the same frame. Main CI does not run on a stacked base, so I ran the motion-blur core suite at the stack head (178 pass) and a Chrome 152 probe of both tiers.
— Genesis (pr-review)
| const layer = layerOf(el); | ||
| aim(layer, plan); | ||
| const base = strip(el) || layer.css; | ||
| el.style.filter = base ? `${base} ${layer.url}` : layer.url; |
There was a problem hiding this comment.
nit: on the fallback path, every mover gets filter only on frames where it moves. A non-none filter makes the element a stacking context and the containing block for its absolute and fixed descendants. So a left/top mover with no transform jumps between moving and still frames if it has a position: fixed or z-indexed child. Before this PR the same page rendered sharp and correct. #6108's hasOwnContext guards the auto choice only. The same check here could leave such movers sharp.
The base branch was changed.
…ure cannot run html-in-canvas cannot capture a WebGL canvas, an iframe or a transform on the root, and some browsers lack it. Blur used to turn off for the whole composition. Now the runtime hands the composition to a filter tier: an SVG filter on each mover, 32 offset copies averaged along its sampled path, softened along the motion so long smears do not step. It filters the live DOM, so it works over a WebGL canvas, in any Chrome, and leaves glows and shadows on the element. Turn and scale only soften; capture draws those truthfully, so it stays the first choice and a scene re-init tries it again. Capture turning itself off for a defect or three failed captures hands over; the renderer's explicit off (HDR, distributed, engine blur) stays off. The report names the tier. Core's unpacked size budget goes to 3,965,000 for the tier. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
09d41cc to
8e15e47
Compare
Edit accuracy: accurate 271 (base branch 271), smooth 169 of thoseThe gate passes. Quarantined, measured but not gated (0) |
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · 09d41cce → 8e15e477
Rebase only: the patch matches the head I approved. One new blocker: the required CI / Test (runtime) failure is not flaky. In captureMotionBlur.pixels.browser.test.ts, the two backface tests (lines 269 and 275 onward) still expect state: "off", but this PR now hands those pages to the filter tier (tier: "filter"). They fail the same way on Linux CI, on Windows CI and locally on this head (2 failed, 8 passed). Rerunning will not help. Moving #6108's toMatchObject({ tier: "filter", reasonCode: "backface-visibility" }) updates for both tests into this PR fixes it; with them, the file passes 16/16 at #6108.
— Genesis (pr-review)
The two backface tests still expected blur off; with the filter tier a backface page reports tier filter. Fails on CI without this. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: APPROVE — 1 resolved, 1 open, 0 new · 8e15e477 → 73cb91d7
Resolved: the two backface tests now expect tier: "filter", and CI / Test (runtime) is green. The only delta is those 2 assertions. Still open: the earlier nit. The Windows engine-cli job fails on a 5 s timeout in browserManager.test.ts (resolveHeadlessShellPath, darwin/arm64). This PR does not touch that file, so rerun it.
— Genesis (pr-review)
What
When capture cannot run, blur no longer turns off for the whole composition. It hands over to a filter tier: an SVG filter on each mover, 32 offset copies averaged along its sampled path (in pairs, so 8-bit buffers do not band), softened along the motion so a long smear does not step. It filters the live DOM, so it works over a WebGL canvas, in any Chrome, and leaves a mover's glow and shadow on the element. Turn and scale only soften (capture draws those truthfully, so it stays the first choice).
Capture cannot run when: a WebGL/WebGPU canvas is in the page, a transform or opacity or blend mode is on the root, an iframe/object/embed is in the root,
backface-visibility: hiddensits in a 3D context, a nested capture canvas exists, the browser lacks html-in-canvas, or capture failed three times in a row in preview. The renderer's explicit off (HDR, distributed, engine blur) stays off. A scene re-init tries capture again.How it fits
tier.ts: sharedTierinterface,Report(gainstier),chooseTier(pure, tested).filterPlan.ts: pure arithmetic (offsets, softening, region) from a mover's sampled path.filterTier.ts: the DOM layer and the tier.frames.ts: pose reading shared with capture.index.ts: picks the tier at init and hands over when a scan turns capture off. The window report names the tier.Evidence
off reasonCode=accelerated-canvas); now blurred with the live gradient behind it, matching his render.Notes for review
setFilterFallbackForTests) lets the existing capture-tier defect tests keep judging capture alone.useRenderQueue) is unchanged.Stacked on
feat/capture-blur-quality.🤖 Generated with Claude Code