Slide rows along time and restack them, at any depth

A node's bar drags along the timeline: one write to its :at, for every node
alike, carried down through the instances above it. The stage and rows show
the slide live through ::render/clip, and it lands as one edit on release.

A row dropped on another's top or bottom edge goes in front of it or behind:
one write to :z, between its new neighbours (symbol/z-between). Onto the edge
of a row in another symbol, it moves there first. Neither needs anything on
screen — nest/down walks a row path by structure, without a frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Olive Vaughn 2026-09-30 00:51:34 -04:00
parent 1b8bbc7372
commit 38850a29ba
8 changed files with 306 additions and 32 deletions

View file

@ -660,9 +660,16 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
/* The preview row of a drop in flight: its own length, where it would start. */
.tl-span.ghost, .tl-label.ghost { pointer-events: none; }
/* A row being dragged over another: into an instance, or grouped with a node. */
/* A row being dragged over another: into an instance, or grouped with a node,
by its middle; in front of it or behind it, by its top or bottom edge. */
.tl-label.drop-into { box-shadow: inset 0 0 0 2px var(--sel); background: var(--sel-bg); }
.tl-label.drop-group { box-shadow: inset 0 -2px 0 var(--sel); }
.tl-label.drop-group { outline: 2px dashed var(--sel); outline-offset: -2px; }
.tl-label.drop-front { box-shadow: inset 0 2px 0 var(--sel); }
.tl-label.drop-back { box-shadow: inset 0 -2px 0 var(--sel); }
/* A node's bar slides it along its symbol's time. */
.tl-span.movable { cursor: ew-resize; touch-action: none; }
.tl-span.movable.sliding { border-color: var(--sel); }
.tl-span.ghost {
background: transparent;
border: 1px dashed var(--sel);
@ -678,6 +685,8 @@ button.share-button:hover, button.share-button.on { filter: brightness(1.1); }
margin: -3.5px 0 0 -3.5px;
background: var(--key);
border-radius: 50%;
/* So grabbing a dot grabs the bar under it. */
pointer-events: none;
}
.tl-playhead {