You're reading the 2.x docs. quantum-forge 3.0 is out: this page in 3.x / migration guide

Skip to content

Packages ​

Optional, composable pieces you can add to a game. They are subpaths of the quantum-forge-engine package, so using one is an import rather than an install.

Two of them need an optional peer dependency first:

bash
npm install pixi.js   # PixiRenderer
npm install howler    # AudioManager

Available packages ​

PackageImportDescription
Inputquantum-forge-engine/inputKeyboard, mouse, gamepad, touch, gestures, local multiplayer
Collisionquantum-forge-engine/collisionRect, circle, and point tests plus a SpatialGrid
Audioquantum-forge-engine/audioHowler.js wrapper for sounds and music
Particlesquantum-forge-engine/particlesBurst, trail, and explosion effects
Animationquantum-forge-engine/animationTweening with easing functions
Entitiesquantum-forge-engine/entitiesEntity registry with spatial queries
State machinequantum-forge-engine/state-machineConfig-driven finite state machine
Timerquantum-forge-engine/timerGame-aware timers, pause- and scale-aware
Savequantum-forge-engine/saveSlot-based saves with versioning and auto-save
Scenesquantum-forge-engine/scenesStack-based scene lifecycle

Collision ​

Collision is a set of pure functions plus a grid for narrowing candidates.

typescript
import { SpatialGrid, circleOverlaps } from "quantum-forge-engine/collision";

const grid = new SpatialGrid<Enemy>(64);
for (const enemy of state.enemies) grid.add(enemy);

for (const other of grid.getNearby(player.x, player.y)) {
  if (circleOverlaps(player, other)) {
    // handle collision
  }
}

getNearby(x, y) takes coordinates and returns everything in that cell and the eight around it. Confirm real overlaps with rectOverlaps, circleOverlaps, rectCircleOverlaps, or one of the point tests.

Audio ​

typescript
import { AudioManager } from "quantum-forge-engine/audio";

const audio = new AudioManager({ soundVolume: 0.8, musicVolume: 0.4, logger });
await audio.loadSound("hit", "/sounds/hit.mp3");
audio.play("hit");

audio.setMasterVolume(0.8);
audio.mute();    // no argument
audio.unmute();

Browsers block audio until the player interacts with the page. isUnlocked() reports whether that has happened, which is what a "tap to enable sound" prompt keys off.

Particles ​

typescript
import { ParticleSystem } from "quantum-forge-engine/particles";

const particles = new ParticleSystem({ gravity: 200 });

particles.emit({ x, y, count: 20, color: "#a855f7", speed: 100, life: 0.5 });
particles.burst(x, y, Math.PI / 2, 20, "#a855f7");  // positional arguments

// In game loop
particles.update(dt);
particles.render(ctx);              // Canvas 2D
particles.renderToGraphics(this.graphics);  // PixiJS

burst, trail, and explode take positional arguments. emit(config) is the options-object entry point, and its lifetime field is life, in seconds.

Animation ​

typescript
import { Tween, MultiTween, Easing } from "quantum-forge-engine/animation";

const fade = new Tween({
  from: 0,
  to: 1,
  duration: 500,          // milliseconds
  easing: Easing.easeOutCubic,
  onUpdate: (value) => { sprite.alpha = value; },
});
fade.start();

function frame(now: number) {
  fade.update(now);       // pass a timestamp, not a delta
  if (fade.isActive()) requestAnimationFrame(frame);
}

Tween animates one number. For object-shaped animations use MultiTween with a values map:

typescript
const move = new MultiTween({
  values: { x: { from: 0, to: 100 }, y: { from: 0, to: 200 } },
  duration: 500,
  easing: Easing.easeOutCubic,
  onUpdate: (values) => { sprite.x = values.x; sprite.y = values.y; },
});

Easings live on the Easing object. AnimationManager starts animations for you and updates them all from one call.

Save ​

typescript
import { SaveManager } from "quantum-forge-engine/save";

const saves = new SaveManager<GameState>({ prefix: "my-game", version: 1 });

saves.save("slot-1", engine.getState());
const data = saves.load("slot-1");

saves.enableAutoSave("autosave", () => engine.getState(), 30); // seconds
saves.update(dt);  // in the game loop, drives auto-save

Every method takes a named slot. Auto-save is turned on with enableAutoSave() rather than a constructor flag, and it advances only when you call update(dt).

Scenes ​

typescript
import { SceneManager, fadeTransition } from "quantum-forge-engine/scenes";

const scenes = new SceneManager<GameContext>({ logger });

await scenes.push("menu", menuScene, context);
await scenes.push("game", gameScene, context, fadeTransition(0.3, drawFade));
await scenes.pop();  // back to menu, which gets onResume()

There is no register() step: you pass the scene object to push() or replace(). A scene implements update(dt) and render(), and may add onEnter, onExit, onPause, and onResume. Drive the stack by calling scenes.update(dt) and scenes.render() each frame.

Powered by Quantum Forge