An anchor is a peg
`[:xform :anchor]` is deleted. `T(a)·M·T(-a)` is a transform conjugated by a translation — "do M in a frame shifted by a" — and a parent already IS a shifted frame, so an anchor was a peg written inline: one that could not be selected, keyed, shared between nodes, or placed above a measured channel. Same expressive content, strictly less reach. `node-test` asserts the two produce the same matrix. Its two jobs split, and neither is a field on a node any more. A pivot nobody chose is DERIVED PER DRAG and stored nowhere. `gesture/pivot` is the middle of what the node draws — `pick/bounds-of`, the same call the stage draws the selection box from, on the same frame — or the node's own origin when it draws nothing. `gesture/about` solves for the position that holds that point still, so a turn now writes `pos` as well as `rot`. Nothing is cached, so nothing goes stale: the stored anchor was that same middle captured once at creation while the box beside it was recomputed every render, so on anything edited since it was made the cross and the box disagreed and the pivot was wrong. A symbol with more than one node diverged on its first edit. A pivot somebody chose is a PEG — `nest/peg`, an ordinary `:group` parent sitting on the derived pivot with `:pinv` captured so nothing moves. It is the answer to the three things a derived pivot cannot do: a pivot that persists (an arm about its shoulder), a pivot that travels (a keyed `pos`), and a hand transform over a measured one. The last was impossible before — `local`'s translation is `pos − M·a`, so under a measured `M` writing an anchor moves the thing it was meant to leave alone. `flow/freeze`'s `pivoted` pass knew this and skipped every `node/measured?` node, which is exactly why the traced mouth pivoted about (-234, -395) on a 320x200 stage: the top-left corner of the footage. That pass is gone; there is no node a derived pivot can be missing from. `demo/stage` is the one place the anchor did work a static `pos` cannot: `:scale` is keyed, and the source's middle has to stay on its authored centre throughout. It is now seven pegs, identical to the pixel. Also: `events/ui`'s `fitted` rescales a dropped tracing right after placement, and the anchor had been silently keeping the picture centred through that; it solves for the middle explicitly now. Schema 7. Nothing is converted, as in 6: every project is marked 7 and one still carrying an anchor is refused by name, with what to do about it. Dropping an anchor is pixel-exact wherever rotation and scale are the identity — everywhere a freeze or a drop wrote one — but not on anything since turned by hand, and not at all where `pos` is dense, so a conversion would be silent and wrong for exactly the nodes somebody had placed themselves. 601 CLJS tests, 68 Django tests, and the onion and take browser suites pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HkinzDz1VtahZVsujAGRBD
This commit is contained in:
parent
a6b6c116c6
commit
925c12fc77
25 changed files with 1009 additions and 429 deletions
|
|
@ -146,7 +146,6 @@ Full specification in `docs/animation-model.md`. The subset to build:
|
|||
[:xform :rot] {:animated? false :value 0.0}
|
||||
[:xform :scale] {:animated? false :value [1.0 1.0]}
|
||||
[:xform :skew] {:animated? false :value [0.0 0.0]}
|
||||
[:xform :anchor] {:animated? false :value [0.0 0.0]}
|
||||
[:geom :pts] {:animated? true :interp :hold
|
||||
:dense {:store "sha256:…" :offset 0 :stride 40 :frames 600}
|
||||
:generated {:by :roto/lips-outer :analysis "sha256:…"
|
||||
|
|
@ -170,15 +169,24 @@ uses to offer a parameter panel instead of raw keys. It lives on the *channel*,
|
|||
not the node, because a node wants a rotoscoped `[:geom :pts]` and a
|
||||
hand-animated `[:xform :pos]` at the same time.
|
||||
|
||||
`:skew`, `:span`, `:anchor` and `:over` stay in the shape even though nothing
|
||||
drives them yet: each is a component of a decomposition or of a composition
|
||||
order, and adding one later migrates every stored transform.
|
||||
`:skew`, `:span` and `:over` stay in the shape even though nothing drives them
|
||||
yet: each is a component of a decomposition or of a composition order, and adding
|
||||
one later migrates every stored transform.
|
||||
|
||||
`:anchor` was in this list and has since been **deleted**, which is the one place
|
||||
the reasoning above came out wrong. It is not a component of the decomposition:
|
||||
`T(a)·M·T(-a)` is `M` conjugated by a translation, and a parent already is a
|
||||
translated frame, so an anchor is a peg written inline — one that cannot be
|
||||
selected, keyed, shared, or put above a measured channel. Rotation and scale
|
||||
happen about the node's own origin; a pivot nobody chose is derived per drag by
|
||||
`domain/gesture` and a pivot somebody chose is a peg. See
|
||||
docs/animation-model.md, "There is no `:anchor`, because an anchor is a peg".
|
||||
|
||||
Transform composition, per node:
|
||||
|
||||
```
|
||||
local = T(pos) · T(anchor) · R(rot) · K(skew) · S(scale) · T(-anchor)
|
||||
world = world(parent) · local
|
||||
local = T(pos) · R(rot) · K(skew) · S(scale)
|
||||
world = world(parent) · pinv · local
|
||||
```
|
||||
|
||||
## What the prototype knows that you would otherwise rediscover
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue