feat(studio): multi-clip drag preview math#2197
Open
ukimsanov wants to merge 1 commit into
Open
Conversation
This was referenced Jul 11, 2026
Collaborator
Author
This was referenced Jul 11, 2026
4622bb9 to
d0a6ab1
Compare
7312dd0 to
7da8833
Compare
d0a6ab1 to
206097c
Compare
miga-heygen
reviewed
Jul 11, 2026
miga-heygen
left a comment
Contributor
There was a problem hiding this comment.
Reviewed as part of the 25-PR NLE overhaul stack. Full stack review on #2205 (the keystone). No blockers on this PR. — Miga
vanceingalls
left a comment
Collaborator
There was a problem hiding this comment.
Verdict: LGTM (green) — rigid group, no shearing
A concise study in "the formation moves as one". Every passenger inherits the same delta; the leftmost member sets the floor; the grabbed clip stops with the group rather than out-running it. That is the correct model.
The pointed queries
- Group-clamping by the leftmost element (no shearing).
packages/studio/src/player/components/timelineMultiDragPreview.ts:100–:106—clampGroupMoveDeltareadsminStart = Math.min(...memberStarts)and boundsrawDelta ≥ -minStart. The test at :113–:116 nails the invariant: grabbed clip at 10, passenger at 1,clampGroupMoveDelta(-8, [10, 1, 4]) === -1. The passenger — not the grabbed clip — sets the floor. This is precisely the "group shears if you per-element-clamp" bug the module documents at :90–:98. - Individual snap participation vs group delta. The module's own docstring at :2–:20 is explicit: the preview start (
draggedPreviewStart) is ALREADY group-clamped upstream (updateDraggedClipPreviewrunsclampGroupMoveDeltabefore setting it), so the delta this module returns is by construction the clamped delta. Passengers inherit it viamultiDragPassengerOffsetPx(:74–:82). Snap participation happens for the grabbed clip at the upstream layer; the group moves rigidly by its outcome. That's the correct sequencing. - Unit consistency.
multiDragDeltaSecondsreturns seconds (:52–:55);multiDragPassengerOffsetPxconverts to pixels via explicit× ppsat :81 and treatsNumber.isFinite(pps) ? pps : 0(guards NaN input, tested at :86–:88). Clean boundary. - Edge cases exercised. Zero-delta when inactive (:49), leftward negative delta (:45), NaN pps → 0 offset (:87), already-at-0 forbids further leftward (:118–:122), empty formation returns raw delta (:124).
One observation (not a blocker)
- Line :103 uses
Math.min(...memberStarts)— for extremely large selections (10k+ elements) this can spread-args the call stack. Timeline selections are single-digit-to-dozens in practice, so purely theoretical. WouldmemberStarts.reduce((a, b) => a < b ? a : b)be more defensive? Yes. Necessary here? No.
R1 by Via
7da8833 to
85079ea
Compare
206097c to
1ed5c27
Compare
85079ea to
f441a84
Compare
1ed5c27 to
f2fbc25
Compare
f2fbc25 to
6730438
Compare
25372cc to
a399c01
Compare
6730438 to
7f34c4e
Compare
What: new pure module timelineMultiDragPreview — group-drag passenger offsets and clamped group deltas (isMultiDragActive, multiDragDeltaSeconds, multiDragPassengerOffsetPx, clampGroupMoveDelta) with tests. Why: the group-drag math, standalone and DOM-free. How: new files only; consumed later by TimelineLanes. Test plan: bunx vitest run timelineMultiDragPreview.test.ts; tsc --noEmit; fallow audit clean.
a399c01 to
ff3ddb7
Compare
7f34c4e to
4a2773c
Compare
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.

What
new pure module timelineMultiDragPreview — group-drag passenger offsets and clamped group deltas (isMultiDragActive, multiDragDeltaSeconds, multiDragPassengerOffsetPx, clampGroupMoveDelta) with tests.
Why
the group-drag math, standalone and DOM-free.
How
new files only; consumed later by TimelineLanes.
Test plan
bunx vitest run timelineMultiDragPreview.test.ts; tsc --noEmit; fallow audit clean.
Stack position 6/25 — studio NLE overhaul (CapCut-parity timeline + canvas). Graphite manages bases; merge from #2192 upward. Temporary
TEMP(studio-dnd)fallow entries (unwired-component windows) are all removed by #2213 (app-shell swap), whose tree is byte-identical to the fully-verified integration branch.