feat(studio): drag automation segments - #3465
Conversation
somanshreddy
left a comment
There was a problem hiding this comment.
APPROVE — verified at 51d5396a. Traced both concerns to source; clean.
Concern A — segment drag (the feature)
- Geometry refactor is behavior-preserving.
envelopePath's inner loop was extracted tosegmentLineCommands; the newArray.from({length: DRAW_SAMPLES}, (_, sample) => … (sample+1))reproduces the oldfor k=1..DRAW_SAMPLESexactly (same sample points, same straight-line shortcut on!curve && viaX===undefined && scale==="linear",[]for the skip case matches the oldcontinue).envelopePathis on the core render path for every lane, so this equivalence mattered — it holds. - Drag math reuses the proven group-move path.
armSegmentDragsnapshots endpoints[i, i+1]with the pointer as anchor (no jump), thencomputeGroupMovedoes the translation + clamp. Tests cover every class that matters: equal Δt/Δv on both endpoints,viaX/viaYcurve preserved through the translate, neighbor clamp stops the pair atnext.t − MIN_POINT_GAP_SECwhile preserving the segment's own width, preview-per-move + commit-once-on-release. - Precedence is right: point-grab wins over segment-grab; Alt→curve (span-wide hit), unmodified→segment (only within
SEGMENT_GRAB_PX=5of the drawn line); a press >5px off the line still falls through to a background range drag (test confirms). Read-only suppresses hover + cursor correctly.
Concern B — audio-group FX rack / stale clip reclaim
The load-bearing question was the ordering: the bus selection clears the clip selection (the new hf-audio-group branch in domSelectionTimelineMirror), and the fix relies on publishing the reveal after that clear so revealTargetsSelection (playerStore:533) doesn't nix it. That ordering is guaranteed by construction: handleTimelineElementSelect awaits the selection build, then applyDomSelection → announceTimelineSelection → the clip-clear all run synchronously before the async fn's promise resolves (useDomSelection.ts:389‑393). openGroupFxRack's selection.then(() => revealAudioFx(…)) therefore fires on a strictly-later microtask than the clear — the fresh reveal survives. revealedAudioFxTarget has real consumers (useAudioFxRevealSection, propertyPanelAudioFxGroup), so it's a live write, not a dead one.
Non-blocking notes
- Test depth on the B ordering. Both new tests (
TimelineGroupRow,useDomSelectionSelectionGuards) mockhandleTimelineElementSelect, so the select→clip-clear→reveal microtask sequence that makes the fix correct isn't actually exercised — the guarantee rests on the sync/await structure above (which I verified) and manual validation. An integration-level test driving the realhandleTimelineElementSelect→ reveal-survives sequence would lock the contract against a future refactor that makesapplyDomSelectionasync. - Cosmetic: when a stretch-edge hover and a segment-grab hover coincide,
laneCursorcorrectly showscol-resize(stretch wins), butsegmentHoverIndexstill thickens the segment — cursor and highlight momentarily disagree. Harmless.
Nothing blocking.
Summary
Validation
Preview
Open the local Studio composition at http://127.0.0.1:5194/#project/automate-lineage