Repository navigation
feat(core): data-motion-blur-phase sets when the shutter opens - #6983
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
Edit accuracy: accurate 267 (base branch 267), smooth 94 of thoseThe gate passes. Quarantined, measured but not gated (8)
Unstable (1)
|
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at 51da80f8. The code is good and I found nothing blocking. I'm posting COMMENT, not APPROVE, only because this head conflicts with main and CI never ran on it. I'll approve the rebased head once it's green.
Merge state. git merge-tree --write-tree HEAD origin/main shows two conflicts, both in tests:
frames.test.tsis add/add. #7080 created the same file on main, with its ownlaidOutandrecthelpers. Keep both describe blocks.index.test.tsgets your new describe at the end of the file, and main changed the same tail.
The source changes merge cleanly: frames.ts, filterTier.ts and index.ts all auto-merge, and #7080's readMoverFrames changes keep your start = t + req.phaseSeconds line intact. Every CI job at this head shows skipping, so there's no test evidence at this SHA yet.
What I checked
shutterTimesis now the only place either tier computes the window (frames.ts;index.ts:277,filterTier.ts:189). I greppedshutterDeg,shutterSecondsandshutter / 2on main, and no other site builds a window. The remainingshutterDeguses are report fields (index.ts:563,703,filterTier.ts:231) and the Studio level presets.- Unset is unchanged:
-shutterSeconds / 2is the oldt - shutter / 2term exactly, so no float drift. That fits your md5-identical renders. - It matches the engine's sub-frame blur convention:
windowStart = t + shutterPhase / 360 / fps, with default-90at 180° (engine/src/services/motionBlur.ts:14,61,93). Sophasemeans the same thing on both blur paths. - Mover discovery (
discoverMovers) scans the whole timeline, not the shutter window, so an off-centre window can't hide a mover from the scan. - Studio round trip:
settingsOfreadsphaseDegandchangedEditswrites it back, andpatchForLevelonly touches enabled, events, shutter and samples. So an authored phase survives a level change, as the body says.
Nits (none block)
ReporthasshutterDegbut no phase, so an off-centre render looks the same as a centred one in the[motion-blur]log. AddingphaseDegbesideshutterDegin both tiers'report()would make it debuggable.- At phase 360 with shutter 720 the window ends 3 frames past
t, so the last frame seeks past the composition's duration. Seeks clamp to the end today, and a centred 720 already reads 1 frame past, so this is only more of an existing case. One test att = durationwould pin it.
Need: yes, the After Effects exporter needs non-centred shutters · Size: ok · Reuse: same phase convention as engine motionBlur.ts, one formula per package, sharing across the core/engine boundary isn't worth it · Simpler: already minimal · Structure: fine
Risk: low. Unset is byte-identical, and the new behavior only applies when the attribute is set.
Verdict: COMMENT
Reasoning: The change is correct and minimal. It can't be approved at this head because it conflicts with main and CI didn't run. I'll approve after a rebase and green CI.
— Rames
Page motion blur always centres the shutter on the frame. Add a phase in degrees of a frame, -360 to 360: the window starts at t + phase / 360 / fps and lasts shutter / 360 / fps. Unset stays centred, so a page without the attribute renders the same bytes. Both tiers take the window from one place, shutterTimes in frames.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51da80f to
9aaf099
Compare
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Rebased onto main (the two test conflicts were only in |
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · head 08896be
The code is correct, but the new Report.phaseDeg doc comment turns the required Comments check red. The fix is one line, inline.
Scope and CI
Additive to @jrusso1020's review at 51da80f8, whose checks I re-ran against the rebased head. shutterTimes is still the only place either tier builds the window, and the source merged cleanly. Both conflicted test files keep #7080's blocks next to the new shutter phase describes. phaseDeg is now on every Report built by both tiers and offReport, which addresses the nit.
CI at this head: CI, Docs, CodeQL, Windows, Player and the captures all pass. Two checks are red. Comments is the blocker, inline. regression shard-2 failed before running any test: the Docker cache fetch returned could not fetch content descriptor ... not found. That's infra, and the push that fixes the comment will rerun it.
— Genesis
… may only fall Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pstream review to aace91b Hand-ported upstream aace91b (data-motion-blur-phase sets when the shutter opens) since it does not apply cleanly; the fork's seek recovery in captureMotionBlur stays as is. Ledger, baseline, UPSTREAM, DECISIONS and ROADMAP advance the commit watermark to aace91b. Co-authored-by: Vance Ingalls <vance@heygen.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What this adds
A new root attribute,
data-motion-blur-phase, that sets when the shutter opens. It is in degrees of a frame, like the shutter angle, and clamps to -360 to 360.The sampling window starts at
t + phase / 360 / fpsand lastsshutter / 360 / fps. So at 180°:-90: centred on the frame, as today0: opens on the frame and runs half a frame ahead360: opens one whole frame laterIt works on both the capture and filter tiers, which now take the window from one function,
shutterTimesinframes.ts. It is parsed inmotionBlurSettings.ts, and the Studio panel's level control leaves it alone. Documented indocs/guides/motion-blur.mdxand the CLI docs.Why
Page blur can only centre the shutter, and After Effects has a Shutter Phase setting. In a test corpus of 68 After Effects exports, 133 of the 134 blurred layers use a non-centred shutter (180/0 is the most common, then 299/360), and every one of those layers that moves in 2-D is off-centre. Without this, a smear lands in the wrong place, and the difference grows with speed. The After Effects exporter needs it to reproduce those shutters.
What it does not change
Evidence
A 2-D box moving 10 px/frame, shutter 180°, rendered through this branch. At t = 1 s the box's left edge is at x = 300. Smear columns give the first pixel with any ink and the first fully lit one:
df1341e3b1e8ae7f-90df1341e3b1e8ae7f0e471c1d888e006f43602aaa32e785d1b52bUnset and
-90are md5-identical to each other and to the same page on released 0.8.223.Tests
New tests were seen failing first, and reverting the one line in
frames.tsturns 4 of them red.0kept as a real value, unreadable treated as unset, round trip.frames.test.ts: no phase reads exactly the old times; phase 0 at 180° starts att; phase 360 starts a frame late;-90at 180° equals unset; reads never go before 0.index.test.ts: a root attribute reaches the seek times on both tiers, and both stay centred without it.Local: core 2,730 passed, Studio panels 95 passed;
tsc, runtime typecheck, oxlint, oxfmt, comment citations and the comment ratchet all clean.🤖 Generated with Claude Code