Conversation
The empty space on a lane was a second way to drag the playhead. It is now the selection surface: a drag there draws a rubber band and takes every clip it covers, on every lane it reaches. The playhead keeps its own surface — the ruler above — and Shift+drag still marks the in/out range. The habits are the file manager's: Ctrl+drag adds a band to what is already selected, Ctrl+click adds or removes one clip, Shift+click takes everything in the rectangle between the first selected clip and the clicked one, and a plain click on a member of a group narrows it back down to that clip. Ctrl+CLICK on empty space still closes the gap — only a Ctrl-DRAG is a band, so nothing is taken away. The band's anchor is a TIME, not a screen position: the wheel scrolls and zooms the timeline mid-drag, and a pixel anchor would then sit at a different moment than the one that was grabbed. A LOCKED track never enters a selection, not even through withLinked() — that helper adds an A/V twin without looking at the lock, and the store skips locked clips, so the pair would have come apart on the first move. What can be done to one clip could already be done to many (move, delete, copy, split, link): the store has worked on the whole selection all along. Two places had not caught up — deleting from a clip's context menu first collapsed the selection to the clicked clip, and a group dragged past t=0 piled onto zero instead of stopping there, because setClipStarts clamps each clip on its own. windowDrag now also listens for pointercancel, for every drag in the file: a gesture cancelled by the system never sends pointerup, and its overlay used to stay on screen and keep following the mouse with no button held. Checks: node scripts/check-select.mjs (the band, range and lock maths), node scripts/e2e44.mjs (the gestures, text clips only — no media needed). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Empty space on a lane used to be a second way to drag the playhead. It is now
the selection surface.
The gestures
covers, on every lane it reaches.
Shift+dragstillmarks the in/out range, on the lane and on the ruler alike.
Ctrl+dragadds a band to what is already selected;Ctrl+CLICKon emptyspace still closes a gap, so nothing is taken away.
Ctrl+clickon a clip adds or removes it;Shift+clicktakes the wholerectangle between the first selected clip and the clicked one; a plain
click on a member of a group narrows it back down to that clip.
What the selection can do. Move, delete, copy, split and link already
worked on the whole selection — the store has never been single-clip. Two
places had not caught up, and both are fixed here: deleting from a clip's
context menu first collapsed the selection to the clicked clip, and a group
dragged past
t=0piled onto zero instead of stopping there, becausesetClipStartsclamps each clip on its own.Three things worth reading in the diff
zooms the timeline mid-drag, and a pixel anchor would then sit at a
different moment than the one that was grabbed.
scripts/e2e44.mjspinsthis: it scrolls the timeline in the middle of a band drag.
withLinked()—that helper adds an A/V twin without looking at the lock, while the store
skips locked clips, so the pair would have come apart on the first move.
unlocked()insrc/engine/timelineSelect.tsis where that is enforced.windowDragnow also listens forpointercancel, for every drag in thefile. A gesture cancelled by the system never sends
pointerup, and thedrag's overlay used to stay on screen and keep following the mouse with no
button held.
Checks
node scripts/check-select.mjs— the band, range and lock maths, purenode, 15 assertions. Written before the code and seen red.
node scripts/e2e44.mjs— the gestures in a running app, 13 assertions.It uses TEXT clips only, so it needs no media and no ffmpeg, and it puts
the track height back the way it found it.
Geometry lives in
src/engine/timelineSelect.tswith no DOM in it, which iswhat makes the first suite possible.
🤖 Generated with Claude Code