Recording & Replay
Quantum state lives in WASM memory and cannot be directly serialized. The recording system solves this by logging every state-mutating quantum operation. On replay, the log recreates identical quantum state — measurements are forced to their recorded outcomes via forcedMeasureProperties.
Starting a Recording
// Begin recording — all gate wrappers will log operations
registry.startRecording();
// ... gameplay happens ...
// registry.cycle(), registry.iSwap(), registry.measureProperties()
// — all automatically logged
// Stop and get the log
const log: QuantumOperation[] = registry.stopRecording();Save / Load
import type { QuantumOperation } from "quantum-forge-framework/quantum";
// SAVE
const saveData = {
gameState: engine.getState(),
quantumLog: registry.stopRecording(),
};
localStorage.setItem("save", JSON.stringify(saveData));
// LOAD
const loaded = JSON.parse(localStorage.getItem("save")!);
engine.setState(loaded.gameState);
registry.replayLog(loaded.quantumLog);
// Quantum state is now identical to the moment of saveHow Replay Works
replayLog() performs these steps:
- Clears all existing properties, ID mappings, and pool
- Replays each operation in order:
acquire→ creates a fresh property or pops from the replay poolcycle,hadamard,iSwap, etc. → applies the gate to recreated handlesmeasure→ callsforcedMeasurePropertieswith the recorded outcomerelease→ resets to|0⟩and returns to poolassign/unassign→ restores ID-to-handle mappings
- After replay,
getProperty("ball-1")returns the correct handle in the correct quantum state
The key insight: because measurements are forced to recorded outcomes, the quantum state evolves identically. The same gates + same measurement results = same final state.
Recording API
| Method | Description |
|---|---|
startRecording() | Begin recording; resets log; assigns indices to existing handles |
stopRecording() | Stop recording; return QuantumOperation[] |
isRecording() | Check if recording is active |
getOperationLog() | Get a copy of the log (works even while recording) |
replayLog(ops) | Clear all state and replay from scratch |
Operation Types
The QuantumOperation union type covers all state mutations:
type QuantumOperation =
| { op: "acquire"; index: number }
| { op: "release"; index: number; value: number }
| { op: "assign"; index: number; id: string }
| { op: "unassign"; id: string }
| { op: "cycle"; index: number; fraction: number }
| { op: "shift"; index: number; fraction: number }
| { op: "clock"; index: number; fraction: number }
| { op: "hadamard"; index: number; fraction: number }
| { op: "inverse_hadamard"; index: number }
| { op: "i_swap"; index1: number; index2: number; fraction: number }
| { op: "swap"; index1: number; index2: number }
| { op: "phase_rotate"; indices: number[]; values: number[]; angle: number }
| { op: "y"; index: number; fraction: number }
| { op: "measure"; indices: number[]; outcomes: number[] }
| { op: "measure_predicate"; indices: number[]; values: number[]; outcome: number }
| { op: "reset"; index: number; value: number };Each WASM property handle is mapped to a sequential integer index for serialization. On replay, fresh handles are created and mapped back.
What Gets Recorded
Recorded (state-mutating gate wrappers):
this.cycle(),this.shift(),this.x()this.hadamard(),this.inverseHadamard()this.clock(),this.z()this.y()this.iSwap(),this.swap()this.phaseRotate()this.measureProperties(),this.measurePredicate()this.forcedMeasureProperties()this.resetProperty()this.acquireProperty(),this.releaseProperty()this.setProperty(),this.deleteProperty()
Not recorded (read-only queries):
this.getModule().probabilities()this.getModule().reduced_density_matrix()this.getProperty(),this.hasProperty()
This is correct — read-only operations don't change state, so they don't need to be replayed.
Snapshot vs Continuous Recording
You can get a snapshot of the log without stopping recording:
registry.startRecording();
// ... gameplay ...
// Periodic auto-save without interrupting recording
const snapshot = registry.getOperationLog();
autoSave({ gameState: engine.getState(), quantumLog: snapshot });
// ... more gameplay ...
// Final save
const finalLog = registry.stopRecording();Tips
When to start recording
Start recording at the beginning of a "saveable" state — typically when the game begins or when entering a new level. Everything before startRecording() is lost.
Recording overhead
Recording adds minimal overhead — it's just appending to an array. Only enable it when you need save/load or replay. Normal gameplay without save/load doesn't need recording.
Log size
The log grows linearly with the number of quantum operations. For long game sessions, consider periodic checkpoints: stop recording, save the log, start a new recording.