Skip to content

[generator] — for star_pattern

KeyValuesNotes
tilingsquare/4/4.4.4.4, hexagon/6/6.6.6, octagon/8/4.8.8, dodecagon/12/3.12.12, noneStar order n. Required. none draws no interlace at all — the rings-only mandala below — and is a load error unless rings has at least one entry, because a preset with neither draws nothing.
contact_angle_degnumberHankin contact angle. Default 30. Inert at tiling = "none".
ringsarray of ring tables (below)The mandala interior. Optional — absent is the Hankin interlace alone, segment for segment.

rings — concentric rings of repeated motifs

The answer to star_pattern reading as a hollow ring. Each entry is one concentric ring; copy i of a ring of k sits at angle 2*pi*i/k + phase, at radius from the frame centre, scaled by scale. Motifs are drawn through the same line renderer as the interlace, so the stroke, joins, glow and palette are the ones you already know.

KeyValuesNotes
motifone of the eight names belowRequired. An unknown name is a load error listing the legal set — the roster is closed, not extensible.
count1 .. 512Required. Copies around the ring. 0, a negative, or anything over the ceiling is a load error.
radiusnumberRequired. Distance from the frame centre, in the fit-normalized world the figure lands in: it spans +/- 0.9, so 0.9 is the rim and anything smaller is interior. 0.0 is a single centre boss.
scalenumberMotif size multiplier — close to the copy’s diameter, since every outline spans about one unit. Default 0.25.
phasenumber (radians)Angular offset of copy 0. Default 0. Use it to stagger a ring against its neighbours.

scallop reads three of those keys differently, and it is the only member that does. It is a boundary, not a bead repeated around a ring, so there is no copy count: count is its lobe count (floored at 3 — below that there is no boundary, and a smaller number is raised rather than refused), radius is the base circle its lobes bulge from, and scale is the depth of the bulge, which is the only size a lobe has once count has fixed its width. phase turns the whole boundary, as it turns every other ring. Each key keeps its spirit; none of them means a copy.

The closed motif roster is eight names, every one picked from rendered samples, and closed on purpose: a look outside it routes back through architect + dev, it is not a preset-side extension point:

motifwhat it isinstances per copy
circlea plain bead; the ring that reads as a dotted orbit1 arc
petala pointed oval (vesica), cusped at both ends along the radius22 arcs
teardropround outward, cusped inward — the only motif with an unambiguous “which way is out”16 arcs
diamonda four-vertex rhombus, long along the radius4
arcan open outward-bulging arc, chord tangential; the nearest this roster comes to a scalloped boundary1 arc
trefoila three-lobed rose — the densest member, and the one that reads as ornament rather than as a bead24 arcs
chevronan open two-segment wedge, apex outward; a sawtooth border at high counts2
scallopthe scalloped boundary — one closed chain of outward-bulging arcs meeting at cusps. Not a bead: see the key note above1 arc per lobe

Six of the eight are drawn as real curves (ADR-0098) — only diamond and chevron are still sampled polylines — and the two circular ones are the cheapest members of the roster. Every arc’s stroke is a distance evaluated per pixel, so it has no vertices at any scale.

  • circle and arc are exact, one instance each, with no interior joint at all. Where a circle cost 24 segments and 24 additively-overlapping joints, it costs one instance and none.
  • petal, teardrop and trefoil are fitted G1 chains — 22, 16 and 24 arcs, against the 24, 24 and 36 segments they were. Consecutive arcs share a tangent, so a chain has no corner where its pieces meet; what it does keep is the figure’s own corners, which is why a trefoil still cusps three times and a teardrop once. Three tangent breaks where there were 36 is the remaining bead count, and it does not depend on the scale you draw at.
  • scallop is exact and needs no fit at all — a scallop is a chain of circular arcs, which is what makes it a scallop and not a sine wave. At scale = 0 every lobe is an arc of the base circle, so the boundary is a plain ring: sweeping ring_scale through zero passes through that rather than through anything undefined.
  • diamond and chevron stay sampled polylines, which is the right primitive for them: a distance field is strictly more expensive for a straight line, and these two are nothing but straight lines.

star and triangle were cut at the same sitting and are load errors now. The property they were cut on is the one to judge a candidate by: does it hold its identity across the whole 8-to-32 count range. star is an ornament at ×8 and dissolves into texture by ×32; triangle duplicates chevron’s role at twelve times the cost.

The instance budget, and what happens when you exceed it. A ring costs count × instances-per-copy, and the interlace adds 2n on top. Segments and arcs share one ceiling — 20 000 at the floor tier, 60 000 at rich — so the four-ring mandala roster at 24 + 12×4 + 18×22 + 24×1 = 492 plus a 24-segment interlace uses under 3 % of it. (Drawn as sampled polylines instead, the same roster would cost 1 092 — its circle ring alone is 576 segments against 24 arcs.) Two things to know:

  • Truncation at the cap is silent. The build stops emitting and nothing warns you — no load error, no --report column. The figure simply ends part-way through a ring, in roster order, so it is the outermost rings you lose. If a dense mandala looks like it is missing its outer ring, count your segments.
  • There are two ways to exhaust the same cap. The interlace grows with the tiling and the rings grow as rings × count × resolution; the failure looks identical from either direction.

The three bindable levers (ring_phase, ring_spread, ring_scale) move this roster without changing what is in it — see the ring levers.

system = "star_pattern"
[generator]
tiling = "none" # the ornament alone; "12" composites it inside the interlace
rings = [
{ motif = "trefoil", count = 1, radius = 0.00, scale = 0.46 },
{ motif = "diamond", count = 12, radius = 0.30, scale = 0.20 },
{ motif = "petal", count = 18, radius = 0.52, scale = 0.26, phase = 0.09 },
{ motif = "circle", count = 24, radius = 0.70, scale = 0.13 },
# count = lobes, radius = the circle they bulge from, scale = the depth.
{ motif = "scallop", count = 40, radius = 0.86, scale = 0.05 },
]

scallop is the boundary motif; arc is not. A ring of 40 overlapping arc motifs faking a continuous edge was judged against a real scalloped boundary and lost. arc is an open arc; reach for scallop when you want a boundary.

The ring levers — and why two of them are radial

ParamDefaultWhat it does
ring_phase0Turns alternate rings in opposite directions, in radians: ring 0 by +phase, ring 1 by −phase, and so on down the roster. Counter-rotation is the strongest ornamental gesture this geometry has. Wraps at one turn.
ring_spread1Multiplies every ring’s radius about the centre — the figure opening and closing. Clamped to 0 .. 4.
ring_scale1Multiplies every motif’s scale — the copies growing in place, without moving the rings. On a scallop ring that is its lobe depth, so the boundary breathes between a plain circle and a deep scallop. Clamped to 0 .. 8.

All three default to the exact identity, so a preset that binds none of them draws the roster it declared, and one that declares no rings is untouched by their existence.

Do not carry a mandala’s animation on ring_phase alone. A ring mandala is very rotationally symmetric — an 18- and 24-fold figure turned by any angle lands almost on top of itself — so a spin moves few pixels however fast it runs, and both the eye at a distance and core/tests/animation.rs read it as frozen. ring_spread and ring_scale change what the figure is at each radius rather than where it points, so they are what actually carries the motion. Spend ring_phase on the gesture and the radial pair on the liveness.

A mandala that must hold up in a portrait window carries a narrower scale or zoom. The shared line renderer divides world x by the target’s aspect, so at 720×1280 a figure is 1.78× wider in NDC than it is tall: a radius-0.62 ring that fits comfortably at 16:9 runs off both sides in portrait. This is an authoring fact rather than a defect — the three shipped mandalas are sized for a landscape window and do graze the frame in portrait.

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