Circuit Trace Generators
Public Made by Adomby adom
Two dependency-free, seeded circuit-background generators: a seamless torus tile with ambient or progressive reveal, and the v9 continuous field with obstacles, scroll reveal, and five ambient systems.
Circuit Trace Generators
Two independent, dependency-free generators that draw the Adom Nitrogen hero background (procedural PCB traces, vias, and routed light) as seeded SVG.
Both recreate the reference artwork's visual grammar rather than copying its path data, and both were measured off the same original:
| Reference constant | Value |
|---|---|
| Routing pitch | 7.895 units (150 / 19) |
| Trace stroke | 1.58 units, #151b25 |
| Via annulus | 3.34 outer / 1.76 inner |
| Board | #0d1117 |
| Routed-light palette | #00e6dc 60%, #64abff 25%, #c5b3ff 15% |
They diverge on the thing that matters most: how the board is filled. One routes a torus and tiles forever; the other routes one continuous field at the mount's real size. Pick by whether you want a repeatable texture or a bespoke backdrop.
| Tiling router | Field router | |
|---|---|---|
| Fill strategy | one 900×450 tile, repeats in both axes |
one continuous field, no repeat |
| Router | A* nets between placed terminal formations | flow field and vortex trace packing |
| Wrap | torus occupancy grid (no seam, no crossings) | reserved grid nodes (no crossings) |
| Headless output | generate-tile.mjs writes an SVG tile |
generateCircuitField() returns geometry |
| Motion | signal fountain or progressive reveal | three reveal modes and five ambient systems |
| Entry file | circuit-background.js or circuit-background-reveal.js |
circuit-background-v9.js |
| Live demo | classic tile and tile reveal | v9 field |
Both ship createCircuitBackground(mount, options) returning
{ regenerate, exportSvg, destroy }, both are seeded (the same seed and
dimensions give identical geometry), and both honour prefers-reduced-motion.
All three demos run live, hosted on this page. These are the real src/ engines,
served by the wiki straight from this page's repo, so they need no container and
will not go dark:
- Open the interactive playground with all three demos on one page
- Launch the tiling-router demo on its own
- Launch the tiling-reveal demo on its own
- Launch the field-router demo on its own
1. Tiling router: circuit-background.js
▶ Launch the live tiling-router demo · the real engine: drag the twelve generation sliders, switch presets, click the board for a signal burst.
An occupancy-grid router run on a torus, so the 900×450 tile it emits
repeats in both axes with no visible seam and no two traces ever cross. That makes
its output usable directly as a CSS background-image with
background-repeat: repeat.
How a tile is built
placeFormationsscatters terminal groups (via ladders and rows) across the grid. These are the pads everything else routes between.routeNetsruns A* between pins, weighted by a turn penalty (higher means longer, calmer runs) and a weave preference for 2-lane neighbour spacing, with a matching cramp aversion to 1-lane spacing outside bundles.replicateWalkadds translated-copy bundle followers, so neighbouring traces bend together the way a real bus does, re-routed in bundle mode when blocked.tapCombsandrouteStubsadd comb and stub motifs as punctuation.sealEndenforces the via mandate: every trace starts and ends on a via, trimming blocked ends with per-step claim tracking. A wrap-aware checker passes with zero bare ends.
Tuning
Twelve generation knobs, all exposed as sliders in the demo and as kebab-case flags on the CLI:
density, formations, busWidth, turnPenalty, weave, cramp,
horizontalBias, netReach, jogBias, stubChance, inlineViaChance, combs
Motion: the signal fountain
Every signal is mortal. A passive spawn timer (signalInterval, 240 ms) is the
fountain: each tick, if the census is under maxSignals (12), one new signal
appears near the cursor. pickStart scores the actual launch pad by pointer
distance plus spawnRadius jitter, falling back to a whole-board spread when the
pointer idles past 4 s. A signal runs to a trace-end via, then rolls its chain's
survival: survivors hop to a nearby via (hopRadius 440) inheriting speed,
colour, and survival rate, and the rest die so the timer refills next tick.
Equilibrium census is roughly spawn rate times life.
Passive and clicked chains decay at separate rates, hopSurvival 0.4 against
burstSurvival 0.72, so a clicked burst keeps its own longer life for the whole
chain. colorDrift (0.18 per hop) crossfades a leg, and maxBurstSignals (25) is
a hard ceiling.
Animation presets: None (the page default, a static board), Fireflies, Swarm, Cursor sparks, Slow streams.

