Summary
hyperframes snapshot --at <t> does not seek to the exact time <t> — it renders the state for floor(t * 30) / 30, a 30 fps grid, regardless of the project's own declared data-fps. On a project with data-fps below 30 (the common NTSC-derived 29.97 case), this silently renders the wrong instant by up to 1/30 s (≈33 ms).
Numeric proof (research on hyperframes-ae-mcp, corpus row long-shadow-titles, data-fps="29.97")
Four independent back-solves against an AE-rendered reference frame all landed on the same ~0.019 s offset:
- Root time requested: 19.019018 s (AE frame 126 at 29.97 fps, i.e. AE's own frame boundary for that instant).
hyperframes snapshot --at 19.019018 actually rendered the state for 19.000 s (sample 125.43 of a 29.97 fps composition), not 19.019.
- The back-solved sample values from the four independent measurements: 125.42–125.46, all clustering just below sample 125.5 (19.000 s), while AE's own reference measured 125.99–126.03 (19.019 s) — a constant ~0.019 s (0.57 of a 29.97 fps frame) offset, in every case.
Step 1 reproduction (AE-free, CLI 0.8.72, this issue's own isolated measurement)
Built a synthetic project (data-fps="29.97", one .clip element with a linear GSAP tween ease:"none" moving at exactly 1000 px/s, so the rendered x position back-solves the exact instant the runtime rendered) and swept --at across several 1/30 s boundaries. Measured the element's left edge in each PNG:
--at requested (s) |
rendered as (s) |
back-solved from pixels |
| 1.0190 |
1.0000 |
left = 1000 → t = 1.000 |
| 1.0333 |
1.0000 |
left = 1000 → t = 1.000 |
| 1.0500 |
1.0333 |
left = 1033 → t = 1.033 |
| 1.0667 |
1.0667 |
left = 1067 → t = 1.067 |
| 2.3457 |
2.3333 |
left = 2333 → t = 2.333 |
| 19.000000 |
19.0000 |
left = 1900 → t = 19.000 |
| 19.019018 |
19.0000 |
left = 1900 → t = 19.000 |
| 19.038000 |
19.0333 |
left = 1903 → t = 19.033 |
| 19.050000 |
19.0333 |
left = 1903 → t = 19.033 (byte-identical to 19.038) |
| 19.066700 |
19.0667 |
left = 1907 → t = 19.067 |
This exactly reproduces the plan's back-solve (19.019018 → 19.000, not 19.019) and confirms the rule is floor to the nearest 1/30 s, not round-to-nearest and not the project's own 29.97 fps grid: 19.05 s (571.5/30, past the half-frame boundary) still floors down to 571/30 = 19.0333, which a round-to-nearest rule would not do.
Ask
Either:
- Make
--at seek to the exact requested time (no quantization), or
- Document the quantization explicitly and add a
--fps (or similar) flag so a caller can request the project's own frame grid instead of a hardcoded 30.
Right now snapshot --help on 0.8.72 documents --at, --frames, --no-end with no mention of any seek grid, so a caller has no way to know --at is quantized at all.
Environment
hyperframes --version: 0.8.72
- Reproduced with
--no-browser-gpu --no-end --describe false
Summary
hyperframes snapshot --at <t>does not seek to the exact time<t>— it renders the state forfloor(t * 30) / 30, a 30 fps grid, regardless of the project's own declareddata-fps. On a project withdata-fpsbelow 30 (the common NTSC-derived 29.97 case), this silently renders the wrong instant by up to 1/30 s (≈33 ms).Numeric proof (research on
hyperframes-ae-mcp, corpus rowlong-shadow-titles,data-fps="29.97")Four independent back-solves against an AE-rendered reference frame all landed on the same ~0.019 s offset:
hyperframes snapshot --at 19.019018actually rendered the state for 19.000 s (sample 125.43 of a 29.97 fps composition), not 19.019.Step 1 reproduction (AE-free, CLI 0.8.72, this issue's own isolated measurement)
Built a synthetic project (
data-fps="29.97", one.clipelement with a linear GSAP tweenease:"none"moving at exactly 1000 px/s, so the rendered x position back-solves the exact instant the runtime rendered) and swept--atacross several 1/30 s boundaries. Measured the element's left edge in each PNG:--atrequested (s)This exactly reproduces the plan's back-solve (19.019018 → 19.000, not 19.019) and confirms the rule is floor to the nearest 1/30 s, not round-to-nearest and not the project's own 29.97 fps grid: 19.05 s (571.5/30, past the half-frame boundary) still floors down to 571/30 = 19.0333, which a round-to-nearest rule would not do.
Ask
Either:
--atseek to the exact requested time (no quantization), or--fps(or similar) flag so a caller can request the project's own frame grid instead of a hardcoded 30.Right now
snapshot --helpon 0.8.72 documents--at,--frames,--no-endwith no mention of any seek grid, so a caller has no way to know--atis quantized at all.Environment
hyperframes --version: 0.8.72--no-browser-gpu --no-end --describe false