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.measureProperties([prop]);
// value is 0 or 1 (for dim=2)
// The property is now in state |value⟩ — no more superpositionKey behaviors:
- The outcome is probabilistic — follows Born's rule, not a PRNG
- The state collapses permanently to the measured value
- Entangled partners collapse instantly too
- The operation is recorded when recording is active
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.measureProperties([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.measureProperties(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() uses this.getModule() directly (not a gate wrapper) because it doesn't change state. It is not recorded in the operation log.
Reduced Density Matrix
For advanced analysis — extract 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-framework/quantum";
const predicates: PredicateSpec[] = [
{ property: prop1, value: 1, isEqual: true },
{ property: prop2, value: 0, isEqual: true },
];
const outcome = this.measurePredicate(predicates);
// 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 replayLog() to reproduce exact quantum states during save/load:
const [value] = this.forcedMeasureProperties([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 genuinely probabilistic.
Game Examples
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 valueQuantris — Line Clearing
When a line is complete, all quantum pieces in it are measured:
for (const piece of piecesInLine) {
const exists = registry.measurePiece(piece.id);
if (exists === 0) {
// Piece was quantum and collapsed to "doesn't exist"
// Remove from the board — creates gaps
removePiece(piece);
}
}Hex Diffusion — Battle Resolution
Combat pulses measure overlapping hexes:
const results = registry.measureBattle(hexIds);
// Each hex collapses to one player's ownership
// Entangled hexes respect correlationsBloch Invaders — Basis Measurement
The player chooses X, Y, or Z basis, then measures the invader:
// Decompose measurement into gate sequence
if (basis === "X") {
registry.hadamard(prop); // rotate to X basis
} else if (basis === "Y") {
registry.inverseSGate(prop); // rotate to Y basis
registry.hadamard(prop);
}
const [value] = registry.measureProperties([prop]);
// Damage depends on how well the basis matches the invader's state