From 89771a2380f1fb6a92f684381bc9cc24a73d183c Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Tue, 19 May 2026 23:45:41 -0400 Subject: [PATCH] feat(timeline): ripple delete on Del, extract/lift on Shift+Del --- services/web-ui/public/js/timeline.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/services/web-ui/public/js/timeline.js b/services/web-ui/public/js/timeline.js index e0e5c87..64af11d 100644 --- a/services/web-ui/public/js/timeline.js +++ b/services/web-ui/public/js/timeline.js @@ -430,10 +430,33 @@ if (e.key === 'h' || e.key === 'H') { setTool('hand'); return; } } - // Delete selected clip + // Delete / ripple-delete selected clip if ((e.key === 'Delete' || e.key === 'Backspace') && s.selectedId) { e.preventDefault(); - s.clips = s.clips.filter(function (c) { return c._id !== s.selectedId; }); + var clip = s.clips.find(function (c) { return c._id === s.selectedId; }); + if (!clip) return; + + if (e.shiftKey) { + // Shift+Delete: extract / lift — remove clip and leave the gap + s.clips = s.clips.filter(function (c) { return c._id !== s.selectedId; }); + } else { + // Delete: ripple — close the gap by shifting later clips on the same track + var clipDur = clip.timeline_out_frames - clip.timeline_in_frames; + var cutPoint = clip.timeline_in_frames; + var trackId = clip.track; + s.clips = s.clips + .filter(function (c) { return c._id !== s.selectedId; }) + .map(function (c) { + if (c.track === trackId && c.timeline_in_frames >= cutPoint) { + return Object.assign({}, c, { + timeline_in_frames: c.timeline_in_frames - clipDur, + timeline_out_frames: c.timeline_out_frames - clipDur, + }); + } + return c; + }); + } + s.selectedId = null; _renderClips(); if (s.onClipsChanged) s.onClipsChanged(s.clips.slice());