A position is an argument, not another command
Everything could only be added to the end, because `append` computed its own position — the max end of the lane — and so had no opinion to state. Insert is not a new command; it is the argument that function was missing. `:at` takes a lane frame or `:end`, `:end` is the position where nothing has to move, and appending stops being a separate operation from inserting. New, reused and duplicated drawings all take it, because there was only ever one placement rule. Placing ripples: occurrences at or after the position move later by the new exposure's duration, and `:keep` against `:grow-symbol` still decides what happens at the shot's end. OVERWRITE is deliberately not a policy argument yet. Taking frames away from the occurrence already there is TRIMMING, and an argument whose second value is unimplemented is worse than an argument that is not there. A position strictly inside an existing exposure refuses and names `split`, rather than splitting on the quiet: one command performing two is how a command stops being predictable. Then split, which turned out to cost almost nothing, and that is the interesting part. The two pieces keep ONE `:time` and differ only in `:span`. The right piece's own frames therefore carry on exactly where the left's stopped, so its source clock, its keys and its corrections go on meaning what they meant: a held drawing holds the same frame either side of the cut, and a playing insert plays through it without a seam. There is no arithmetic on in-points to get wrong, and no shot-length question, since the pieces occupy the frames the one exposure occupied. The test samples every frame before and after and asserts the picture is identical — for a hold, for an exposure with a correction of its own, and for a playing insert. That is not a clever split. It is `:span` being in the node's OWN coordinates, which was decided long before there were lanes, paying for something it was not designed for. The same property is why extending a hold leaves lane keys alone. Both new commands act at the playhead, which needed `lane-frame` — the symbol's frame as a frame of the lane's own time, nil through a stepped or looping lane where one is not the other. Nil refuses; it does not snap to a nearby frame. Two smaller things found while doing it. `placeable` promised "a whole lane frame" in its refusal and then accepted 2.5, so both it and `split` now require an integer, as `extend-hold` already did for its delta. And `lane-end` is private: `:end` is the only way to ask for it. 401 tests, 5,612 assertions. The browser flow now splits an exposure at the playhead and puts a drawing in the gap, and checks that six exposures are still one row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9446829774
commit
26517af2fd
6 changed files with 296 additions and 42 deletions
|
|
@ -1,9 +1,9 @@
|
|||
# The Lane Model
|
||||
|
||||
Revised 2026-09-30. Target design. Occurrence ownership, source playback, the
|
||||
content and exposure commands and a one-row cel strip are implemented;
|
||||
correction layers, the range and retiming commands, and the remaining views are
|
||||
not. See the status note under
|
||||
content and exposure commands, placement anywhere in a lane, and a one-row cel
|
||||
strip are implemented; correction layers, overwrite and the retiming commands,
|
||||
and the remaining views are not. See the status note under
|
||||
[Proof obligations](#proof-obligations-and-implementation-order).
|
||||
|
||||
This revises the Claude artifact [The Lane Model](https://claude.ai/code/artifact/cd42981d-ed08-493f-94df-b7dd6657f0e6).
|
||||
|
|
@ -442,23 +442,43 @@ The source-channel prototype has been removed: an occurrence 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
|
||||
one — add lane, append drawing, reuse drawing, duplicate drawing, make unique,
|
||||
and extend hold with explicit ripple and shot-length policy. 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 shares its drawing.
|
||||
one — add lane, place a drawing (new, reused or duplicated), make unique, split,
|
||||
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
|
||||
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
|
||||
`: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
|
||||
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 too, and names `split` — one command does not quietly perform two.
|
||||
|
||||
Splitting turned out to cost almost nothing, which is evidence for the
|
||||
representation rather than for the command. The two pieces keep ONE `:time` and
|
||||
differ only in `:span`, so the right piece's own frames carry on where the
|
||||
left's stopped and its source clock, keys and corrections go on meaning what
|
||||
they meant — a held drawing holds the same frame either side, a playing insert
|
||||
plays through the cut without a seam, and the test for it samples every frame
|
||||
before and after and asserts the picture is identical. That falls out of `:span`
|
||||
being in the node's own coordinates; it is not something split arranges.
|
||||
|
||||
Content copies are shallow by default and keep their references to other
|
||||
symbols; `:deep? true` is the explicit copy that shares nothing, so the promise
|
||||
of independence is only made where it is kept.
|
||||
|
||||
Correction layers, the range and retiming commands (blank, split, trim, move,
|
||||
slip source, retime) and the exposure-sheet view are not implemented; a refusal
|
||||
is the current behavior where the model demands an explicit choice nobody has
|
||||
made yet. The suite stands at 397 tests and 5,561 assertions, with
|
||||
Correction layers, overwrite, and the range and retiming commands (blank, trim,
|
||||
move, slip source, retime) and the exposure-sheet view are not implemented; a
|
||||
refusal is the current behavior where the model demands an explicit choice
|
||||
nobody has made yet. The suite stands at 401 tests and 5,612 assertions, with
|
||||
`frontend/test/browser/sequence.mjs` driving the editor through create, hold,
|
||||
overflow, undo, reuse, make unique and duplicate. Rewrite tests that encode
|
||||
superseded behavior rather than preserving behavior to keep them green.
|
||||
overflow, undo, reuse, make unique, duplicate, split and insert. Rewrite tests
|
||||
that encode superseded behavior rather than preserving behavior to keep them
|
||||
green.
|
||||
|
||||
Build small adversarial documents and test their domain operations before
|
||||
expanding the interface:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue