RUNE-1015: Story Motion Action Proposed
Summary
motion moves an AnchorSprite along one inline static path:
- motion@heroArc: hero
path: "M 240,760 C 520,140 1320,140 1650,760"
with:
tween: 2.4s
easing: 0.16,1,0.3,1The target is the default SpriteRef. path accepts absolute M/L/H/V/Q/C plus optional final Z. Omitted with resolves the built-in $default animation facet; with: none is immediate. Animation token references are frozen during compilation, while inline timing may use a visible completion source.
Coordinate and State Semantics
Path coordinates are absolute in the target's parent-local space. The sampled point controls the same anchor represented by X/Y and alignment. Model X/Y and ActualX/Y become the endpoint immediately, while presentation follows one 0→1 progress animation through RuneNode.SamplePath. The endpoint model update uses a dedicated internal bypass because ordinary position assignment is forbidden while a motion binding is active.
All anchor translation/alignment rendering resolves position through AnchorSprite.ResolvePresentationPosition(node). Sampled RuneValues remain render-local and never become retarget inputs.
SamplePath uses the same source-aware measured-path algorithm as path stroke trim. Authors can animate PathSprite.trimEnd with the same timing as motion; the follower then aligns to the mathematical trim endpoint. Butt caps stop there, while round/square caps may paint beyond it. There is no combined trace action in V1.
Completion and Cleanup
Motion registers anonymous settle, named/selector rest, and X/Y StoryPropertySettleInfo from progress metadata. Precise rest generation-checks the active binding, replaces derived presentation with static endpoint X/Y, clears the binding, and marks state dirty. Immediate/zero-duration motion registers pre-completed settle/rest sources before clearing the binding, so named and tag waits still resolve.
A new motion replaces the old binding and starts at the new path start. Detach, destroy, and morph invalidate the generation, making late callbacks no-ops. While a binding is active, immediate and animated set assignment to x, y, or pos is rejected; authors wait for rest or replace the motion. Finite springs are supported and SamplePath clamps overshoot to [0,1]; undamped or other non-settling springs fail action execution rather than teleporting to the endpoint.
Validation
Story parses the inline path strictly, converts it to a static PathBuilder, and calls ValidateForSampling() before installation. Empty paths, unsupported/relative commands, multiple figures, missing segments, non-final Close, and oversized sampling payloads fail action execution with diagnostics. Installation revalidates capacity with the target renderer's exact reservation for both aligned data records and expression-program bytes. Every alignment-capable renderer reserves two alignment expressions regardless of current alignment, protecting active near-limit motion from later center-to-non-center mutation. PathSprite also reserves its visible DATA_PATH, one viewBox mapping expression per coordinate, and worst-case alignment. Rune derives record and operation sizes through shared capacity helpers and actual RuneExpr encoding rather than unexplained Story constants. Managed expression creation reports any remaining capacity failure explicitly instead of silently substituting static zero.
Verification Contract
Verification MUST cover follower/trim agreement on line and high-curvature paths, shared timing, closed-path seams, and cap extension. Motion cleanup remains independent from persistent trim properties: completing motion staticizes X/Y, but MUST NOT disable or rewrite PathSprite trim state.