Skip to content

QuantumPropertyManager

QuantumPropertyManager is the core abstraction for working with quantum properties in your game. Every game that uses Quantum Forge extends this class to create a game-specific registry that manages quantum property lifecycles.

The Pattern

Every production game built with Quantum Forge follows the same pattern:

  1. Extend QuantumPropertyManager with a game-specific registry
  2. Acquire properties (from pool or fresh)
  3. Apply gates to create superposition, entanglement, phase
  4. Measure to collapse superposition into definite outcomes
  5. Release measured properties back to the pool
typescript
import { QuantumPropertyManager, ensureLoaded } from "quantum-forge-framework/quantum";

class MyRegistry extends QuantumPropertyManager {
  constructor(logger?: LoggerInterface) {
    super({ dimension: 2, logger });
  }

  // Game-specific operations go here
}

await ensureLoaded();
const registry = new MyRegistry(logger);

Constructor Options

OptionTypeDefaultDescription
dimensionnumber2Number of basis states per property (must be ≥ 2)
loggerLoggerInterfaceundefinedOptional structured logger

The dimension determines how many states each property can be in. For most games, 2 (qubit — two states) is the right choice. Use higher dimensions only when your game design specifically needs more basis states.

Property Lifecycle

Acquire

typescript
const prop = this.acquireProperty();
// prop starts in |0⟩
// If pool has a reset property, reuses it (no tensor product growth)
// If pool is empty, creates a fresh property from the WASM module

Register with ID

typescript
this.setProperty("ball-1", prop);

// Later:
const p = this.getProperty("ball-1");  // retrieve by ID
const exists = this.hasProperty("ball-1"); // check existence

Apply Gates

Use the protected gate wrapper methods (see Gates):

typescript
this.cycle(prop);                  // |0⟩ → |1⟩
this.hadamard(prop);               // → superposition
this.iSwap(prop1, prop2, 0.5);    // entangle two properties
this.clock(prop, 0.5);            // phase rotation

Measure

typescript
const [value] = this.measureProperties([prop]);
// value is 0 or 1 (for dim=2), determined by quantum probabilities

Release to Pool

typescript
this.deleteProperty("ball-1");     // remove ID mapping
this.releaseProperty(prop, value); // reset to |0⟩ and return to pool

CRITICAL

Always release properties after measurement. Without pooling, every new property grows the tensor product until the qudit limit is reached and operations fail. See Performance for details.

Complete Registry Example

From Quantum Pong — the canonical example:

typescript
class QuantumRegistry extends QuantumPropertyManager {
  constructor(logger?: LoggerInterface) {
    super({ dimension: 2, logger });
  }

  /** Split a classical ball into an entangled quantum pair */
  entangleSplit(originalId: string, newId: string): void {
    const prop1 = this.acquireProperty();
    const prop2 = this.acquireProperty();

    this.cycle(prop1);               // |0⟩ → |1⟩ (exists)
    // prop2 stays |0⟩              (doesn't exist)
    this.iSwap(prop1, prop2, 0.5);   // entangle: (|10⟩ + i|01⟩)/√2

    this.setProperty(originalId, prop1);
    this.setProperty(newId, prop2);
  }

  /** Get probability that a ball exists */
  getExistenceProbability(id: string): number {
    const prop = this.getProperty(id);
    if (!prop) return 1.0; // classical balls always exist

    const results = this.getModule().probabilities([prop]);
    for (const r of results) {
      if (r.qudit_values[0] === 1) return r.probability;
    }
    return 0;
  }

  /** Measure existence — collapses state, pools property */
  measureExistence(id: string): number {
    const prop = this.getProperty(id);
    if (!prop) return 1;

    const [value] = this.measureProperties([prop]);
    this.deleteProperty(id);
    this.releaseProperty(prop, value);
    return value; // 1 = exists, 0 = ghost
  }
}

Read-Only Queries

For operations that don't change quantum state, use this.getModule() directly:

typescript
// Probability distribution (no collapse)
const probs = this.getModule().probabilities([prop]);
// Returns: [{ probability: 0.5, qudit_values: [0] }, { probability: 0.5, qudit_values: [1] }]

// Reduced density matrix (for phase/coherence)
const rdm = this.getModule().reduced_density_matrix([prop1, prop2]);
// Returns: [{ row_values, col_values, value: { real, imag } }, ...]

TIP

Read-only queries are not recorded in the operation log. This is correct — they don't change state, so they don't need to be replayed.

String ID Mapping

The ID system maps human-readable strings to WASM property handles:

MethodDescription
setProperty(id, prop)Register a property with a string ID
getProperty(id)Get the WASM handle for an ID (or undefined)
hasProperty(id)Check if an ID has a registered property
deleteProperty(id)Remove the ID mapping (does NOT release the property)
removeProperty(id)Measure, release, and delete in one call

Multiple Registries

Different quantum systems in your game can use separate registries:

typescript
const enemyRegistry = new QuantumEnemyRegistry(logger);  // dim=2
const puzzleRegistry = new QuantumPuzzleRegistry(logger); // dim=4

// Each manages its own pool and qudit space independently

Pattern: Every Game Has a Registry

All five production games extend QuantumPropertyManager:

GameRegistry ClassDimensionKey Operations
Quantum PongQuantumRegistry2entangleSplit, quantumSplit, applyPhase, measureExistence
QuantrisQuantumPieceRegistry2setExistence, entangleGroup, measurePiece, getCoherenceInfo
Hex DiffusionHexQuantumRegistry7diffuse (fractional H), interfere, barrier (phase rotate), battle
Bloch InvadersBlochRegistry2rotateTheta (Y), rotatePhi (Z), measureBasis, entangleTwins
PonqPonqQuantumRegistry2chargePhase, entangleSplit, getCoherence (RDM), activateZone

The dimension and operations vary, but the lifecycle pattern — acquire, gate, measure, release — is universal.

Powered by Quantum Forge