main
John Lauer Thumbnail index on the summary; full write-ups as rendered pages with the live 3D viewer inline 96790b1 12d ago
<!doctype html><html><head><meta charset="utf-8"><meta name="readme-max-height" content="60000"><meta name="viewport" content="width=device-width, initial-scale=1"><style>
  /* No @font-face here: the wiki renders README.html in a null-origin iframe,
     so adom.inc's font files fail CORS on every load and only add console
     noise. Fall back to the system stack, which the wiki chrome matches. */
  :root { --bg:#0d1117; --surface:#161b22; --elev:#1c2128; --border:#30363d;
           --text:#e6edf3; --body:#c9d1d9; --muted:#8b949e; --accent:#00b8b1; --purple:#8C6BF7; }
  * { box-sizing:border-box; margin:0; padding:0; }
  html,body { background:var(--bg); color:var(--body);
    font:15px/1.65 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
    scrollbar-width:none; }
  html::-webkit-scrollbar, body::-webkit-scrollbar { width:0; height:0; display:none; }
  #wrap { max-width:900px; margin:0 auto; padding:34px 22px 60px; }
  h1 { color:var(--text); font-size:40px; line-height:1.1; letter-spacing:-.02em; margin:0 0 10px; }
  h2 { color:var(--text); font-size:21px; letter-spacing:-.01em;
       margin:38px 0 12px; padding-bottom:7px; border-bottom:1px solid var(--border); }
  h3 { color:var(--text); font-size:16px; margin:22px 0 8px; }
  p { margin:0 0 13px; }
  .lede { font-size:17.5px; color:var(--text); margin-bottom:20px; }
  a { color:var(--accent); }
  code { font:13px/1.5 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
         background:var(--elev); border:1px solid var(--border);
         border-radius:5px; padding:1px 5px; color:var(--text); }
  pre { background:var(--elev); border:1px solid var(--border); border-radius:10px;
        padding:14px 16px; overflow-x:auto; margin:0 0 16px; }
  pre code { background:none; border:0; padding:0; font-size:12.5px; line-height:1.6; }
  ul,ol { margin:0 0 14px; padding-left:22px; }
  li { margin:0 0 6px; }
  table { width:100%; border-collapse:collapse; margin:0 0 18px; font-size:13.5px; }
  th,td { text-align:left; padding:8px 11px; border-bottom:1px solid var(--border); vertical-align:top; }
  th { color:var(--muted); font-weight:600; white-space:nowrap; }
  td:first-child { color:var(--text); white-space:nowrap; }
  .viewer { border:1px solid var(--border); border-radius:12px; overflow:hidden;
             background:var(--surface); margin:22px 0 8px;
             box-shadow:0 12px 40px rgba(0,0,0,.45); }
  .viewer iframe { display:block; width:100%; height:620px; border:0; }
  .poster { display:block; width:100%; padding:0; border:0; background:none;
             cursor:pointer; position:relative; font:inherit; color:inherit; }
  .poster img { display:block; width:100%; height:auto; opacity:.55; transition:opacity .18s; }
  .poster:hover img { opacity:.75; }
  .play { position:absolute; inset:0; display:flex; flex-direction:column;
           align-items:center; justify-content:center; gap:6px; text-align:center; }
  .play b { background:var(--accent); color:#04120f; padding:10px 20px;
             border-radius:999px; font-size:15px; font-weight:700; }
  .play i { color:var(--text); font-style:normal; font-size:12.5px; opacity:.85; }
  .cap { color:var(--muted); font-size:13px; margin:0 0 26px; }
  .cap a { color:var(--accent); text-decoration:none; }
  .call { background:var(--surface); border:1px solid var(--border);
          border-left:3px solid var(--accent); border-radius:0 10px 10px 0;
          padding:14px 18px; margin:0 0 22px; color:var(--body); }
  .call b { color:var(--text); }
  .warn { border-left-color:var(--purple); }
  figure { margin:0 0 20px; }
  figure img { display:block; width:100%; height:auto; border-radius:10px;
               border:1px solid var(--border); background:#000; }
  figcaption { color:var(--muted); font-size:12.5px; margin-top:7px; }
  .grid2 { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
  @media (max-width:680px) { .grid2 { grid-template-columns:1fr; } }
  .muted { color:var(--muted); }

  iframe.live { display:block; width:100%; height:600px; border:1px solid var(--border); border-radius:12px;
                background:var(--surface); margin:8px 0 10px; box-shadow:0 12px 40px rgba(0,0,0,.45); }
  img { max-width:100%; height:auto; border-radius:10px; border:1px solid var(--border); margin:6px 0 14px; }
  table { display:block; overflow-x:auto; }
  blockquote { border-left:3px solid var(--accent); padding:4px 14px; margin:0 0 14px; color:var(--muted); }
</style></head>
</head><body><div id="wrap"><h1>Rev 1: 3 x 5 LED dot matrix</h1>
<p>The first attempt. An AI designed a desk nameplate that spells STEVEN in 58 white LEDs, powered
from an iPhone charger through a USB-C port on the right edge. It works electrically. It fails
as typography: the N reads as an H. That failure is the reason Rev 2 exists.</p>
<p><img src="https://wiki.adom.inc/adom/steven-led-nameplate/render/docs/img/steven-v1-hero.jpg" alt="Rev 1, 3D render of the assembled board" /></p>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Status</td>
<td>Designed and verified in software. <strong>Not fabricated.</strong></td>
</tr>
<tr>
<td>Date</td>
<td>2026-09-11</td>
</tr>
<tr>
<td>Board</td>
<td>98.4 x 26.4 mm, 2 layer FR4, Adom molecule <code>96x24</code> nominal, medium machine pins</td>
</tr>
<tr>
<td>Letters</td>
<td>58 LEDs, 3 x 5 pixel font, 3.5 mm pixel pitch, 4 mm letter gap, 62 mm of text</td>
</tr>
<tr>
<td>Power</td>
<td>USB-C on the east edge, 5 V, about 520 mA with every LED lit</td>
</tr>
<tr>
<td>Result</td>
<td>0 DRC errors, 62 of 62 nets connected, USB-C geometry inside the guide's reference window</td>
</tr>
<tr>
<td>Outcome</td>
<td>Superseded by <a href="https://wiki.adom.inc/adom/steven-led-nameplate/render/rev2/README.html" target="_blank">Rev 2</a>. Kept as the record of what was tried first.</td>
</tr>
</tbody>
</table>
<h2>The board, live</h2>
<iframe class="live" loading="lazy" allow="fullscreen" src="https://wiki.adom.inc/adom/steven-led-nameplate/render/rev1/viewer/index.html" width="100%" height="560" title="Steven nameplate Rev 1, interactive 3D"></iframe>
<p>Orbit, zoom, hover any part for its refdes and net, x-ray the copper with the Nets panel, or run
the guided walkthrough. The PCB, Schematic and Parts tabs across the top are live too.
<a href="https://wiki.adom.inc/adom/steven-led-nameplate/render/rev1/viewer/index.html" target="_blank">Open full screen</a>.</p>
<h2>The question this revision asked</h2>
<p>Can an AI, given one sentence, produce a manufacturable board that puts a person's name in lights
and runs off a phone charger, using the same pipeline (tscircuit, the Adom molecule library, the
adom-tsci viewer) that produced earlier Adom nameplates?</p>
<p>The prompt, verbatim, as typed by John Lauer on 2026-09-11:</p>
<blockquote>
<p>hey, we want to put Steven's name in lights on a pcb nameplate. put a usbc connector on the
right side of the board so he can plug it into his iphone. use adom-tsci and open it in the
webview when done.</p>
</blockquote>
<h2>Method</h2>
<ol>
<li><strong>Template.</strong> The AI started from <code>vijay-nameplate</code>, an earlier 3 x 5 LED nameplate on the
same stack, and changed the word, the board size and the connector position. The 3 x 5 font
came with it unexamined. That inherited assumption is the defect this revision records.</li>
<li><strong>Board size.</strong> Six letters at 3 mm pitch need 56 mm of text plus about 13 mm reserved for the
USB-C receptacle and its support parts, which does not fit the <code>80x24</code> molecule Vijay used.
It moved up to <code>96x24</code> (98.4 x 26.4 mm real outline).</li>
<li><strong>USB-C.</strong> The <code>UsbCReceptacle</code> wrapper was copied byte-for-byte from the adom-usbc guide and
placed with <code>mount=&quot;east&quot;</code> at <code>pcbX = W/2 - 4 = 44</code>. Two 4.7 kohm CC pulldowns (Rd) make a
USB-C charger turn VBUS on. A 100 nF capacitor bypasses VBUS.</li>
<li><strong>Build, then verify geometry, not just DRC.</strong> Every build ran <code>tsci build</code>, <code>adom-tsci lint</code>,
and a new union-find connectivity check (<code>source/scripts/check-connectivity.py</code>) that follows
copper pad to trace to via to pad, layer by layer.</li>
<li><strong>Iterate on layout until the router produced a fully connected board.</strong> See Results.</li>
</ol>
<h2>Results</h2>
<h3>Negative results: the router's silent opens</h3>
<p>The first build passed tscircuit's own checks for most nets, yet the board did not work. The
autorouter (tscircuit 0.0.1753) sometimes ends a bottom-layer trace directly under a top-layer
pad with no via. The trace carries an <code>end_pcb_port_id</code>, so both tscircuit and <code>adom-tsci lint</code>
count it as routed. Only the geometric check sees that nothing connects.</p>
<p>Every layout tried, in order:</p>
<table>
<thead>
<tr>
<th>Layout</th>
<th>DRC errors</th>
<th>Nets split into islands</th>
</tr>
</thead>
<tbody>
<tr>
<td>3 mm pitch, resistor 1.5 mm below LED (the Vijay layout)</td>
<td>6</td>
<td>3</td>
</tr>
<tr>
<td>same, resistors rotated 180 degrees</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>3.5 mm pitch, resistor 1.5 mm below</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>3.5 mm pitch, resistor 1.75 mm below</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>3.5 mm pitch, 1.9 mm / 4.5 mm letter gap / y offset 6.5 (three variants)</td>
<td>0 to 342</td>
<td>1 to 2</td>
</tr>
<tr>
<td>router preset <code>auto_cloud</code></td>
<td>n/a</td>
<td>59</td>
</tr>
<tr>
<td>router preset <code>sequential_trace</code></td>
<td>build fails on the molecule</td>
<td>n/a</td>
</tr>
<tr>
<td><strong>3.5 mm pitch, resistor 1.6 mm below, rotated 180 degrees</strong></td>
<td><strong>0</strong></td>
<td><strong>0</strong> (shipped)</td>
</tr>
</tbody>
</table>
<p>The same checker, run against the shipped <code>vijay-nameplate</code> this was copied from, found one real
open there too (R24 and R26 isolated from VBUS). That finding was reported, not fixed, since it
is a different board.</p>
<h3>Final numbers</h3>
<table>
<thead>
<tr>
<th>Check</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Components</td>
<td>128: 58 LEDs, 60 resistors, 1 capacitor, 1 USB-C, 4 test contacts, 4 machine pins</td>
</tr>
<tr>
<td>Routing</td>
<td>186 routed traces for 188 declared (the 2 are the merged same-net USB-C tabs), 78 vias</td>
</tr>
<tr>
<td>DRC errors in <code>circuit.json</code></td>
<td>0</td>
</tr>
<tr>
<td>Connectivity</td>
<td>62 of 62 nets, each one island</td>
</tr>
<tr>
<td>USB-C pad gap to edge</td>
<td>7.00 mm (guide window 5 to 8)</td>
</tr>
<tr>
<td>USB-C anchor hole gap to edge</td>
<td>1.83 mm (guide: more than 0.8)</td>
</tr>
<tr>
<td>USB-C mouth overhang</td>
<td>2.31 mm (guide window 2 to 3)</td>
</tr>
<tr>
<td>USB-C pads / holes</td>
<td>12 / 6</td>
</tr>
</tbody>
</table>
<h3>What went wrong: the N</h3>
<p><img src="https://wiki.adom.inc/adom/steven-led-nameplate/render/docs/img/n-glyph-rev1-vs-rev2.png" alt="The N in the 3 x 5 font next to the H from the same font" /></p>
<p>Three columns give an N nowhere to put its diagonal. The glyph becomes two verticals and a
bar near the top, which reads as an H. Seen in the top view, STEVEN reads closer to STEVEH.</p>
<p><img src="https://wiki.adom.inc/adom/steven-led-nameplate/render/docs/img/steven-v1-top.jpg" alt="Rev 1 top view" /></p>
<p>Other known gaps, all fixed in Rev 2:</p>
<ul>
<li>LEDs and resistors are generic (<code>color=&quot;white&quot;</code>, <code>220 ohm</code>) with no manufacturer part numbers.
The BOM in <code>rev1/fab/bom.csv</code> says so. A fab house could not assemble it without substitution.</li>
<li>520 mA exceeds the 500 mA a USB-C source guarantees without negotiation. Most phone chargers
advertise 1.5 A or 3 A through CC, so it would likely light, but it is out of spec.</li>
<li>The texture renderer shows the board at 2048 px, and the served GLB had to be checked for a
known cache bug (a 0-vertex USB-C body). It was clean: 46,644 vertices.</li>
</ul>
<h2>Reproduce this experiment</h2>
<h3>Tools used</h3>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Version</th>
<th>What it did here</th>
<th>Get it</th>
</tr>
</thead>
<tbody>
<tr>
<td>Claude Code, in Adom's Hydrogen desktop</td>
<td>Claude Opus 5</td>
<td>The AI that wrote the board, ran every build and check, and wrote this page</td>
<td>Adom Hydrogen</td>
</tr>
<tr>
<td>bun</td>
<td>1.4.0</td>
<td>JavaScript runtime that runs tscircuit</td>
<td><code>curl -fsSL https://bun.sh/install | bash</code></td>
</tr>
<tr>
<td>tscircuit, @tscircuit/cli</td>
<td>0.0.1753 / 0.1.1382</td>
<td>Board description in TSX, autorouter, DRC, gerber and GLB export</td>
<td><code>bun install --frozen-lockfile</code> (pinned in <code>bun.lock</code>)</td>
</tr>
<tr>
<td>@tsci/adom-inc.molecule, @tsci/adom-inc.library</td>
<td>1.1.15 / 1.1.14</td>
<td>Adom molecule outline and corner machine pins</td>
<td>same, through the <code>.npmrc</code> registry <code>npm.tscircuit.com</code></td>
</tr>
<tr>
<td>adom-tsci</td>
<td>1.4.24</td>
<td>Live 3D / PCB / schematic preview, <code>lint</code>, gerber export, walkthrough, the viewer embedded on this page</td>
<td><code>adom-wiki pkg install adom/adom-tsci</code></td>
</tr>
<tr>
<td>adom-usbc guide</td>
<td>ships with adom-tsci</td>
<td>The USB-C wrapper (copied verbatim) and the edge checks</td>
<td><code>~/.claude/skills/adom-tsci/guides/adom-usbc.md</code></td>
</tr>
<tr>
<td><code>scripts/check-connectivity.py</code></td>
<td>this page</td>
<td>Geometric pad-trace-via connectivity per net; catches opens DRC misses</td>
<td>Python 3 standard library</td>
</tr>
<tr>
<td><code>scripts/sweep.sh</code></td>
<td>this page</td>
<td>Parallel layout sweep, reports DRC errors and split nets per variant</td>
<td>bash + bun</td>
</tr>
<tr>
<td><code>scripts/make-bom.py</code></td>
<td>this page</td>
<td>Real BOM and pick-and-place spliced into the gerber zip</td>
<td>Python 3 standard library</td>
</tr>
<tr>
<td>glb-datauri-textures.mjs, glb-make-zup.mjs</td>
<td>adom-tsci page</td>
<td>Makes the 3D models load in the wiki's sandbox and lie flat</td>
<td><code>https://wiki.adom.inc/adom/adom-tsci/render/scripts/</code></td>
</tr>
<tr>
<td>pup (Adom Bridge)</td>
<td></td>
<td>The renders on this page, shot in a background browser</td>
<td><code>adom-bridge pup_open_window</code></td>
</tr>
<tr>
<td>adom-wiki</td>
<td></td>
<td>Publishing this page</td>
<td>preinstalled on Adom containers</td>
</tr>
</tbody>
</table>
<h3>What actually ran, in order</h3>
<ol>
<li>Read the adom-tsci and adom-usbc guides, then copied <code>vijay-nameplate</code> (lib, lockfile,
node_modules) to a new project and changed the word, board size and connector position.</li>
<li><code>bunx tsci build lib/index.tsx --glbs --svgs</code>, then read every <code>*_error</code> in <code>circuit.json</code>
and ran <code>adom-tsci lint</code>.</li>
<li>Wrote <code>scripts/check-connectivity.py</code> after seeing traces reported as routed that connected
nothing, and checked it against a known-good board (<code>bill-nameplate</code>: 0 split).</li>
<li>Swept layouts (the table above) by editing <code>GRID</code>, <code>LETTER_GAP</code>, <code>yOff</code> and the resistor
offset, rebuilding each in a scratch copy, until one came back 0 errors and 0 split.</li>
<li>Ran the adom-usbc edge check (pad gap, hole gap, overhang, pad and hole counts).</li>
<li><code>adom-tsci start . --texture-resolution 2048</code>, checked the console for a USB-C placeholder,
compared the served GLB's J1 vertex count with the tscircuit-built one, then took the
body-on and body-off USB-C screenshots and read them.</li>
<li><code>adom-tsci export --format gerbers</code>, then <code>scripts/make-bom.py</code> to replace the empty BOM.</li>
</ol>
<h3>Rebuild it yourself</h3>
<p>Everything needed is in <code>rev1/source/</code>. From a Linux or macOS shell with
<a href="https://bun.sh" target="_blank">bun</a> installed:</p>
<pre><code class="language-bash">adom-wiki repo download adom/steven-led-nameplate --extract ./steven
cd steven/rev1/source
bun install --frozen-lockfile          # pins tscircuit 0.0.1753, @tscircuit/cli 0.1.1382
bunx tsci build lib/index.tsx --glbs --svgs
python3 scripts/check-connectivity.py  # expect: 62 nets checked, 0 split
</code></pre>
<p>Expected: 0 entries whose <code>type</code> ends in <code>_error</code> in <code>dist/lib/index/circuit.json</code>, 186 routed
traces. The autorouter is deterministic for a fixed input and fixed package versions; a different
tscircuit version routes differently (Rev 2 shows how much).</p>
<p>To preview interactively: <code>adom-tsci start .</code> (Adom's viewer), or open
<a href="https://wiki.adom.inc/adom/steven-led-nameplate/render/rev1/viewer/index.html" target="_blank">the Rev 1 live viewer</a> on this page.</p>
<p>To fabricate: <code>rev1/fab/gerbers.zip</code> holds copper, mask, silkscreen, paste, outline and drill
files plus <code>bom.csv</code> and <code>pick_and_place.csv</code>. Do not fabricate Rev 1; build Rev 2.</p>
<h2>Outputs</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>What it is</th>
<th>License</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>rev1/source/lib/index.tsx</code></td>
<td>The board, as tscircuit TSX</td>
<td>MIT</td>
</tr>
<tr>
<td><code>rev1/source/lib/UsbCReceptacle.tsx</code></td>
<td>USB-C wrapper, verbatim from the adom-usbc guide</td>
<td>MIT</td>
</tr>
<tr>
<td><code>rev1/source/scripts/check-connectivity.py</code></td>
<td>Geometric net connectivity check</td>
<td>MIT</td>
</tr>
<tr>
<td><code>rev1/source/package.json</code>, <code>bun.lock</code></td>
<td>Exact dependency pins</td>
<td>MIT</td>
</tr>
<tr>
<td><code>rev1/viewer/circuit.json</code></td>
<td>Complete circuit description (netlist, placement, routing)</td>
<td>CC0</td>
</tr>
<tr>
<td><code>rev1/viewer/3d.glb</code></td>
<td>3D model, 2048 px board texture</td>
<td>CC0</td>
</tr>
<tr>
<td><code>rev1/fab/gerbers.zip</code></td>
<td>Fabrication files</td>
<td>CC0</td>
</tr>
<tr>
<td><code>rev1/fab/bom.csv</code>, <code>pick_and_place.csv</code></td>
<td>Assembly data</td>
<td>CC0</td>
</tr>
<tr>
<td>this document</td>
<td>Method, results, negative results</td>
<td>CC BY 4.0</td>
</tr>
</tbody>
</table>
<h2>Provenance</h2>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Requested by</td>
<td>John Lauer, Adom Industries (PI, NSF PCL Test Bed node, Fort Worth)</td>
</tr>
<tr>
<td>Designed by</td>
<td>Claude Opus 5 (Anthropic), running in Claude Code inside Adom's Hydrogen desktop</td>
</tr>
<tr>
<td>Toolchain</td>
<td>tscircuit 0.0.1753, @tscircuit/cli 0.1.1382, @tsci/adom-inc.molecule 1.1.15, @tsci/adom-inc.library 1.1.14, adom-tsci 1.4.24, bun 1.4.0</td>
</tr>
<tr>
<td>Template</td>
<td><code>vijay-nameplate</code> (Adom, 2026-09-11)</td>
</tr>
<tr>
<td>Human review</td>
<td>John Lauer viewed the live 3D preview and asked for the font change that became Rev 2</td>
</tr>
</tbody>
</table>
<p>Contributor roles (<a href="https://credit.niso.org/" target="_blank">CRediT</a>): John Lauer, conceptualization and
supervision. Claude (AI), design, software, validation, writing.</p>
<h2>Funding</h2>
<p>Adom Industries' electronics prototyping node is funded by the U.S. National Science Foundation
Programmable Cloud Laboratories (PCL) Test Bed program
(<a href="https://ror.org/021nxhr62" target="_blank">ROR 021nxhr62</a>). This nameplate was made as a worked example of
open publishing for the Astera Institute (<a href="https://ror.org/00ydx1s47" target="_blank">ROR 00ydx1s47</a>); Astera
did not fund it.</p>
</div><script>
(function(){var w=document.getElementById('wrap'),last=0;function post(){var h=w.offsetHeight+24;if(h!==last){last=h;parent.postMessage({type:'readme-height',height:h},'*');}}
post();addEventListener('load',post);addEventListener('resize',post);
document.querySelectorAll('img,iframe').forEach(function(e){e.addEventListener('load',post)});
if(window.ResizeObserver)new ResizeObserver(post).observe(w);[100,400,1200,3000].forEach(function(t){setTimeout(post,t)});})();
</script></body></html>