Measurement
Measurement is the moment quantum becomes classical. A property in superposition collapses to a single definite value, and that collapse is the most dramatic thing your game can do.
Basic Measurement
const prop = this.getProperty("ball-1");
const [value] = this.getModule().measure_properties([prop]);
// value is 0 or 1 (for dim=2)
// The property is now in state |value⟩. No more superpositionKey behaviors:
- The outcome is probabilistic, sampled from the quantum state's probability distribution
- The state collapses permanently to the measured value
- Entangled partners collapse instantly too
Measure and Pool
Always release properties after measurement to stay within qudit limits:
measureEntity(id: string): number {
const prop = this.getProperty(id);
if (!prop) return 1; // classical fallback
const [value] = this.getModule().measure_properties([prop]);
this.deleteProperty(id); // remove ID mapping
this.releaseProperty(prop, value); // reset to |0⟩, return to pool
return value;
}This pattern appears in every production game. The specifics vary (what the value means, what to do after), but the sequence (measure, delete, release) is universal.
Batch Measurement
Measure multiple properties at once:
const props = [this.getProperty("a")!, this.getProperty("b")!, this.getProperty("c")!];
const [va, vb, vc] = this.getModule().measure_properties(props);Batch measurement is slightly more efficient than measuring one at a time, and the outcomes are correlated correctly (entangled properties respect their correlations within the batch).
Reading Probabilities (No Collapse)
Query the probability distribution without disturbing the quantum state:
const prop = this.getProperty("ball-1");
const results = this.getModule().probabilities([prop]);
// results: [{ probability: 0.7, qudit_values: [1] }, { probability: 0.3, qudit_values: [0] }]This is a read-only operation. It does not collapse the state. Use this for:
- Rendering ghost objects at their existence probability
- Showing probability meters in the UI
- AI decision-making based on quantum state
TIP
probabilities() is a read-only query. It does not change state or appear in recording logs.
Reduced Density Matrix
For advanced analysis (phase, coherence, and correlations between properties):
const rdm = this.getModule().reduced_density_matrix([prop1, prop2]);
// rdm: array of { row_values: number[], col_values: number[], value: { real: number, imag: number } }The off-diagonal entries carry relative phase information. From Quantum Pong:
getRelativePhase(refId: string, targetId: string): number {
const propRef = this.getProperty(refId);
const propTarget = this.getProperty(targetId);
if (!propRef || !propTarget) return 0;
const rdm = this.getModule().reduced_density_matrix([propRef, propTarget]);
for (const entry of rdm) {
if (
entry.row_values[0] === 1 && entry.row_values[1] === 0 &&
entry.col_values[0] === 0 && entry.col_values[1] === 1
) {
const { real, imag } = entry.value;
if (Math.abs(real) < 1e-10 && Math.abs(imag) < 1e-10) return 0;
return Math.atan2(imag, real);
}
}
return 0;
}Game use cases:
- Quantum Pong: Relative phase drives the phase dial display and biases entanglement interactions
- Ponq: Off-diagonal magnitude (coherence) drives ball steering forces
- Quantris: Coherence info drives piece glow/pulse visualization
Measure Predicate
Projective measurement that checks whether specific predicates are satisfied:
import type { PredicateSpec } from "quantum-forge/quantum";
const predicates: PredicateSpec[] = [
{ property: prop1, value: 1, isEqual: true },
{ property: prop2, value: 0, isEqual: true },
];
const wasmPreds = predicates.map(s =>
s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value)
);
const outcome = this.getModule().measure_predicate(wasmPreds);
// outcome: 0 or 1
// 1 = predicates were satisfied (state projected onto matching subspace)
// 0 = predicates were NOT satisfiedUnlike measureProperties, this doesn't fully collapse to a basis state. It performs a projective measurement onto the subspace defined by the predicates.
Forced Measurement (Replay)
Force a measurement to produce a specific outcome. Used internally by QuantumRecorder.replayLog() to reproduce exact quantum states during save/load:
const [value] = this.getModule().forced_measure_properties([prop], [1]); // forces outcome to 1WARNING
Forced measurement is for replay/testing only. Using it during normal gameplay breaks the quantum contract. Outcomes should be probabilistic.
Game Example: Quantum Pong Scoring
When a ball exits the play field, it's measured to determine if it scores:
const exists = registry.measureExistence(ballId);
if (exists === 1) {
// Ball existed → scores a point
state.score[scoringSide]++;
showScoreBurst(ball.position);
} else {
// Ball was a ghost → no score
showGhostBurst(ball.position);
}
// Entangled partner (if any) collapses to the opposite valueOther measurement patterns include batch measurement for line-clearing (measure all pieces in a row), basis measurement (rotate before measuring for different observables), and battle resolution (measure overlapping hexes to determine ownership).