Nesting is a gesture of its own, not an overlap
Now that a lane is generic, the obvious next move is to read a clip dropped on another clip as "put it inside that symbol". It cannot mean that: dropping a clip on occupied lane time already means it claims that time and trims the incumbent. Structural nesting therefore needs an explicit affordance -- a grab handle with `grab`/`grabbing` cursors, distinct from the body's temporal move and the edges' trims -- and its drop must route through `nest/move-node`, which preserves world transform and root timing, rather than through a weaker `:parent` assignment that would make a drawing jump when it is rehoused. The second half of the note is what expansion should be. One permanently expanded row per lane clip is the vertical growth the one-row lane exists to avoid, so an expanded lane shows exactly one portal: the currently selected clip, swapped in place when the selection changes, not following the playhead. The portal header is the structural drop target, sub-expanding it walks the source symbol's lanes through the existing recursive root-time mapping, and collapsed clips carry their instance-level keys as ticks. The cost of inspection stays constant. No lane-as-symbol type and no second ownership edge: the hierarchy is still symbol, lane, clip, source symbol, its nodes. Lane membership owns time; a symbol instance owns composition. Written before the interaction is built, because the capability it protects is easy to lose by accident. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
5ebe776ce4
commit
95451798d2
1 changed files with 116 additions and 0 deletions
116
docs/lane-nesting-notes.md
Normal file
116
docs/lane-nesting-notes.md
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
# Lane nesting interaction notes
|
||||||
|
|
||||||
|
Status: design note, 2026-10-01. This records the interaction before more lane
|
||||||
|
UI is implemented.
|
||||||
|
|
||||||
|
## The capability that must not be lost
|
||||||
|
|
||||||
|
A lane owns temporal placement, but a symbol instance is still a doorway into
|
||||||
|
another symbol. A drawing accidentally authored at the root must be movable into
|
||||||
|
an instance in any lane, including another lane, without changing its visible
|
||||||
|
position or timing.
|
||||||
|
|
||||||
|
That operation already exists as `nest/move-node`. It resolves the source and
|
||||||
|
destination at the current root frame, transplants the node, and re-expresses
|
||||||
|
its transform and time under the new parent. The lane UI must expose a target
|
||||||
|
path for it; it must not replace it with a weaker `:parent` assignment.
|
||||||
|
|
||||||
|
There are therefore two different drag intentions:
|
||||||
|
|
||||||
|
1. **Temporal move:** drag a clip body onto lane space. It remains a clip in a
|
||||||
|
lane, moves in time, and claims the destination interval by trimming/removing
|
||||||
|
incumbents.
|
||||||
|
2. **Structural move:** drag from the clip's grab affordance onto another symbol
|
||||||
|
instance. The dragged node is transplanted into the target instance's source
|
||||||
|
symbol with `nest/move-node`, preserving its world transform and root timing.
|
||||||
|
|
||||||
|
These cannot be inferred from overlap alone. Dropping clip A onto time occupied
|
||||||
|
by clip B already means “A claims that time and trims B.” Structural nesting
|
||||||
|
therefore needs an explicit grab affordance/mode. Its cursor is `grab` and
|
||||||
|
`grabbing`; trim edges keep their resize cursors and the ordinary body keeps its
|
||||||
|
timeline-move behavior.
|
||||||
|
|
||||||
|
Both visible clip blocks and an expanded symbol header are structural drop
|
||||||
|
targets. This permits moving a root drawing directly into `symbol-3` even when
|
||||||
|
its lane is collapsed.
|
||||||
|
|
||||||
|
## Compact expansion: one selected-clip portal
|
||||||
|
|
||||||
|
Expanding a lane must not restore row-per-clip vertical growth. Instead, an
|
||||||
|
expanded lane reveals exactly one clip portal: the currently selected clip in
|
||||||
|
that lane.
|
||||||
|
|
||||||
|
```text
|
||||||
|
▾ foreground lane [symbol-1][symbol-2][symbol-3]
|
||||||
|
▾ symbol-3 instance/source header and drop target
|
||||||
|
▸ body lane nested rows, mapped to the root ruler
|
||||||
|
▸ face lane
|
||||||
|
position nested keyframes mapped to root time
|
||||||
|
```
|
||||||
|
|
||||||
|
- Selecting another block in the same lane swaps the portal in place.
|
||||||
|
- With no selected clip in that lane, expansion shows a compact “select a clip
|
||||||
|
to inspect” row. It must not follow the playhead during playback; that would
|
||||||
|
make the timeline restructure itself while playing.
|
||||||
|
- The portal header represents the selected instance and is the structural drop
|
||||||
|
target for moving root or sibling content into its source symbol.
|
||||||
|
- Sub-expanding the portal uses the existing recursive symbol-row walk. Nested
|
||||||
|
lanes and channels are mapped through the instance clock into the open/root
|
||||||
|
ruler, as ordinary expanded instances already are.
|
||||||
|
- The lane's own transform/channel rows remain available separately. They affect
|
||||||
|
every clip in the lane and are not properties of the selected portal.
|
||||||
|
|
||||||
|
This keeps the cost of inspection constant: an expanded lane adds one selected
|
||||||
|
symbol branch, not one branch for every temporal clip it contains.
|
||||||
|
|
||||||
|
## Keyframe visibility
|
||||||
|
|
||||||
|
Two levels should be visible without changing editors:
|
||||||
|
|
||||||
|
- The selected clip's instance-level keys (transform, visibility, corrections)
|
||||||
|
appear as ticks inside that clip block on the lane row.
|
||||||
|
- Expanding the lane opens the selected clip portal, where source-symbol and
|
||||||
|
recursively nested keys appear on their own rows, mapped to root time.
|
||||||
|
|
||||||
|
Thus the collapsed lane answers “where does this clip change?” and the expanded
|
||||||
|
portal answers “which property inside this symbol changes?” The second view is
|
||||||
|
still the root timeline; entering the symbol is not required merely to see or
|
||||||
|
edit its keys.
|
||||||
|
|
||||||
|
## Drag targets and feedback
|
||||||
|
|
||||||
|
- Grab onto lane background: move/adopt the instance into that lane.
|
||||||
|
- Grab onto a symbol clip: structurally transplant into that clip's source
|
||||||
|
symbol.
|
||||||
|
- Grab onto the expanded portal header: the same structural transplant, with a
|
||||||
|
larger and less ambiguous target.
|
||||||
|
- Grab onto itself or one of its descendants: refuse before drop to prevent a
|
||||||
|
symbol cycle.
|
||||||
|
- A structural target receives an inset highlight and the preview stays in that
|
||||||
|
target. A lane-time target receives the dashed temporal clip preview.
|
||||||
|
- Successful structural drops expand the target lane and select the moved node
|
||||||
|
beneath the target portal, so the result is immediately visible.
|
||||||
|
|
||||||
|
## Data model consequence
|
||||||
|
|
||||||
|
No lane-as-symbol type is required. The hierarchy remains:
|
||||||
|
|
||||||
|
```text
|
||||||
|
symbol -> sequence lane -> instance clip -> source symbol -> its lanes/nodes
|
||||||
|
```
|
||||||
|
|
||||||
|
Lane membership owns time partitioning. Symbol instances own composition
|
||||||
|
nesting. The UI may present the selected instance below its lane, but that is a
|
||||||
|
derived portal, not another ownership edge and not a duplicated node.
|
||||||
|
|
||||||
|
## Implementation order
|
||||||
|
|
||||||
|
1. Render instance-level key ticks within lane clips.
|
||||||
|
2. Add selected-clip portal expansion to `timeline/rows` using the existing
|
||||||
|
recursive walk and root-time mapping.
|
||||||
|
3. Add the explicit structural grab affordance and clip/portal drop targets.
|
||||||
|
4. Route structural drops through `nest/move-node`; add browser coverage for a
|
||||||
|
root drawing moved into a clip in another lane without a visual jump.
|
||||||
|
5. After the transplant, expand the destination portal and reveal/select the
|
||||||
|
moved row.
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue