← Commit history

Add interactive readme.html: both demos embedded as live iframes + full docs (rich readme, replaces markdown on Overview)

AdityaAngajala ·1268ac075e ·2mo ago ·parent a36fe29
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 &gt; 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>