The demo splits its knobs into two panels, Generation tuning and Animation tuning, each with its own reset scoped to just its own sliders.
Headless CLI
node generate-tile.mjs --seed traces --out tile.svg
node generate-tile.mjs --seed foo --turn-penalty 0.8 --bus-width 1.4 --combs 0 --transparent > tile.svg
Seed traces yields 334 traces and 482 vias per tile. Run with --help for the
full flag list.
API
import {
generateCircuitTile, tileSvg, pathData, createCircuitBackground,
} from "./circuit-background.js";
const tile = generateCircuitTile({ seed: "traces", turnPenalty: 0.8 });
const svg = tileSvg(tile, { background: "#0d1117" });
Progressive reveal
Launch the tiling-reveal demo.
circuit-background-reveal.js grows the same tile geometry on a canvas above the
static SVG. It redraws only routes that are moving or cooling, then clears the
canvas after the glow reaches zero. The handoff reveals the exact SVG without a
brightness dip or color jump.
Reveal styles are Etch, Flood, Sweep, Bloom, and Scatter.
See src/TILING-REVEAL.md for the measured implementation notes.
2. Field router: circuit-background-v9.js
Launch the live field-router demo to switch geometry, obstacle, reveal, and ambient presets or export the current SVG.
No tile. A deterministic planar trace-packing pass fills one continuous field at the mount's real dimensions with hundreds of independent routes. A rotatable vector field plus seeded, low-frequency vortices organise long carriers, diagonal runs, and gentle swirls, and channel attraction collects nearby routes into natural local buses. Every occupied grid node is reserved, so separate traces never cross.
Version 9 separates geometry, obstacles, reveal, and ambient motion. It can avoid or outline embedded marks, reveal by time or scroll progress, and append seeded world chunks without moving existing geometry. Versions 2 through 8 remain for reference.
Tuning
fill, routeLength, horizontalFlow, flowAngle, diagonalFlow, longFlow,
swirl, swirlScale, jogLength, channelAttraction, edgeDensity,
featureScale
featureScale proportionally scales routing pitch, trace width, via rings, and
routed-light geometry together, so the motif stays coherent at any size.
Geometry presets: Original match (the default, tuned to the reference's path count, route-length distribution, stroke, via count, and orientation mix), Dense, Diagonal sweep, Broad swirl, Sparse. Geometry presets never touch motion settings; the two preset rows are independent.
Ambient systems
Five presets are available in the demo's Animation row:
- None mounts only the static SVG and creates no animation layer at all.
- Adom reflection (
circuit-animation-reflection.js) sends a restrained brand-color sheen across a precomposed trace mask. - Conductor (
circuit-animation-conductor.js) is the full system: ambient currents, breathing endpoint nodes, core and halo packets, convoys, timed spatial waves, pointer wake, endpoint flashes. - Routed field (
animationSystem: "adom", implemented inv4) is a third system, not a retune of the conductor. It drives a slow angled sweep across the board (sweepDuration15.2 s,sweepAngle18°) plus periodic blooms that light traces near a moving cursor, capped at three concurrent blooms. - Handshake (
circuit-animation-handshake.js) is the restrained alternative. Each transaction charges a source via, traverses one complete trace once, settles into its destination via, and sends a dim acknowledgement back. It uses exact polyline intervals instead of wrapping dashes, never flood-lights the field, and avoids the protected hero-copy reading zone. OnlymaxHandshakes(3) transactions coexist, so per-frame work does not grow with geometry density. That is the reason to reach for it on a dense board.

API
import { createCircuitBackground } from "./circuit-background-v9.js";
const circuit = createCircuitBackground(document.querySelector("#hero-circuit"), {
seed: "product-launch",
fill: 0.668,
swirl: 0.28,
channelAttraction: 0.78,
obstaclePreset: "adom",
obstacleMode: "outline-wrap",
revealSystem: "scroll",
continuousGeneration: true,
animationSystem: "reflection",
liveliness: 0.82,
motion: true,
});
circuit.regenerate({ seed: "another-layout" });
circuit.triggerAnimation({ x: 240, y: 180 }); // in SVG coordinates
const svg = circuit.exportSvg(); // static, no motion layers
circuit.destroy();
generateCircuitField(options) returns deterministic geometry with no DOM
involvement. Each trace carries points, length, viaStart, and viaEnd, and
pathData(points) turns one into SVG path data. That is how the two images on
this page were rendered.
The mount needs a real width and height. The helper observes resizes, clips overflow, and leaves pointer interaction to the surrounding page.
Running the demos
On this page (no setup, always up)
All three demos are the actual src/ files, rendered by the wiki straight from this
page's repo:
| Surface | Live on the wiki |
|---|---|
| All three, embedded on one page | render/src/playground.html |
| Tiling router | render/src/index-classic.html |
| Tiling reveal | render/src/index-reveal.html |
| Field router | render/src/index.html |
These need no container and do not expire. They run in the render sandbox, which the engines are fine with since they use no storage or network. The playground embeds each demo as an iframe, which works because the page is public.
Locally
The two projects live in adjacent source directories and run on separate ports:
cd ~/project/circuit-generator
# Tiling router, http://localhost:8930
node serve-classic.mjs # serves index-classic.html + circuit-background.js
cd ~/project/circuit-generator-codex
# Field router, http://localhost:8124
./serve.sh # serves index.html via server.js
File map
The two local source directories are combined under src/ in this package:
| File | Belongs to |
|---|---|
circuit-background.js |
tiling router (engine) |
circuit-background-reveal.js |
tiling router (progressive reveal) |
index-classic.html, index-reveal.html |
tiling demos |
generate-tile.mjs |
tiling router (CLI) |
circuit-background-v9.js |
field router entry |
circuit-geometry-v9.js, circuit-obstacles-v9.js |
field geometry and obstacles |
circuit-reveal-*.js |
field reveal systems |
circuit-animation-*.js |
field ambient systems |
index.html, server.js, serve.sh |
field router (demo, port 8124) |
TILING-REVEAL.md, FIELD-ROUTER.md |
full implementation notes |
# Circuit Trace Generators
Two independent, dependency-free generators that draw the Adom **Nitrogen** hero
background (procedural PCB traces, vias, and routed light) as seeded SVG.
Both recreate the reference artwork's visual grammar rather than copying its path
data, and both were measured off the same original:
| Reference constant | Value |
| --- | --- |
| Routing pitch | `7.895` units (`150 / 19`) |
| Trace stroke | `1.58` units, `#151b25` |
| Via annulus | `3.34` outer / `1.76` inner |
| Board | `#0d1117` |
| Routed-light palette | `#00e6dc` 60%, `#64abff` 25%, `#c5b3ff` 15% |
They diverge on the thing that matters most: **how the board is filled.** One
routes a torus and tiles forever; the other routes one continuous field at the
mount's real size. Pick by whether you want a repeatable texture or a bespoke
backdrop.
| | Tiling router | Field router |
| --- | --- | --- |
| Fill strategy | one `900×450` tile, repeats in both axes | one continuous field, no repeat |
| Router | A\* nets between placed terminal formations | flow field and vortex trace packing |
| Wrap | torus occupancy grid (no seam, no crossings) | reserved grid nodes (no crossings) |
| Headless output | `generate-tile.mjs` writes an SVG tile | `generateCircuitField()` returns geometry |
| Motion | signal fountain or progressive reveal | three reveal modes and five ambient systems |
| Entry file | `circuit-background.js` or `circuit-background-reveal.js` | `circuit-background-v9.js` |
| Live demo | [classic tile](/adom/circuit-trace-generators/render/src/index-classic.html) and [tile reveal](/adom/circuit-trace-generators/render/src/index-reveal.html) | [v9 field](/adom/circuit-trace-generators/render/src/index.html) |
Both ship `createCircuitBackground(mount, options)` returning
`{ regenerate, exportSvg, destroy }`, both are seeded (the same seed and
dimensions give identical geometry), and both honour `prefers-reduced-motion`.
**All three demos run live, hosted on this page.** These are the real `src/` engines,
served by the wiki straight from this page's repo, so they need no container and
will not go dark:
- **[Open the interactive playground](/adom/circuit-trace-generators/render/src/playground.html)** with all three demos on one page
- **[Launch the tiling-router demo](/adom/circuit-trace-generators/render/src/index-classic.html)** on its own
- **[Launch the tiling-reveal demo](/adom/circuit-trace-generators/render/src/index-reveal.html)** on its own
- **[Launch the field-router demo](/adom/circuit-trace-generators/render/src/index.html)** on its own
---
## 1. Tiling router: `circuit-background.js`
[](/adom/circuit-trace-generators/render/src/index-classic.html)
▶ **[Launch the live tiling-router demo](/adom/circuit-trace-generators/render/src/index-classic.html)** · the real engine: drag the twelve generation sliders, switch presets, click the board for a signal burst.
An occupancy-grid router run **on a torus**, so the `900×450` tile it emits
repeats in both axes with no visible seam and no two traces ever cross. That makes
its output usable directly as a CSS `background-image` with
`background-repeat: repeat`.
### How a tile is built
1. **`placeFormations`** scatters terminal groups (via ladders and rows) across
the grid. These are the pads everything else routes between.
2. **`routeNets`** runs A\* between pins, weighted by a *turn penalty* (higher
means longer, calmer runs) and a *weave* preference for 2-lane neighbour
spacing, with a matching *cramp* aversion to 1-lane spacing outside bundles.
3. **`replicateWalk`** adds translated-copy bundle followers, so neighbouring
traces bend together the way a real bus does, re-routed in bundle mode when
blocked.
4. **`tapCombs`** and **`routeStubs`** add comb and stub motifs as punctuation.
5. **`sealEnd`** enforces the **via mandate**: every trace starts *and* ends on a
via, trimming blocked ends with per-step claim tracking. A wrap-aware checker
passes with zero bare ends.
### Tuning
Twelve generation knobs, all exposed as sliders in the demo and as kebab-case
flags on the CLI:
`density`, `formations`, `busWidth`, `turnPenalty`, `weave`, `cramp`,
`horizontalBias`, `netReach`, `jogBias`, `stubChance`, `inlineViaChance`, `combs`
### Motion: the signal fountain
Every signal is mortal. A passive spawn timer (`signalInterval`, 240 ms) is the
fountain: each tick, if the census is under `maxSignals` (12), one new signal
appears near the cursor. `pickStart` scores the actual launch pad by pointer
distance plus `spawnRadius` jitter, falling back to a whole-board spread when the
pointer idles past 4 s. A signal runs to a trace-end via, then rolls its chain's
survival: survivors hop to a nearby via (`hopRadius` 440) inheriting speed,
colour, and survival rate, and the rest die so the timer refills next tick.
Equilibrium census is roughly spawn rate times life.
Passive and clicked chains decay at **separate rates**, `hopSurvival` 0.4 against
`burstSurvival` 0.72, so a clicked burst keeps its own longer life for the whole
chain. `colorDrift` (0.18 per hop) crossfades a leg, and `maxBurstSignals` (25) is
a hard ceiling.
Animation presets: **None** (the page default, a static board), **Fireflies**,
**Swarm**, **Cursor sparks**, **Slow streams**.

The demo splits its knobs into two panels, Generation tuning and Animation
tuning, each with its own reset scoped to just its own sliders.
### Headless CLI
```bash
node generate-tile.mjs --seed traces --out tile.svg
node generate-tile.mjs --seed foo --turn-penalty 0.8 --bus-width 1.4 --combs 0 --transparent > tile.svg
```
Seed `traces` yields 334 traces and 482 vias per tile. Run with `--help` for the
full flag list.
### API
```js
import {
generateCircuitTile, tileSvg, pathData, createCircuitBackground,
} from "./circuit-background.js";
const tile = generateCircuitTile({ seed: "traces", turnPenalty: 0.8 });
const svg = tileSvg(tile, { background: "#0d1117" });
```
### Progressive reveal
[Launch the tiling-reveal demo](/adom/circuit-trace-generators/render/src/index-reveal.html).
`circuit-background-reveal.js` grows the same tile geometry on a canvas above the
static SVG. It redraws only routes that are moving or cooling, then clears the
canvas after the glow reaches zero. The handoff reveals the exact SVG without a
brightness dip or color jump.
Reveal styles are **Etch**, **Flood**, **Sweep**, **Bloom**, and **Scatter**.
See [`src/TILING-REVEAL.md`](src/TILING-REVEAL.md) for the measured implementation notes.
---
## 2. Field router: `circuit-background-v9.js`
[](/adom/circuit-trace-generators/render/src/index.html)
**[Launch the live field-router demo](/adom/circuit-trace-generators/render/src/index.html)** to switch geometry, obstacle, reveal, and ambient presets or export the current SVG.
No tile. A deterministic planar trace-packing pass fills one continuous field at
the mount's real dimensions with hundreds of independent routes. A rotatable
vector field plus seeded, low-frequency vortices organise long carriers, diagonal
runs, and gentle swirls, and *channel attraction* collects nearby routes into
natural local buses. Every occupied grid node is reserved, so separate traces
never cross.
Version 9 separates geometry, obstacles, reveal, and ambient motion. It can avoid
or outline embedded marks, reveal by time or scroll progress, and append seeded
world chunks without moving existing geometry. Versions 2 through 8 remain for reference.
### Tuning
`fill`, `routeLength`, `horizontalFlow`, `flowAngle`, `diagonalFlow`, `longFlow`,
`swirl`, `swirlScale`, `jogLength`, `channelAttraction`, `edgeDensity`,
`featureScale`
`featureScale` proportionally scales routing pitch, trace width, via rings, and
routed-light geometry together, so the motif stays coherent at any size.
Geometry presets: **Original match** (the default, tuned to the reference's path
count, route-length distribution, stroke, via count, and orientation mix),
**Dense**, **Diagonal sweep**, **Broad swirl**, **Sparse**. Geometry presets never
touch motion settings; the two preset rows are independent.
### Ambient systems
Five presets are available in the demo's Animation row:
- **None** mounts only the static SVG and creates no animation layer at all.
- **Adom reflection** (`circuit-animation-reflection.js`) sends a restrained
brand-color sheen across a precomposed trace mask.
- **Conductor** (`circuit-animation-conductor.js`) is the full system: ambient
currents, breathing endpoint nodes, core and halo packets, convoys, timed
spatial waves, pointer wake, endpoint flashes.
- **Routed field** (`animationSystem: "adom"`, implemented in `v4`) is a third
system, not a retune of the conductor. It drives a slow angled sweep across the
board (`sweepDuration` 15.2 s, `sweepAngle` 18°) plus periodic blooms that light
traces near a moving cursor, capped at three concurrent blooms.
- **Handshake** (`circuit-animation-handshake.js`) is the restrained alternative.
Each transaction charges a source via, traverses one complete trace once,
settles into its destination via, and sends a dim acknowledgement back. It uses
exact polyline intervals instead of wrapping dashes, never flood-lights the
field, and avoids the protected hero-copy reading zone. Only `maxHandshakes`
(3) transactions coexist, so per-frame work does **not** grow with geometry
density. That is the reason to reach for it on a dense board.

### API
```js
import { createCircuitBackground } from "./circuit-background-v9.js";
const circuit = createCircuitBackground(document.querySelector("#hero-circuit"), {
seed: "product-launch",
fill: 0.668,
swirl: 0.28,
channelAttraction: 0.78,
obstaclePreset: "adom",
obstacleMode: "outline-wrap",
revealSystem: "scroll",
continuousGeneration: true,
animationSystem: "reflection",
liveliness: 0.82,
motion: true,
});
circuit.regenerate({ seed: "another-layout" });
circuit.triggerAnimation({ x: 240, y: 180 }); // in SVG coordinates
const svg = circuit.exportSvg(); // static, no motion layers
circuit.destroy();
```
`generateCircuitField(options)` returns deterministic geometry with no DOM
involvement. Each trace carries `points`, `length`, `viaStart`, and `viaEnd`, and
`pathData(points)` turns one into SVG path data. That is how the two images on
this page were rendered.
The mount needs a real width and height. The helper observes resizes, clips
overflow, and leaves pointer interaction to the surrounding page.
---
## Running the demos
### On this page (no setup, always up)
All three demos are the actual `src/` files, rendered by the wiki straight from this
page's repo:
| Surface | Live on the wiki |
| --- | --- |
| All three, embedded on one page | [render/src/playground.html](/adom/circuit-trace-generators/render/src/playground.html) |
| Tiling router | [render/src/index-classic.html](/adom/circuit-trace-generators/render/src/index-classic.html) |
| Tiling reveal | [render/src/index-reveal.html](/adom/circuit-trace-generators/render/src/index-reveal.html) |
| Field router | [render/src/index.html](/adom/circuit-trace-generators/render/src/index.html) |
These need no container and do not expire. They run in the render sandbox, which
the engines are fine with since they use no storage or network. The playground
embeds each demo as an iframe, which works because the page is public.
### Locally
The two projects live in adjacent source directories and run on separate ports:
```bash
cd ~/project/circuit-generator
# Tiling router, http://localhost:8930
node serve-classic.mjs # serves index-classic.html + circuit-background.js
cd ~/project/circuit-generator-codex
# Field router, http://localhost:8124
./serve.sh # serves index.html via server.js
```
## File map
The two local source directories are combined under `src/` in this package:
| File | Belongs to |
| --- | --- |
| `circuit-background.js` | tiling router (engine) |
| `circuit-background-reveal.js` | tiling router (progressive reveal) |
| `index-classic.html`, `index-reveal.html` | tiling demos |
| `generate-tile.mjs` | tiling router (CLI) |
| `circuit-background-v9.js` | field router entry |
| `circuit-geometry-v9.js`, `circuit-obstacles-v9.js` | field geometry and obstacles |
| `circuit-reveal-*.js` | field reveal systems |
| `circuit-animation-*.js` | field ambient systems |
| `index.html`, `server.js`, `serve.sh` | field router (demo, port 8124) |
| `TILING-REVEAL.md`, `FIELD-ROUTER.md` | full implementation notes |

