quantum-forge
v3.1.1
Published
Quantum Forge WASM loader, quantum() handle API, and Vite plugin for quantum game development (Qutrit Edition d3n12 + Qubit Edition d2n20).
Maintainers
Readme
quantum-forge
Real quantum mechanics for game developers. Superposition, entanglement, and interference powered by a compiled C++ quantum simulator running via WebAssembly.
This package is everything you need to put quantum mechanics in a game: the WASM simulator, quantum property handles, and a Vite plugin. It has no runtime dependencies and works with any renderer or engine.
Install
npm install quantum-forgeTry the example
Quantum Pong ships inside this package. It needs nothing else, so a copy that runs means your install works:
npx quantum-forge example my-pong
cd my-pong
npm run dev # play it in the browser
npm test # play it headless against the same WASMIts logic/QuantumRegistry.ts holds every quantum call the game makes, and is the quickest way to see the API in a real game.
Optional: quantum-forge-engine
quantum-forge-engine bundles this package with extras that are handy for web games: an Engine base class, PixiJS rendering, input, audio, collision, particles and a project scaffolder (npx quantum-forge-engine init). You don't need it to use quantum-forge.
Quick Start
1. Configure Vite
// vite.config.ts
import { defineConfig } from "vite";
import { quantumForgeVitePlugin } from "quantum-forge/vite-plugin";
export default defineConfig({
plugins: [quantumForgeVitePlugin()],
});ESM note: If using
vite.config.js(not.tsor.mjs), add"type": "module"to yourpackage.json.
2. Declare a quantum property
import { ensureLoaded, quantum } from "quantum-forge/quantum";
await ensureLoaded(); // once, before the first quantum() call
const color = quantum(["red", "green", "blue"]); // a qutrit, starts "red"
color.superpose(); // equal superposition (alias for hadamard())
// Read without collapsing
color.probability("green"); // 1/3
color.probabilities();
// [{ value: "red", probability: 1/3 }, { value: "green", ... }, { value: "blue", ... }]
// Measure (collapses to one value)
const seen = color.measure(); // "red", "green" or "blue"
// End its life. dispose() measures, then frees the qudit for the next quantum() call.
color.dispose();A property is declared by the values it can take, and the dimension is how many there are.
quantum(3) is the numeric form, with values 0, 1, 2. A property needs at least two
values. A using declaration disposes the handle at the end of the scope; it needs TypeScript
5.2 or newer with "ESNext.Disposable" in the tsconfig lib. Code that never writes using
needs neither.
3. Entanglement
Entanglement is what an interaction leaves behind. A gate that touches two properties is an interaction:
import { quantum, measure } from "quantum-forge/quantum";
const a = quantum([false, true]).flip(); // a = true
const b = quantum([false, true]); // b = false
a.iSwap(b, 0.5); // half iSwap: exactly one of the pair ends up true
const [va, vb] = measure(a, b); // one step, both collapse
// va !== vb, every timeSo is a gate whose predicate reads another property. b.flip({ when: [a.is(true)] }) is a
CNOT: b flips only where a is true. a.is(1) builds the same predicate by index.
Editions
Two WASM builds are included:
| Edition | Dimensions | Max Qudits | Use Case | |---------|-----------|------------|----------| | Qutrit (default) | 2 to 3 | 12 | Games using qutrits (3-state quantum digits) | | Qubit | 2 | 20 | Games needing more qubits at dimension 2 |
To use the Qubit Edition:
import { useQuantumForgeBuild, ensureLoaded } from "quantum-forge/quantum";
useQuantumForgeBuild("qubit"); // before ensureLoaded()
await ensureLoaded();Node and headless use
The same code runs in Node (tests, servers, agents) with no Vite plugin. The loader finds the WASM inside the installed package, and useQuantumForgeBuild("qubit") picks the variant the same way. Point the loader elsewhere only when the WASM files live outside the package:
import { setWasmBasePath, ensureLoaded } from "quantum-forge/quantum";
import { pathToFileURL } from "node:url";
setWasmBasePath(pathToFileURL("/opt/wasm/quantum-forge-qubit").href);
await ensureLoaded();Node 22 or newer.
Package Exports
| Export | Contents |
|--------|----------|
| quantum-forge/quantum | quantum, Quantum, measure, forcedMeasure, probabilities, densityMatrix, measureWhen, forcedMeasureWhen, probabilityWhen, phaseRotate, isQuantum, observeQuantum, clearQuantumCache, QuantumRecorder, ensureLoaded, startBackgroundLoad, isReady, useQuantumForgeBuild, setWasmBasePath, getVersion, getMaxDimension, getMaxQudits, getMaxStateSize, getAttribution, registerServiceWorker, OP |
| quantum-forge/logging | Logger |
| quantum-forge/vite-plugin | quantumForgeVitePlugin |
Gates
Gates are methods on the handle. Each alias runs exactly the same gate as the physics name beside it.
| Gate | Alias | Qudits | Description |
|------|-------|--------|-------------|
| hadamard | superpose | 1 | Equal superposition |
| inverseHadamard | | 1 | Undoes hadamard |
| cycle | next, and flip on qubits | 1 | |0⟩→|1⟩→|2⟩→|0⟩ (a NOT at dimension 2) |
| shift | previous | 1 | Inverse of cycle; same as cycle at dimension 2 |
| clock | phase | 1 | Phase rotation |
| x, z | | 1 | Pauli X (same as shift) and Pauli Z (same as clock) |
| y | | 1 | Pauli Y, dimension 2 only |
| iSwap(other, fraction) | | 2 | Entangling swap; fraction is required |
| swap(other) | | 2 | Value swap |
| phaseRotate(angle, { when }) | | any | Free function: phase on the part of the state where the predicates hold |
Every gate except inverseHadamard, swap and iSwap takes an optional fraction first. An
omitted fraction, or exactly 1, is the discrete gate; any other number is the continuous
version, and 0.5 is the square root of the gate. Predicates go last, in { when: [...] }.
Measurement: prop.measure(), measure(...props), measureWhen(preds), and the forced
variants for replays and tests, which throw if the forced value has zero probability.
Read-only: prop.probability(value), prop.probabilities(),
probabilities(...props), probabilityWhen(preds), densityMatrix(...props).
Documentation
License
TypeScript source: MIT (see LICENSE.md). WASM binaries: proprietary, free for apps under $100K annual revenue with attribution. See dist/LICENSE-BINARY.md for binary terms.
