Skip to content

fix(studio): splitting a video in an untimed wrapper cuts the video, not the wrapper - #5486

Merged
miguel-heygen merged 1 commit into
mainfrom
dclipmenu/split-wrapper
Oct 12, 2026
Merged

miguel-heygen merged 1 commit into
mainfrom
dclipmenu/split-wrapper

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Splitting a clip whose <video> sits inside an untimed wrapper <div> now produces two working clips. The second video gets its own id and starts its media at the cut, and neither wrapper gets timing written onto it.

Why

Before this change, the split treated the wrapper as the clip:

<!-- before: split of #wrap at 3s -->
<div id="wrap" data-start="1" data-duration="2"><video id="v" data-start="1" data-duration="6"></video></div>
<div id="wrap-split" data-start="3" data-duration="4"><video id="v" data-start="1" data-duration="6"></video></div>

Both wrappers got timing, both videos kept the full original window, and both kept the id v. The two halves played over each other, so the sound was doubled.

<!-- after -->
<div id="wrap"><video id="v" data-start="1" data-duration="2" data-media-start="0"></video></div>
<div id="wrap-split"><video id="v-split" data-start="3" data-duration="4" data-media-start="2"></video></div>

How

splitElementInHtml is the one HTML rewrite behind every split: the Studio single-clip route, the Studio split-all batch route, the CLI and freeze frame. It now cuts the inner media instead of the wrapper when all of these hold:

  • the target has no data-start, no authored duration, and is not a sub-composition host;
  • it holds a video or audio with an authored start and duration;
  • the clip's range on the timeline is that media's own window (or no range was sent).

In that case the media pair gets the start, duration and in-point, and the wrappers stay untimed. The cloned media gets a fresh unique id that also avoids the wrapper copy's new id, and its CSS rules are copied.

A GSAP scene whose range differs from the video inside it still splits on its own window, as before. Every other target (a timed div, a media element, a composition host) goes through the same code as before.

Known limits of this change:

  • The wrapper's own box (background, border) and anything else inside it (a title next to the video, say) is not windowed, so it shows in both wrapper copies. Leaving the wrappers untimed is what makes this happen.
  • A GSAP scene cut inside the window of a shorter video it holds still copies that video unchanged, as it did before.
  • Tweens that target the video's own id do not follow it to the renamed copy.
  • A second timed media in the same wrapper is not cut.

Test plan

  • Unit tests added/updated in sourceMutationSplitAndGroup.test.ts:
    • the wrapper case, including a requested id that collides with the media's split id and a copied CSS rule: fails on main (the wrapper gets data-start), passes with the fix;
    • a GSAP scene around a shorter video still splits on the scene's window. This fails if the media is picked without checking the clip's range;
    • a wrapper with its own data-start, its own duration, or a composition id is still cut itself. Each case fails if its guard is removed.
  • sourceMutationSplitAndGroup.test.ts 48/48 (3 runs in a row), routes/files.test.ts and routes/freezeFrame.test.ts pass. CLI timeline.e2e.test.ts: 49/49 passed.
  • tsc --noEmit (studio-server), oxlint and oxfmt --check on the changed files are clean.
  • Manual testing performed
  • Documentation updated (if applicable)
  • Comments follow CONTRIBUTING.md "Comments"

…not the wrapper

The split timed both wrapper copies and left both inner videos on the
original window with the same id, so the two halves played together.
@github-actions

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 2061 (base branch 2061), smooth 1567 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@miguel-heygen
miguel-heygen merged commit aa9413b into main Oct 12, 2026
79 checks passed
@miguel-heygen
miguel-heygen deleted the dclipmenu/split-wrapper branch October 12, 2026 22:39
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.

1 participant