Line-art parameter notes — strokes, joins, and per-scene shape
Strokes join at their interior vertices
(ADR-0041).
A line scene builds its figure as a list of segments, but a connected run of
them renders as one continuous stroke: where the stroke turns, the quads either
side of the vertex overlap instead of leaving a wedge of background between them.
There is no parameter for this and it is not authorable — each scene declares
its own connectivity, so a genuinely separate segment keeps its exact ends and
does not grow. A spectrum bar still stands exactly on baseline, a radial
spoke still starts exactly on radius, and an L-system branch still begins where
it begins.
Two things follow for authoring. A thin stroke is a real option: nothing about
a sharp-turning figure — a polyline spectrum above all — forces it to be drawn
heavy. And a very sharp turn reads slightly bright rather than broken, since
the two overlapping quads add under the additive blend. That is the trade taken in
place of a miter limit; if a near-reversal is meant to read as a fine point rather
than a bead, soften the turn rather than the stroke. On star_pattern the
turn is [generator] contact_angle_deg, not a [params] binding: a low angle
makes the outer points sharper, so their studs tighten and the point blunts by
about a half-width. The bead is most distinct in the middle of the range, where
the two strokes leave the vertex far enough apart to overlap in a compact spot
instead of along the whole point.
Four parameters shape a stroke and they do not substitute for each other.
thickness is how wide it is, softness is how the light is distributed across
that width, brightness is the colour it carries, and glow scales that colour
again per segment. A figure that reads blurred wants softness; too heavy
wants thickness; too bright wants brightness or glow. Reaching for the
wrong one is the trap the glow entry below records.
-
thickness— stroke weight (roughly 1–5); scaled to a projector-friendly glow. Pick it for the weight you want: it no longer trades against a joint artifact. The weight is the same at every orientation — a vertical stroke and a horizontal one measure the same across on screen, on any aspect.Below
0.167is a DEAD ZONE — every value there renders identically. The param maps to a world half-width asthickness * 0.003, floored at0.0005so a zero cannot degenerate the quad; below that threshold the floor wins and the stroke is ~0.27 px at 1080p, which rasterizes as a broken dotted line rather than a stroke.fragment_vitrailshipped at0.016— two orders low — and its Maurer rose read as scattered dots for its whole life.The dead zone is the trap, not the floor. Re-tuning inside it changes nothing at all, so the obvious experiment (
0.016→0.022→0.038, no visible difference) disproves the right hypothesis. If a line figure looks stippled, check the magnitude against the 1.5–3.2 the shipped line presets use before suspecting sample count or geometry density. Nothing warns (backlog 0098). -
softness— the shape of the stroke across its width,0to1, default0.25: a solid stroke with a short shoulder.0is solid with a one-pixel antialiased edge;0.5makes the inner half solid and ramps across the outer half;1.0is a pure quadratic falloff, where brightness starts falling at the centreline and a 14 px line is a 4 px spine inside a 10 px gradient. The edge is one pixel of the render target at any resolution and any aspect, so a lowsoftnessreads the same on a laptop panel and on a 4K screen.1.0is a legitimate value, not a leftover. The look gate that set the default returned1.0for the Maurer roses,0forcurve_ionwakeand0.25forlsystem_vellum— the right stroke is a property of the figure. A preset keeping1.0wants a header line saying why, or the next reader will “fix” it.A crisper stroke reads brighter at the same
brightness, because more of the footprint sits at full coverage. Loweringsoftnesson an existing preset usually means trimmingbrightness, and oftenbloom_amounttoo — the bloom threshold is a brightness cut, so a solid core is more fuel for it.Below about two pixels of stroke there is no room for an edge, so
softnessstops doing anything there and the stroke is drawn at the1.0profile whatever it asks for. That is the same regime as thethicknessdead zone above, one derivative up. -
stroke_blend— which seam the figure draws through, default0. At0the batch is additive light, which is what these four scenes draw by default: overlapping strokes sum, so white over red is pink. At1the whole batch — segments and any arcs together — composites over, so a stroke laid on another replaces the interior of what it covers and a quantized palette keeps its plateaus. That is the difference between a luminous world and a printed one, and it is what puts these four systems in the limited-ink class, whose enumerated list of every later stage that would put a fourth colour in your frame — and each one’s off switch — is on that page.It is a switch, not a mix: a draw call has one blend mode, so the decision is taken at
0.5on the CPU each frame. Values in between select one seam or the other, not a blend of the two — a[smoothing]entry on this param buys you a delayed flip, nothing more.Opaque strokes are ordered. Additive light is order-independent; OVER is not, so which stroke wins an overlap is the order the scene emits its geometry in. That is what makes the seam useful and also what makes a figure look different beyond its palette when you flip it.
Turning it on usually costs
brightness. Additive light builds up where a figure crosses itself, and a dense rosette leans on that. Under OVER it does not, so the samebrightnessreads flatter and often darker. -
glow— the line renderer’s per-segment light multiplier, default1.0, whole-figure on all four. It multiplies the stroke’s colour and never its coverage: a dimmed stroke still covers its whole footprint. It is emphatically not a falloff multiplier — it cannot sharpen a line, only dim it, andsoftnessis the parameter that shapes the edge. Below1the stroke recedes toward a dim hairline, above1it saturates the core and only widens the visible skirt. There is more range downward than upward — measured per lit pixel,1.0 → 0.3moves a rose about 0.25 while1.0 → 2.5moves it 0.17 — so reach forglow < 1when you want the figure to recede. It is not the same quantity asglowonfragment_fieldorreaction_diffusion, which is a term inside those shaders; the name is shared, the meaning is not, and a value that reads well on one will not transfer. Also not a post-process bloom — there is no bloom stage in the engine. -
hue— where the figure sits in the palette (addtime * kfor a slow drift). With no[palette]that palette is the line scenes’ own cosine ramp, and it is not a hue wheel. The measured swatch table is in Colour and palettes; read it rather than guessing, because a guess costs a render round-trip.hueis no longer the only colour control — see the colour axes below. -
scale— overall size in the frame;draw_progressin0..1reveals the figure from the start (a line-draw-on; ride it onbarfor a per-beat redraw). -
parametric_curve:n/dare the rose parameters,spinis angular velocity in radians a second,samplesthe chord count (clamped to the segment cap).spinintegrates a phase (ADR-0132), the same shapefragment_field’sfield_speed/fold_speedandwarp_mesh’swarp_speedtake — so it is safe to bind to audio. A rate that instead multiplied the shared clock would turn the figure through a hundred and forty radians in one frame on a swing from0.1to1.5a hundred seconds into a set: a teleport, not an acceleration. Two shape params morph the curve itself (default0.0, a no-op):phase(radians added inside the sine,r = sin(n*theta + phase) + radial_offset) reshapes the petals as it advances — distinct fromspin, which rotates the finished figure;radial_offsetadds to the radius, opening the rose off-origin into spiral/annular/rosette forms. Both makerexceed[-1, 1]when nonzero — large values push geometry past the frame (the intended blowout; the renderer clips). Bind them tobass/bar/beatfor an audio-driven shape morph. -
lsystem:visible_depthpicks which precomputed iteration is shown — drive it off a band/beat to grow the structure (e.g.4 + floor(2 * bass));rotationis an angle in radians, so multiply bytimeyourself. Itshue_spreadwalks the palette by generation depth — see the colour axes below. -
star_pattern:variantis a continuous contact angle in0..2(clamped), not an index — see below;rotationis an angle in radians. Itshue_spreadaxis is radius, and it is inert on the current rosette — see the colour axes.
star_pattern variant — a continuous contact angle
variant sweeps the Hankin construction’s contact angle
(ADR-0060) rather than
indexing one of three precomputed rosettes. 0 is 24° below the [generator] contact_angle_deg (a sharper star), 1 is the base angle, 2 is 24° above (a
blunter one), the whole thing clamped into the 8–80° range that makes a sensible
figure. Values outside 0..2 clamp to the ends.
0, 1 and 2 name the three rosettes the discrete form did, so an
existing preset is unchanged. What is new is everything between them:
[smoothing]onvariantnow morphs instead of stuttering. Easing it used to spend its time on fractional values afloorthrew away, which is why both shipped star presetsfloorit and why their comments told you not to smooth it. That advice is now backwards.- A
flooraroundmod(…, 3)is no longer the way to drive it. The shipped presets still carry one, and removing it alone would be worse than the cut it replaces — a sawtooth snaps 2 → 0 at every wrap. Drive it with something continuous and closed instead: a triangle wave (1 + sin(time * 0.14)is the cheapest one), or a band term easing between two angles. - The morph is quantized to 0.1° of contact angle, so the figure rebuilds only
when the request has walked that far. That is 480 steps across the whole
variantrange and at most a 1.1 px jump at 1080p on the sharpest rosette — a resolution, not a shape. Avariantjittering inside one step does not rebuild at all.
The line scenes’ colour axes — what hue_spread walks
Every line scene honours [palette] / [palette_b] / palette_mix /
hue_spread / saturation
(ADR-0059),
sampled on the CPU per segment. hue places the whole figure in the palette;
hue_spread says how far the palette travels across the figure, and each
generator walks the axis its own construction makes meaningful. The axis is a
property of the scene, not a parameter you pick — this table is the thing you
cannot infer from the param names:
| System | hue_spread walks | 0 is | 1 is |
|---|---|---|---|
parametric_curve | position along the traced path — chord 0 is the walk’s first | one flat hue | first chord at hue, last a full palette away |
lsystem | generation depth — branch nesting, 0 on the trunk and one more per open [ | one flat hue | trunk at hue, deepest twigs a full palette away |
star_pattern | radius from the figure’s centre — live on a rings preset, inert on a bare interlace, see below | one flat hue | innermost ring at hue, outermost a full palette away |
spectrum | band index — element 0 is the bottom of the spectrum | one flat hue | low band at hue, top band a full palette away |
hue_spread = 0 is the default on every one of them and reproduces exactly the
single flat colour these scenes drew before the palette reached them, so adding
a [palette] to an existing preset changes its colours and adding nothing
changes nothing.
On lsystem the axis is the figure’s own, so a grammar without branches has
nothing to ramp along. The retired lsystem_fern reached generation 11 at
visible_depth = 6; the retired lsystem_arrowhead had no [ in its rules at
all, so every segment of it sat at generation 0 and hue_spread was a no-op
there however large — the property is the grammar’s, not the file’s. That is a
property of a Sierpinski arrowhead — every segment genuinely is at the same
recursion level — not a missing feature. Such a preset still reaches
[palette]; what it cannot reach is a ramp. The ramp is normalized over the
figure’s own deepest generation, so hue_spread = 1 spans the palette once
whatever the grammar’s branching factor and whichever depth is visible.
On parametric_curve the divisor is samples, not the revealed prefix. So a
draw_progress riding bar draws the gradient on — a half-revealed curve shows
the palette’s first half — rather than re-tinting every chord it already drew.
hue_spreadonstar_patternis live if and only if the preset declaresrings, and that is measured both ways. A Hankin rosette is2ncongruent segments about the frame centre, so every one of them occupies the same radial interval: on the retiredstar_rosetteandstar_lanternthe spread of segment radii across the whole figure measured1.2e-7(f32 noise) at every tiling order and every contact angle. There is no range for a radial ramp to walk, so the ramp collapses to the flathuerather than sweeping on noise, and what those presets gain from the palette surface is[palette]itself — the rosette can be an ember or an ice figure instead of a point on the built-in cosine — plussaturationandpalette_mix.The empty half was the rosette’s interior: at
star_rosette’s 12-fold / 20° the strokes live between radius 0.54 and 0.90, so the inner 60% of the disc is bare, andstar_lantern’s 55° variant empties 87% of it. That was the open half of design-backlog 0007, andringsclosed it: a mandala preset puts segments at four to six different radii, the ramp is computed over the combined figure, andhue_spreadbecomes a real lever on exactly the presets that have an interior to spread across. On a composited preset — rings plus a tiling — the interlace’s own segments are all at one radius, so the ramp puts the whole interlace at one end and spreads the ornament along the rest, which is a way to separate the two figures by colour rather than by brightness.
star_rosewindow(Rose Window) is the shippedringspreset, and it stays at interlace scale deliberately — the reason is design-backlog 0073: a motif built as a parametric outline sampled to straight segments shows its vertices at ornament scale, and a circle reads as a polygon. That is what retired the first three rings presets (star_mandala,star_mandala_six,star_weave, 2026-08-06). The ornament-scale mandala register moved to an analytic iso-contour fold and now lives infragment_mandala(Banded Mandala), which has no geometry to facet.The curved members of the roster no longer carry that ceiling.
circleandarcare single per-pixel arcs;petal,teardropandtrefoilare G1 arc chains — a handful of arcs that share a tangent where they meet, so the chain has no tangent discontinuity for the eye to read as a corner and no sampled vertex to bead at. A ring of any of the five is round atscale = 0.13and at full frame. Onlydiamondandchevronare still sampled polylines, and their vertices are the figure. The three retired presets have not been re-judged, so read Rose Window’s header before authoring the next rings preset.
Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.