techmannih/museview
A 50×35 mm USB‑C 5 V camera board combining an ESP32‑S3 module, M0031 parallel camera connector, buck/LDO power rails, USB/ESD protection, controls, status LED, and passives.
- Version
- 0.1.18
- License
- unset
- Stars
- 1
docs/routing.md
# Routing and reproducibility
V1.1 uses a 50 × 35 mm outline. The source circuit, local bypasses, FPC fanout, copper planes and RF exclusion are defined in `index.circuit.tsx`. All assembly is on top. Signal routing uses the two outer copper layers; L2 is GND and L3 is VDD_IO.
The remaining copper is generated by `scripts/route-grid.py` on a 0.05 mm grid from tscircuit's exported geometry. USB data contacts escape under the receptacle; active ESP32 signal pads escape toward the free area under the module. Local ground and I/O supply spurs terminate directly on their planes. All fixed and generated vias use 0.30 mm drills and 0.60 mm copper pads (0.15 mm annular rings). The board declares `minViaHoleDiameter={0.3}` and `minViaPadDiameter={0.45}`. The pad minimum is a lower bound; `pcbStyle` and the explicit vias retain actual 0.60 mm pads. The generator reads the captured minima and selects a pad of at least drill + 0.30 mm, preserving the 0.15 mm annular ring and reserving its full clearance. Feedback traces are routed before plane drops, with JTAG_TDO routed after the camera bus to keep the larger via escapes clear. C4's ground via is at (-13, 10.1) mm to clear its pad and the antenna exclusion. The router checks expanded pad, fixed-track, via, hole, RF and board-edge obstacles, then joins each remaining net.
`routing/input.simple-route.json` is the exact native routing input. `routing/geometry.json` contains the source/port/placement records needed by this board-specific generator, including the explicit USB ESD bypass and 39 fixed vias. These are regeneration inputs, not manufacturing files. Python 3.11+ and the pinned NumPy package in `routing/requirements.txt` are needed only to regenerate routing. Bun builds replay the checked copper without Python.
```sh
python3 -m venv .venv
.venv/bin/pip install -r routing/requirements.txt
bun run capture:routing
PYTHON=.venv/bin/python bun run regenerate:routing
bun run verify
```
The generator refuses to replace `pcb-routes.json` if any connection fails. `scripts/board-router.ts` then replays that copper only when the geometry/net fingerprint matches the current tscircuit input. Native DRC, exact endpoint checks and the separate Gerber short analysis still run. GitHub CI regenerates the copper, checks that the saved file matches, and runs the full verification suite.
When changing electrical values, nets or placement, run `bun run capture:routing` to capture native prerouting geometry from the current JSX source. This uses an empty capture-only router and never exports that unrouted intermediate as manufacturing output. Regenerate the grid copper and run the full verification suite next. The fingerprint now includes the hardware contract, so divider-value or power-net changes also invalidate replay even if physical coordinates are unchanged. Ordinary schematic display-text edits remain excluded. Never copy a fingerprint onto stale routes.
After verification, update and compare the 2D and 3D snapshots and run `bun run export:release`. All exported drills are through plated L1–L4 or nonplated. There are no blind/buried drills. The bottom stencil is intentionally empty; bottom copper is routing, with no fitted components. Recheck JLC rotations, stackup and physical USB/camera operation before production.
The snapshot tool's optional selector route-cache writer may warn that a via selector is ambiguous. That secondary cache is not used; the explicit geometry-guarded route file supplies the copper.
## Viewer troubleshooting
The 2026-10-04 report of 137 errors came from a checkout without local dependencies, running global tscircuit 0.0.2308. Its browser renderer rejected the saved routing fingerprint; the 134 disconnected ports and two missing traces followed from that rejection. Use the locked tscircuit 0.0.2687 installation with `bun run dev`, stop the old server, and reload the browser. The launcher now checks the installed version before starting the local CLI. Do not remove the fingerprint guard or copy an expected hash over stale copper.
The pinned viewer also runs supplier orientation analysis. This exposed D1's unused pin-label map: native numbering put the anode at pin 1, while C193402 numbers the cathode as pin 1. The import now explicitly maps pin 1/cathode to the west VBUS_5V pad and pin 2/anode to the east GND pad. The electrical contract and a regression test enforce this. The TVS symbol is imported from `imports/SMF5_0A/TVSSymbol.tsx`, with explicit cathode/anode ports and drawing paths. Its upper cathode bar connects to VBUS_5V; its lower anode connects to GND. Native routing inputs and route endpoints were regenerated for the corrected port identities; physical pad positions, net geometry, component rotations and copper paths are unchanged. JLC's actual assembly placement preview remains pending.
### Missing TVS symbol
The published v0.1.11 viewer displayed `Symbol not found: avalanche_diode_sm_up`, although the pinned local renderer could draw it and the cloud build passed. Build success did not establish viewer symbol compatibility. D1 now imports a self-contained unidirectional TVS symbol instead of requesting that catalog entry. The drawing, labels and numbered ports are included in circuit JSON, keeping C193402 pin 1 as the cathode. This is a schematic-only change.
`bun run check:schematic-render` renders every sheet, rejects missing-symbol diagnostics and verifies the embedded TVS cathode bar, triangle and both leads. It runs in verification and release export; regression tests also reject reverting D1 to the catalog-only symbol. The published viewer must still be inspected after deployment because its renderer is versioned independently.
### Published tscircuit.com renderer
The hosted compatibility capture was repeated on 2026-10-05 after the 0.30 mm via reroute. Its complete routing-input fingerprint is `904ff28e-139073e2-1060756`, versus the pinned input `c6bc715a-6984f1ee-1060756`. Capturing the same source with tscircuit 0.0.2744 / core 0.0.2079 showed exactly four changes: obstacles 257–260 use `type: rect` instead of `type: oval`. These are the four unconnected, all-layer mounting-hole keepouts, each 4.6 × 4.6 mm at (±22.25, ±14.75). Core 0.0.2021 emitted ovals; the newer core emits their bounding rectangles.
The grid router uses these rectangular bounds. Both runtime captures describe the same current placement, nets and regenerated copper. `board-router.ts` accepts this one reviewed **complete input fingerprint**, only when the saved routing still has its corresponding original fingerprint. No shapes, dimensions, nets or other fields are removed from fingerprinting. Every other input continues to fail closed. The added replay tests check identical returned copper for both captures and rejection of moved/resized keepouts, changed layers, changed pad shapes and changed nets.
This compatibility entry is specific to this routing revision. A future renderer or design change needs a fresh capture, full input comparison and verification; do not add its hash merely to dismiss the error. Use the pinned release pipeline for fabrication exports. Website edits must also be saved/published: pushing GitHub alone does not update a separately published registry release.
### Cloud sandbox file-size failure
Release v0.1.5 failed before circuit compilation while copying repository files into the cloud sandbox. The [build log](https://tscircuit.com/techmannih/museview/releases/a095f8d4-827e-4740-89f3-d1a58d011f7a) reports a 46,622,166-byte serialized RPC payload against a 32 MiB limit. The next input after the successfully copied GLB was the 23,312,026-byte assembled `release/museview-v1.step`.
The assembled model is now distributed as `release/museview-v1-step.zip`; extracting it restores the full STEP. The [GitHub importer filter](https://github.com/tscircuit/api.tscircuit.com/blob/01251be3e667f5f4b03e488bc4ed214bf7caec4f/lib/github/file-filter.ts) skips ZIP files, so the large handoff artifact is not a cloud build input. Individual component STEP/OBJ assets under `imports/` remain in the package. `export:release` generates the loose assembled STEP under ignored `dist/release/` before packaging it; `check-handoff.mjs` validates the archive and rejects loose release STEP files.
`ignoredFiles: ["release/**", ...]` also prevents generated handoff files from entering the local dev file server. This setting alone does not fix GitHub cloud imports, which use their own fixed filter. A new GitHub sync/release is needed; retrying the already-copied v0.1.5 file set will repeat the failure. No electrical, routing, schematic or 3D geometry changes are part of this packaging fix.
## Layer review, 2026-10-05
Four layers are retained for this revision. The inner layers are active: the regenerated routing includes 25 top-to-GND-plane and 16 top-to-VDD_IO-plane transitions, in addition to explicitly placed bypass/ground vias. All 176 via barrels span L1–L4; a route transition to an inner plane does not denote a blind via. The outer signal routing includes 841 bottom-layer wire points. Removing the inner copper would disconnect the current power/ground distribution and change its return paths.
A two-layer ESP32-S3 design is possible in principle. Espressif's [PCB layout guidelines](https://docs.espressif.com/projects/esp-hardware-design-guidelines/en/latest/esp32s3/pcb-layout-design.html) recommend four layers, and describe two layers with minimal bottom routing and a continuous ground plane. This board uses a WROOM module, so chip-level RF layout rules are not all baseboard requirements. The present dense baseboard does use its planes; a two-layer version needs rerouted power, a reviewed ground pour and USB return paths. No two-layer layout has been qualified in this revision. This assessment preserves the existing 50 × 35 mm component placement rather than claiming four layers are mandatory for every implementation.
An [isolated two-layer routing trial](layer-feasibility.md) subsequently completed the generated routes but failed native ground connectivity checks. Polygon analysis found separate C13/C16 and J2.DGND ground islands, and USB reference-coverage sampling found gaps. That draft was rejected before manufacturing export; the four-layer source and release artifacts remain unchanged.
J1 now uses tscircuit's native `standard="usb_c"` schematic, with grouped VBUS/CC/data/GND pins and S1–S4 shield tabs below. Supplier pad numbering is retained: pins 7/9 are D− and 8/10 are D+. The contract rejects changes to that mapping. Its exact footprint and user-supplied CAD alignment are unchanged.