One word for one thing: it is a cel

Four words had accumulated for a node that puts a symbol inside another symbol.
`instance` was the document's, from the model. `placement` was the stage and
export work's. `occurrence` came in with the lane model. `exposure` came in with
me, because it is what an animator would say. Three bodies of work each brought
a word and none of them retired anybody else's, which is how you get a codebase
that reads like three people describing the same object over each other.

It is a CEL. One drawing, held for some duration. `cel` was already the view's
word — `.tl-cel`, the cel strip — so choosing it was also the smallest change,
and the app already says "drawing" for the content, which is what frees the word
up: historically a cel IS the celluloid with the drawing on it, and that sense
has somewhere else to live here.

  instance   the `:kind`. The general thing, anywhere in a document.
  cel        an instance in a lane. UI labels, command names, prose.
  lane       the group with `:layout :sequence`.
  drawing    the content a cel names.
  placement  kept ONLY for where a node sits — `nest/placement` and the
             transform that puts a face on the stage. Retired as a noun for the
             node itself.
  occurrence gone.

AND IT SETTLES A COLLISION I SHOULD HAVE SEEN EARLIER. `:time :expose` already
existed and means something else entirely: how many frames each step of a
subtree lasts, which is what shooting on twos is. Had the block been called an
exposure too, `node/expose`, `clock/exposed-frame` and `subs/render ::exposure`
would have been permanently confusable with it. Choosing `cel` lets the word
`exposure` keep the thing it actually names, and every remaining use of it in
`src` is now that one.

`:layout :sequence` stays as the field, and it is the one place two words are
kept deliberately: the layout names the RULE — children follow one another and
may not overlap — and a group carrying it is called a lane. `node/lane?` says so
where the two meet.

The second view is traditionally the exposure sheet. It will be the CEL SHEET,
for one vocabulary.

Renamed with a script and then read, because a blind pass does real damage: it
produced "an cel" thirty times, renamed the `::exposure` sub that is about the
`:expose` grid, and turned an "exposure grid" into a "cel grid" in two
docstrings. All three classes are fixed. `arthur.domain.sequence` is now
`arthur.domain.lane`, which is what its test file was already called.

424 tests, 5,749 assertions, and both browser flows — `test/browser/lane.mjs`,
renamed too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-09-30 19:43:18 -04:00
parent 76106d36ee
commit 598c186c4f
21 changed files with 427 additions and 419 deletions

View file

