Repository navigation
feat: automatic tier, 240°/32 defaults, check finding, and Studio stops opting out - #6108
Conversation
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important · 2 nits · 393e017e
chooseTier does what its doc comment says: renderer-off gives off; forced or unavailable capture gives filter when allowed. check stays quiet for the two chosen cases. The optional Comments check is red because the comment-share ratchet fails on tier.ts (8/71, base 5/51). Trim 3 comment lines before this reaches main.
— Genesis (pr-review)
| const sig = linearSignature(el, scene); | ||
| const first = signatures.get(el); | ||
| if (first === undefined) signatures.set(el, sig); | ||
| else if (first !== sig) notPlain.add(el); |
There was a problem hiding this comment.
important: the linear signature is only compared on a mover's first fast step and every 10th scan step. A turn or zoom that falls between those samples is classified as translation-only, and auto picks the filter tier, which only softens the spin. Repro (Chrome 152, built runtime, 1 s composition): a box slides from 0 to 0.2 s, then spins 360° from 0.4 to 0.6 s. The report is tier: filter, reasonCode: translation-only. Move the spin to 0.3–0.45 s so step 10 lands inside it and the report is tier: capture. Fix: compare at least the element's own transform's linear part on every step it is fast. Those steps already read its rect, and a spin in place changes it. The full ancestor chain can stay on the 10-step cadence.
| /** Who should draw instead of capture: it turned itself off, or the filter tier does as well for less. */ | ||
| function handOff(): CaptureDefect | null { | ||
| if (disabled) return { code: disabledCode ?? "capture-failures", reason: disabled }; | ||
| if (config.tier === "auto" && reader && translationOnly && filterTierAllowed()) { |
There was a problem hiding this comment.
nit: a translation-only hand-off scans the whole timeline twice. Capture's discover() decides translationOnly, then createFilterTier rescans from scratch, and with -events="on" every callback fires twice. Now that this is the default path for most compositions, passing the Discovery (movers, pads, dynamic) into createFilterTier would make it one scan.
| | `data-motion-blur-shutter` | `240` | Shutter angle in degrees, 0–720. Larger is a longer smear. | | ||
| | `data-motion-blur-samples` | at least 32 | A fixed number of samples per frame, 2–64. Left unset, each mover gets at least 32, and about one per 2 px of smear when that is more, so a fast move never shows steps. | | ||
| | `data-motion-blur-events` | off | `on` runs timeline callbacks (`onUpdate` and similar) while blur looks for movers and at each sample. Needed when the motion is set from a callback, such as a `render(t)` function, which blur cannot otherwise see. | | ||
| | `data-motion-blur-tier` | `auto` | `capture` or `filter` forces one of the two ways blur is drawn (below). | |
There was a problem hiding this comment.
nit: capture does not strictly force. chooseTier returns filter for tier: "capture" when capture cannot run, and a later scan defect hands off too. So the advice under Cost and limits ("Force one tier … for an exact match") does not hold in a preview browser without HTML in Canvas. Suggest wording such as "capture prefers capture and falls back to filter where it cannot run".
09d41cc to
8e15e47
Compare
393e017 to
00442fe
Compare
There was a problem hiding this comment.
Verdict: APPROVE — 1 resolved, 3 open, 0 new · 393e017e → b40dc365
Resolved: the Comments ratchet (2 comment lines removed from tier.ts; the check is green). Still open: the earlier inline important and 2 nits. The pixel suite passes locally on this head (16/16). Once #6107 takes the test fix, this needs a rebase and a fresh review.
— Genesis (pr-review)
b40dc36 to
4ce56ce
Compare
There was a problem hiding this comment.
Verdict: APPROVE — 0 resolved, 3 open, 0 new · b40dc365 → 4ce56cea
Rebase only: the patch matches the approved head, minus the 2 test assertions that moved down into #6107.
— Genesis (pr-review)
The base branch was changed.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
… Studio stops opting out hyperframes check reports motion_blur_filter_fallback (info) with the reason capture could not run and the way back to it. The engine's per-session log line gains tier=, and its pixel test covers the fallback over a WebGL page. Studio no longer sends previewMotionBlur: every Chrome can preview blur now, through the fallback where it lacks html-in-canvas; the server still accepts false from an older Studio. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…translates The scan now notes whether any mover turns or scales (the linear part of its transform chain changes) and whether it already forms a stacking context while it moves. When every mover only translates, the filter tier draws as well as capture and costs about what no blur costs: on an 8 s bench shot a render took 7.0 s against 9.9 s with capture and 7.3 s with no blur. Anything that turns or scales, or moves without a transform, stays on capture. data-motion-blur-tier="capture" or "filter" forces a tier. The report says which one drew and why (translation-only, tier-attribute); hyperframes check stays quiet for those two, which are choices, not fallbacks. The pixel tests run the shared assertions through both tiers. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d in limits The guide described blur turning off for WebGL, a root transform and similar. It now says the filter tier draws instead, how the tier is chosen and forced, what each does with a turn or a zoom, the measured cost of each, and which findings check emits. The skill note drops the off-for-WebGL advice and the 1.7x figure. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…samples The shutter opens 240 degrees by default (was 180) and each mover gets at least 32 taps (was sized to the smear alone, down to 2), growing with the smear as before. These are the settings the shutter blur Jake built uses; on the card whip the default render is now 51 dB from his (34.6 dB at the old defaults). The guide's attribute table says so. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
4ce56ce to
0b4c3b8
Compare
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Edit accuracy: accurate 271 (base branch 271), smooth 131 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (2)
|
What
hyperframes checkreportsmotion_blur_filter_fallback(info) when the filter tier draws because capture could not run, with the cause and the way back. The engine's per-session log line gainstier=.previewMotionBlur. Every Chrome can preview blur now (the fallback covers browsers without html-in-canvas), so a render no longer has to be switched off to match a preview that could not blur. The server still acceptsfalsefrom an older Studio.data-motion-blur-tier="capture"or"filter"forces a tier.checkstays quiet for these two choices.Evidence
Cost, 8 s bench (four whips), wall time including startup, two runs each: no blur 5.3–5.9 s, Jake's filter 5.4 s, ours automatic 5.2–5.4 s, capture forced 9.8 s.
Distance from Jake's own render at his settings (PSNR, higher is closer), default settings: whip 51.0 dB (was 34.6), glow 51.2, waterfall 55.7 (was 39.9), WebGL 50.6. Spin 28.2 and crash zoom 29.4 stay apart on purpose: capture streaks along the arc or zoom where his softens the whole element.
The real-Chrome pixel tests run the shared assertions (trail shape, centroid, ink conservation, backdrop untouched, glow carried, centred box) through both tiers.
Behaviour changes to be aware of
data-motion-blur-tier.data-motion-blur="on").Rebased onto
mainafter #6106 and #6107 merged.No visible change
The only Studio edit removes the 8 lines in
useRenderQueue.tsthat sentpreviewMotionBlurwith a render, and its test. Blur now picks its tier from the page, so nothing on screen moves.🤖 Generated with Claude Code