Adom TSCI - Tscircuit Board Viewer

Install

Interactive tscircuit board viewer in a Hydrogen webview — first-class 3D / PCB / Schematic tabs, an Inspect tool, a Fusion-style Measure tool, net x-ray, guided Walkthrough demos, one-click autorouter re-run, and auto high-res board-surface texture. Fully AI-drivable (CLI + HTTP + JS eval). Also publishes molecules/boards to the Adom Wiki.

adom-wiki pkg install adom/adom-tsci

Latest: v1.4.24, published

Contents

Tscircuit Board Viewer (adom-tsci)

Interactive tscircuit preview inside a Hydrogen webview panel. First-class 3D / PCB / Schematic tabs rendered from the tscircuit build output, plus:

  • 🔍 Inspect tool (key I) — hover any feature for a labelled info card: chip refdes + footprint + pin count, pad → net routing ("Connects to MC1.pin1, TP1.pin1 via 2 direct traces"), machine- contact role (mechanical-only vs wired), board stackup + baked- texture resolution, silkscreen text.
  • 📏 Measure tool (key M) — Fusion 360-style picking (pad / hole / chip / pin / edge), precision + mm/inches/mils.
  • 🎬 Walkthrough Demo — narrated tour generated deterministically from circuit.json by adom-tsci walkthrough-gen (connectors → ICs → grouped passives → nets x-ray), with 3D flyover animations. Connector edges are computed (not hardcoded), long ref lists are capped, and it finishes on the ViewCube Home view with the Nets/x-ray panel turned off. Don't hand-edit walkthrough.json — it auto-regenerates on circuit.json drift.
  • ⟳ Re-run autorouter — one click touches lib/index.tsx + spawns bunx tsci build --glbs --svgs.
  • --texture-resolution N — re-bakes the board-surface texture (silkscreen + copper pads + annular rings + solder mask) up to 8192×8192 via circuit-json-to-gltf, cached by circuit.json content hash. Essential for readable silkscreen on big boards.
  • Stale-deps check against @tscircuit/cli on startup.
  • Secondary tabs: tsci live (raw RunFrame) and 3d compare.

Recent (1.4.x):

  • Canonical Adom app-header — one-row brand · subject · actions with a hover app-info popover (version / engine / wiki / GitHub), brand fonts (Familjen Grotesk / Satoshi / JetBrains Mono), Adom-teal accent.
  • Parts inspector lists EVERY component, grouped by kind (Resistors 92, LEDs 90, …) with collapsible groups — passives are no longer hidden.
  • Ground plane is 65% transparent and self-heals — the bottom layer / bottom silkscreen show through; a footer readout reports the live transparency so a regression to opaque is caught instantly.
  • Panel deep-linking#3d / #pcb / #schematic / #parts / #tsci-live URL hashes select a panel (shareable + AI-drivable).
  • view home — CLI/HTTP preset for the ViewCube Home view.
  • TTY-gated CLI color so OK:/ERROR:/Hint: never leak ANSI into pipes.

As of v0.3.0 the 3D tab is fully AI-drivable: every toolbar button has a CLI subcommand + HTTP endpoint, plus there's a /eval channel for hot-patching the running JS and a /console forwarder so Claude can read uncaught errors without clicking anything. No Adom Viewer service dependency — the Adom 3D viewer library is bundled into the binary.

As of v0.4.1, adom-tsci start does a pre-flight /proc sweep for stale bun tsci dev processes and cleans them up before spawning, plus holds an atomic PID lock at /tmp/adom-tsci-<port>.pid. No more orphan tsci devs compounding across crashed restarts.

3D tab — first-class, default

Credit to Ray

