Skip to content
Русский

Shaped marks — the particle silhouette

swarm and emitter both carry shape and points. They are the only two scenes that do: the attractor’s marks are a chaos-game accumulation, and at the densities that make a figure one mark is a point, so a silhouette there would be invisible on principle rather than by tuning (ADR-0084).

shape is numeric — the expression grammar has no strings, so a star is shape = "3".

shapemarkwhat it draws
0discthe default, and exactly what these scenes drew before the roster existed. On the swarm a round blob; on the emitter its elongated glint (see spin above)
1ringan annulus the same size as the disc: brightest at 0.7 of the mark’s radius, dark at the centre, with a hole reaching 0.4 of it
2polygona regular points-sided polygon, one vertex pointing along +x
3stara points-pointed star, valleys at 0.45 of the tip radius
4hearta heart, point down

points is the count for polygon and star, 3 to 12, default 5. It does nothing on disc, ring or heart. Past a dozen the marks these are for — a few pixels across — are a disc with a rough edge.

A whole shape is that figure exactly; a value between two whole ones travels between them. shape = "2.5" is half a polygon and half a star — the two arms’ distance fields blended, so an eased or bound shape carries the figure from a heart to a star across a phrase instead of cutting on a beat (ADR-0226). Four things come with that:

  • Only adjacent pairs travel. The table’s order is the travel order, so a polygon can reach a star and cannot reach a heart without passing through one. A binding that sweeps 1 to 4 visits every arm in between.
  • The in-between figure is nobody’s design. A blend of two silhouettes can pinch, disconnect, or grow a lobe neither arm has. Some pairs read beautifully and some do not; there is no lever but to pick a different pair.
  • Mid-travel the field stops being a metric distance, so anything measured in it drifts: on shape_field, stroke’s width and the spacing between contour bands are the figure’s at a whole index and approximate in between. The interior, the outline and the particle falloff are unaffected.
  • On shape_field, travelling anywhere between disc and polygon turns coord_mode = "1" off. That whole open span touches the ring, and a blend with the ring on either side inherits its hole, so the scaled-copy coordinate has no single value there and the scene falls back to the distance — see Two coordinates. A binding easing shape from 0 to 2 therefore draws scaled copies at each end and offset curves through the middle, which is a change of contour kind rather than a drift. Nothing warns: the load-time notice reads the resting value, and a preset resting on a whole, off-ring shape rests off the combination. Travel from polygon through star to heart is unaffected.

The star arm’s shape params

The star was one welded silhouette until a batch of six reference images turned out to be five requests for parameters this arm did not have. It has them now, and they reach swarm, emitter and shape_field alike — one chunk, one roster, so a shape a particle wears and a figure a field draws cannot drift.

paramrangedefaultdoes
star_valley0.05..0.950.45the valley radius as a fraction of the tip’s. Low is a sharp, thin-spiked star; high is a bumpy polygon
star_curve-0.9..0.90bows the edge between tip and valley. Positive bows it inward — the concave sparkle, which a straight-edged star cannot make at any valley radius. Negative bulges it out
star_jitter0..10per-spike variation in tip length, for the irregular “bang” look
star_wobble0..10waves each edge in and out along its length, leaving the tips and notches exactly where they are. This is the one that reads as hand-drawn
star_wobble_freq0.5..2.51how many waves fit between a tip and the notch beside it. Inert while star_wobble is 0
star_seed0..2550which arrangement the jitter and the wobble draw. A whole number; every value is exactly as rough as every other

Every default is an exact identity, and that is an obligation rather than taste: the shared chunk means these knobs reach the particle path, so anything but the old welded constants would move every shipped shape = "3" preset. All 30 golden baselines re-bless byte-identical.

[params]
shape = "3"
points = "4"
star_valley = "0.18" # a long, sharp four-point sparkle
star_curve = "0.55" # ...with concave edges

Five things worth knowing before you tune them:

  • star_jitter and star_wobble are two different quantities, and only one of them is what “hand-drawn” means. The jitter makes spikes unequal; a star whose spikes are ragged but whose edges are dead straight reads as damaged rather than as drawn. The wobble waves the line between a tip and a notch while leaving both ends where they are. Reach for the wobble for a drawn outline and the jitter for a shape that was knocked about.
  • star_seed re-scatters without re-sizing. Both roughnesses come from an integer hash, so the same preset draws the same figure in every run and on every machine; the seed moves the hash’s input, so it picks a different arrangement of the same amount. If one seed’s star has an ugly spike, try the next one — you are not trading away roughness to do it.
  • The wobble is radial, and the two edges of one spike mirror each other. The wander scales each point’s radius rather than pushing it sideways, which is what keeps the figure something coord_mode = 1 can still measure. And the engine folds a star into one half-wedge, so a spike is symmetric about its own axis however much it wobbles. A figure whose every spike is internally symmetric is what this arm can draw.
  • star_curve is where the field’s precision goes. A bowed edge has no closed-form distance, so it is sampled; the contours shape_field draws are 0.0032 off true, which is invisible. star_jitter costs much more — up to 0.54 at seven points, because the angular fold measures against a point’s own spike and a longer neighbour can be nearer. star_wobble costs about a quarter of that, up to 0.12 at full amplitude, and adding it on top of a heavy jitter barely moves the jitter’s own figure. On a particle mark none of this is visible (the sprite reads only the interior); on a big banded field, a heavily jittered star’s outer rings are approximate.
  • They are inert on the other four shapes, and nothing warns — the name is known, so no unknown-parameter warning fires. This paragraph is the warning. star_wobble at any non-zero value also takes the star off its closed-form branch onto the sampled one, which is the same branch star_curve selects.

