Skip to content

[path] — for shape_field

The one table that carries geometry rather than a selector or a size, and the only place a preset draws a silhouette nobody put in the marks roster. Inline SVG path data, parsed once at load into a closed contour, rendered as the same signed distance field the roster is rendered as — so an authored figure gets palette_steps, palette_contour, gamma and both coord_modes for free.

KeyValuesNotes
dSVG path dataThe silhouette, as one closed contour. Required — the table exists to carry it.
morph_toSVG path dataA second silhouette the bindable morph param travels towards. Optional; absent, morph is inert.
samplesinteger 3..=64The arity both contours are resampled to, by arc length. Default 64. Optional — and a lever downward.

Coordinates read the way SVG writes them: y increases downward, so M 0,-1 sits above M 0,1. That is what a design tool exports and what a browser draws, so a path pasted out of one arrives the right way up with nothing to edit.

system = "shape_field"
[path]
d = "M 0,-1 C 0.9,-0.4 0.9,0.4 0,1 C -0.9,0.4 -0.9,-0.4 0,-1 Z"
morph_to = "M 0,-1 L 0.87,0.5 L -0.87,0.5 Z"
[params]
morph = "beat" # an ordinary binding; [smoothing] reaches it like any other
stroke = "0" # 0 fills the figure; above 0 draws its outline at that width

The subset, and what it refuses

Accepted: M m L l H h V v C c S s Q q T t Z z — moveto, the three line forms, cubic and quadratic Béziers with their smooth-continuation shorthands, and closepath. Relative commands, implicit repeats (M x y x y is a moveto and a lineto), missing separators and exponent notation all parse, because that is what an exported file actually contains. A path with no Z is closed anyway: a filled silhouette has no open form.

Two things are refused by name, and you will meet them holding a file a browser renders correctly:

  • A / a, the elliptical arc. Every design tool can re-export the same curve as cubics; look for a “convert arcs to paths” or “flatten” option.
  • A second subpath — a second M anywhere after the first. Any letterform with a counter has one, as does any shape with a hole. There is no natural point correspondence between two paths with different subpath counts, which is what a morph needs, so the pair that could not be aligned is refused at the one path rather than guessed at the morph.

Everything else that goes wrong is a load error carrying the character offset into d — a mis-parsed path would otherwise render as a plausible wrong figure, which reads as a design decision rather than as a mistake.

The arity ceiling, and the measurement behind it

samples is capped at 64, and asking for more is a load error naming both your number and the ceiling. It is not a memory bound: the field is fullscreen and evaluates a distance to every segment at every pixel of every frame, whether or not the figure is on screen.

The number is measured rather than reasoned. At 1920x1080 on an integrated GPU — the class Non-functional requirements’s floor tier is calibrated against — the contour walk costs about 0.105 ms per segment, so 64 segments is 46 % of the 60 fps frame budget and 128 would be 87 %. A traced logo pasted at 500 points is refused rather than quietly decimated, because a reduced contour would draw a figure you did not author and never say so.

A curved path is cheaper than that suggests, because it is not drawn as segments. A contour whose outline is smooth is fitted at load to a chain of circular arcs, and the same figure needs four or five times fewer of them: the leaf above costs 4.15 ms as 16 arc pieces where its 64-point polyline costs 7.09 ms. Nothing in the table selects this — a smooth figure gets it, a polygon does not need it, and a figure carrying a morph_to cannot use it (see below).

Set samples low for a polygonal figure. A hexagon needs 6, not 64, and pays for what it asks.

What morphs well

A pair travels well when both are single closed contours of comparable complexity. That is the thing you can act on; the alignment does the rest:

  • Winding is normalized for you. A clockwise path morphing into a counter-clockwise one would turn inside out through the middle — every intermediate frame a valid shape, the whole motion wrong — so the target is reversed where the two disagree. You do not have to draw them the same way round.
  • The start point is chosen for you, by minimising how far the points travel in total. Without it a square morphing into the same square from another corner unwinds through a spiral.
  • Both endpoints resample by arc length, not per command, so a shape whose commands are unevenly sized does not bunch its correspondence where you happened to click.

What no alignment fixes is a mismatch of kind. Two figures of very different complexity — a triangle into a thirty-point starburst — correspond point for point, so most of the starburst’s detail collapses onto three corners on the way. Sweep the travel and look at the middle rather than at the two ends: the intermediate is a shape nobody authored, and it is where a bad pair shows.

A morphing pair draws through its polyline, not through the arc fit — two arc chains have no point correspondence to interpolate. So a morph_to costs the samples arity above, and a figure that does not morph does not.

A long path stops being readable

This is a real cost of the feature and not something to discover in review. A 64-point traced outline is one very long unreadable line in a file format whose whole value has been that a person can read what a look does. Prefer a path you could redraw from the numbers — a dozen commands, round coordinates — and keep the shapes that genuinely need tracing rare. If a preset’s d is longer than the rest of the file put together, the file has stopped explaining itself.

Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.