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
Add interactive readme.html: both demos embedded as live iframes + full docs (rich readme, replaces markdown on Overview)
1 file changed
+218
readme.htmladded+218@@ -0,0 +1,218 @@+<!doctype html>+<html lang="en">+<head>+<meta charset="utf-8" />+<meta name="viewport" content="width=device-width, initial-scale=1" />+<title>Circuit Trace Generators</title>+<style>+ :root { color-scheme: dark; }+ * { box-sizing: border-box; }+ body {+ margin: 0; background: #0d1117; color: #c9d4e3;+ font: 15px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;+ }+ .wrap { max-width: 1120px; margin: 0 auto; padding: 8px 20px 72px; }+ h1 { font-size: 27px; color: #eaf2ff; letter-spacing: -0.01em; margin: 18px 0 6px; }+ h2 { font-size: 20px; color: #eaf2ff; margin: 40px 0 10px; padding-bottom: 6px; border-bottom: 1px solid #1e2633; }+ h3 { font-size: 16px; color: #dbe6f5; margin: 24px 0 6px; }+ p { margin: 0 0 12px; max-width: 78ch; }+ a { color: #00e6dc; text-decoration: none; }+ a:hover { text-decoration: underline; }+ .accent { color: #00e6dc; }+ .lede { color: #a7b3c4; }+ code { color: #64abff; background: #151b25; padding: 1px 5px; border-radius: 4px; font-size: 13px; }+ pre { background: #0a0e14; border: 1px solid #1e2633; border-radius: 8px; padding: 14px 16px; overflow-x: auto; }+ pre code { color: #c9d4e3; background: none; padding: 0; }+ table { border-collapse: collapse; width: 100%; margin: 8px 0 14px; display: block; overflow-x: auto; }+ th, td { border: 1px solid #1e2633; padding: 7px 11px; text-align: left; font-size: 13.5px; vertical-align: top; }+ th { background: #141b26; color: #dbe6f5; }+ ol, ul { max-width: 78ch; padding-left: 22px; }+ li { margin: 3px 0; }+ .demo { margin: 22px 0 30px; }+ .demo .meta { color: #8b97a8; font-size: 13.5px; margin: 0 0 10px; }+ .frame { width: 100%; height: 74vh; min-height: 540px; border: 1px solid #1e2633;+ border-radius: 12px; background: #0d1117; display: block; }+ .open { margin-top: 9px; font-size: 13.5px; }+ .pill { display:inline-block; font-size:11px; letter-spacing:.08em; text-transform:uppercase;+ color:#5ff5e8; background:#0b3d33; border:1px solid #0e5548; border-radius:999px; padding:2px 9px; margin-left:8px; vertical-align:middle; }+ footer { margin-top: 52px; color: #5c6675; font-size: 12.5px; border-top: 1px solid #1e2633; padding-top: 16px; }+ .cols { display:grid; gap:22px; }+ @media (min-width: 900px) { .cols { grid-template-columns: 1fr 1fr; } }+</style>+</head>+<body>+<div class="wrap">++ <header>+ <h1>Circuit Trace Generators <span class="pill">live</span></h1>+ <p class="lede">Two dependency-free, seeded SVG generators that draw the Adom+ <strong>Nitrogen</strong> hero background, procedural PCB traces, vias, and routed+ light. Both are embedded and running below. Drag the sliders, switch presets, and+ move the pointer over each board.</p>+ </header>++ <!-- ================= LIVE DEMOS ================= -->+ <section class="demo">+ <h2>1 · Tiling router <span class="accent">·</span> seamless torus tile</h2>+ <p class="meta">Occupancy-grid A* router on a torus. Twelve generation knobs, a cursor-fed signal fountain, and five animation presets. Engine: <code>circuit-background.js</code>.</p>+ <iframe class="frame" src="/adom/circuit-trace-generators/render/src/index-classic.html" title="Tiling router, live interactive demo" loading="lazy"></iframe>+ <p class="open">▶ <a href="/adom/circuit-trace-generators/render/src/index-classic.html" target="_blank" rel="noopener">Open this demo full screen</a></p>+ </section>++ <section class="demo">+ <h2>2 · Field router <span class="accent">·</span> continuous packed field</h2>+ <p class="meta">Flow-field and vortex trace packing, sized to the mount. Five geometry presets and four animation systems. Entry: <code>circuit-background-v5.js</code>.</p>+ <iframe class="frame" src="/adom/circuit-trace-generators/render/src/index.html" title="Field router, live interactive demo" loading="lazy"></iframe>+ <p class="open">▶ <a href="/adom/circuit-trace-generators/render/src/index.html" target="_blank" rel="noopener">Open this demo full screen</a></p>+ </section>++ <!-- ================= OVERVIEW ================= -->+ <h2>What they are</h2>+ <p>Both recreate the reference artwork's visual grammar rather than copying its+ path data, and both were measured off the same original:</p>++ <table>+ <tr><th>Reference constant</th><th>Value</th></tr>+ <tr><td>Routing pitch</td><td><code>7.895</code> units (<code>150 / 19</code>)</td></tr>+ <tr><td>Trace stroke</td><td><code>1.58</code> units, <code>#151b25</code></td></tr>+ <tr><td>Via annulus</td><td><code>3.34</code> outer / <code>1.76</code> inner</td></tr>+ <tr><td>Board</td><td><code>#0d1117</code></td></tr>+ <tr><td>Routed-light palette</td><td><code>#00e6dc</code> 60%, <code>#64abff</code> 25%, <code>#c5b3ff</code> 15%</td></tr>+ </table>++ <p>They diverge on the thing that matters most: <strong>how the board is filled.</strong>+ 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.</p>++ <table>+ <tr><th></th><th>Tiling router</th><th>Field router</th></tr>+ <tr><td>Fill strategy</td><td>one <code>900×450</code> tile, repeats in both axes</td><td>one continuous field, no repeat</td></tr>+ <tr><td>Router</td><td>A* nets between placed terminal formations</td><td>flow field and vortex trace packing</td></tr>+ <tr><td>Wrap</td><td>torus occupancy grid (no seam, no crossings)</td><td>reserved grid nodes (no crossings)</td></tr>+ <tr><td>Headless output</td><td><code>generate-tile.mjs</code> writes an SVG tile</td><td><code>generateCircuitField()</code> returns geometry</td></tr>+ <tr><td>Motion</td><td>cursor-fed signal fountain</td><td>conductor or handshake system</td></tr>+ <tr><td>Entry file</td><td><code>circuit-background.js</code></td><td><code>circuit-background-v5.js</code></td></tr>+ </table>++ <p>Both ship <code>createCircuitBackground(mount, options)</code> returning+ <code>{ regenerate, exportSvg, destroy }</code>, both are seeded (the same seed and+ dimensions give identical geometry), and both honour <code>prefers-reduced-motion</code>.</p>++ <div class="cols">+ <div>+ <!-- ============ TILING ============ -->+ <h2>1 · Tiling router</h2>+ <p><code>circuit-background.js</code>. An occupancy-grid router run <strong>on a+ torus</strong>, so the <code>900×450</code> 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 <code>background-image</code> with <code>background-repeat: repeat</code>.</p>++ <h3>How a tile is built</h3>+ <ol>+ <li><strong><code>placeFormations</code></strong> scatters terminal groups (via ladders and rows) across the grid. These are the pads everything else routes between.</li>+ <li><strong><code>routeNets</code></strong> runs A* between pins, weighted by a <em>turn penalty</em> (higher means longer, calmer runs) and a <em>weave</em> preference for 2-lane neighbour spacing, with a matching <em>cramp</em> aversion to 1-lane spacing outside bundles.</li>+ <li><strong><code>replicateWalk</code></strong> adds translated-copy bundle followers, so neighbouring traces bend together the way a real bus does.</li>+ <li><strong><code>tapCombs</code></strong> and <strong><code>routeStubs</code></strong> add comb and stub motifs as punctuation.</li>+ <li><strong><code>sealEnd</code></strong> enforces the <strong>via mandate</strong>: every trace starts and ends on a via, trimming blocked ends with per-step claim tracking.</li>+ </ol>++ <h3>Tuning</h3>+ <p>Twelve generation knobs, all sliders in the demo and kebab-case flags on the CLI:+ <code>density</code>, <code>formations</code>, <code>busWidth</code>,+ <code>turnPenalty</code>, <code>weave</code>, <code>cramp</code>,+ <code>horizontalBias</code>, <code>netReach</code>, <code>jogBias</code>,+ <code>stubChance</code>, <code>inlineViaChance</code>, <code>combs</code>.</p>++ <h3>Motion: the signal fountain</h3>+ <p>Every signal is mortal. A passive spawn timer (<code>signalInterval</code>, 240 ms)+ is the fountain: each tick, if the census is under <code>maxSignals</code> (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 (<code>hopSurvival</code>+ 0.4 against <code>burstSurvival</code> 0.72). Presets: <strong>None</strong> (default),+ <strong>Fireflies</strong>, <strong>Swarm</strong>, <strong>Cursor sparks</strong>,+ <strong>Slow streams</strong>.</p>++ <h3>Headless CLI</h3>+ <pre><code>node generate-tile.mjs --seed traces --out tile.svg+node generate-tile.mjs --seed foo --turn-penalty 0.8 --combs 0 --transparent > tile.svg</code></pre>+ <p>Seed <code>traces</code> yields 334 traces and 482 vias per tile.</p>+ </div>++ <div>+ <!-- ============ FIELD ============ -->+ <h2>2 · Field router</h2>+ <p><code>circuit-background-v5.js</code>. 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+ <em>channel attraction</em> collects nearby routes into local buses. <code>v5</code>+ is the animation shell over <code>v4</code>'s geometry.</p>++ <h3>Tuning</h3>+ <p><code>fill</code>, <code>routeLength</code>, <code>horizontalFlow</code>,+ <code>flowAngle</code>, <code>diagonalFlow</code>, <code>longFlow</code>,+ <code>swirl</code>, <code>swirlScale</code>, <code>jogLength</code>,+ <code>channelAttraction</code>, <code>edgeDensity</code>, <code>featureScale</code>.+ Geometry presets: <strong>Original match</strong> (default), <strong>Dense</strong>,+ <strong>Diagonal sweep</strong>, <strong>Broad swirl</strong>, <strong>Sparse</strong>.</p>++ <h3>Animation systems</h3>+ <ul>+ <li><strong>None</strong> mounts only the static SVG.</li>+ <li><strong>Conductor</strong> (<code>circuit-animation-conductor.js</code>): ambient currents, breathing nodes, core and halo packets, convoys, spatial waves, pointer wake.</li>+ <li><strong>Routed field</strong> (<code>animationSystem: "adom"</code>, in <code>v4</code>): a slow 18° sweep plus periodic blooms near the cursor, capped at three.</li>+ <li><strong>Handshake</strong> (<code>circuit-animation-handshake.js</code>): each transaction charges a source via, traverses one trace once, settles, and acks back. Only <code>maxHandshakes</code> (3) coexist, so per-frame cost does not grow with density. Reach for it on a dense board.</li>+ </ul>++ <h3>API</h3>+ <pre><code>import { createCircuitBackground } from "./circuit-background-v5.js";++const circuit = createCircuitBackground(mount, {+ seed: "product-launch",+ animationSystem: "handshake", // none | conductor | routed | handshake+ motion: true,+});+circuit.regenerate({ seed: "another-layout" });+const svg = circuit.exportSvg(); // static, no motion layers</code></pre>+ <p><code>generateCircuitField(options)</code> returns deterministic geometry with no+ DOM. Each trace carries <code>points</code>, <code>length</code>,+ <code>viaStart</code>, <code>viaEnd</code>; <code>pathData(points)</code> makes SVG.</p>+ </div>+ </div>++ <!-- ================= RUNNING ================= -->+ <h2>Running the demos</h2>+ <p>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:</p>+ <table>+ <tr><th>Surface</th><th>Live on the wiki</th></tr>+ <tr><td>Tiling router</td><td><a href="/adom/circuit-trace-generators/render/src/index-classic.html">render/src/index-classic.html</a></td></tr>+ <tr><td>Field router</td><td><a href="/adom/circuit-trace-generators/render/src/index.html">render/src/index.html</a></td></tr>+ </table>+ <p>Locally the two projects share one working directory and run on separate ports:</p>+ <pre><code>cd ~/project/circuit-generator+node serve-classic.mjs # tiling router, http://localhost:8930+./serve.sh # field router, http://localhost:8124</code></pre>++ <!-- ================= FILE MAP ================= -->+ <h2>File map</h2>+ <p>Both projects live side by side in one directory, mirrored under <code>src/</code> in this page's repo:</p>+ <table>+ <tr><th>File</th><th>Belongs to</th></tr>+ <tr><td><code>circuit-background.js</code></td><td>tiling router (engine)</td></tr>+ <tr><td><code>index-classic.html</code>, <code>serve-classic.mjs</code></td><td>tiling router (demo, port 8930)</td></tr>+ <tr><td><code>generate-tile.mjs</code></td><td>tiling router (CLI)</td></tr>+ <tr><td><code>circuit-background-v5.js</code></td><td>field router (entry: animation shell)</td></tr>+ <tr><td><code>circuit-background-v4.js</code></td><td>field router (geometry)</td></tr>+ <tr><td><code>circuit-animation-conductor.js</code>, <code>circuit-animation-handshake.js</code></td><td>field router (motion)</td></tr>+ <tr><td><code>index.html</code>, <code>server.js</code>, <code>serve.sh</code></td><td>field router (demo, port 8124)</td></tr>+ </table>++ <footer>+ This is the page's interactive readme (<code>readme.html</code>). The plain-text+ version lives in <code>README.md</code> on the Files tab, alongside all source under+ <code>src/</code>.+ </footer>+</div>+</body>+</html>