From 12ca209bef6c5a25123ec8d2391f37bd6ae9c2d7 Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Sun, 28 Jun 2026 19:41:07 +0300 Subject: [PATCH] fix: split leaves a phantom/duplicated video transition on the first half splitScene deep-clones the scene into the second half, then clears the first half's transition_to_next and transition_frames so the internal split seam reads as a hard cut (store.js). But it never cleared video_transition (the NLE video blend). Two consequences: - videoTransitionState (timeline.js:484) treats ANY non-empty video_transition as active and falls back to 16 frames when transition_frames is null, so a phantom transition renders on the internal A1|A2 seam that should be a clean cut. - the transition is duplicated: the deep clone kept it on the second half (correct) AND it survived on the first half (wrong). - on export _renderClips emits transition="" with tdur=0 for the first half (store.js:3434-3435), a malformed transition to the stitcher. Clear video_transition on the first half alongside the other two transition fields. The clone happens before the clear, so the second half still correctly inherits the original transition. Co-Authored-By: Claude Opus 4.8 --- movie_editor/frontend/store.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/movie_editor/frontend/store.js b/movie_editor/frontend/store.js index cdbc27fa..4005dc79 100644 --- a/movie_editor/frontend/store.js +++ b/movie_editor/frontend/store.js @@ -1816,7 +1816,12 @@ second.transition_to_next = s.transition_to_next || ""; second.transition_frames = s.transition_frames || null; s.gen_unit_id = unitId; - s.frames = cut; s.transition_to_next = ""; s.transition_frames = null; + // The split seam between the two halves is an internal HARD CUT: the original clip's + // outgoing edge now belongs to the second half. Clear ALL transition fields on the first + // half — the prompt transition (transition_to_next), the NLE video blend (video_transition), + // and its frame count — so the seam doesn't show/render a phantom (the deep clone already + // carried these onto the second half, which correctly keeps them). + s.frames = cut; s.transition_to_next = ""; s.transition_frames = null; s.video_transition = ""; if (playsFromSourceMedia(s)) { const srcIn = s.source_in || 0; const totalDur = s.source_dur != null ? s.source_dur : (frames / effFps);