Part of #326. Batch 2 — depends on #327.
Nothing in a scenario can refer to anything else in it. Eight lines joining a logo to badges orbiting around it were abandoned during the rebuild, because a line's endpoint cannot follow a node whose position is animated. A ? detaching from the end of a typed sentence was abandoned for the same reason: there is no way to ask where that sentence ends.
Glyph positions are already computed at paint time in engine/renderer/text.rs (str_to_glyphs_vec, get_widths, then a positions vector). They are simply never exposed. This workstream is mostly exposure, not new geometry.
Owned files
crates/rustmotion-core/src/engine/deps.rs (new — the dependency graph)
crates/rustmotion-core/src/engine/layout_pass.rs, paint_pass.rs
crates/rustmotion-core/src/engine/renderer/text.rs (retain and expose the glyph run)
crates/rustmotion-components/src/intrinsic.rs
Do NOT write: crates/rustmotion-core/src/expr/** (#327 owns the evaluator; add reference resolution as a resolver it calls).
Deliverables
-
A node takes an optional id, unique within its scene. An expression then reads @id.prop.
-
Four families of readable property.
| Family |
Properties |
Resolved |
| Geometry |
x y width height cx cy right bottom |
after layout_pass |
| Animated transform |
tx ty scale rotation opacity |
per frame |
| Text measurement |
textWidth capHeight ascender baseline |
after layout_pass |
| Glyphs |
glyph(n).x, glyph(n).cx, glyphCount |
after layout_pass |
The animated-transform family is the one that carries the architectural cost, and it is the one the eight lines need.
-
A dependency graph built once at load and topologically sorted. Static references resolve in a pass after layout_pass. Animated references resolve per frame, in topological order rather than tree order. Getting this wrong yields values one frame stale, which is invisible until someone pauses, so the ordering needs a test that would catch exactly that.
-
Errors — a cycle is reported at load with the full chain, named and located. A reference crossing a scene boundary is reference_cross_scene and is rejected, since scenes are independent render units.
-
The detaching glyph needs no glyph slicing. The author writes the sentence without its last character and places a separate node at "x": "= @q.right" with its own animation. glyph(n) remains for per-letter work the char_* presets do not cover.
Acceptance
- A
line whose x2 is "= @chip3.cx + @chip3.tx" tracks an orbiting badge across every frame, with no one-frame lag
- A cycle
A -> B -> A fails at load naming both nodes
text.caret still works unchanged; it already covers the caret case and is not re-implemented here
Part of #326. Batch 2 — depends on #327.
Nothing in a scenario can refer to anything else in it. Eight lines joining a logo to badges orbiting around it were abandoned during the rebuild, because a line's endpoint cannot follow a node whose position is animated. A
?detaching from the end of a typed sentence was abandoned for the same reason: there is no way to ask where that sentence ends.Glyph positions are already computed at paint time in
engine/renderer/text.rs(str_to_glyphs_vec,get_widths, then apositionsvector). They are simply never exposed. This workstream is mostly exposure, not new geometry.Owned files
crates/rustmotion-core/src/engine/deps.rs(new — the dependency graph)crates/rustmotion-core/src/engine/layout_pass.rs,paint_pass.rscrates/rustmotion-core/src/engine/renderer/text.rs(retain and expose the glyph run)crates/rustmotion-components/src/intrinsic.rsDo NOT write:
crates/rustmotion-core/src/expr/**(#327 owns the evaluator; add reference resolution as a resolver it calls).Deliverables
A node takes an optional
id, unique within its scene. An expression then reads@id.prop.Four families of readable property.
x y width height cx cy right bottomlayout_passtx ty scale rotation opacitytextWidth capHeight ascender baselinelayout_passglyph(n).x,glyph(n).cx,glyphCountlayout_passThe animated-transform family is the one that carries the architectural cost, and it is the one the eight lines need.
A dependency graph built once at load and topologically sorted. Static references resolve in a pass after
layout_pass. Animated references resolve per frame, in topological order rather than tree order. Getting this wrong yields values one frame stale, which is invisible until someone pauses, so the ordering needs a test that would catch exactly that.Errors — a cycle is reported at load with the full chain, named and located. A reference crossing a scene boundary is
reference_cross_sceneand is rejected, since scenes are independent render units.The detaching glyph needs no glyph slicing. The author writes the sentence without its last character and places a separate node at
"x": "= @q.right"with its own animation.glyph(n)remains for per-letter work thechar_*presets do not cover.Acceptance
linewhosex2is"= @chip3.cx + @chip3.tx"tracks an orbiting badge across every frame, with no one-frame lagA -> B -> Afails at load naming both nodestext.caretstill works unchanged; it already covers the caret case and is not re-implemented here