@ -822,7 +822,7 @@ collaborator's keying. The fix is addressing, not an algorithm:
```
palette
sequence/:sid
lane/:sid
clip/:cid/timing clip rate
clip/:cid/subject/:sid tracked subject and settings
clip/:cid/feature/:fid tracked feature and settings

View file

@ -1,7 +1,7 @@
# The Lane Model
Revised 2026-09-30. Target design. Occurrence ownership, source playback, the
content and exposure commands, placement anywhere in a lane, a one-row cel strip
Revised 2026-09-30. Target design. Cel ownership, source playback, the
content and cel commands, placement anywhere in a lane, a one-row cel strip
and the correction-layer evaluator are implemented; the commands that produce a
correction, overwrite, the retiming commands and the remaining views are not.
See the status note under
@ -21,7 +21,7 @@ and conflicting proposals in `animation-model.md`, `timing-model.md`, and
## Goal and compatibility policy
Arthur is one animation document with several ways to see and edit it: drawing
on the stage, arranging clips, timing exposures, editing curves, and generating
on the stage, arranging clips, timing cels, editing curves, and generating
motion from footage. Each view exposes relevant facts and invokes shared editing
operations. Switching views must preserve the meaning of the work.
@ -48,61 +48,61 @@ rules. Minimizing field count is secondary to representing independent choices.
export, and optimized cursors must agree with it.
- Existence, visibility, and missing measured data remain distinct facts.
## Content, occurrences, lanes, and rows
## Content, cels, lanes, and rows
These have different identities and responsibilities:
| Concept | Owns | Example |
| --- | --- | --- |
| Content | Reusable nodes and their animation | Drawing `a2`, an animated head, or a sound asset |
| Occurrence | One use of content, its interval, source playback, and local treatment | `a2` exposed on frames 12–16 |
| Lane | A sequence of occurrences and shared properties | The girl's drawings and the girl's overall transform |
| View row or column | Presentation and editor state | Timeline row, exposure-sheet column, or property curve |
| Cel | One use of content, its interval, source playback, and local treatment | `a2` exposed on frames 12–16 |
| Lane | A sequence of cels and shared properties | The girl's drawings and the girl's overall transform |
| View row or column | Presentation and editor state | Timeline row, cel-sheet column, or property curve |
Use the existing instance/node identity mechanism for occurrences. An exposure
Use the existing instance/node identity mechanism for cels. A cel
should not acquire a second identity system just because it is shown as a cel.
Lanes group occurrences; they do not introduce another node-holding content type.
Lanes group cels; they do not introduce another node-holding content type.
The concrete candidate below uses existing group and instance nodes; its ownership
boundaries are part of the design. It is now the implemented shape, and the field
spellings below are the ones the runtime reads.
Each occurrence has a stable ID. Moving it, changing its hold, swapping its source,
or trimming it preserves that ID. Repeating it creates a new occurrence that may
Each cel has a stable ID. Moving it, changing its hold, swapping its source,
or trimming it preserves that ID. Repeating it creates a new cel that may
reference the same content. A split retains the original ID on the left and gives
the right piece a new ID; commands return the resulting selection explicitly.
Occurrences are the canonical authored arrangement. A source-at-time channel or
Cels are the canonical authored arrangement. A source-at-time channel or
interval index may be compiled from them for evaluation, but is not a second
editable copy of the schedule. This replaces the earlier proposal that every cel
must be represented solely as a source key. Ordinary property animation still
uses lightweight keys; it does not need occurrence objects.
uses lightweight keys; it does not need cel objects.
A sequence lane has non-overlapping half-open occurrence intervals `[start,end)`
A lane has non-overlapping half-open cel intervals `[start,end)`
in its own time space. Uncovered intervals are gaps. Empty lanes are valid.
Compositing and simultaneous sounds are represented by multiple lanes or ordinary
scene composition; an accidental overlap never silently selects a winner.
Transitions, if added, need explicit overlap and mixing semantics.
Properties can belong to content, one occurrence, or the lane. For example:
Properties can belong to content, one cel, or the lane. For example:
- Rotate the reusable drawing: all its uses change.
- Rotate one occurrence: only that exposure changes.
- Rotate one cel: only that cel changes.
- Animate the lane's rotation: whichever drawing is showing follows it.
An occurrence can have its own transform, gain, corrections, and source timing
A cel can have its own transform, gain, corrections, and source timing
while remaining a block in the same timeline row. Independent treatment never
requires a new row or an otherwise unnecessary wrapper symbol.
### Concrete candidate: a sequence group and ordinary instances
### Concrete candidate: a lane and ordinary instances
A lane is a group node with `:layout :sequence`. Its occurrences are ordinary
A lane is a group node with `:layout :sequence`. Its cels are ordinary
instance nodes whose `:parent` points to the group. All remain in their symbol's
flat node map. The sequence constraint is document semantics; which rows the UI
expands remains editor state. Ordinary groups retain unconstrained composition.
This example is a document the runtime accepts, built and evaluated by
`frontend/test/arthur/domain/lane_test.cljs`. Times here are zero-based. Channels
use the existing representation; occurrence source references and playback have
use the existing representation; cel source references and playback have
replaced the `[:source]` channel, which no longer exists.
```clojure
@ -112,14 +112,14 @@ replaced the `[:source]` channel, which no longer exists.
:channels {[:xform :rot]
{:animated? true :interp :linear :keys {0 0, 6 30, 12 0}}}}
:exposure-a
{:id :exposure-a :kind :instance :parent :girl :z "a"
:cel-a
{:id :cel-a :kind :instance :parent :girl :z "a"
:time {:at 0 :rate 1} :span [0 4]
:source {:symbol :drawing-a}
:playback {:in 0 :speed 0 :end :stop}}
:exposure-b
{:id :exposure-b :kind :instance :parent :girl :z "b"
:cel-b
{:id :cel-b :kind :instance :parent :girl :z "b"
:time {:at 4 :rate 1} :span [0 4]
:source {:symbol :drawing-b}
:playback {:in 0 :speed 0 :end :stop}
@ -133,20 +133,20 @@ replaced the `[:source]` channel, which no longer exists.
:playback {:in 3 :speed 1 :end :stop}}}
```
The lane's rotation reads lane time. Each occurrence's channels read occurrence
The lane's rotation reads lane time. Each cel's channels read cel
time. Its content reads source time. The stills sample frame 0, while the insert
samples source frames 3, 4, 5, and 6. The group transform composes with the
occurrence transform and then the content's own transform.
cel transform and then the content's own transform.
`:span` remains in the node's own coordinates, consistent with ordinary nodes.
The interval in lane time is derived through `:time`; do not also store parent
start/end values. Sequence children require finite intervals and positive
placement rates. Ordering and overlap checks use the mapped intervals, not `:z`.
The sequence group may contain visual occurrences or audio occurrences; its
The sequence group may contain visual cels or audio cels; its
capability must reject an incompatible mixture rather than infer it per frame.
A source reference is fixed within an occurrence. The lane changes content when
another occurrence becomes active. This is a deliberate revision of the original
A source reference is fixed within a cel. The lane changes content when
another cel becomes active. This is a deliberate revision of the original
diagnosis that making `:of` a channel was necessary to avoid vertical growth:
multiple instances can occupy one row when the view presents their containing
sequence. A lane-level source schedule is therefore derived, not authored twice.
@ -157,14 +157,14 @@ The current implementation makes framed sources play and keyed sources hold.
Retire that rule. Channel storage shape must not determine playback behavior.
Adding or removing a key must not turn a still into an animation or vice versa.
An occurrence names content and describes how its source time is sampled. In the
basic case, after mapping lane time into occurrence time:
A cel names content and describes how its source time is sampled. In the
basic case, after mapping lane time into cel time:
```text
source_time = in_point + speed × occurrence_time
source_time = in_point + speed × cel_time
```
A newly created occurrence starts at local time zero. Moving it preserves this
A newly created cel starts at local time zero. Moving it preserves this
origin relative to its content. Trimming can narrow its local support without
resetting that origin; split pieces likewise preserve the source and property
values at the cut. Trimming, slipping, and retiming are distinct operations with
@ -174,7 +174,7 @@ explicitly different effects on the interval and the source map.
| --- | --- |
| Hold a drawing | Constant source frame, equivalently speed 0 |
| Play an animated symbol | Advancing source time, normally speed 1 |
| Cut between animations | Several occurrences, each with its own in-point and speed |
| Cut between animations | Several cels, each with its own in-point and speed |
| Mix stills and animation in a lane | Constant and advancing maps in the same sequence |
The source reference itself is discrete and never numerically interpolated.
@ -188,28 +188,28 @@ source, hold an endpoint, or loop an explicit range. A still uses a valid consta
frame. A loop uses a nonempty half-open range and a defined modulo rule. Playback
never guesses these policies from whether a channel happens to have keys.
Audio shares occurrence arrangement, trimming, gain ownership, and clock mapping.
Audio shares cel arrangement, trimming, gain ownership, and clock mapping.
It does not inherit visual frame-hold semantics: holding one audio sample is not
an audio freeze effect. Validate supported playback policies by media capability.
Actual audio scheduling must follow active occurrences, including gaps and cuts,
Actual audio scheduling must follow active cels, including gaps and cuts,
rather than playing every sound reachable through a structural reference.
## Time spaces and sampling
Name the relevant space whenever an API accepts a time or range: project,
symbol/lane, occurrence, or source. Store authored frame coordinates exactly;
symbol/lane, cel, or source. Store authored frame coordinates exactly;
avoid cumulative rounding when moving through nested mappings. Quantize at a
declared sampling boundary, not at every traversal step. Audio also needs its
continuous clock/sample space rather than visual frame quantization.
A hold is an evaluable time map with no unique inverse. A loop can map many
displayed occurrences to one source time. APIs must distinguish forward sampling
from inverse editing, and expose enough context to resolve an occurrence or
displayed cels to one source time. APIs must distinguish forward sampling
from inverse editing, and expose enough context to resolve a cel or
explicitly refuse an ambiguous operation. Do not report a missing time map merely
because inversion is unavailable.
Separate invertible placement timing from source sampling. A zero source speed
can mean hold without making the occurrence's own edit clock non-invertible.
can mean hold without making the cel's own edit clock non-invertible.
Reparenting through changing transforms or non-invertible timing must either
preserve the full result by an explicit bake or return a reason it cannot; a
matrix captured at one frame does not prove preservation across the animation.
@ -220,12 +220,12 @@ transform. An explicit whole-subtree stepping operation can exist separately.
Share the quantization primitive where possible, but retain its units, phase,
rounding policy, and order relative to retiming and lead. The original suggestion
that exposure and picture-rate sampling are simply one floor is insufficient:
that cel and picture-rate sampling are simply one floor is insufficient:
noninteger grids and source-frame quantization require specified behavior.
Identity timing can be implicit; remove `:time :mode` if it only duplicates that.
An occurrence interval is authored. Lane content extent is derived from its
occurrences, including the explicit end of the last one. A separately authored
A cel interval is authored. Lane content extent is derived from its
cels, including the explicit end of the last one. A separately authored
container trim/window is legitimate when it intentionally gates children. Do not
conflate that window with occupied extent or infer a final hold from the next key
when no next key exists. A range of frame numbers alone cannot encode visibility
@ -236,23 +236,23 @@ or a missing measurement.
Every view issues the same domain commands. A command accepts an explicit target
and edit policy, computes a valid change, and returns the change, resulting
selection, and any refusal reason. A button and a drag must not implement two
versions of exposure extension.
versions of cel extension.
An edit target identifies the symbol, occurrence path, selected entities or
An edit target identifies the symbol, cel path, selected entities or
properties, and the time range with its space. Navigation also distinguishes
editing shared content directly from editing it through a particular occurrence.
editing shared content directly from editing it through a particular cel.
Crossing a source cut must not silently redirect an active drawing edit to a
different symbol: retain the explicit content target until navigation changes it.
Core commands include new drawing, reuse drawing, duplicate drawing, make unique,
blank range, split, trim, move, extend exposure, slip source, retime, and apply a
blank range, split, trim, move, extend cel, slip source, retime, and apply a
bounded property edit. Ripple/overwrite policy and the set of affected lanes are
explicit command arguments. Preview consequences before committing a gesture.
New drawing creates fresh empty content and an occurrence. Blank range removes
New drawing creates fresh empty content and a cel. Blank range removes
content coverage without inventing a hidden drawing. These are different actions.
Reuse creates another occurrence pointing at existing content. Duplicate creates
a new content identity. Make unique rebinds the selected occurrence only.
Reuse creates another cel pointing at existing content. Duplicate creates
a new content identity. Make unique rebinds the selected cel only.
Copy semantics must specify nested sharing. A normal content copy duplicates its
owned nodes and channels while preserving references to other reusable symbols.
@ -268,57 +268,57 @@ and detects conflicts at the owned data being changed. One leaf per channel does
not solve simultaneous edits to different keys of that same channel; define a
conflict policy rather than claiming that granularity solves all collaboration.
### Default timing behavior: exposure edits preserve lane keys
### Default timing behavior: cel edits preserve lane keys
Working default from the follow-up discussion: extending a drawing's hold changes
exposure timing, leaving lane animation at its authored times. The user raised
cel timing, leaving lane animation at its authored times. The user raised
keeping keyframes in place as a possibility; this is the proposed predictable
default, not a claim that they selected every timing policy below.
Ownership supplies the remaining rule: properties attached to an occurrence
Ownership supplies the remaining rule: properties attached to a cel
travel with it. Extending its end does not stretch those properties; moving it
changes where their existing local times land. No per-key attachment flag is
needed to recover ownership that the document already expresses.
For the concrete example, extend `:exposure-a` by two lane frames with ripple:
For the concrete example, extend `:cel-a` by two lane frames with ripple:
| Fact | Before | After |
| --- | --- | --- |
| Exposure A's lane interval | `[0,4)` | `[0,6)` |
| Exposure B's lane interval | `[4,8)` | `[6,10)` |
| Cel A's lane interval | `[0,4)` | `[0,6)` |
| Cel B's lane interval | `[4,8)` | `[6,10)` |
| Animated insert's lane interval | `[8,12)` | `[10,14)` |
| Girl's rotation peak | Lane frame 6 | Lane frame 6 |
| B's position change | B frame 1, lane frame 5 | B frame 1, lane frame 7 |
| Insert's first source frame | Source frame 3 | Source frame 3 |
The rotation peak now coincides with a different point in the drawing sequence.
That is the intended consequence of changing exposures underneath timed motion.
The position correction stays attached to drawing B's occurrence. Neither the
That is the intended consequence of changing cels underneath timed motion.
The position correction stays attached to drawing B's cel. Neither the
background's keys nor audio on another lane moves.
The command contract for this edit names the symbol and occurrence, a delta in
lane frames, `:ripple` behavior, and an explicit scope of exposure timing. It
The command contract for this edit names the symbol and cel, a delta in
lane frames, `:ripple` behavior, and an explicit scope of cel timing. It
extends A's local support by the delta converted through A's placement rate,
and shifts subsequent occurrence placements by that delta in lane time. It does
and shifts subsequent cel placements by that delta in lane time. It does
not modify any channel's key map, source in-point, or playback speed. Reject a
nonpositive resulting duration. Validate and commit the entire change together.
The symbol's authored end is another explicit boundary: preview an overflow and
offer to extend the symbol or cancel. A command can request that extension as
part of its transaction; it must not silently truncate later occurrences or grow
part of its transaction; it must not silently truncate later cels or grow
other uses of a shared symbol. In the example, a 12-frame symbol needs an explicit
extension to 14 frames or the edit must be refused without partial changes.
Retime performance is a separate operation over explicitly selected occurrences
Retime performance is a separate operation over explicitly selected cels
and channels. It applies the same time transformation to their relevant clocks,
keys, and correction supports. Stretching an interval requires a defined warp
and interpolation behavior; it is not merely moving keys whose frame numbers
happen to lie inside the selection. Until supported, refuse this operation
rather than approximating it with an exposure ripple.
rather than approximating it with a cel ripple.
The initial UI should default stage transforms to the lane when drawing in a cel
workflow, so movement usually remains independent of exposure timing. The
inspector names the target: lane motion, this occurrence, or shared drawing.
workflow, so movement usually remains independent of cel timing. The
inspector names the target: lane motion, this cel, or shared drawing.
Changing that scope is explicit. It changes what the edit means, not just which
panel happens to be open.
@ -368,19 +368,19 @@ merely two drawings that happen to look related.
Derived library grouping may collect drawings used by a single lane. This is a
convenience, not ownership or deletion authority. Reference discovery for cycle
validation, copying, and deletion examines all structural references, including
currently inactive occurrences. Authored folders, favorites, and labels remain
currently inactive cels. Authored folders, favorites, and labels remain
legitimate user data even when the UI could have suggested defaults.
## UX: location, selection, and controls
The breadcrumb sits above the timeline and states the editing location, shared
content identity, and occurrence context when applicable. Show local time and
content identity, and cel context when applicable. Show local time and
its project context where a useful mapping exists. Holds and loops need an honest
description instead of a fictitious unique global frame.
Creation controls next to the breadcrumb act in that explicit location. Selection
does not secretly change where a new symbol goes. A shared drawing indicates its
reuse and offers Make this occurrence unique. Names help identify content;
reuse and offers Make this cel unique. Names help identify content;
linked-use indicators must rely on IDs, because different drawings can share names.
| Surface | Primary scope and controls |
@ -390,7 +390,7 @@ linked-use indicators must rely on IDs, because different drawings can share nam
| Cel action strip | New drawing, duplicate drawing, hold longer/shorter, blank range |
| Lane header | Lane selection, lock, mute/solo where applicable, onion settings, expansion |
| Stage tools | Drawing and transform modes, active target and scope |
| Inspector | Selected content/occurrence/lane properties and valid key controls |
| Inspector | Selected content/cel/lane properties and valid key controls |
Cel actions have visible contextual buttons, shortcuts, a context menu, and
command-palette entries. These are different entrances to the same commands.
@ -411,52 +411,52 @@ preferences can be saved separately.
## A session, revised
1. In `main`, create a girl lane and a new drawing. Draw; use New drawing (`N`)
to create the next one with the previous exposure ghosted behind it.
to create the next one with the previous cel ghosted behind it.
2. Use Duplicate drawing (`D`) when the current shapes are the starting point.
Use Reuse drawing for a deliberately linked exposure. The UI shows the
Use Reuse drawing for a deliberately linked cel. The UI shows the
difference before an edit can change other uses.
3. Time the performance. Hold longer (`H`) extends the selected occurrence and
ripples later occurrences in the explicitly targeted lane. A trim gesture
3. Time the performance. Hold longer (`H`) extends the selected cel and
ripples later cels in the explicitly targeted lane. A trim gesture
can use overwrite instead. The preview shows which boundaries will move.
4. Choose a two-frame default exposure for newly created drawings, or run a
separate Retime exposures command on a selected range. This does not quantize
lane transforms or silently retime already authored exposures.
4. Choose a two-frame default cel for newly created drawings, or run a
separate Retime cels command on a selected range. This does not quantize
lane transforms or silently retime already authored cels.
5. Place the background in a lane below. Its source holds one frame throughout
its occurrence. Key the lane's X position at the beginning and end and choose
its cel. Key the lane's X position at the beginning and end and choose
linear interpolation. The background slides while the girl's drawings cut.
6. Select three frames on the girl's lane, choose Return motion, and rotate to
the desired peak. A bounded rotation correction affects the girl across any
drawing boundaries in that range. Existing motion survives outside it.
7. Insert a playing animated symbol among the girl's held drawings. Set that
occurrence's source playback to advance. No lane conversion is required.
cel's source playback to advance. No lane conversion is required.
The timeline shows named exposure blocks with property marks and optional curve
subrows. The exposure sheet shows the same occurrences by frame and lane. The
The timeline shows named cel blocks with property marks and optional curve
subrows. The cel sheet shows the same cels by frame and lane. The
graph editor edits the same properties; the stage resolves the same document.
Onion skin is configurable and counts neighboring exposure events, skipping gaps
Onion skin is configurable and counts neighboring cel events, skipping gaps
by default; a long hold does not consume the budget. Repeated uses of the same
drawing remain distinct events. Deduplicating identical ghosts is a display option.
## Proof obligations and implementation order
The source-channel prototype has been removed: an occurrence names one symbol
The source-channel prototype has been removed: a cel names one symbol
and carries its own playback clock, and `node/problems` rejects the old
`[:source]` channel. What a lane IS lives in `arthur.domain.symbol` beside the
other rules about a node map; `arthur.domain.sequence` holds the commands over
other rules about a node map; `arthur.domain.lane` holds the commands over
one — add lane, place a drawing (new, reused or duplicated), make unique, split,
trim, move, blank and extend hold. Each is one history step, and each refuses rather than
half-applying. The timeline draws a lane's occurrences as cel blocks on the
lane's own row, and offers Make unique only where the selected exposure actually
half-applying. The timeline draws a lane's cels as cel blocks on the
lane's own row, and offers Make unique only where the selected cel actually
shares its drawing.
There is ONE placement function and a position argument, so appending is not a
different operation from inserting: `:end` is a position like any other, the one
where nothing has to move. Placing ripples — occurrences at or after the
position move later by the new exposure's duration — and `:keep` versus
where nothing has to move. Placing ripples — cels at or after the
position move later by the new cel's duration — and `:keep` versus
`:grow-symbol` still decides what happens at the shot's end. OVERWRITE is not a
policy argument yet, deliberately: taking frames away from the occurrence
policy argument yet, deliberately: taking frames away from the cel
already there is trimming, and until `trim` exists, placement that would need it
refuses instead of approximating it. A position inside an existing exposure
refuses instead of approximating it. A position inside an existing cel
refuses too, and names `split` — one command does not quietly perform two.
Splitting turned out to cost almost nothing, which is evidence for the
@ -474,7 +474,7 @@ of independence is only made where it is kept.
THE SHOT LENGTH IS AUTHORED, which is the decision the range commands forced.
`:frames` is the symbol's window — how long the shot IS — and the occupied
extent of its lanes is a different fact derived from the occurrences. A command
extent of its lanes is a different fact derived from the cels. A command
grows the window only when the caller says `:grow-symbol`, and never shrinks it:
blanking the end of a shot leaves a shot with empty frames at the end, because
that is a true statement about what somebody authored, and deriving the window
@ -487,12 +487,12 @@ which carries the ripple and shot-length policies because it needs them.
Move is one write to `:time :at` and REFUSES a destination that would overlap,
because moving a drawing and re-timing the ones around it are different
intentions — clear the room with `blank` or `trim` first, which is the
composition. Blank leaves a gap and does not close it; an exposure wholly inside
composition. Blank leaves a gap and does not close it; a cel wholly inside
the range goes, one overlapping an end is trimmed to it, and the one spanning
the range is split. Their drawings stay in the library, since a lane does not
own its content.
All three are the same geometry as `split`: a `:span` is in the occurrence's own
All three are the same geometry as `split`: a `:span` is in the cel's own
frames, so moving an edge is one write and `:time` and `:playback` are never
touched. That is why trimming the front of a playing insert starts it later into
its animation instead of restarting it — the difference between trimming and
@ -512,7 +512,7 @@ plumbing, since `node/problems` already reports every channel's problems.
Both halves of ownership are under test at lane level: a three-frame correction
on the girl's lane reaches across the drawing boundary beneath it and leaves
every frame outside its support identical, and a correction owned by one
exposure travels with that exposure when a hold before it grows.
cel travels with that cel when a hold before it grows.
Regeneration keeps them, which is the obligation the layer design exists to
meet: `rebased` replaces a base and carries its corrections across, and a
@ -529,7 +529,7 @@ report.
Still unbuilt: overwrite as a placement policy (which is now `blank` then
`place`, composed inside one transaction), slip source, retime, and deleting
reused content. A lane cannot hold AUDIO occurrences — `sequence-problems`
reused content. A lane cannot hold AUDIO cels — `lane-problems`
requires visual ones, though this document says a lane may hold either and
should reject only a mixture.
@ -537,7 +537,7 @@ What is NOT implemented is a command that produces a layer — the doc's Constan
adjustment, Ramp and Return motion — and with it the question of how a view
offers those three over a selected range, and how it offers a conflict for
resolution. Overwrite, the range and retiming
commands (blank, trim, move, slip source, retime) and the exposure-sheet view
commands (blank, trim, move, slip source, retime) and the cel-sheet view
are also not implemented; a refusal is the current behavior where the model
demands an explicit choice nobody has made yet. The suite stands at 424 tests
and 5,749 assertions, with `frontend/test/browser/sequence.mjs` driving the
@ -552,23 +552,23 @@ expanding the interface:
| --- | --- |
| Same drawing exposed twice, then one made unique | Linked edits affect both before copying and only the selected content after |
| Holds, playing inserts, nonzero in-points, and gaps on one lane | Source behavior is independent of property key count and channel encoding |
| Adjacent occurrences, final hold, split, trim, ripple, and overwrite | Exact boundaries, stable IDs, deterministic collision handling |
| Extend a hold under lane keys and occurrence-local corrections | Lane key times remain fixed; later occurrence corrections travel with their owners; source playback origins survive |
| Adjacent cels, final hold, split, trim, ripple, and overwrite | Exact boundaries, stable IDs, deterministic collision handling |
| Extend a hold under lane keys and cel-local corrections | Lane key times remain fixed; later cel corrections travel with their owners; source playback origins survive |
| Ripple beyond the symbol end | Explicit extent policy; refusal leaves the document unchanged; resizing and retiming undo together |
| Girl on twos over a moving background | Drawing cadence does not quantize either lane's continuous properties |
| Three-frame correction crossing a drawing boundary | Exact support, same result outside it, one undo step |
| Nested retiming, holds, loops, and fractional sampling | Explicit time spaces; ambiguous inverse edits cannot silently choose a target |
| Audio inside changing source occurrences | Only active intervals sound, with correct trim and source timing |
| Audio inside changing source cels | Only active intervals sound, with correct trim and source timing |
| Regenerate with corrections and a topology change | Compatible edits survive; incompatible ones produce actionable conflicts |
| Reference cycles and deletion of reused content | Inactive references are validated too; no dangling references |
| Save/load and command undo/redo | Identity, source maps, corrections, and evaluation round-trip |
| Timeline and exposure-sheet invocation of one command | Identical document changes and selection targets |
| Timeline and cel-sheet invocation of one command | Identical document changes and selection targets |
| Random forward/backward seeks and export | Reference and optimized evaluation agree, including defaults and absence |
| Concurrent commands on overlapping and disjoint targets | Transactions remain valid; conflicts are explicit and undo preserves others' work |
Implementation order: occurrence ownership and playback semantics; shared
Implementation order: cel ownership and playback semantics; shared
commands and validation; correction layers and time-addressing contracts; then
breadcrumb, cel strip, and an exposure-sheet projection. Use those two temporal
breadcrumb, cel strip, and a cel-sheet projection. Use those two temporal
views plus direct stage editing to prove the model before broadening the UI.
A new presentation should not require duplicate animation state. A genuinely new