Adom TSCI - Tscircuit Board Viewer
Public Made by Adomby adom
Interactive tscircuit preview in a Hydrogen webview — first-class 3D / PCB / Schematic tabs, Components & Nets HUDs, an auto-glow x-ray view, Inspect, Measure, a Walkthrough Demo, and a one-click `exp
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.jsonbyadom-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-editwalkthrough.json— it auto-regenerates oncircuit.jsondrift. - ⟳ Re-run autorouter — one click touches
lib/index.tsx+ spawnsbunx tsci build --glbs --svgs. --texture-resolution N— re-bakes the board-surface texture (silkscreen + copper pads + annular rings + solder mask) up to 8192×8192 viacircuit-json-to-gltf, cached bycircuit.jsoncontent hash. Essential for readable silkscreen on big boards.- Stale-deps check against
@tscircuit/clion startup. - Secondary tabs:
tsci live(raw RunFrame) and3d compare.
Recent (1.4.x):
- Canonical Adom app-header — one-row
brand · subject · actionswith 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-liveURL 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.

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.svgin 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.



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.

Click it to:
- Touch
lib/index.tsxvia the slingshot →tsci devfile server. Fires aFILE_UPDATEDevent, RunFrame's in-memory view refreshes. - Spawn
bunx tsci build lib/index.tsx --glbs --svgsin the background. Regenerates the on-disk3d.glb,pcb.svg, andschematic.svg, which the first-class tabs poll for (/glb/metaevery 3 s). Within ~30 s the 3D tab re-renders with the new layout and the PCB + Schematic tabs re-fetch on next click. - Shift-click for a clean re-run — also deletes
manual-edits.jsonfirst 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.

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).

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).


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.


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 PROGsilkscreen callout) that carry the FT2232H's SPI bus out to mate with a downstreamiCE40HX1K-VQ100-Molecule. Dock that molecule here and a singleiceproginvocation 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


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
Boardcatch-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.jslibrary is 13 MB,environmentSpecular.envis ~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 thehydrogen-tab-iconsskill that documents how tab icons actually work.
License
MIT. See LICENSE.
# 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.

## 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.



**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.

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
```bash
# 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](https://wiki.adom.inc/adom/adom-tsci)
— 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/`](demo/) and is
reproducible — see [`demo/README.md`](demo/README.md). Run it against
any tscircuit project to re-cut the tour.
## Examples
Ready-to-build example molecules live under [`examples/`](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.

### `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).

### `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).


### `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.


### `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


## 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:
```js
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`](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:
```bash
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`](SKILL.md) for the full reference.
## Development
```bash
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):
```bash
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`](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](LICENSE).