Repository navigation
fix(studio): audio keeps playing after a timeline move or trim in a static composition - #6428
Conversation
Edit accuracy: accurate 271 (base branch 271), smooth 145 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (2)
|
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · head 78193530
The code looks right. The one blocker is the PR body: the required Studio and player captures check fails at this head (runs 40342610006, 40343059105) because the body has no ## Before / ## After headings. The two screenshots are there, but they sit under "Studio check". Put them under ## Before and ## After. Edit the body text in place (gh pr edit --body-file drops attachments), and the check will rerun.
Scope
reconcileTimeline:getSafeTimelineDurationSeconds(null, 0)returns the declared length first (resolveCompositionLengthSeconds), so removing thetransport.playfallback changes nothing. A composition with no timeline now gets the same media/derived length as at first bind, and an empty one still gets 0.finalizeSoftReload:isPlayingis read after any async commit, so a pause during the save is respected.play()is idempotent. A parent-owned audio proxy follows the paused→playingpostState. All five callers (live retime, undo restore, track visibility, timing sync, script soft reload) pass through it.- Run locally: the new tests fail with the source files reverted to the merge base and pass at the head.
core/src/runtimepasses (2549 tests), and so do studioutils+hooks, including thegsapUndoRestoreandgsapValueAtPlayheadbrowser tests on Chromium. - CI on this head: CI, regression, Windows render, CodeQL, preview-regression and both player perf runs are green (the first run set; a later duplicate set is still running).
…tatic composition A composition with no GSAP timeline was treated as zero length after an edit, which dropped preview audio, and an edit made during playback left the transport stopped. The runtime now keeps the declared length when it rebinds, and the soft reload resumes a transport that was playing.
7819353 to
fe51748
Compare
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits · 1 resolved, 0 open, 1 new · 78193530 → fe51748c
The captures blocker is fixed: ## Before / ## After are in place and PR captures passes at this head.
New blocker, in the PR body only: this fixes #6302, so the body needs a literal fails without the fix: line naming the test, e.g. fails without the fix: init.compositionLength.test.ts > keeps a timeline-less composition's declared length when a rebind finds no timeline. The Tests table says this in prose, but there is no such line. Edit the body in place so the attachments stay.
Scope
reconcileTimeline: the no-timeline branch now resolves the declared length (plus media floors). An empty root still gives 0.transport.play: the removedelsebranch was already dead.getSafeTimelineDurationSeconds(null, 0)returns the declared length first.finalizeSoftReload:isPlayingis read when finalize runs, so on the deferred MotionPath path a pause made in the meantime is respected. All six callers go through it.- CI, regression, Windows and Safari perf were still running at this head when I reviewed.
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 0 important · 0 nits · 1 resolved, 0 open, 0 new · fe51748c (body-only edit)
The fails without the fix: line is now in the body. I checked the core test locally: it fails with the base init.ts and passes here (13/13). CI, regression, Windows, PR captures and Comments all pass at this head.
What
Moving or trimming an audio clip in Studio no longer silences preview audio in a composition that has no GSAP timeline, and an edit made during playback no longer leaves the transport stopped.
Fixes #6302. Thanks to the reporter, whose diagnosis named both causes exactly.
Why
Two separate causes, both from the issue:
How
reconcileTimeline(core runtime): the no-timeline branch now usesgetSafeTimelineDurationSeconds(null, 0), the same helper that already resolves the declared length. A genuinely empty composition still gets 0.transport.playhad its own copy of the declared-length fallback; it is removed so the length has one owner.finalizeSoftReload(Studio): records whether the transport was playing before the seek and callsplay()after the rebind and manual edits are applied. A paused edit stays paused.Design call: resume at
finalizeSoftReload, the one function every soft-reload caller (live retime, undo restore, track visibility, timing sync) goes through. The alternatives were a runtime-level seek that preserves play state, or restoring play state in each caller; both leave a path that can still stop the transport.Tests
init.compositionLength.test.ts: the declared 6 s length survives__hfForceTimelineRebindand play works; an empty composition gives 0. Fails on main withexpected +0 to be 6.gsapSoftReload.test.ts: a playing transport resumes after seek, rebind and manual edits (in that order), a paused one stays paused, andapplySoftReloadresumes too. Fail on main.fails without the fix:
packages/core/src/runtime/init.compositionLength.test.ts> "keeps a timeline-less composition's declared length when a rebind finds no timeline", andpackages/studio/src/utils/gsapSoftReload.test.ts> "resumes playing once the timeline is rebuilt when an edit lands during playback". Rechecked after the rebase onto main: with main's two source files, all three new tests fail; on this branch they pass 3 runs in a row.Run on base
575f68cf5bwith only the two source files reverted, then on the branch three times:init.compositionLength.test.tsgsapSoftReload.test.tskeeps a timeline-less composition's declared length when a rebind finds no timelineresumes playing once the timeline is rebuilt when an edit lands during playback,resumes after a script soft reload too, which shares the finalizationStudio check
The reduced fixture from the issue, driven in Studio with real timeline drags: seek to 70 s from the ruler, move the audio clip by about 5 s, trim its right edge, each once paused and once while playing, reading the audio meters.
One note on the fixture: as written, with no script at all, Studio reloads the preview after an edit and the failure does not show. Adding the gsap script tag with no timeline registered takes the soft-reload path and reproduces it on main.
Captures of the playing-move case follow.
Before
After