app
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.
← Commit history
README.md+55−51@@ -1,7 +1,7 @@ # 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.+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:@@ -12,7 +12,7 @@ data, and both were measured off the same original: | 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% |+| 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@@ -21,40 +21,42 @@ backdrop. | | Tiling router | Field router | | --- | --- | --- |-| Fill strategy | seamless `900×450` tile, repeats in both axes | one continuous field, no repeat |-| Router | A\* nets between placed terminal formations | flow-field + vortex trace packing |-| Wrap | torus occupancy grid (seamless, crossing-free) | reserved grid nodes (crossing-free) |-| Headless output | `generate-tile.mjs` → SVG tile | `generateCircuitField()` → geometry |+| 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 | cursor-fed signal fountain | conductor **or** handshake system | | Entry file | `circuit-background.js` | `circuit-background-v5.js` | | Live demo | [traces-fuyou1ziuokn.adom.cloud](https://traces-fuyou1ziuokn.adom.cloud) | [circuit-y2uq81e4dp1d.adom.cloud](https://circuit-y2uq81e4dp1d.adom.cloud) | Both ship `createCircuitBackground(mount, options)` returning-`{ regenerate, exportSvg, destroy }`, both are seeded (same seed + dimensions →-identical geometry), and both honour `prefers-reduced-motion`.+`{ regenerate, exportSvg, destroy }`, both are seeded (the same seed and+dimensions give identical geometry), and both honour `prefers-reduced-motion`. --- -## 1. Tiling router — `circuit-background.js`+## 1. Tiling router: `circuit-background.js`  An occupancy-grid router run **on a torus**, so the `900×450` tile it emits-repeats seamlessly in both axes and no two traces ever cross. That makes its-output usable directly as a CSS `background-image` with `background-repeat: repeat`.+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`** — A\* between pins, weighted by a *turn penalty* (higher =- 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`** — translated-copy bundle followers, so neighbouring traces- bend together the way a real bus does, re-routed in bundle mode when blocked.-4. **`tapCombs`** / **`routeStubs`** — comb and stub motifs as punctuation.-5. **`sealEnd`** — enforces the **via mandate**: every trace starts *and* ends on a- via, trimming blocked ends via per-step claim tracking. A wrap-aware checker+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@@ -62,26 +64,26 @@ output usable directly as a CSS `background-image` with `background-repeat: repe 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`+`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+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; the rest die and the timer refills next tick.-Equilibrium census ≈ spawn rate × life.+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 vs-`burstSurvival` 0.72 — so a clicked burst keeps its own longer life for the whole-chain. `colorDrift` (0.18/hop) crossfades a leg; `maxBurstSignals` (25) is a hard-ceiling.+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**,+Animation presets: **None** (the page default, a static board), **Fireflies**, **Swarm**, **Cursor sparks**, **Slow streams**. ### Headless CLI@@ -91,7 +93,7 @@ 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 / 482 vias per tile. Run with `--help` for the+Seed `traces` yields 334 traces and 482 vias per tile. Run with `--help` for the full flag list. ### API@@ -107,24 +109,25 @@ const svg = tileSvg(tile, { background: "#0d1117" }); --- -## 2. Field router — `circuit-background-v5.js`+## 2. Field router: `circuit-background-v5.js`  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; *channel attraction* collects nearby routes into natural-local buses. Every occupied grid node is reserved, so separate traces never cross.+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. -`v5` is the animation shell over `v4`'s geometry (`v2` and `v3` are earlier-iterations, kept for reference).+`v5` is the animation shell over `v4`'s geometry. `v2` and `v3` are earlier+iterations, kept for reference. ### Tuning -`fill` · `routeLength` · `horizontalFlow` · `flowAngle` · `diagonalFlow` ·-`longFlow` · `swirl` · `swirlScale` · `jogLength` · `channelAttraction` ·-`edgeDensity` · `featureScale`+`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.@@ -132,20 +135,20 @@ 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.+touch motion settings; the two preset rows are independent. ### Two animation systems -- **Original conductor** (`circuit-animation-conductor.js`) — the full system:+- **Original 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.-- **Adom handshake** (`circuit-animation-handshake.js`) — the restrained+- **Adom 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 —- the reason to reach for it on a dense board.+ transactions coexist, so per-frame work does **not** grow with geometry density.+ That is the reason to reach for it on a dense board. - **None** mounts only the static SVG and creates no animation layer at all. ### API@@ -169,11 +172,11 @@ circuit.destroy(); ``` `generateCircuitField(options)` returns deterministic geometry with no DOM-involvement — each trace carries `points`, `length`, `viaStart`, `viaEnd`, and+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+The mount needs a real width and height. The helper observes resizes, clips overflow, and leaves pointer interaction to the surrounding page. ---@@ -186,10 +189,10 @@ run on separate ports. ```bash cd ~/project/circuit-generator -# Tiling router → http://localhost:8930+# Tiling router, http://localhost:8930 node serve-classic.mjs # serves index-classic.html + circuit-background.js -# Field router → http://localhost:8124+# Field router, http://localhost:8124 ./serve.sh # serves index.html via server.js ``` @@ -200,12 +203,13 @@ Public mappings on container `beziswazskpw`: | Tiling router | 8930 | <https://traces-fuyou1ziuokn.adom.cloud> | | Field router | 8124 | <https://circuit-y2uq81e4dp1d.adom.cloud> | -If either URL 502s, the process died — re-run its command above.+If either URL returns a 502, the process died. Re-run its command above. ## File map Both projects live side by side in one directory, which is the single most-confusing thing about the source. This is the split:+confusing thing about the source. This is the split, mirrored under `src/` in+this package: | File | Belongs to | | --- | --- |
SKILL.md+14−14@@ -1,6 +1,6 @@ --- name: circuit-trace-generators-description: Generate the Adom Nitrogen circuit-trace background as seeded SVG — either a seamless 900x450 tile you can repeat as a CSS background-image, or one continuous non-repeating field sized to a mount. Use when a page needs the PCB-trace backdrop, when asked to "generate a circuit background", "make a PCB trace pattern", "seamless circuit tile", "nitrogen hero background", or when tuning trace density, bus width, swirl, or the routed-light animation.+description: Generate the Adom Nitrogen circuit-trace background as seeded SVG, either a repeating 900x450 tile you can use as a CSS background-image or one continuous non-repeating field sized to a mount. Use when a page needs the PCB-trace backdrop, when asked to "generate a circuit background", "make a PCB trace pattern", "circuit tile", "nitrogen hero background", or when tuning trace density, bus width, swirl, or the routed-light animation. user-invocable: true --- @@ -8,22 +8,22 @@ user-invocable: true Two engines. Pick by whether the output must repeat. -## Need a repeatable texture → tiling router+## Need a repeatable texture: tiling router -Emits a `900×450` tile routed on a torus, so it repeats seamlessly in both axes-and no traces cross the seam.+Emits a `900×450` tile routed on a torus, so it repeats in both axes with no+visible seam and no traces cross the boundary. ```bash node src/generate-tile.mjs --seed traces --out tile.svg ``` Use it as `background-image` with `background-repeat: repeat`. Tuning flags are-kebab-case versions of the twelve generation knobs — `--turn-penalty` (higher =+kebab-case versions of the twelve generation knobs: `--turn-penalty` (higher means longer, calmer runs), `--bus-width`, `--formations`, `--density`, `--weave`, `--cramp`, `--horizontal-bias`, `--net-reach`, `--jog-bias`, `--stub-chance`, `--inline-via-chance`, `--combs`. `--transparent` drops the board fill. -## Need a bespoke backdrop → field router+## Need a bespoke backdrop: field router One continuous field at the mount's real size, packed with a flow field and seeded vortices. Mount it in a page:@@ -38,18 +38,18 @@ const circuit = createCircuitBackground(document.querySelector("#hero"), { }); ``` -`animationSystem: "handshake"` is the one to reach for on a dense board — it caps-concurrent transactions at 3, so per-frame cost does not grow with geometry.-`"none"` mounts a static SVG with no animation layer at all.+Reach for `animationSystem: "handshake"` on a dense board. It caps concurrent+transactions at 3, so per-frame cost does not grow with geometry. `"none"` mounts+a static SVG with no animation layer at all. For geometry without a DOM, call `generateCircuitField(options)` and render-`pathData(trace.points)` yourself; each trace carries `points`, `length`,-`viaStart`, `viaEnd`.+`pathData(trace.points)` yourself. Each trace carries `points`, `length`,+`viaStart`, and `viaEnd`. ## Both -Seeded — the same seed and dimensions give identical geometry. Dependency-free ES-modules. Board `#0d1117`, traces `#151b25`, routed light-`#00e6dc`/`#64abff`/`#c5b3ff`. Both honour `prefers-reduced-motion`.+Seeded, so the same seed and dimensions give identical geometry. Dependency-free+ES modules. Board `#0d1117`, traces `#151b25`, routed light `#00e6dc`, `#64abff`,+`#c5b3ff`. Both honour `prefers-reduced-motion`. See the page README for the full parameter reference and the two live demos.
package.json+1−1@@ -2,7 +2,7 @@ "slug": "circuit-trace-generators", "title": "Circuit Trace Generators", "type": "app",- "version": "0.1.0",+ "version": "0.1.1", "description": "Two dependency-free, seeded SVG generators for the Adom Nitrogen hero background: a tiling router that emits a seamless 900x450 PCB-trace tile from a torus occupancy grid, and a field router that packs one continuous non-repeating trace field using a flow field and seeded vortices.", "tags": [ "svg",
page.json+1−1@@ -2,7 +2,7 @@ "slug": "circuit-trace-generators", "title": "Circuit Trace Generators", "type": "app",- "version": "0.1.0",+ "version": "0.1.1", "description": "Two dependency-free, seeded SVG generators for the Adom Nitrogen hero background: a tiling router that emits a seamless 900x450 PCB-trace tile from a torus occupancy grid, and a field router that packs one continuous non-repeating trace field using a flow field and seeded vortices.", "tags": [ "svg",