quantum-forge 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/QUANTUM_FORGE.md +528 -0
  2. package/package.json +3 -2
@@ -0,0 +1,528 @@
1
+ ---
2
+ name: quantum-forge
3
+ description: Quantum Forge framework reference — quantum operations, gates, entanglement, rendering, input. Use when writing game code, debugging WASM/imports, or understanding quantum mechanics in games.
4
+ allowed-tools: Read Glob Grep
5
+ user-invocable: true
6
+ argument-hint: [topic]
7
+ ---
8
+
9
+ # Quantum Forge Reference
10
+
11
+ ## Project Configuration
12
+
13
+ ```!
14
+ node -e "
15
+ const fs = require('fs');
16
+ try {
17
+ const p = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
18
+ const deps = { ...p.dependencies, ...p.devDependencies };
19
+ const core = deps['quantum-forge'] || deps['@quantum-native/quantum-forge'] || 'not installed';
20
+ const engine = deps['quantum-forge-engine'] || deps['@quantum-native/quantum-forge-engine'] || 'not installed';
21
+ const corePkg = deps['quantum-forge'] ? 'quantum-forge' : '@quantum-native/quantum-forge';
22
+ const enginePkg = deps['quantum-forge-engine'] ? 'quantum-forge-engine' : '@quantum-native/quantum-forge-engine';
23
+ console.log('Core: ' + corePkg + '@' + core);
24
+ if (engine !== 'not installed') console.log('Engine: ' + enginePkg + '@' + engine);
25
+ console.log('Type: ' + (p.type || 'commonjs'));
26
+ } catch { console.log('No package.json found'); }
27
+ " 2>/dev/null
28
+ ```
29
+
30
+ ## Initialization
31
+
32
+ ```typescript
33
+ import { ensureLoaded } from "quantum-forge/quantum";
34
+ await ensureLoaded(); // MUST be called before any quantum operations
35
+ ```
36
+
37
+ For the Qubit Edition (d2n20):
38
+
39
+ ```typescript
40
+ import { useQuantumForgeBuild, ensureLoaded } from "quantum-forge/quantum";
41
+ useQuantumForgeBuild("qubit"); // before ensureLoaded()
42
+ await ensureLoaded();
43
+ ```
44
+
45
+ ### Vite Plugin
46
+
47
+ ```typescript
48
+ import { quantumForgeVitePlugin } from "quantum-forge/vite-plugin";
49
+ export default defineConfig({
50
+ plugins: [quantumForgeVitePlugin()],
51
+ build: { rollupOptions: { external: [/quantum-forge-web-api/] } },
52
+ });
53
+ ```
54
+
55
+ ESM note: if using `vite.config.js` (not `.ts`/`.mjs`), add `"type": "module"` to `package.json`.
56
+
57
+ ## Core Concepts
58
+
59
+ Quantum Forge gives game objects real quantum state. The usage loop:
60
+
61
+ 1. **Attach quantum properties** to things — each property is a qudit (d-dimensional quantum digit)
62
+ 2. **Apply gates** to transform state without collapsing it
63
+ 3. **Use predicated gates** to create entanglement — correlations between properties
64
+ 4. **Measure** to collapse quantum state to a classical value (the game moment)
65
+
66
+ ### Programmer's Mental Model
67
+
68
+ **Superposition** is a weighted collection of values. A qubit in equal superposition is `{|0⟩: 0.707, |1⟩: 0.707}`.
69
+
70
+ **Gates** are collection algorithms that transform every entry at once. `cycle` increments each value. `hadamard` creates equal superposition.
71
+
72
+ **Predicated gates** apply a filter: "if property A is |1⟩, flip property B." This creates entanglement — correlated entries in the collection.
73
+
74
+ The weights are **complex amplitudes**, not probabilities. When two entries with the same value meet, their amplitudes add. In phase = constructive interference (probability increases). Out of phase = destructive interference (probability cancels). Probability of a value = squared magnitude of its amplitude.
75
+
76
+ ## QuantumPropertyManager
77
+
78
+ Extend this class to build your game's quantum system. It manages property lifecycle, pooling, and WASM access.
79
+
80
+ ```typescript
81
+ import { QuantumPropertyManager, ensureLoaded } from "quantum-forge/quantum";
82
+
83
+ await ensureLoaded();
84
+
85
+ class QuantumRegistry extends QuantumPropertyManager {
86
+ constructor(logger?: any) { super({ dimension: 2, logger }); }
87
+
88
+ makeQuantum(id: string): void {
89
+ const prop = this.acquireProperty();
90
+ const m = this.getModule();
91
+ m.cycle(prop); // |0⟩ → |1⟩
92
+ m.hadamard(prop); // → 50/50 superposition
93
+ this.setProperty(id, prop);
94
+ }
95
+
96
+ entangle(id1: string, id2: string): void {
97
+ const p1 = this.getProperty(id1);
98
+ const p2 = this.getProperty(id2);
99
+ if (!p1 || !p2) return;
100
+ this.getModule().i_swap(p1, p2, 0.5);
101
+ }
102
+
103
+ getProbability(id: string): number {
104
+ const prop = this.getProperty(id);
105
+ if (!prop) return 1.0;
106
+ const results = this.getModule().probabilities([prop]);
107
+ for (const r of results) {
108
+ if (r.qudit_values[0] === 1) return r.probability;
109
+ }
110
+ return 0;
111
+ }
112
+
113
+ measure(id: string): number {
114
+ const prop = this.getProperty(id);
115
+ if (!prop) return 1;
116
+ const [value] = this.getModule().measure_properties([prop]);
117
+ this.deleteProperty(id);
118
+ this.releaseProperty(prop, value); // reset to |0⟩, return to pool
119
+ return value;
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### Dimension
125
+
126
+ | Dimension | States | Use Case |
127
+ |-----------|--------|----------|
128
+ | 2 (qubit) | `\|0⟩`, `\|1⟩` | Binary: exists/doesn't, alive/dead |
129
+ | 3 (qutrit) | `\|0⟩` – `\|2⟩` | Three-way: rock/paper/scissors |
130
+
131
+ Start with dimension 2 unless your design needs more. Shipped package supports up to 3.
132
+
133
+ ## Gates
134
+
135
+ All gates are called via `getModule()`. Every gate accepts optional `predicates` for conditional execution (creates entanglement).
136
+
137
+ | Gate | Method | Dim | Description |
138
+ |------|--------|-----|-------------|
139
+ | Cycle | `m.cycle(prop, fraction?, preds?)` | Any | Cyclic permutation. `\|0⟩→\|1⟩→\|0⟩` for dim=2 (NOT gate) |
140
+ | Shift / X | `m.shift(prop, fraction?, preds?)` | Any | Inverse of cycle. Same as cycle for dim=2 |
141
+ | Hadamard | `m.hadamard(prop, fraction?, preds?)` | Any | Equal superposition. The main "make it quantum" gate |
142
+ | Inv. Hadamard | `m.inverse_hadamard(prop, preds?)` | Any | Reverse of hadamard |
143
+ | Clock / Z | `m.clock(prop, fraction, preds?)` | Any | Phase rotation. Invisible until interaction |
144
+ | Y | `m.y(prop, fraction?, preds?)` | **2 only** | Pauli Y. Throws if dimension != 2 |
145
+ | iSwap | `m.i_swap(p1, p2, fraction, preds?)` | Any | Anti-correlated entanglement |
146
+ | Swap | `m.swap(p1, p2, preds?)` | Any | Direct state exchange, no entanglement |
147
+ | Phase Rotate | `m.phase_rotate(preds, angle)` | Any | Phase rotation conditioned on predicates (required) |
148
+
149
+ **Fractional gates**: `fraction=1` is the full gate, `0.5` is the square root, `0.1` barely moves state. Key for gradual quantum effects.
150
+
151
+ ### Predicates (Conditional Gates)
152
+
153
+ Every gate accepts predicates that condition it on other properties' states. **This is how entanglement works** — a gate that depends on another property's state correlates them.
154
+
155
+ ```typescript
156
+ // CNOT: flip target only when control is |1⟩
157
+ m.shift(target, 1, [control.is(1)]);
158
+ // Result: (|00⟩ + |11⟩)/√2 — positively correlated
159
+
160
+ // Controlled Hadamard: target enters superposition conditionally
161
+ m.hadamard(target, 1, [control.is(1)]);
162
+
163
+ // Predicate types:
164
+ prop.is(value) // true when property is |value⟩
165
+ prop.is_not(value) // true when property is NOT |value⟩
166
+
167
+ // Multiple predicates are AND'd
168
+ m.shift(target, 1, [controlA.is(1), controlB.is(1)]);
169
+ ```
170
+
171
+ For `PredicateSpec` objects (used in some APIs):
172
+
173
+ ```typescript
174
+ import type { PredicateSpec } from "quantum-forge/quantum";
175
+ const specs: PredicateSpec[] = [
176
+ { property: controlProp, value: 1, isEqual: true },
177
+ ];
178
+ const wasmPreds = specs.map(s =>
179
+ s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value)
180
+ );
181
+ ```
182
+
183
+ ## Entanglement Patterns
184
+
185
+ ### Entangle-Split (iSwap)
186
+
187
+ Object splits into anti-correlated pair. Exactly one is real.
188
+
189
+ ```typescript
190
+ entangleSplit(originalId: string, newId: string): void {
191
+ const prop1 = this.acquireProperty();
192
+ const prop2 = this.acquireProperty();
193
+ const m = this.getModule();
194
+ m.cycle(prop1); // |1⟩ (exists)
195
+ m.i_swap(prop1, prop2, 0.5); // entangle
196
+ this.setProperty(originalId, prop1);
197
+ this.setProperty(newId, prop2);
198
+ }
199
+ ```
200
+
201
+ ### Correlated Pair (CNOT)
202
+
203
+ Both match — both alive or both dead.
204
+
205
+ ```typescript
206
+ createLinkedPair(id1: string, id2: string): void {
207
+ const prop1 = this.acquireProperty();
208
+ const prop2 = this.acquireProperty();
209
+ const m = this.getModule();
210
+ m.cycle(prop1);
211
+ m.hadamard(prop1);
212
+ m.shift(prop2, 1, [prop1.is(1)]); // CNOT
213
+ this.setProperty(id1, prop1);
214
+ this.setProperty(id2, prop2);
215
+ }
216
+ ```
217
+
218
+ ### Quantum-Split
219
+
220
+ Split an already-quantum object. Pooled properties preferred (no tensor product growth).
221
+
222
+ ```typescript
223
+ quantumSplit(originalId: string, newId: string): boolean {
224
+ const prop1 = this.getProperty(originalId);
225
+ if (!prop1) return false;
226
+ const prop2 = this.acquireProperty();
227
+ try {
228
+ this.getModule().i_swap(prop1, prop2, 0.5);
229
+ } catch {
230
+ this.releaseProperty(prop2, 0); // qudit limit
231
+ return false;
232
+ }
233
+ this.setProperty(newId, prop2);
234
+ return true;
235
+ }
236
+ ```
237
+
238
+ ### Overlap Entanglement
239
+
240
+ Objects that spatially overlap become entangled:
241
+
242
+ ```typescript
243
+ this.getModule().i_swap(propA, propB, 0.5);
244
+ ```
245
+
246
+ ### Conditional Superposition
247
+
248
+ A control property determines whether a target enters superposition:
249
+
250
+ ```typescript
251
+ m.hadamard(target, 1, [control.is(1)]);
252
+ ```
253
+
254
+ ### Choosing Between Mechanisms
255
+
256
+ | Mechanism | Correlation | Use |
257
+ |-----------|-------------|-----|
258
+ | Predicated shift (CNOT) | Positive — both match | Linked states: both alive or both dead |
259
+ | Predicated hadamard | Conditional superposition | One object's quantumness depends on another |
260
+ | `i_swap(0.5)` | Anti-correlated — exactly one | Object splits into two ghosts |
261
+ | `i_swap` + phase | Tunable bias | Player-influenced split probability |
262
+
263
+ ## Measurement
264
+
265
+ Measurement collapses superposition to a definite value. Entangled partners collapse instantly too.
266
+
267
+ ```typescript
268
+ const [value] = m.measure_properties([prop]); // probabilistic collapse
269
+ // Always pool after:
270
+ this.deleteProperty(id);
271
+ this.releaseProperty(prop, value);
272
+ ```
273
+
274
+ ### Batch Measurement
275
+
276
+ ```typescript
277
+ const [va, vb, vc] = m.measure_properties([propA, propB, propC]);
278
+ ```
279
+
280
+ ### Reading State (No Collapse)
281
+
282
+ ```typescript
283
+ // Probabilities — read-only, no state change
284
+ const results = m.probabilities([prop]);
285
+ // [{ probability: 0.5, qudit_values: [0] }, { probability: 0.5, qudit_values: [1] }]
286
+
287
+ // Reduced density matrix — phase and correlation info
288
+ const rdm = m.reduced_density_matrix([prop1, prop2]);
289
+ // Off-diagonal entries carry relative phase
290
+
291
+ // Measure predicate — projective measurement
292
+ const outcome = m.measure_predicate([prop1.is(1), prop2.is(0)]);
293
+ // 1 = satisfied, 0 = not
294
+
295
+ // Forced measurement — replay/save-load only
296
+ const [value] = m.forced_measure_properties([prop], [1]);
297
+ ```
298
+
299
+ ## Phase & Interference
300
+
301
+ Phase is invisible to measurement but changes how properties interact. Phase + iSwap = probability redistribution through interference.
302
+
303
+ ```typescript
304
+ // Apply phase bias
305
+ m.clock(prop, 0.5); // π/2 phase on |1⟩
306
+
307
+ // Later, entangle → phase redistributes probability
308
+ m.i_swap(propA, propB, 0.5);
309
+ // Same phase = constructive interference (probability concentrates)
310
+ // Opposite phase = destructive interference (probability cancels)
311
+ ```
312
+
313
+ **Grover oracle** (walls/barriers): mark states with π phase, then diffuse with fractional Hadamard. Probability "bounces off" marked states.
314
+
315
+ ```typescript
316
+ m.phase_rotate([hexProp.is(wallState)], Math.PI); // mark
317
+ m.hadamard(hexProp, 0.1); // diffuse
318
+ ```
319
+
320
+ **Key insight:** Phase is the control knob that lets players influence quantum outcomes without directly choosing them. The player can't pick which ball exists, but they can bias the odds by applying phase before the next entanglement interaction.
321
+
322
+ ### Visualizing Phase
323
+
324
+ Extract from the reduced density matrix:
325
+
326
+ ```typescript
327
+ const rdm = m.reduced_density_matrix([propRef, propTarget]);
328
+ for (const entry of rdm) {
329
+ if (entry.row_values[0] === 1 && entry.row_values[1] === 0 &&
330
+ entry.col_values[0] === 0 && entry.col_values[1] === 1) {
331
+ const phase = Math.atan2(entry.value.imag, entry.value.real);
332
+ // Map to dial rotation, color hue, force magnitude, compass direction
333
+ }
334
+ }
335
+ ```
336
+
337
+ ## Recording & Replay
338
+
339
+ ```typescript
340
+ import { QuantumRecorder } from "quantum-forge/quantum";
341
+
342
+ const recorder = new QuantumRecorder(qpm);
343
+ recorder.startRecording();
344
+ // ... operations ...
345
+ const log = recorder.getLog(); // serializable JSON
346
+ // Save: localStorage.setItem("quantum-save", JSON.stringify(log));
347
+ // Load: recorder.replayLog(JSON.parse(saved)); // forced measurements
348
+ ```
349
+
350
+ ## Performance
351
+
352
+ **The one rule: pool your properties.** Measure → delete → release. Every time.
353
+
354
+ Shipped limits: Qutrit Edition has dimension 3, 12 max qudits. Qubit Edition has dimension 2, 20 max qudits.
355
+
356
+ | Active Properties | Performance |
357
+ |-------------------|-------------|
358
+ | 1–4 | No issues |
359
+ | 4–8 | Good with pooling |
360
+ | 8–12 | At the limit, aggressive pooling required |
361
+
362
+ **Most expensive operation**: tensor product (triggered by iSwap between properties in different shared states). Pooled properties avoid this — they're already in the shared state.
363
+
364
+ **Strategies**: aggressive pooling, limit concurrent quantum objects, use dimension 2 unless needed, separate registries for independent systems, batch measurements, throttle probability queries.
365
+
366
+ ```typescript
367
+ // Monitor WASM memory
368
+ import { getWasmMemoryBytes } from "quantum-forge/quantum";
369
+ const mem = getWasmMemoryBytes(); // bytes, or null
370
+ ```
371
+
372
+ ## Engine
373
+
374
+ `Engine<TState>` is the state coordinator. Define your state type, expose mutations through `getHelpers()`.
375
+
376
+ ```typescript
377
+ import { Engine } from "quantum-forge-engine/engine";
378
+
379
+ class MyEngine extends Engine<GameState> {
380
+ constructor() { super(initialState); }
381
+ getHelpers() {
382
+ return {
383
+ movePlayer: (dx: number, dy: number) => {
384
+ const state = this.getState();
385
+ this.setState({ ...state, player: { ...state.player, x: state.player.x + dx } });
386
+ },
387
+ };
388
+ }
389
+ reset() { this.setState(initialState); }
390
+ }
391
+ ```
392
+
393
+ | Method | Description |
394
+ |--------|-------------|
395
+ | `getState()` | Current game state |
396
+ | `setState(state)` | Replace game state |
397
+ | `getHelpers()` | Object of state-mutating functions (override) |
398
+ | `reset()` | Reset to initial state (override) |
399
+
400
+ ## Rendering
401
+
402
+ ### PixiRenderer (WebGL/WebGPU)
403
+
404
+ ```typescript
405
+ import { PixiRenderer, GameLoop } from "quantum-forge-engine/rendering";
406
+
407
+ class MyRenderer extends PixiRenderer {
408
+ protected draw(state: GameState) {
409
+ this.graphics.circle(state.player.x, state.player.y, 10).fill("#fff");
410
+ this.drawText("score", `Score: ${state.score}`, 10, 10, { fill: "#fff", fontSize: 16 });
411
+ }
412
+ }
413
+
414
+ await renderer.init(); // required before game loop
415
+ ```
416
+
417
+ - `this.graphics` — PixiJS Graphics, cleared each frame
418
+ - `this.drawText(key, content, x, y, style?)` — managed text by key, no texture churn
419
+ - `this.stage` — PixiJS Container root
420
+ - `this.app` — PixiJS Application for sprites/containers
421
+
422
+ ### CanvasRenderer (Canvas 2D)
423
+
424
+ ```typescript
425
+ import { CanvasRenderer } from "quantum-forge-engine/rendering";
426
+
427
+ class MyRenderer extends CanvasRenderer {
428
+ render(state: GameState) {
429
+ this.clear("#000");
430
+ // draw with this.ctx (CanvasRenderingContext2D)
431
+ }
432
+ }
433
+ ```
434
+
435
+ ### GameLoop
436
+
437
+ ```typescript
438
+ const loop = new GameLoop({
439
+ update: (dt) => { input.poll(); /* update state */ },
440
+ render: () => renderer.render(engine.getState()),
441
+ targetFps: 60,
442
+ });
443
+ loop.start();
444
+ ```
445
+
446
+ `dt` is in seconds (~0.0167 at 60 FPS).
447
+
448
+ **Rule:** renderers derive visuals from state. Never compute, cache, or decide in the renderer.
449
+
450
+ ### Quantum Visualization
451
+
452
+ Map probability to visual properties (opacity, size, color):
453
+
454
+ ```typescript
455
+ protected draw(state: GameState) {
456
+ for (const ball of state.balls) {
457
+ const alpha = ball.isQuantum ? ball.existenceProbability : 1.0;
458
+ this.graphics.circle(ball.x, ball.y, ball.radius).fill({ color: ball.color, alpha });
459
+ }
460
+ }
461
+ ```
462
+
463
+ ## Input
464
+
465
+ ```typescript
466
+ import { InputManager, GamepadButtons, GamepadAxes } from "quantum-forge-engine/input";
467
+
468
+ const input = new InputManager({ logger });
469
+ input.bind("jump", { type: "key", code: "Space" }, { type: "gamepad-button", index: GamepadButtons.A });
470
+ input.bind("move-up", { type: "key", code: "KeyW" }, { type: "gamepad-axis", index: GamepadAxes.LeftStickY, direction: -1 });
471
+
472
+ // In update loop:
473
+ input.poll();
474
+ if (input.isActionJustPressed("jump")) { /* edge */ }
475
+ if (input.isActionDown("move-up")) { /* held */ }
476
+ const speed = input.getActionValue("move-up") * MAX_SPEED; // analog 0-1
477
+
478
+ // Event handlers
479
+ const unsub = input.on("pause", () => togglePause());
480
+
481
+ // Active device detection
482
+ const device = input.getActiveDevice(); // "keyboard" | "mouse" | "touch" | "gamepad"
483
+
484
+ // Always clean up
485
+ input.destroy();
486
+ ```
487
+
488
+ **Source types:** `key`, `mouse-button`, `gamepad-button`, `gamepad-axis` (with direction), `touch-zone`, `touch-joystick`, `touch-gesture`
489
+
490
+ **Touch controls:** `input.addTouchZone({ name, x, y, w, h })` and `input.addJoystick({ name, zone, radius, deadZone, dynamic })`
491
+
492
+ **Local multiplayer:** `LocalMultiplayerManager` wraps multiple `InputManager` instances with automatic gamepad assignment.
493
+
494
+ ## Package Exports
495
+
496
+ ### Core (`quantum-forge`)
497
+
498
+ | Export | Key APIs |
499
+ |--------|----------|
500
+ | `./quantum` | `ensureLoaded`, `QuantumPropertyManager`, `QuantumRecorder`, `useQuantumForgeBuild` |
501
+ | `./logging` | `Logger` |
502
+ | `./vite-plugin` | `quantumForgeVitePlugin` |
503
+
504
+ ### Engine (`quantum-forge-engine`)
505
+
506
+ | Export | Key APIs |
507
+ |--------|----------|
508
+ | `./engine` | `Engine<TState>` |
509
+ | `./rendering` | `PixiRenderer`, `CanvasRenderer`, `GameLoop`, `Camera` |
510
+ | `./input` | `InputManager`, `LocalMultiplayerManager`, `GamepadButtons`, `GamepadAxes` |
511
+ | `./events` | `EventBus` |
512
+ | `./collision` | `SpatialGrid`, AABB/circle/point |
513
+ | `./audio` | `AudioManager` (Howler.js) |
514
+ | `./particles` | `ParticleSystem` |
515
+ | `./animation` | `AnimationSystem` |
516
+ | `./entities` | `EntityManager` |
517
+ | `./state-machine` | `StateMachine` |
518
+ | `./timer` | `TimerManager` |
519
+ | `./save` | `SaveManager` |
520
+ | `./scenes` | `SceneManager` |
521
+
522
+ Optional packages can be added via `npx quantum-forge-engine add-system`.
523
+
524
+ ## Links
525
+
526
+ - Documentation: https://docs.quantum.dev
527
+ - Developer site: https://quantum.dev
528
+ - Discord: https://discord.gg/quantumforge
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantum-forge",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "Quantum Forge WASM loader, property manager, and Vite plugin for quantum game development (Qutrit Edition d3n12 + Qubit Edition d2n20).",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,7 +22,8 @@
22
22
  "scripts/prepare.mjs",
23
23
  "scripts/copy-quantum-forge.mjs",
24
24
  "scripts/build-quantum-forge-variant.mjs",
25
- "LICENSE.md"
25
+ "LICENSE.md",
26
+ "QUANTUM_FORGE.md"
26
27
  ],
27
28
  "scripts": {
28
29
  "prepare": "node scripts/prepare.mjs",