Most of them MORPH the figure with the music, and that needs no engine work

star_valley, star_curve, star_jitter, star_wobble and star_wobble_freq are clamp-only — no rounding — so a binding drives them continuously and the silhouette genuinely deforms. That is worth stating because two params beside them are rounded and therefore step: points, and star_seed. A seed names an arrangement and there is nothing between two arrangements, so a binding that sweeps it flickers through unrelated figures instead of morphing — which is exactly what a re-scatter is, and why the seed is the knob you pick a look with rather than the one a phrase rides. Verified by rendering: star_valley on bass and star_curve on treble over a 120 BPM click visibly thickens and thins the arms and changes the spike proportions.

[params]
star_valley = "0.20 + clamp(bass * 0.2941, 0, 0.25)" # spikes lengthen on the low end
star_curve = "0.55 - clamp(treb * 0.5000, 0, 0.30)" # edges straighten on the top end
[smoothing]
star_valley = 0.25
star_curve = 0.30

Three things to know before binding them:

  • On shape_field, an eased star_valley silently changes the RING COUNT as well as the shape. The scene normalizes by the arm’s inradius, and the inradius is a function of the valley radius — so morphing the valley changes what color_span means, and the contour structure breathes along with the figure. On a particle mark this does not arise; on a banded field it is a continuous wobble in the background structure that you did not ask for.
  • A binding that sweeps star_curve through 0 crosses a small discontinuity. At exactly zero the arm takes a closed-form straight-edge branch; either side of it takes a sampled one, and the two disagree by about 0.0032 (the polyline’s sagitta). Small, but it sits in the middle of the range you are most likely to animate through — bias the range to one side if it shows. The same seam sits under star_wobble at 0, and under star_jitter at 0, for the same reason: any of the three being non-zero is what selects the sampled branch.
  • star_wobble_freq past about 2.5 has nowhere to go, which is why the range stops there. The edge is sampled into eight sub-segments, so a wave of 2.5 cycles gets about three samples per cycle; a faster one would be read by the polyline as a slower, differently-shaped wave rather than as the wave you asked for.
  • A curved or jittered star’s interior normalizes differently from a straight-edged one, and so does its contour spacing. That branch divides by the figure’s own deepest-point distance rather than by the straight edge plane’s perpendicular, so a color_span carried over from a straight-edged star is out by the ratio of the two references — roughly 1.1x at a shallow curve and 1.9x at star_valley = 0.18.

Not in the roster and not a parameter: a star with eyes. Composing two discs onto a silhouette is multi-shape composition, which is neither a knob nor a name in the closed roster, and it is the one thing in that reference batch this engine still cannot reach.

polygon has far less range than star, and the reason is geometry rather than tuning. A polygon’s corners sit at radius 1 and its edges at cos(pi / points) of that, so by seven sides the figure is within 10 % of a circle everywhere and reads as one: rendered side by side, a 7-gon field and a disc field are the same picture. Reach for points = 3 or 4 — a field of triangles is unmistakable — or reach for star, whose valleys sit at 0.45 of its tips at every count.

points is a stepped parameter: it is rounded to a whole number, so an eased points snaps at each half-integer rather than morphing. Both silhouettes fold the angle by the count, and that fold only absorbs atan2’s branch cut when the count divides the circle evenly — at a fractional count the mark tears along one ray. This is kaleido_order’s rule for kaleido_order’s reason, and it is worth stating because the surrounding vocabulary teaches the opposite: variant interpolates (ADR-0060) and the attractor’s IFS morphs (ADR-0075). A star’s angle fold is periodic in the count, so a fractional count is a discontinuity and not an intermediate figure. shape is the one that does not step, and the difference is the fold: a roster position has two neighbouring fields to blend, and a fractional count has nothing to average — it tears.

Two consequences worth planning around:

  • hash(beat_index) on points is the trick. The count flipping on each onset detection is what already worked on parametric_curve’s radial_offset lobes, and it carries over: points = "7 + floor(hash(beat_index) * 2.999)" gives a field that re-cuts itself every beat, and the stepping is a feature there rather than a cost.
  • Small marks are where a silhouette earns its keep and also where it disappears. A seven-pointed star three pixels across is mostly its own anti-aliasing. If the shape is not reading, raise size before anything else — and note that on the swarm the population is fixed, so a mark large enough to have a legible figure fills the frame. The engine’s own shaped fixture reaches for zoom to thin the field rather than for a smaller mark.

A shaped mark drawn straight into the chain is a silhouette in additive light — there is no fill and no outline. The compositor adds, so black adds nothing and a dark edge cannot exist there: a heart drawn this way is a heart-shaped glow, brightest in its middle and fading to nothing at its outline, not a red body with a black rim. That is the scene’s deliberate scope.

It is not the whole story, though, and the route out is not a workaround. Put the same scene in a [layer] with blend = "multiply" and its marks subtract light instead — dark figures on a light ground, measured to display luma 0.9. See Dark on light. What stays true is the sentence’s other half: nothing in this engine decides what is in front of what, so a mark that occludes another figure is still unbuilt, and that is engine feedback.

The roster is closed: a shape that is not in the table is architect + dev work, not a preset. That is the same trade ADR-0061 made for fold edges.

Built from 13c7582 at version 0.158.0. This site tracks main and is not versioned per release.