Skip to content

fix: keep adjacent clips contiguous when an export changes the frame rate - #67

Open
moneymaker-ux wants to merge 1 commit into
diffusionstudio:mainfrom
moneymaker-ux:fix/contiguous-clip-frames
Open

moneymaker-ux wants to merge 1 commit into
diffusionstudio:mainfrom
moneymaker-ux:fix/contiguous-clip-frames

Conversation

@moneymaker-ux

Copy link
Copy Markdown

A project is edited at 30 fps, and an export rebuilds it at video.fps from the export settings. syncTiming rounds a clip's start, sourceIn and sourceOut to frames of that rate one by one, so the clip's end on the timeline (start - sourceIn + sourceOut, in frames) can land a frame before or after the next clip's start. The export then shows a blank frame at the cut, or the two clips overlap for a frame.

Repro, exported at 25 fps (times on the 30 fps grid, as the canvas writes them):

<video src={...} start={0} sourceIn={0.033333} sourceOut={1.133333} />
<video src={...} start={1.1} sourceIn={0} sourceOut={2} />

The first clip ends at frame 27 (0 - round(0.83) + round(28.33)), the second starts at frame 28 (round(27.5)): frame 27 is blank.

Change

  • syncTiming: a sourceOut is rounded where the end it implies falls on the timeline, start + (sourceOut - sourceIn) / rate, the way an authored end already is.
  • toFrames: settles a time to the runtime's time base (snapToMs), then to a thousandth of a frame, then rounds it to a frame. An end worked out from three decimals lands a hair either side of the same instant written as the next clip's start, and on a half frame that hair rounded the two apart even with the first change alone.

Independent of #66.

Verification

  • Timing math, property check on random pairs of adjacent clips (the second starts at start + (sourceOut - sourceIn) / rate of the first): times on 24, 25, 30 and 60 fps grids and on microseconds, exported at 24, 25, 30, 50 and 60 fps. Mismatched cuts out of 800,000: 200,037 before, 0 after. Of 80,000 clips whose start and length are whole frames of the export rate, 41 changed, each by one frame toward its authored length (the old rounding missed it on a half-frame tie).
  • Real project, v0.204.2 (4a652f5) + fix: keep scheduled audio when a clip ends during an export #66, with and without this change: 77 s, 19 back-to-back cuts edited on the 30 fps canvas, exported at 2160×3840. Blank frames found by the luma of every frame (ffmpeg signalstats):
Export Without this change With this change
25 fps one blank frame at 51.64 s none
30 fps none none
  • npm run check: the same output before and after (fails in packages/assets/src/browser.ts with TS2339, showSaveFilePicker, as on main). After rebasing onto main (2593b92), tsc --noEmit in packages/reconciler reports only that error.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AybThRmRHP14dmvwixan1h

…rate

A project is edited at 30 fps, and an export rebuilds it at the frame rate
from its settings. syncTiming rounded a clip's start, sourceIn and
sourceOut to frames of that rate one by one, so the clip's end on the
timeline (start - sourceIn + sourceOut) could land a frame before or after
the next clip's start. At 25 fps that is a blank frame or an overlap at the
cut: clip A `start={0} sourceIn={0.033333} sourceOut={1.133333}` ends at
frame 27, clip B `start={1.1}` starts at frame 28.

A sourceOut is now rounded where the end it implies falls on the timeline,
as an authored end is. toFrames settles a time to the runtime's time base,
then to a thousandth of a frame, then to a frame: an end worked out from
three decimals drifts a hair from the same instant spelled out as the next
start, and on a half frame that hair rounded the two apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AybThRmRHP14dmvwixan1h
@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown

@moneymaker-ux is attempting to deploy a commit to the Diffusion Studio Team on Vercel.

A member of the Team first needs to authorize it.

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