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:
parent
76106d36ee
commit
598c186c4f
21 changed files with 427 additions and 419 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue