Repository navigation
feat(core,producer): decide blur defects once per timeline, off on routes that cannot host it - #5990
vanceingalls wants to merge 1 commit into
Conversation
2d4f676 to
92598cf
Compare
7408da4 to
bf775cc
Compare
92598cf to
a03da4f
Compare
bf775cc to
4f40902
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head 4f40902c27d2c38ee4ee35f73e80983af29dd480 relative to a03da4f7d8af648e4dd020030ea1f844333ab876.
Audited t=0 mover baseline, sampled defects/cached candidates/per-frame fallback, root individual transforms/blend, global GPU, and HDR/layered/distributed off reasons through capture consumers. Own delta has no additional demonstrated blocker. It does preserve #5971's animated hidden-face miss: its cached scan and facesNow never inspect that omitted face. This is a delta approval only; the composition remains held on #5971.
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: Timeline-baseline discovery, cached backface scan and per-frame backstop; root individual transforms/blend and document-wide GPU; HDR/layered/distributed off decisions and capture-option consumers.
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.
…utes that cannot host it Decide the html-in-canvas defects once for the whole timeline instead of at the frame being drawn. The mover scan already seeks the timeline, so the defect scan samples along it and a defect that only appears mid-timeline (a rotated root, a flipped card) turns blur off from frame 0. Defects now block on every Chrome version, so a render matches the preview it came from, and GSAP's identity transform on the root no longer counts as one. A per-frame check stays as a backstop for what scripts add later, and it costs only that frame: a defect the scan missed (a short root shake, a backface flip between samples) renders that frame sharp and logs once, and blur resumes when the defect is gone. A block raised by the scan is lifted when its cause is removed or the timeline changes; a capture failure stays for the life of the instance. The candidates a scan checks include faces whose backface-visibility: hidden arrives through an animation. Each rescan adds to them and the per-frame backstop reads the same set, so an animated-only flip card is caught by both. Look for WebGL canvases in the whole document: a render's shader-transition compositor appends its canvas to body, while preview puts it inside the root. Turn page blur off on routes that cannot host it. The HDR and layered compositors screenshot each DOM layer after hiding the others, which does not reach blur's canvases, and a distributed (cloud or Lambda) chunk render has no Studio preview to match and no guarantee of html-in-canvas in the worker's Chrome. The producer sets pageMotionBlur to hdr-render, layered-composite or distributed-render there, the distributed plan's compile-time hint no longer forces screenshot capture, and the runtime says which route turned it off. Find the same movers whatever time a scan starts: the baseline is read at t=0, so each worker of a parallel render picks the same set. An ancestor's pan is not counted as its child's move. Folded review fixes: R5, R10, R15, R19. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
a03da4f to
3d6c41b
Compare
4f40902 to
83f05ec
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head 83f05ec5fd2d0bcb3f8188e7bc1f9cbc5f63ece9 against its actual parent 3d6c41b95fe38297b778db01f73eed91a2bac20b and the previously reviewed tree.
The same animation-derived candidates reach the timeline scan and frame-time backstop. The candidate set now grows across rescans, so an animation disappearing after discovery cannot erase its face. The moved chunkFrames test is restored byte-identically in #5991.
Independent verification: own-head and composed-tip synthetic computed-style controls 4/4 pass; predecessor witness remains red (inline positive passes). Exact-source authored detector suites run locally:31 own-head +47 tip tests pass, including WAAPI containment, named/multiple animations and cached-candidate retention. The computed animation-name seam is explicit because jsdom does not expand animation shorthand. These are deterministic detector controls, not fresh Chrome pixel/performance proof.
Current exact-head check snapshot has no failed or pending check. Read completed regression gate logs and executed #5991 preflight lint/format output; stacked broad-suite skips and aggregate gate success do not prove execution of the new pixel/unit suites. Author Chrome152 experiments, 26ms scan cost and package-budget margin remain attributed.
Known sampling limit remains: a short WAAPI-only face absent at every scan cannot enter the cached set. This bounded sampling residual differs from the repaired omission of ordinary animation-derived candidates; no universal detection guarantee is claimed. No new source blocker found in this successor composition. No browser/app/model call, merge or release.
— Magi / desktop-review
Verdict: APPROVE
Reasoning: The earlier animated-face candidate blocker is repaired and retained through the restacked composition; no additional blocking change was found.

