← Commit history

Initial commit: app/circuit-trace-generators

AdityaAngajala ·753a927881 ·3mo ago
2 files changed +269
README.mdadded+219
@@ -0,0 +1,219 @@+# 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 | 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 |+| 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`.++---++## 1. Tiling router — `circuit-background.js`++![Tiling router output, seed "traces", tiled across 1200x600](docs/tiling-router.png)++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`.++### 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+   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; the rest die and the timer refills next tick.+Equilibrium census ≈ spawn rate × 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.++Animation presets: **None** (the page default — a static board), **Fireflies**,+**Swarm**, **Cursor sparks**, **Slow streams**.++### 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 / 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" });+```++---++## 2. Field router — `circuit-background-v5.js`++![Field router output, seed "nitrogen", one continuous 1200x600 field](docs/field-router.png)++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.++`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`++`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.++### Two animation systems++- **Original conductor** (`circuit-animation-conductor.js`) — 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+  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.+- **None** mounts only the static SVG and creates no animation layer at all.++### API++```js+import { createCircuitBackground } from "./circuit-background-v5.js";++const circuit = createCircuitBackground(document.querySelector("#hero-circuit"), {+  seed: "product-launch",+  fill: 0.668,+  swirl: 0.28,+  channelAttraction: 0.78,+  animationSystem: "handshake",+  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`, `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 both demos++The two projects share one working directory, `~/project/circuit-generator`, 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++# Field router → http://localhost:8124+./serve.sh                      # serves index.html via server.js+```++Public mappings on container `beziswazskpw`:++| Demo | Port | URL |+| --- | --- | --- |+| 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.++## 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:++| File | Belongs to |+| --- | --- |+| `circuit-background.js` | tiling router (engine) |+| `index-classic.html`, `serve-classic.mjs` | tiling router (demo, port 8930) |+| `generate-tile.mjs` | tiling router (CLI) |+| `circuit-background-v5.js` | field router (entry: animation shell) |+| `circuit-background-v4.js` | field router (geometry) |+| `circuit-animation-conductor.js`, `circuit-animation-handshake.js` | field router (motion) |+| `circuit-background-v2.js`, `circuit-background-v3.js` | field router (earlier iterations) |+| `index.html`, `server.js`, `serve.sh` | field router (demo, port 8124) |
page.jsonadded+50
@@ -0,0 +1,50 @@+{+  "slug": "circuit-trace-generators",+  "title": "Circuit Trace Generators",+  "type": "app",+  "version": "0.1.0",+  "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",+    "generative",+    "background",+    "pcb",+    "brand"+  ],+  "dependencies": {},+  "discovery_triggers": [+    "generate a circuit background",+    "make a PCB trace background",+    "nitrogen hero background",+    "seamless circuit tile",+    "procedural trace pattern"+  ],+  "discovery_pitch": "Reach for this when a page needs the Adom circuit-trace backdrop — either a seamless tile you can repeat as a CSS background-image, or one continuous generated field sized to the mount.",+  "sample_prompts": [+    {+      "label": "Seamless tile",+      "prompt": "generate a seamless circuit-trace tile I can use as a repeating CSS background"+    },+    {+      "label": "Hero backdrop",+      "prompt": "put the Nitrogen circuit background behind this hero section"+    }+  ],+  "scripts": {+    "install": "./install.sh",+    "uninstall": "./uninstall.sh"+  },+  "hero": {+    "type": "billboard",+    "headline": "Circuit Trace Generators",+    "subhead": "Two seeded SVG routers for the Nitrogen hero background — one tiles a torus, one packs a continuous field.",+    "screenshot": "docs/hero.png",+    "accent": "#00e6dc"+  },+  "visibility": "private",+  "org": "adom",+  "author": {+    "name": "AdityaAngajala",+    "email": "[email protected]"+  }+}\ No newline at end of file