Follow-up to #27. render_blend built a GeometryMorph (contours, alignment)
for every morphing shape on every frame, though only t and the current box
change while a transition plays. The Renderer now keeps the aligned morphs,
keyed by both geometries and their own sizes, and drops those a frame did
not use, so the cache ends with the transition.
- render: morph_path::Cache replaces morph_path::geometry; blend sweeps it.
- test: one alignment per transition, same geometry as a fresh one.
generated with Claude Code
* Morph: a changed geometry morphs its outline (a circle turns into a star)
Paired shapes that differ only in geometry (another preset, other adjust
values, a custom path) and fill colour no longer cross-fade: one shape moves
and its outline turns from the old geometry into the new one.
- geom::morph aligns two outlines the way manim does: the same number of
contours, the same number of cubic curves per contour pair, then every
point moves in a straight line. Closed contours are turned and reversed so
the points travel least (a triangle does not twist into a circle), extra
points go to the longest curves, and a sub-path without partner grows out
of (or shrinks into) a point, so a cube's faces appear and a donut's hole
closes. Fill mode, outline and fill rule switch at the midpoint.
- anim::morph_frame lists such shapes in MorphFrame::paths; the renderer
draws them with the morphed geometry (PathMorph, a new render_blend
argument next to TextMorph).
Ported from the path morph in alexplain (MIT, same author).
generated with Claude Code
* Morph: differing looks of an outline cross-fade instead of switching
When a sub-path pair differs in fill mode, outline or fill rule, the two
looks no longer switch at the midpoint. A fill or outline only one side has
fades out (or in), so a filled shape turning into a line loses its fill
gradually. When both fill, the even-odd side lies opaque underneath and the
other fades over it, so a donut's hole fills smoothly while it shrinks.
generated with Claude Code
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>