What
scale,rotateortranslateproperties (identity values ignored) is a root transform; a rootmix-blend-modeother thannormalis a defect (root-blend-mode); the backface check treats an individualrotatewith an axis or 3D angle (rotate: y 180deg,rotate: 0 1 0 180deg) and atranslatewith z as 3D (sharedindividualIs3d); and theiframe-in-rootentry covers everything that is torn down and re-initialised when the root moves:<iframe>,<object>,<embed>and defined custom elements (hyphenated name withcustomElements.get). Measured on Chrome 152 against the previous build: ascale: .5root, arotate, atranslate, amultiplyroot, arotate: y 180degface,<object>,<embed>and a defined custom element all reportedonand now reportoffwith their code; plain compositions and flat uses (scale: 1,rotate: 90degon a face outside 3D) still reporton.<body>, while preview puts it inside the root.pageMotionBlurtohdr-render,layered-compositeordistributed-renderthere, and the runtime reportsthe renderer turned it off (…). The distributed plan's compile-time hint no longer forces adata-motion-blurcomposition onto screenshot capture: it freezes the same capture mode as the same composition without the attribute.Why
Part 7 of 9 in the capture motion blur stack: #5875 → #5967 → #5968 → #5969 → #5970 → #5971 → #5990 → #5991 → #5992. It builds on the defect list in #5971.
Stack goal: opt-in capture motion blur for compositions, in Studio preview and in renders, drawn with Chrome's html-in-canvas. A composition must blur in every frame the scan trusts, and be sharp in the rest.
Notes
*{backface-visibility:hidden}. The candidates include the animation-derived faces (feat(core): block capture motion blur on html-in-canvas defects #5971); each rescan adds to them and they are kept for the rest of the scan, because the last sample can fall after an animation has ended (the per-frame backstop then still reads them).SCAN_STEPS) is under-measured.Testing
htmlInCanvasDefects.test.ts: the scan finds a defect that appears at any sampled time and says where it first appeared; identity transforms are ignored; a rootscale/rotate/translate(identity values ignored), a rootmix-blend-mode,<object>/<embed>/ defined custom elements (an undefined hyphenated tag is ignored), and a backface-hidden face turned byrotate: y 180deg,rotate: 0 1 0 180degor a ztranslate(a flatrotate: 90degis not); the document-wide WebGL check;facesNowreads the scan's backface candidates at the current time (a hidden face that flips into 3D after the scan is seen without rescanning; a face an animation keys tohiddenis a candidate, stays one after the animation is gone, and is found by the scan and byfacesNow).captureMotionBlur/index.test.ts: blur off from frame 0 for a mid-timeline defect; a defect the scan missed renders only that frame sharp and blur resumes; an engine frame that is sharp resolves at once and leaves the composite step idle; a block lifts when its cause is gone or the timeline changes, and a capture-failure block does not; the distributed route is named as the reason.discover.test.ts: the same movers whatever time a scan starts, an ancestor's pan is no child's move when the child's style first changes, and the scan reports each step after its seek.pageMotionBlur.test.tsand producermotionBlurRoute.test.ts: the off reason for the HDR, layered and distributed routes; producer distributedplan.test.ts(thechunkFrames.test.tsfor every chunk session is in feat(core,engine): report why blur is off, and what each render session did #5991): the plan probe session and every chunk session stand blur down, and the frozen capture mode matches the plain composition's; orchestrator request validation.bun run build,tsc --noEmitin core, engine and producer pass; comment ratchet against feat(core): block capture motion blur on html-in-canvas defects #5971's branch passes; every package is within its size budget.🤖 Generated with Claude Code