fix(studio): auto-enable loop when work-area markers are set#859
Merged
miguel-heygen merged 1 commit intoMay 15, 2026
Merged
Conversation
Setting an in or out point now turns on loopEnabled so the playhead respects the marker instead of running past the out-point. Closes the last open sub-bug of heygen-com#834. Background: PR heygen-com#811 wired the work-area RAF loop to read inPoint/outPoint but kept the loop branch gated behind loopEnabled. Default for that flag is false, so users who set markers without first toggling the loop button saw playback sail past the out-point (or, with the L shuttle, overshoot by a few frames before pausing). The original spec for the feature in issue heygen-com#807 described markers as logic that "constrains the playback engine"; the actual UX did not match that until the toggle was on. Fix: setInPoint and setOutPoint flip loopEnabled to true when given a non-null value. This sits next to the existing "smart setter" behavior already in the store (setting one marker past the other nullifies the counterpart). Clearing a marker with null preserves the current loopEnabled, so a user who manually toggles the loop button stays in control after that point. Tests: full coverage for setInPoint and setOutPoint (none existed before), including overlap nullification, non-finite rejection, auto-enable on set, and preserve-on-clear in both directions. Closes heygen-com#834
miguel-heygen
approved these changes
May 15, 2026
Collaborator
miguel-heygen
left a comment
There was a problem hiding this comment.
Verified the fix end-to-end:
- RAF loop (
useTimelinePlayer.ts:192-211forward,296-314reverse): both paths compute loop bounds frominPoint/outPointunconditionally but gate the actual loop-back onloopEnabled. FlippingloopEnabledtotrueon marker set is the minimal, correct fix. - All 3 call sites (
usePlaybackKeyboard.tsfor I/O/Shift+I/Shift+O,PlayerControls.tsxfor the X-clear buttons) pass either a time value ornull, both handled correctly by the ternary. reset()bypasses the setters entirely (directset(...)) so it won't auto-enable loop — verified.- Tests: 14 new tests covering set/clear/non-finite/overlap/auto-enable/preserve-on-clear, all passing (44/44 in the player store suite).
One optional nit: setOutPoint omits the 2-line comment that setInPoint has for the loopEnabled line — could add a brief // see setInPoint for symmetry, but not blocking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Setting an in-point or out-point now auto-enables
loopEnabled, so the playhead respects the work-area marker instead of running past the out-point. Closes the last open sub-bug of #834.Background
PR #811 wired the work-area RAF loop to read
inPoint/outPoint(useTimelinePlayer.ts:185-201), but kept the loop branch gated behindloopEnabled. Default for that flag isfalse(playerStore.ts:102), so users who set markers without first toggling the loop button saw playback sail past the out-point. With the L-key shuttle (multi-x speed), the playhead also overshoots by a few frames before the next RAF tick clamps it.The original spec for the feature in #807 described markers as logic that "constrains the playback engine". The actual UX did not match that intent until the loop toggle was on, which the issue's reporter flagged as the bug under sub-bug #1.
Fix
setInPointandsetOutPointfliploopEnabledtotruewhen given a non-null value. This extends the existing "smart setter" pattern already in the store (setting one marker past the other already nullifies the counterpart). Clearing a marker withnullpreserves the currentloopEnabled, so a user who manually toggles the loop button afterward stays in control.Symmetric for
setOutPoint. The RAF loop body inuseTimelinePlayer(both forward and reverse paths) already does the right thing onceloopEnabledis true.Tests
packages/studio/src/player/store/playerStore.test.tshad no existing coverage forsetInPoint/setOutPoint. Added 14 new tests across both setters covering:loopEnabledon clear (in both directions: was-true stays true, was-false stays false)Full studio suite: 525/525 ✅, oxlint clean, oxfmt clean, typecheck clean.
Behavior of edge cases
setInPoint(null)orsetOutPoint(null)does not touchloopEnabled, so a user who built up a loop-on state by other means keeps it.reset()continues to preserveloopEnabledas before (it bypasses the setters with a directset(...)).Issue #834 status after this PR
Issue can be closed once this lands.