Repository navigation
feat(core): harden the capture motion blur runtime lifecycle - #5968
Conversation
a4a310e to
68737fe
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Delta review at full head68737fe2aa6c4b3b6f4357fc6af54583a19baa13, relative to69441a0e.
Audited: previewMotionBlur flow from useRenderQueue through studio-server/CLI adapter/producer to engine installPageMotionBlur before navigation; CSS/device pixel conversions in composite.ts and density resets; runtime thrown-capture fallback. Explicit false propagates to render-off, while absent/true preserves opt-in. Large see-through movers stay sharp. The no-paint deadline is distinct from the repaired exception path.
Trusting: authored browser/render measurements and the private review's broader test/caller audit; no new pixel rendering by Home.
The inherited #5875 pose and #5967 timeout findings remain; this delta approval does not clear the complete stack. Saved/fresh prior human reviews and inline comments were empty. Exact-head hosted checks pass/skip; the private focused core run passed124 authored tests. Inspected child regression logs execute3 visual/audio cases, not every new unit test. Browser-version screenshots, HDR output, worker parity, colour and performance measurements were not independently rerun. No provider call, merge or release.
— Magi (Home)
Verdict: APPROVE
Reasoning: No additional blocking defect found in this change relative to its stack parent; the foundation fixes remain required.
69441a0 to
9e77fa5
Compare
68737fe to
c47bef3
Compare
9e77fa5 to
16b4b2e
Compare
c47bef3 to
27f076c
Compare
16b4b2e to
254e20a
Compare
27f076c to
3a35ca0
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head 3a35ca04264c42a87c610b9ecfa15620b3629569 relative to 254e20a5d84aafbb29dea1e9744694aa1b258326.
Audited exception versus timeout fallback, DPR, hidden-preview rest, event-suppressed discovery, quiet mutation/re-seek, preview clock hold and the shared WAAPI hunk. The latter drops only idle browser-created CSSAnimation/CSSTransition, preserving script animations; its25 authored tests pass locally. The init.blurHold suite could not load from the existing cached parser generated-output dependency; I source-inspected the integration rather than claim its local execution.
Independent revision-bound review of the nine-PR composition. Earlier approvals/requests covered older heads. Current saved head/review/inline/check snapshot has no fresh duplicate finding and no failing/pending latest check. Stacked broad-suite skips are not executed tests.
Audited: DPR propagation, exception fallback versus timeout, hidden preview, event-suppressed discovery, mutation filtering and re-seek, preview clock hold; narrowed browser-created CSS idle handling in WAAPI.
Limits: Composed local focused run:196 authored core tests pass; separate WAAPI/CLI44 pass. Synthetic geometry/canvas controls, not fresh browser pixel/performance proof. No app/model/provider call, source fix, merge or release.
— Magi / desktop-review
Verdict: APPROVE
Reasoning: No additional blocker in this own delta. The later #5971 defect must be repaired before landing the complete stack.
The base branch was changed.
Make the lifecycle from the previous change safe for real compositions. - Frames are drawn in device pixels: the canvases and the compositor buffers follow the page's scale, so a 2x render is not blurred at half resolution. - A render never gives up mid-video: a frame whose capture throws is plain DOM and the next one wraps again; in Studio, three capture exceptions in a row turn blur off. (Paint timeouts render plain and never count; they are handled in the previous change.) - A hidden preview tab rests on plain DOM instead of waiting on paints that never come. - Timeline callbacks no longer fire during the mover scan, even with data-motion-blur-events="on". - Wrapping and unwrapping the root no longer reload iframes, restart CSS animations or leak timing invalidations: each move runs through the runtime's record filter and the adapters re-seek right after it. The waapi adapter drops animations Chrome cancelled, limited to browser-created CSS animations (a small, separate hunk in adapters/waapi.ts). - Studio preview holds the playback seek while a blurred frame is in flight, so the poses and both captures belong to the same time. - The host exposes now() for the re-seek. - Tests for the wrap, two-phase and painting paths, and for the guards that survived a deliberate break. Folded review fixes: R4, R8, R9 (runtime, init and waapi parts), R11, T1. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
3a35ca0 to
d2489eb
Compare
Edit accuracy: accurate 271 (base branch 271), smooth 140 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
What
Hardens the runtime lifecycle from #5967 so it holds up on real compositions, in preview and in renders.
devicePixelRatiothat fell back to 1), so a 2x or 4k render is not blurred at half resolution.failedFrames, logged once per 25). In Studio preview, three capture exceptions in a row turn blur off for the session. Paint timeouts, which render plain and never end blur, are handled since feat(core): capture motion blur runtime lifecycle #5967; herefailedFramesalso counts capture exceptions. A tab that stops painting while the clock keeps running (hidden or minimized) used to turn blur off for good after about 6 s.document.visibilityStateishiddenthe preview does not wrap and requests no paints (a hidden tab delivers none); blur resumes when the tab is visible again. Engine mode is unaffected.tl.call()callbacks no longer fire during discovery even withdata-motion-blur-events="on"; only the sub-frame pose reads honour-events.host.ignoreMutations) and the adapters re-seek at the current time right after it. Measured before the fix (Chrome 152, 6 play/pause cycles): CSS animations restarted at 0 for one displayed frame on every unwrap, and the runtime'sMutationObserverread each move as a composition change (18 stage-size and 12 timeline posts instead of 2 and 1).init.tsgets a small hold (the transport skips a playback seek while a blurred frame is busy; the next tick catches up), with its own test.adapters/waapi.ts(shared runtime code, a small separate hunk): after a wrap Chrome cancels the moved element's CSS animation and starts a new one, and the adapter kept reviving the cancelled (idle) one. The adapter now drops an idle animation, only when it is browser-created (CSSAnimation/CSSTransition); script-created animations are left alone. Please review that hunk on its own: it is the one change here that affects every composition, not only blurred ones.now()for the re-seek.Why
Part 3 of 9 in the capture motion blur stack: #5875 → #5967 → #5968 → #5969 → #5970 → #5971 → #5990 → #5991 → #5992. It builds on #5967.
Stack goal: opt-in capture motion blur for compositions, in Studio preview and in renders, drawn with Chrome's html-in-canvas. The correct frame is always preferred over a blurred wrong one: when the capture cannot be trusted for a frame, that frame renders sharp from the plain DOM.
Notes
overflow:hidden, 2D flips throughscaleX = 0blend as rotation, a fast child inside a parent that moved earlier is not blurred).data-motion-blur="on", except thewaapi.tshunk above.Testing
captureMotionBlur/index.test.ts: wrapping and unwrapping (including the quiet-then-re-seek order and no re-seek when there is nothing to unwrap), the two-phase frames, painting and unwrap-on-pause, the render fallback, the hidden-tab rest, the opt-in switches that moved here from feat(core): capture motion blur runtime lifecycle #5967 (shutter clamp, a browser withoutdrawElementImage, the reason logged for a root that asked for blur, a nested capture canvas, opting back out, a composition where nothing moves; the paint-timeout tests now live in feat(core): capture motion blur runtime lifecycle #5967), the callback spy for the scan, device-pixel canvases, and the guards that survived a deliberate break (exactly three failures, no seek below zero,unwrap()removes the hide rule, canvases and hide attributes, invisible movers are not blurred; each was shown to fail with its mutation applied).compositordevice-pixel test incomposite.test.ts;init.blurHold.test.tsfor the preview hold;adapters/waapi.test.tsfor the narrowed idle skip.bun run build, coretsc --noEmit, and the core runtime tests pass; comment ratchet against feat(core): capture motion blur runtime lifecycle #5967's branch passes; core stays under its size budget.🤖 Generated with Claude Code