fix: keep Studio frame stepping advancing#573
Conversation
jrusso1020
left a comment
There was a problem hiding this comment.
LGTM — clean fix for issue #568 (frame stepping stalls after 2-3 frames).
Root cause: the previous logic was currentTime + frameToSeconds(step) — adding 1/30 (a float-imprecise value) to a runtime time that itself wasn't guaranteed to be on the frame grid. Across multiple keypresses, accumulated float drift could land between frame boundaries; depending on the runtime's quantization (round vs. floor), seeks could become no-ops.
Fix: new stepFrameTime(time, deltaFrames, fps) helper in time.ts — snaps the input to an integer frame via secondsToFrame, adds the integer delta with a Math.max(0, ...) floor, then converts back via frameToSeconds. Output is exactly on the grid by construction, so the runtime can't get stuck between frames. Both call sites updated (PlayerControls.tsx arrow keys, useTimelinePlayer.ts J/L-while-K-held).
Tests: the truncated-input test (stepFrameTime(0.0333333, 1) === 2/30) is the right shape — it directly mimics the runtime emitting an imprecise time and verifies the next step lands cleanly. Plus a zero-clamp test for the lower bound.
— Review by Rames Jusso
Problem
Closes #568.
Studio preview-focused frame stepping could stop advancing after a couple of ArrowLeft/ArrowRight presses. The same integer-frame stepping path also affected the K-held J/L one-frame shuttle controls.
What this fixes
stepFrameTimehelper that advances by integer frame index instead of adding fractional seconds.0.0333333, which previously stepped back onto the same frame.Root cause
The runtime seek path quantizes requested times with
Math.floor(time * fps). Studio was deriving the next frame from the runtime's current seconds value, which can be a truncated decimal such as0.0333333. Adding1 / 30to that value can produce1.999998...frames, so floor-quantization lands back on the previous frame and repeated shortcuts appear to stop responding.Verification
Local checks
bun run --filter @hyperframes/core build:hyperframes-runtimebun run --filter @hyperframes/studio test -- src/player/lib/time.test.ts src/player/hooks/useTimelinePlayer.test.ts src/player/components/PlayerControls.test.tsbunx oxfmt --check packages/studio/src/player/lib/time.ts packages/studio/src/player/lib/time.test.ts packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/components/PlayerControls.tsxbunx oxlint packages/studio/src/player/lib/time.ts packages/studio/src/player/lib/time.test.ts packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/components/PlayerControls.tsxbun run --filter @hyperframes/studio typecheckbun run --filter @hyperframes/studio buildgit diff --checkBrowser verification
/tmp/hf-studio-frame-step-reprowith a 10s GSAP animation.http://localhost:5191/#project/hf-studio-frame-step-repro.agent-browserto reproduce the original stuck behavior before the fix: repeated preview-focusedArrowRightkeydowns were handled but runtime time stayed at0.0333333.agent-browserafter the fix to verify preview-focusedArrowRightadvances 10 frames to0.3333333.agent-browserto verify K-held L steps forward 5 frames to0.1666667and K-held J steps backward from 5 frames to0.Notes
qa-artifacts/studio-frame-step-issue-568/chrome-after-10-arrow-right.pngqa-artifacts/studio-frame-step-issue-568/chrome-frame-step-flow.webmqa-artifacts/studio-frame-step-issue-568/safari-after-10-arrow-right.pngqa-artifacts/studio-frame-step-issue-568/safari-after-20-arrow-right.png