@o.z/ngspice-wasm
v0.0.0
Published
Ngspice circuit simulator compiled to WebAssembly with Emscripten
Readme
ngspice-wasm ⚡
Ngspice circuit simulator compiled to WebAssembly — Run SPICE simulations directly in the browser or Node.js, no native binaries required.
✨ Features
- 🌐 Browser & Node.js — Works everywhere JavaScript runs
- 📦 Zero native dependencies — Pure WebAssembly + JavaScript
- 📘 TypeScript support — Full type definitions included (
ngspice.d.ts) - 🔧 Reproducible builds — Build script included for transparency
- 🎯 Emscripten MODULARIZE — Clean ES6 module interface
- 💾 Memory growth — Automatically expands heap as needed
📦 Installation
# yarn
yarn add @o.z/ngspice-wasm
# npm
npm install @o.z/ngspice-wasm
# pnpm
pnpm add @o.z/ngspice-wasm🚀 Quick Start
Browser (ESM)
<script type="module">
import createNgspiceModule from "@o.z/ngspice-wasm";
const ngspice = await createNgspiceModule({
// Optional: load WASM from CDN instead of bundling
locateFile: (file) =>
`https://cdn.jsdelivr.net/npm/@o.z/ngspice-wasm@latest/${file}`,
});
// Write a netlist to the virtual filesystem
ngspice.FS.writeFile(
"/circuit.cir",
`
Voltage Divider
V1 1 0 DC 10
R1 1 2 1k
R2 2 0 1k
.op
.end
`,
);
// Run ngspice with command-line arguments
const exitCode = ngspice._main(
2,
ngspice.stringToUTF8("/circuit.cir", ngspice._malloc(100), 100),
);
console.log(`Exit code: ${exitCode}`);
</script>Node.js (ESM)
import createNgspiceModule from "@o.z/ngspice-wasm";
const ngspice = await createNgspiceModule();
// Use the virtual filesystem
ngspice.FS.writeFile("/test.cir", "* My circuit\nV1 1 0 DC 5\nR1 1 0 1k\n.end");
// Call ngspice C functions directly
const argc = 2;
const argvPtr = ngspice._malloc(argc * 4);
// ... set up argv ...
const result = ngspice._main(argc, argvPtr);
console.log("Simulation complete");Node.js (CommonJS)
const { default: createNgspiceModule } = require("@o.z/ngspice-wasm");
(async () => {
const ngspice = await createNgspiceModule();
// ... use ngspice ...
})();📘 API Reference
Module Factory
createNgspiceModule(options?: NgspiceModuleOptions): Promise<NgspiceModule>| Option | Type | Description |
| ---------------------- | ------------------------- | ------------------------------------ |
| noInitialRun | boolean | Skip automatic execution of main() |
| stdin | () => number \| null | Custom stdin handler |
| print | (text: string) => void | Capture stdout output |
| printErr | (text: string) => void | Capture stderr output |
| locateFile | (url, prefix) => string | Customize WASM file loading path |
| onRuntimeInitialized | () => void | Callback when WASM is ready |
| onAbort | (reason) => void | Callback on runtime abort |
Key Module Properties
interface NgspiceModule {
// Memory access
HEAP8: Int8Array;
HEAPU8: Uint8Array;
HEAP32: Int32Array;
HEAPF64: Float64Array;
wasmMemory: WebAssembly.Memory;
// Memory management
_malloc(size: number): number;
_free(ptr: number): void;
// String utilities
UTF8ToString(ptr: number): string;
stringToUTF8(str: string, outPtr: number, maxBytes: number): void;
// Virtual filesystem (Emscripten MEMFS)
FS: {
writeFile(path: string, data: string | Uint8Array): void;
readFile(path: string, opts?: { encoding: string }): string | Uint8Array;
mkdir(path: string): void;
// ... more FS methods
};
// ngspice C API (via EXPORT_ALL=1)
_main(argc: number, argv: number): number;
_ngSpice_Command(cmd: string): number;
// ... all exported C functions
}💡 Tip: Use
ngspice._ngSpice_Command("run")to execute ngspice commands programmatically.
🔨 Building from Source
If you need to rebuild the WebAssembly module (e.g., for a different ngspice version):
Prerequisites
# Emscripten SDK
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk && ./emsdk install latest && ./emsdk activate latest
source ./emsdk_env.sh
# Other tools
sudo apt install git make python3 nodejs # Debian/Ubuntu
# or
brew install git make python3 node # macOSBuild Steps
# Clone this repo
git clone https://github.com/z-wasm/ngspice-wasm
cd ngspice-wasm
# Run the build script
./builder.sh
# Output: ngspice.js + ngspice.d.ts in project rootBuild Options
Edit builder.sh to customize:
| Variable | Default | Description |
| -------------------- | ------------ | --------------------------- |
| NGSPICE_TAG | ngspice-46 | ngspice git tag to build |
| INITIAL_MEMORY | 256MB | Initial WASM heap size |
| STACK_SIZE | 10MB | Stack size for ngspice |
| CFLAGS / LDFLAGS | -O3 | Compiler optimization flags |
🧪 Testing
A simple browser demo is included:
# Serve the test page
npx serve .
# Open http://localhost:3000/test.html⚠️ Limitations
- ❌ No dynamic library loading —
dlopen()is disabled (WASM limitation) - ❌ No POSIX signals — Signal handlers are stubbed out
- ❌ No X11/GUI — Built with
--without-x - ⚠️ Single-threaded — pthreads disabled for WASM compatibility
- ⚠️ File I/O via MEMFS — Files exist only in memory unless explicitly exported
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Make your changes + test thoroughly
- Update documentation if needed
- Submit a pull request
Want to help? Check out open issues for good first contributions.
📄 License & Attribution
This package contains a WebAssembly build of ngspice.
ngspice Licensing
ngspice uses a mixed license model:
| Component | License | | ----------------------- | ------------- | | Core Spice3f5 | BSD-3-Clause | | Cider | Old BSD | | Xspice | Public Domain | | KLU, tclspice, numparam | LGPL-2.1 | | OSDI | MPL-2.0 |
📄 See COPYING for full license texts and attribution requirements.
This Build
Modifications, build infrastructure, and TypeScript definitions by Zero are licensed under BSD-3-Clause.
🔗 This project is not affiliated with the official ngspice project.
