Repository navigation
Description
Summary
motion-doctrine's seam-gate.mjs measures entry/exit velocity as an average over roughly ±0.1 s around the cut. With the durations seam-stamp.mjs writes by default (x/y exit 0.34 s → entry 0.42 s; z exit 0.21 s → entry 0.5 s) the speed-match row reports ratio 1.70 on every x/y seam and 3.6–3.7 (WARN) on z seams, on a film that is otherwise stamped "by construction". Swapping the stamped eases for mirrored or steeper ones makes the ratio worse; only the per-seam exit.dur / entry.dur ledger options bring it to ~1.
Repo-native skill (.agents/skills/motion-doctrine, metadata.internal: true), so feel free to triage as low priority. Measured 2026-11-02 against main b23b51f, HyperFrames CLI 0.8.216, GSAP 3.14.2, macOS arm64, chrome-headless-shell 156 from the puppeteer cache.
Reproduction
A 12.7 s, 7-scene 1080×1080 film with six seams (↓ ← ↑ → z+ z−), ledger.json written first, seams stamped with seam-stamp.mjs --write, verified with:
node seam-gate.mjs verify --ledger ledger.json --project . --server-cmd "hyperframes preview --foreground --no-open --port {port}" --json
All variants pass every other row (ledger, exit/entry vector, zero-overlap, z-sign-scan) — only speed-match moves.
Changing the eases (durations as stamped)
| variant | exit / entry ease | travel · duration | x/y ratio (4 seams, identical) | z ratio (2 seams) |
|---|---|---|---|---|
| stamp default | power3.in / power4.out (z: expo.out) | 12 %·0.34 s / 10 %·0.42 s | 1.70 | 3.64 · 3.71 WARN |
| expo.in / expo.out | same | 2.88 | 7.34 · 7.54 WARN | |
| mirrored power4.in / power4.out (cut-the-curve §3 shape) | 12 %·0.34 s both sides | 2.60 | 3.64 · 3.71 | |
| expo.in / expo.out, matched travel+duration | 12 %·0.34 s both sides | 3.84 WARN | 7.34 · 7.54 WARN |
Mirrored eases match the instantaneous velocity at the cut frame, but the gate averages over a window, so an ease that concentrates its velocity at the cut is under-read on exit and over-read on entry.
Changing durations only (stamped eases untouched, via ledger options)
x/y entry.dur |
z exit.dur / entry.dur |
x/y ratio | z ratio |
|---|---|---|---|
| 0.65 | 0.21 / 0.9 | 1.23 | 2.43 · 2.48 |
| 0.85 | 0.21 / 1.2 | 0.99 | 1.93 · 1.97 |
| 1.10 | 0.21 / 1.5 | 0.79 | 1.61 · 1.64 |
| 0.85 | 0.12 / 0.9 | 0.99 | 12.2 · 12.5 (a 0.12 s exit barely moves inside the window) |
| 0.85 | 0.45 / 0.9 | 0.99 | 1.72 · 1.77 |
| 0.85 | 0.45 / 1.4 | 0.99 | 1.21 · 1.24 |
| 0.85 | 0.45 / 1.7 | 0.99 | 1.03 · 1.05 → PASSED 0 fail 0 warn |
hyperframes check stayed at 0 errors throughout.
Suggestions (any one would do)
- Make the stamp defaults closer to what the gate wants (e.g. x/y
entry.dur0.85; zexit.dur0.45,entry.dur1.7), or - document in
references/seam-gate.mdthatspeed-matchis a ±0.1 s window average and list the duration ranges that satisfy it, or - have
seam-stampderiveentry.durfromexit.durso the window averages match by construction.
Also a small note for cut-the-curve §3: "mirrored eases → velocity matches exactly at the cut" is true pointwise but is not what seam-gate measures; a one-line caveat would save a round.
Happy to share the test film (fictional brand, no third-party assets) if useful.
Activity
jrusso1020 commentedon Nov 2, 2026
Thanks, this is a great writeup. We confirmed it: seam-gate samples each side at cut ±0.1 s and compares those averages, while seam-stamp's defaults (x/y 0.34/0.42 s, z 0.21/0.5 s) were tuned for the instantaneous match at the cut frame. We'll bring the stamp defaults in line with what the gate measures and add a note on the window to seam-gate.md and cut-the-curve §3. Low priority since it's a repo-native skill, but it's on our list.
PaprikaChen commentedon Nov 5, 2026
I will try to work on this for my 2nd PR for CS146S
PaprikaChen commentedon Nov 8, 2026
Thanks for the detailed report, and thanks for confirming it! While reproducing it I found a different root cause, so I'd like to suggest a different fix before changing the stamp defaults.
What I measured (same 7-scene / 6-seam layout as the report, default stamp output, current
main):1.8,3.6)The last row matches the report's 1.70 / 3.64–3.71. With cuts half a frame off the grid, the duration table follows the same trend as the report too, including the "0.12 s exit barely moves" row.
Why: the runtime floors every seek to the frame grid (
quantizeTimeToFrameinpackages/core/src/inline-scripts/parityContract.ts). Whencutfalls between two frames, both exit samples (cut - 0.1,cut - dt) land almost a frame early and miss the fastest part of the exit. The first entry sample (cut + dt) lands right at the cut, at the fastest part of the entry. So exit is under-read and entry is over-read.The window average alone doesn't explain the numbers. On a grid-aligned film, mirrored eases with matched travel and duration give exactly 1.00 (the report got 2.60 / 3.84 for the same setup), because the two windows are symmetric. Lengthening the entry only flattens the curve and hides the asymmetry. On a grid-aligned film, the proposed defaults (x/y entry 0.85, z 0.45 / 1.7) move the ratio from 0.82 to 0.57 / 0.68, i.e. further from 1.
Proposed fix:
seam-gate.mjs, snap the cut to the first frame at or aftercut, then sample the same number of frames on each side, so the windows stay symmetric wherever the cut falls. The zero-overlap and carrier checks share these sample times, so they would compare the last frame before the cut with the first frame after it, which is what the render shows.references/seam-gate.md, note that speed-match is a short window average and that cuts should sit on the frame grid. In cut-the-curve §3, add the one-line caveat from the report (pointwise vs. window-measured velocity).My PR for this is due tomorrow evening, so I'll go ahead with this approach for now. If you'd still prefer to change the stamp defaults as you described, just let me know and I'll update the PR.
jrusso1020 commentedon Nov 8, 2026
Thanks @PaprikaChen, this is a better diagnosis than mine. You're right: seeks floor to the frame grid, so a cut that falls between frames makes the gate under-read the exit and over-read the entry, and tuning the stamp defaults would only hide that. Please go ahead with your approach in #7396: snap the cut to the frame grid and sample the same number of frames on each side, keep the stamp defaults as they are, and add the notes to seam-gate.md and cut-the-curve §3.