One time map for every node; move and group nodes between symbols

Every node now has the same time map into its parent, local = rate·(parent
− at), with its span and keys in its own frames: what instances had, made the
rule. A shape without a time map reads as it always did, so no data changes.
The per-kind branches, the span-start term and the rate refusal are gone;
node/time-of, then-time and invert-time compose it like the matrix.

clip/move-node puts a node into another symbol without changing the picture
or the timing — its matrix becomes a :pinv, its time a new :at and :rate, and
its channels, keys and span are untouched — and clip/group makes a new symbol
around side-by-side nodes. Generated parts, split stencils, cycles and
looping instances are refused with the reason. Nested sounds use the same
map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Olive Vaughn 2026-09-29 13:45:34 -04:00
parent 6bec121108
commit eafbe6c4d2
7 changed files with 360 additions and 91 deletions

View file

@ -79,11 +79,19 @@ this way.
over which the node exists at all. Distinct from a `[:vis]` channel, which
blinks an existing node on and off.
A shape's `:span` is in its parent's frames. An **instance's** (or a sound's)
`:span` is in its **own** frames — which part of what it places plays, from its
own 0 — and `:time :at` is where that first frame lands in the parent. Moving an
instance along its parent changes `:at` and nothing else; `node/placed-span` is
the one function that maps an own-time span out to the parent.
**Every node has the same two maps into its parent**, whatever kind it is:
- **space** — the matrix its transform channels compose to, times a `:pinv` if
it has been moved in from elsewhere;
- **time** — `local = rate · (parent − at)`, from `:time :at` and `:rate`,
identity when absent. `:span` and every key are in the node's **own** frames.
A move keeps a node's world maps and re-expresses them under its new parent:
the matrix becomes a `:pinv`, the time becomes a new `:at` and `:rate`, and its
channels, keys and span are not touched. Both maps are affine, so any depth of
nesting is one map and every move is one inverse. `node/time-of`,
`node/then-time` and `node/placed-span` are the time half; `clip/move-node` and
`clip/group` are the move.
### Subjects and tracked features