Two dependency-free, seeded SVG generators that draw the Adom Nitrogen hero background, procedural PCB traces, vias, and routed light. All three demos are embedded below. Drag the sliders, switch presets, and move the pointer over each board.
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 |
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.
circuit-background.js. 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.
placeFormations scatters terminal groups (via ladders and rows) across the grid. These are the pads everything else routes between.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.replicateWalk adds translated-copy bundle followers, so neighbouring traces bend together the way a real bus does.tapCombs and routeStubs add comb and stub motifs as punctuation.sealEnd enforces the via mandate: every trace starts and ends on a via, trimming blocked ends with per-step claim tracking.Twelve generation knobs, all sliders in the demo and kebab-case flags on the CLI:
density, formations, busWidth,
turnPenalty, weave, cramp,
horizontalBias, netReach, jogBias,
stubChance, inlineViaChance, combs.
Every signal is mortal. A passive spawn timer (signalInterval, 240 ms)
is the fountain: each tick, if the census is under maxSignals (12), a new
signal appears near the cursor, runs to a trace-end via, then rolls its chain's
survival. Passive and clicked chains decay at separate rates (hopSurvival
0.4 against burstSurvival 0.72). Presets: None (default),
Fireflies, Swarm, Cursor sparks,
Slow streams.
circuit-background-reveal.js grows the same geometry with
Etch, Flood, Sweep,
Bloom, or Scatter. A canvas layer draws only
moving or cooling routes, then clears after the glow reaches zero and reveals
the exact static SVG beneath it.
node generate-tile.mjs --seed traces --out tile.svg
node generate-tile.mjs --seed foo --turn-penalty 0.8 --combs 0 --transparent > tile.svg
Seed traces yields 334 traces and 482 vias per tile.
circuit-background-v9.js builds one continuous field at the
mount's real dimensions. Version 9 separates geometry, obstacles, reveal, and
ambient motion so each system can change without regenerating the others.
fill, routeLength, horizontalFlow,
flowAngle, diagonalFlow, longFlow,
swirl, swirlScale, jogLength,
channelAttraction, edgeDensity, featureScale.
Obstacles can avoid, outline, or outline and wrap rectangles, ellipses, polygons,
rings, and wordmarks. obstaclePreset: "adom" uses the built-in mark.
import { createCircuitBackground } from "./circuit-background-v9.js";
const circuit = createCircuitBackground(mount, {
seed: "product-launch",
obstaclePreset: "adom",
obstacleMode: "outline-wrap",
revealSystem: "scroll",
continuousGeneration: true,
animationSystem: "reflection",
motion: true,
});
circuit.regenerate({ seed: "another-layout" });
const svg = circuit.exportSvg(); // static, no motion layers
generateCircuitField(options) returns deterministic geometry with no
DOM. Each trace carries points, length,
The demos above are hosted on this page via the wiki render endpoint, so they need no container and do not expire. You can also open each on its own:
| Surface | Live on the wiki |
|---|---|
| Tiling router | render/src/index-classic.html |
| Tiling reveal | render/src/index-reveal.html |
| Field router | render/src/index.html |
Locally the generators live in adjacent source directories and run on separate ports:
cd ~/project/circuit-generator
node serve-classic.mjs # tiling router, http://localhost:8930
cd ~/project/circuit-generator-codex
./serve.sh # field router, http://localhost:8124
The two local source directories are combined under src/ in this page's repo:
| 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, circuit-animation-*.js | field reveal and ambient motion |
index.html, server.js, serve.sh | field router (demo, port 8124) |
TILING-REVEAL.md, FIELD-ROUTER.md | full implementation notes |