Skip to content

Project Structure

Every Quantum Forge game follows the four-layer pattern. Here's what each file does and where things go.

Directory Layout

After npx quantum-forge init my-game:

my-game/
├── package.json          # Dependencies, scripts
├── tsconfig.json         # TypeScript config with path aliases
├── vite.config.ts        # Vite + Quantum Forge plugin
├── index.html            # Canvas element + entry point
├── CLAUDE.md             # AI assistant context
├── src/
│   ├── main.ts           # Controller — wires everything
│   ├── engine/
│   │   └── GameEngine.ts # Engine — state coordinator
│   ├── logic/
│   │   └── GameLogic.ts  # Pure functions — game rules
│   ├── rendering/
│   │   └── GameRenderer.ts # Renderer — draws from state
│   └── game.test.ts      # Tests
└── dist/                 # Built WASM artifacts (after setup)

The Four Layers

1. logic/GameLogic.ts — Pure Functions

All game rules as pure functions. No imports from engine, renderer, or framework. Easy to test.

typescript
export function canMove(player: Player, dx: number, bounds: Bounds): boolean {
  return player.x + dx >= 0 && player.x + dx < bounds.width;
}

2. engine/GameEngine.ts — State Coordinator

Extends Engine<YourState>. Holds state, exposes helpers. Never contains logic or animation.

typescript
import { Engine } from "@quantum-realm-games/quantum-forge-framework/engine";

export class GameEngine extends Engine<GameState> {
  getHelpers() {
    return {
      movePlayer: (dx: number, dy: number) => { /* update state */ },
    };
  }
}

3. rendering/GameRenderer.ts — Visual Output

Extends PixiRenderer or CanvasRenderer. Reads state, draws pixels. Never computes.

typescript
import { PixiRenderer } from "@quantum-realm-games/quantum-forge-framework/rendering";

export class GameRenderer extends PixiRenderer {
  protected draw(state: GameState) { /* render from state */ }
}

4. main.ts — Controller

Creates and wires engine, renderer, input, game loop. Handles timing and user interaction.

typescript
const engine = new GameEngine(logger);
const renderer = new GameRenderer({ canvas, logger });
const input = new InputManager({ logger });
const loop = new GameLoop({ update, render, targetFps: 60, logger });

await renderer.init();
loop.start();

Adding Quantum

When your game needs quantum mechanics, add a registry file:

src/
├── logic/
│   ├── GameLogic.ts
│   └── QuantumRegistry.ts  ← new

The registry extends QuantumPropertyManager:

typescript
import { QuantumPropertyManager, ensureLoaded } from "@quantum-realm-games/quantum-forge-framework/quantum";

export class QuantumRegistry extends QuantumPropertyManager {
  constructor(logger?: any) { super({ dimension: 2, logger }); }
  // Game-specific quantum operations
}

Initialize in main.ts:

typescript
await ensureLoaded();
const registry = new QuantumRegistry(logger);
const engine = new GameEngine(registry, logger);

Adding Packages

Use the CLI to add optional packages:

bash
npm run add-system

Or import directly:

typescript
import { InputManager } from "@quantum-realm-games/quantum-forge-framework/input";
import { SpatialGrid } from "@quantum-realm-games/quantum-forge-framework/collision";
import { AudioManager } from "@quantum-realm-games/quantum-forge-framework/audio";

Import Paths

Within a scaffolded project, imports use the package's subpath exports:

typescript
// ✅ Consumer imports
import { Engine } from "@quantum-realm-games/quantum-forge-framework/engine";
import { PixiRenderer } from "@quantum-realm-games/quantum-forge-framework/rendering";
import { InputManager } from "@quantum-realm-games/quantum-forge-framework/input";

Within the framework monorepo itself, imports use path aliases:

typescript
// Framework-internal imports (not for consumers)
import { Engine } from "@core/engine/Engine";
import { InputManager } from "@packages/input";

Powered by Quantum Forge