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 heygen-com#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 - Adds a shared `stepFrameTime` helper that advances by integer frame index instead of adding fractional seconds. - Uses that helper for preview-surface keyboard shortcuts and the focused seek slider. - Adds regression coverage for truncated runtime times like `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 as `0.0333333`. Adding `1 / 30` to that value can produce `1.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-runtime` - `bun run --filter @hyperframes/studio test -- src/player/lib/time.test.ts src/player/hooks/useTimelinePlayer.test.ts src/player/components/PlayerControls.test.ts` - `bunx 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.tsx` - `bunx 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.tsx` - `bun run --filter @hyperframes/studio typecheck` - `bun run --filter @hyperframes/studio build` - `git diff --check` - Lefthook pre-commit: lint, format, typecheck - Lefthook commit-msg: commitlint ### Browser verification - Created `/tmp/hf-studio-frame-step-repro` with a 10s GSAP animation. - Started Studio preview at `http://localhost:5191/#project/hf-studio-frame-step-repro`. - Used `agent-browser` to reproduce the original stuck behavior before the fix: repeated preview-focused `ArrowRight` keydowns were handled but runtime time stayed at `0.0333333`. - Used `agent-browser` after the fix to verify preview-focused `ArrowRight` advances 10 frames to `0.3333333`. - Used `agent-browser` to verify K-held L steps forward 5 frames to `0.1666667` and K-held J steps backward from 5 frames to `0`. - Used actual Safari 18.6 with System Events key presses to verify 10 and then 20 preview-focused ArrowRight presses continue advancing visually. ## Notes - Safari WebDriver was unavailable because Safari's "Allow remote automation" setting is disabled on this machine, so the Safari check used real Safari GUI key events instead. - Local proof artifacts are intentionally not committed: - `qa-artifacts/studio-frame-step-issue-568/chrome-after-10-arrow-right.png` - `qa-artifacts/studio-frame-step-issue-568/chrome-frame-step-flow.webm` - `qa-artifacts/studio-frame-step-issue-568/safari-after-10-arrow-right.png` - `qa-artifacts/studio-frame-step-issue-568/safari-after-20-arrow-right.png`
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