This app is an onboarding layer over Ray's authoritative tscircuit workflow guide at ~/.claude/skills/adom/guides/adom-tscircuit-skill.md. Everything it does with tscircuit — the <Molecule> component, MachineContactMedium placement rules, the sizing grid, the DRC notes, the bunx tsci build --glbs --svgs flags, the project skeleton — traces back to Ray's guide. Go read it for connector families, molecule generators, review servers, and DRC tooling. adom-tsci just makes the "show me what I'm building" step trivial.

The UI

Primary tabs:

  • 3D (default). Full-bleed canvas rendered by the Adom 3D Viewer (Babylon-based engine, bundled into the binary — no AV). Contact shadow + 65%-transparent ground plane (the board's bottom layer / silkscreen show through; a footer readout reports the live transparency). The ViewCube (top-right) handles Home / Fit / view presets; a floating draggable toolbar over the canvas carries ▭ ground, ⎚ wireframe, axes, 📏 measure, inspect, and the walkthrough. Floating component panel lists every chip / passive / testpoint / contact from circuit.json — click a row to hide that component and see the traces routed under it.
  • PCB. Inline dist/lib/index/pcb.svg in a panzoom container.
  • Schematic. Inline dist/lib/index/schematic.svg, same panzoom.
  • Parts. Inspector listing every component grouped by kind (Connectors / LEDs / Resistors / Capacitors / Machine pins …) — click any to verify its footprint ↔ 3D-body alignment.

PCB tab

Schematic tab

Parts inspector — every component grouped by kind

Secondary tab:

  • tsci live. The raw tscircuit RunFrame through a slingshot proxy. Escape hatch for features upstream tscircuit ships that we haven't wrapped yet. Dimmed 0.78 because RunFrame is hardcoded-light-theme.

The Re-run autorouter button

Top-right of the header, right next to the GLB timestamp pill.

Re-run autorouter flow

Click it to:

  1. Touch lib/index.tsx via the slingshot → tsci dev file server. Fires a FILE_UPDATED event, RunFrame's in-memory view refreshes.
  2. Spawn bunx tsci build lib/index.tsx --glbs --svgs in the background. Regenerates the on-disk 3d.glb, pcb.svg, and schematic.svg, which the first-class tabs poll for (/glb/meta every 3 s). Within ~30 s the 3D tab re-renders with the new layout and the PCB + Schematic tabs re-fetch on next click.
  3. Shift-click for a clean re-run — also deletes manual-edits.json first so any interactive trace edits made in RunFrame's PCB editor are discarded.

Same from the CLI: adom-tsci rerun or adom-tsci rerun --clean.

Stale-deps check

adom-tsci start fires a background query against https://registry.npmjs.org/@tscircuit/cli/latest on launch and compares to the version in <project>/node_modules/@tscircuit/cli/package.json. If you're behind, you get one HINT: line:

HINT: @tscircuit/cli is out of date (installed 0.1.1226, latest 0.1.1234).
Run `adom-tsci upgrade` to refresh.

Non-fatal, 3-second timeout, never blocks startup. tscircuit does daily releases; this nudges you when you drift behind.

adom-tsci upgrade [project-dir] shells out to bun update --latest in the target project.

Quick start

# Install (one-time)
adom-wiki pkg install adom/adom-tsci

# From inside a tscircuit project directory:
adom-tsci start .

# Edit lib/index.tsx, click ⟳ Re-run autorouter in the header,
# watch the 3D / PCB / Schematic tabs re-render.

# When done:
adom-tsci stop

If you don't have a tscircuit project yet, see the adom-tscircuit skill for the 4-file skeleton.

Demo video

A 4-minute feature tour of everything in 1.2.0 is published at apps/adom-tsci on the wiki — 34 scenes with TTS narration, recorded against the RP2040 dev-board molecule.

The full demo pipeline (scene script, TTS generation, per-scene recording, mux + concat) lives under demo/ and is reproducible — see demo/README.md. Run it against any tscircuit project to re-cut the tour.

Examples

Ready-to-build example molecules live under examples/ — clone, bun install, and adom-tsci start <example-dir> to preview.

examples/SN65HVD230-Molecule/

Small reference molecule: a Texas Instruments SN65HVD230 CAN transceiver in SOIC-8, wrapped in a 16×16 mm molecule with power + CAN bus broken out to six MachineContactMedium pins. Includes a 100 nF decoupling cap, the 120 Ω CAN bus termination resistor, and per-pin silkscreen labels.

SN65HVD230 PCB with silkscreen labels

examples/BME680-Breakout-Molecule/

Environmental-sensor breakout: a Bosch BME680 four-in-one sensor (temperature, humidity, barometric pressure, and a heated metal-oxide gas-resistance plate that tracks VOC concentration) in a 3×3 mm LGA-8 package, wrapped in a 24×16 mm molecule. Power + I²C bus + the two SPI-only pins (SDO, CSB) are broken out on six MachineContactMedium pins. Internally: 100 nF decoupling on each supply rail (VDD and VDDIO), 10 kΩ pull-ups on SDA and SCL, and a third 10 kΩ from CSB→VDDIO so the chip boots into I²C mode (address 0x77 by default; tie SDO low at the host to switch to 0x76 and run two BME680s on one bus). One <testpoint> per broken-out signal for probing-workcell access, and a bottom-silk ID card (part number, function, I²C address, supply range, revision).

BME680 PCB with silkscreen labels

examples/BHI360-Breakout-Molecule/

Motion-sensor breakout: a Bosch BHI360 6-axis IMU (accelerometer + gyroscope) with a built-in Fuser2 DSP core that runs orientation-fusion firmware on-chip, so the host MCU can stay asleep while the sensor tracks motion. LGA-20 (3×2.5 mm) package, wrapped in a 24×24 mm molecule. Eight MachineContactMedium pins break out the SPI/I²C interface (CSB / SCK / SDI / SDO, left edge) and power + interrupt (INT / VDD / VDDIO / GND, right edge) — tie CSB high at the host to select I²C, leave it driven for SPI. Internally: 100 nF decoupling on each supply rail (VDD core + VDDIO I/O), silkscreen section headers (SPI/I2C / PWR), a bottom-silk ID card, and one 0.8 mm <testpoint> per broken-out signal for probing-workcell access.

Demonstrates an LGA-20 part on a footprinter that only ships qfn/son/dfn/bga primitives — qfn20_w4mm_h4mm_p0.5mm is used as the closest spatial match (QFN pads sit where the LGA pads land on the bottom of the package).

BHI360 3D breakout

BHI360 PCB with silkscreen labels

examples/iCE40HX1K-VQ100-Molecule/

Big FPGA breakout: a Lattice iCE40HX1K in a 14×14 mm TQFP-100 (VQ100) package, wrapped in a 56×56 mm molecule that breaks out all 100 chip pins to MachineContactMedium contacts on the matching edge. Each pin also gets a dedicated <testpoint> for probing-workcell access.

Silkscreen sections group the pins functionally: SPI (programming), PROG (CRESET/CDONE), IO BANK 0/1/2/3, plus a NO USB / NO UART / NO SWD reminder — the iCE40 is an FPGA, not an MCU, so there's no debug port in the ARM sense; you program it through the SPI pins (pins 67–71) via an iCELink/FT232 adapter and boot from a downstream SPI flash.

iCE40HX1K 3D breakout

iCE40HX1K PCB with silkscreen sections

examples/iCE40HX1K-USB-Molecule/

Same iCE40HX1K FPGA, now with USB-C programming built in — an "easy to use FPGA dev board." Plug a USB-C cable from your host into the board and load a bitstream with iceprog or fujprog. No external programmer, no JTAG dongle, no manual pin wiring.

Onboard stack:

  • USB-C receptacle with ESD protection (USBLC6-2P6)
  • FT2232H — dual-channel USB→SPI/UART bridge. Channel A in MPSSE mode talks to the iCE40's SPI programming pins (iceprog-compatible). Channel B is a USB-UART console you can attach to a soft-UART running inside your FPGA bitstream.
  • W25Q16JV 2 MB SPI boot flash — the FT2232H writes your bitstream here, and the iCE40 reads from it on power-up so the board boots standalone without a host.
  • AP7333-33 (3.3 V) and AP2112-1V2 (1.2 V) LDOs from USB 5 V for FPGA VCCIO + VCC core rails
  • 12 MHz crystal for the FT2232H, 93LC56B EEPROM for its USB VID/PID
  • 32 GPIO + 3 power contacts broken out on the molecule edge
  • Programming pass-through — 6 edge contacts on the left side (SCK / SS / SO / SI / CRESET / CDONE, marked with a → VQ100 PROG silkscreen callout) that carry the FT2232H's SPI bus out to mate with a downstream iCE40HX1K-VQ100-Molecule. Dock that molecule here and a single iceprog invocation reaches the bare FPGA through this board's onboard USB bridge.
  • 16 test points on the critical nets (VBUS, 3V3, 1V2, GND, USB D+/- on both sides of the ESD chip, the SPI programming bus, CRESET/CDONE, UART TX/RX) as SMT copper pads for a probing workcell's pogo pins — footprintVariant="pad", 1 mm diameter, top layer

iCE40HX1K USB dev board — 3D

iCE40HX1K USB dev board — PCB

Architecture

+---------------------------+        +---------------------------+
|  Hydrogen webview tab     |        |  adom-tsci (Rust)         |
|  /proxy/8850/             |<------>|  tiny_http on 8850        |
|                           |        |                           |
|  +----------+             |        |  /              shell.html
|  |   3D     |<------------+------->|  /glb           file stream
|  +----------+             |        |  /pcb.svg       file stream
|  |  PCB     |             |        |  /schematic.svg file stream
|  +----------+             |        |                           |
|  | Schematic|             |        |  /runframe/     slingshot
|  +----------+             |        |  /runframe/api/*  (proxy)
|                           |        |  /runframe/standalone.min.js
|  +----------+             |        |                           |
|  | tsci live|<------------+------->|  /runframe/…    slingshot
|  +----------+             |        |                           |
|                           |        |  /basic-3d.html     (legacy)
|                           |        |  /js/adom-3d-viewer.min.js
|                           |        |  /js/environmentSpecular.env
|                           |        |                           |
|                           |        |  /console  /eval  /eval/* (AI bridges)
|                           |        |  /api/set-view /api/set-camera
|                           |        |  /api/toggle   /api/toggle-component
|                           |        |  /api/components   /api/tour
|                           |        |  /rerun /reload /shutdown /health
|  ⟳ Re-run autorouter -----+------->|                           |
+---------------------------+        +---------------------------+
                                              |
                                              v
                                    +--------------------+
                                    | bun tsci dev       |
                                    |   -p 3040          |
                                    | (process group)    |
                                    +--------------------+

The slingshot fix (why this app exists)

tsci dev emits a hardcoded absolute URL in its HTML shell:

window.TSCIRCUIT_FILESERVER_API_BASE_URL = "http://127.0.0.1:3040/api";

Inside a Hydrogen webview iframe, 127.0.0.1 is the user's machine, not the container — so every fetch fails and RunFrame hangs at loading... forever. adom-tsci's slingshot rewrites that line (and the absolute /standalone.min.js script tag) to relative paths, then transparently proxies /runframe/api/* to tsci dev on port 3040.

v0.2 note: the v0.1 proxy handler had a bug where route-match query-string stripping also dropped the query string on forward, breaking files/get?file_path=.... v0.2 ships a full method/body/ query-aware proxy handler. If you're upgrading from v0.1, this is why your tabs suddenly work.

tsci dev uses HTTP polling (/api/events/list?since=<id>), no WebSockets, so the slingshot is a plain HTTP forwarder.

CLI commands

See SKILL.md for the full reference. Summary:

Command Purpose
start <dir> Spawn tsci dev, start slingshot, open webview tab
stop Clean shutdown (kills whole tsci process group)
status [--json] Query running instance state
open Re-add or navigate webview tab
reload Force first-class tabs to re-poll build outputs
rerun [--clean] [--fast] Re-run the autorouter (touches .tsx + spawns build)
upgrade [dir] bun update --latest in target project
health Probe tsci_reachable
install Drop SKILL.md into ~/.claude/skills/adom-tsci/
AI-drive the 3D viewer
view <preset> home (ViewCube Home)/front/back/left/right/top/bottom/iso
camera [--alpha A] [--beta B] [--radius R] Raw camera position
tour start | stop Cinematic slow-orbit
toggle <flag> Flip ground/wireframe/axes
toggle-component <NAME> [--hide | --show] Show/hide a component (e.g. U1 to see traces)
list-chips List components the UI discovered in the current GLB
eval "<js>" Run JS inside the webview, print the result
console [--follow] Tail the forwarded JS console (logs + uncaught errors)

HTTP API

Every state-mutating CLI command is a thin wrapper over an HTTP endpoint. AI agents and shell scripts can curl them directly:

curl http://127.0.0.1:8850/health
curl http://127.0.0.1:8850/glb/meta
curl -X POST http://127.0.0.1:8850/rerun
curl -X POST "http://127.0.0.1:8850/rerun?clean=1"
curl -X POST http://127.0.0.1:8850/shutdown

See SKILL.md for the full reference.

Development

git clone https://github.com/adom-inc/adom-tsci
cd adom-tsci
cargo build --release
cp target/release/adom-tsci ~/.local/bin/
adom-tsci install

Rust 1.70+, standard cargo toolchain. Unit tests cover the slingshot HTML rewrite (the load-bearing regex):

cargo test

Known v0.3 limitations

  • Component mapping coverage is partial. The UI groups GLB meshes by nearest pcb_component centroid; some multi-mesh components (especially SOIC/SOT bodies with many primitives) can end up split across neighbouring names or fall into the Board catch-all. Kind-aware tolerances (chip=10mm, testpoint=1.2mm, contact=2mm, …) get most of the obvious ones right; edge cases tracked for v0.4.
  • The tsci live tab is dimmed (filter: brightness(0.78)) because tscircuit's RunFrame is hardcoded light-theme. When they ship a dark mode, the filter comes out.
  • Re-run autorouter rebuilds the whole circuit, not just the autorouter. tscircuit doesn't expose a standalone "run just the autorouter" entry point — the only way to refresh route layouts is to re-evaluate the circuit, which runs the whole pipeline. On a single-chip molecule this takes ~30 seconds.
  • GLB is bundled into the binary (the adom-3d-viewer.min.js library is 13 MB, environmentSpecular.env is ~270 KB), pushing the release binary to ~18 MB. Trade-off: self-contained, zero runtime dependencies, offline-friendly.

Design document

The original design plan lives at docs/design/valiant-herding-dove.md, preserved from the v0.1 planning session. Every non-obvious choice (Rust over Bun, three.js in the generic pane, port 8850, the "don't touch Ray's guide" boundary, why the slingshot uses a regex rewrite) is documented there. v0.2 adds the first-class tabs, rerun button, upgrade check, and the renamed binary on top of that foundation — see the commit history for the v0.1 → v0.2 evolution.

Acknowledgements

  • Ray — for the tscircuit workflow guide this app exists to support.
  • tscircuit — for the DSL and the RunFrame bundle.
  • The Adom platform team — for the webview panel API, Basic3dView, serve_glb, the shotlog service, the brand guide (icons must be monochrome #e6edf3 — this app's favicon follows that rule), and the hydrogen-tab-icons skill that documents how tab icons actually work.

License

MIT. See LICENSE.