outlines
outlines · sources · schema v1OUTLINES — stateful particle video generator (LZX-style primitive source; formerly CIRCLES, renamed when the SHAPE selector landed). A GATE event (or the internal RATE clock) spawns a SHAPE at a SEEDED-random position in a 1024-px field; each shape latches its diameter / vector / speed / decay / SHAPE at spawn and moves in that direction, BOUNCING when its CENTER-POINT hits a wall (the velocity reflects; no edge/radius collision math for the WALL, so a fat shape may briefly overhang). SHAPE picks one of six forms — circle, triangle, square, pentagon, hexagon, octagon — each polygon a REGULAR N-gon inscribed in the diameter (every vertex on the circle of radius d/2 — the circumradius), so all six share one bounding-circle radius (d/2) and the COLLIDE math is unchanged across shapes. ROTATION is a LIVE GLOBAL bipolar spin: knob CENTER = no rotation, left extreme = fast CCW, right extreme = fast CW; every live shape shares one rotation angle that accumulates by that angular velocity each frame, so the whole field spins coherently and the spin shows up consistently in the rendered geometry AND in every output (the rotated polygon vertices drive the overlap-count the outputs read; a circle is rotation-invariant so only the 5 polygons visibly turn). With the COLLIDE gate HIGH, shapes ALSO bounce off EACH OTHER: a bounding-circle elastic collision — two shapes collide when the distance between their CENTERS ≤ (r1 + r2), i.e. their circumcircles touch (unlike the center-based wall bounce, this uses the radii), and an equal-mass ELASTIC response swaps the velocity components along the center-to-center normal and separates the pair so they don't stick (each keeps its independent latched SPEED as far as elastic physics allows). Gate LOW / unpatched → shapes PASS THROUGH each other (the default). COLLIDE is a LIVE GLOBAL mode (read every frame), NOT spawn-latched. The inter-shape pass is O(n²) over the active list, bounded by the 200-shape cap (~10k pair tests/frame). Every per-shape property is LATCHED at spawn from the live knob+CV — crucially SPEED and SHAPE: a shape integrates from its OWN latched velocity (and keeps its own latched form) for its whole life, so turning SPD or SHAPE after a shape exists affects ONLY newly-spawned shapes, never the ones already flying. Model: a JS list of active shapes {x,y,vx,vy,diameter,decayS,ageS,alpha,shape,sides,baseAngle} integrated on the engine rAF. Controls — D: DIAMETER (5..270 px, the circumdiameter); V: spawn VECTOR ANGLE (full range = 0..360°, every angle reachable); SPD: SPEED (0 = static scatter, up to 300 px/s ≈ crosses the field in ~3 s; latched independently per shape); DECAY: per-shape FADE-OUT time — 0 = NO decay (the shape PERSISTS, the static-field case, FIFO-capped) ramping up to a 10 s fade where the shape's alpha ramps 1 → 0 and it is removed; SHAPE: the 6-way form selector (circle / triangle / square / pentagon / hexagon / octagon), quantised + latched per shape at spawn; ROT: the bipolar live-global spin (center = still, ± = CW/CCW); RATE: KNOB-ONLY internal clock (0 = spawn ONLY on gate events; turning up spawns faster, hard-capped at 1 shape / 500 ms). Inputs — gate (a rising edge spawns one shape), collide (a LIVE gate: HIGH = shapes bounce off each other elastically, LOW/unpatched = pass through), d / v / spd / decay / shape / rotation (per-param CV; shape latches at spawn, rotation is the live-global spin), video (sampled by the mapped output). Outputs (4, all derived from a per-pixel overlap-COUNT of the active shapes — using the rotated polygon coverage — each shape's contribution scaled by its DECAY fade alpha so a fading shape counts less / draws lighter): OVERLAP (mono-video) white wherever ≥1 shape covers the pixel (dimming as the covering shape fades), black else; CONTOUR (mono-video) shape OUTLINES only, ring width = 10% of that shape's diameter (min 2 px) so many shapes read as "ripples in a pond" (rings lighten as they decay); COMBINE (colour video) the overlap region colourized by overlap COUNT through a hue ramp (1 overlap = one hue; 2,3,4… cycle the spectrum) with brightness + saturation rising as more shapes stack and dimming as the stack fades; MAPPED (colour video) shows the VIDEO input's contents wherever ≥2 shapes overlap, black elsewhere. Bounded sim: shapes bounce forever and accumulate, so a hard cap of 200 active shapes culls the OLDEST first (a safety net even with DECAY) to keep per-frame cost bounded. Determinism: the random spawn position + each shape's seeded initial rotation angle come from a seeded mulberry32 PRNG (fixed default seed; never Math.random), so VRT / per-port / behavioral sweeps are reproducible. Usage: patch a clock/sequencer GATE in (or just turn RATE up) and route OVERLAP / CONTOUR to a SCOPE or mono consumer, COMBINE to OUTPUT for the coloured stack, and a video source → VIDEO in + MAPPED → OUTPUT to punch that source through the ≥2-overlap region. Pick a SHAPE for the spawn (polygons + ROTATION give kaleidoscopic spinning-outline fields), leave DECAY at 0 for an accumulating static field or turn it up for a trail/dissolve look, and gate the COLLIDE input HIGH (any clock/gate/LFO over the high threshold) to switch the field from a soft overlapping wash into a billiards-like cluster where the shapes knock each other around.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
d | cv | CV that modulates the D (diameter) control, centered on the knob and swept across its 5..270px range; latched per shape at spawn. control voltage (CV); modulates d (additive offset — ±1 CV sweeps the full range, centered on the knob) |
v | cv | CV that modulates the V (vector angle) control across its 0..360 degree range; latched per shape at spawn. control voltage (CV); modulates v (additive offset — ±1 CV sweeps the full range, centered on the knob) |
spd | cv | CV that modulates the Spd (speed) control across its 0..300 px/s range; latched per shape at spawn, so a change affects only new shapes. control voltage (CV); modulates spd (additive offset — ±1 CV sweeps the full range, centered on the knob) |
decay | cv | CV that modulates the Decay (fade-out time) control across its 0..10s range; latched per shape at spawn. control voltage (CV); modulates decay (additive offset — ±1 CV sweeps the full range, centered on the knob) |
shape | cv | CV that modulates the Shape selector across its six shapes (circle / triangle / square / pentagon / hexagon / octagon); quantised and latched per shape at spawn. control voltage (CV); modulates shape (additive offset — ±1 CV sweeps the full range, centered on the knob) |
rotation | cv | CV that modulates the Rot control, a LIVE GLOBAL bipolar spin (center = no spin); applied to every live shape at once, not latched. control voltage (CV); modulates rotation (additive offset — ±1 CV sweeps the full range, centered on the knob) |
video | video | Video source sampled by the MAPPED output — its pixels appear only where two or more shapes overlap. Unpatched, MAPPED is black. RGB video stream |
outputs
| id | cable | what it does |
|---|---|---|
overlap | mono-video | Mono-video: white wherever at least one shape covers the pixel, black elsewhere (each shape dimmed by its fade alpha). mono video stream |
contour | mono-video | Mono-video: shape OUTLINES only (ring width 10% of diameter, min 2px), so many stacked shapes read as concentric ripples. mono video stream |
combine | video | Video: the overlap region colorized by overlap COUNT via a hue ramp (1 = first hue, then 2,3,4... cycle the spectrum), with brightness and saturation rising as the stack deepens. This is the card preview and default output. RGB video stream |
mapped | video | Video: the VIDEO input's contents shown wherever two or more shapes overlap, black everywhere else (black if VIDEO is unpatched). RGB video stream |
params
| id | label | range | default | curve |
|---|---|---|---|---|
d | D | 0..1 | — | linear |
v | V | 0..1 | — | linear |
spd | Spd | 0..1 | — | linear |
decay | Decay | 0..1 | — | linear |
shape | Shape | 0..1 | — | linear |
rotation | Rot | 0..1 | — | linear |
rate | Rate | 0..1 | — | linear |
controls
| control | what it does |
|---|---|
| Cv collide | Hidden synthetic gate param backing the COLLIDE jack (not a knob). The engine CV-bridge writes the collide input's LEVEL here; read live every frame, HIGH (>=0.5) makes shapes bounce off each other elastically, LOW passes through. |
| Cv gate | Hidden synthetic gate param backing the GATE jack (not a knob). The engine CV-bridge writes the gate input's sample here; a rising edge spawns ONE shape, latching the live D / V / Spd / Decay / Shape at the moment of the edge. |
| D | Shape DIAMETER (circumdiameter). 0..1 maps to 5..270px; latched per shape at spawn. A polygon is inscribed in this diameter (circumradius = d/2). |
| Decay | FADE-OUT time. 0..1 maps to 0..10s; latched per shape. 0 = persist (oldest shapes FIFO-culled at the cap); above 0 fades alpha to 0 and removes the shape over that many seconds. |
| Rate | Internal spawn CLOCK (knob only, no CV input). 0 = gate-only; turning it up engages a clock that tightens from slow toward a cap of one shape every 500ms. |
| Rot | ROTATION, a LIVE GLOBAL bipolar spin: center (0.5) = no rotation, left = fast counter-clockwise, right = fast clockwise. Every live shape shares one rotation angle (not latched); the card shows CCW / dot / CW. |
| Shape | SHAPE SELECTOR, 0..1 quantised to six shapes: circle, triangle, square, pentagon, hexagon, octagon. Latched per shape at spawn; the card shows the current shape name. |
| Spd | SPEED. 0..1 maps to 0..300 px/s (0 = static). The latched velocity drives integration, so a later change affects only shapes spawned after it. |
| V | Spawn VECTOR ANGLE. 0..1 maps to 0..360 degrees, the direction each new shape drifts; latched per shape at spawn. |
source
outlines.ts on GitHub.