Phase 1a of the mixed-mode simulator project. Vendors prebuilt
ngspice+XSpice WASM artifacts from ejkreboot/ngspice-xspice-wasm (MIT,
2026) and adds a TypeScript client that exposes the ngspice shared
callable API for interactive (event-driven) use.
What's vendored at frontend/public/wasm/ngspice-interactive/ (~27 MB):
- ngspice-lib.wasm (24 MB) — ngspice 33 + XSpice, MAIN_MODULE
- ngspice-lib.js (2.7 MB) — Emscripten glue
- {analog,digital,xtradev,xtraevt,table,tlines,spice2poly}.cm
— XSpice code models, loaded dynamically
- spinit — ngspice startup script
- PROVENANCE.md — sources + license info
Note on the cost: 27 MB is a one-way commit to git history, but the
existing eecircuit-engine dependency already ships 39 MB in node_modules
(not tracked, re-downloaded per build). Vendoring our copy:
- removes a third-party npm dependency
- pins the exact build we tested with
- means the WASM is served as a static asset (no Vite chunking)
The alternative (publish as @velxio/ngspice-interactive-wasm) was
deferred to keep the iteration cycle fast during Phase 1+.
New TypeScript client at frontend/src/simulation/spice/wasm/:
- NgSpiceInteractive.ts — Promise-based client class with
init / loadNetlist / command /
alter / readVec / reset / dispose
- ngspice-interactive-worker.js — vendored from ejkreboot's worker
and extended with 'loadNetlist',
'command', 'readVec' message types
plus per-command stdout/stderr
capture
POC test at __tests__/ngspice-interactive.test.ts (skipped in node env
because Worker isn't available; runs in a browser-mode test env):
- voltage divider .op → reads v(mid) ≈ 2.5V
- RC step → reads v(cap) time series, final ≈ 5V
- alter Vsrc → second .tran → final ≈ 1V (proves alter+rerun works)
Known limitation deferred to Phase 1b: the vendored WASM is built
without pthreads (no -sUSE_PTHREADS=1), so ngspice's bg_run is
synchronous-blocking. True mixed-mode event injection requires a
pthread-enabled rebuild (with SharedArrayBuffer + cross-origin
isolation). For Phase 1a we use the workaround: chained short-tran
invocations with `alter` between them. The new architecture is built
to swap in a real bg_halt/bg_resume implementation later without
changing component handlers — see NgSpiceInteractive.ts docstring.
Tests passing:
- pin-resolver (Phase 0): 8/8
- ngspice-interactive: 3 skipped (need browser env)
- tsc --noEmit on the new files: clean