Skip to content

fix: keep Studio frame stepping advancing#573

Merged
miguel-heygen merged 1 commit intomainfrom
fix/studio-frame-stepping-shortcuts
Apr 30, 2026
Merged

fix: keep Studio frame stepping advancing#573
miguel-heygen merged 1 commit intomainfrom
fix/studio-frame-stepping-shortcuts

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

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

  • 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

Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@miguel-heygen miguel-heygen merged commit 3f6907e into main Apr 30, 2026
28 checks passed
@miguel-heygen miguel-heygen deleted the fix/studio-frame-stepping-shortcuts branch April 30, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

(studio) frame stepping from PR #530 isn't working as expected

2 participants