Skip to main content

Quantum Engine

A minimal, modular Entity Component System (ECS) game engine in TypeScript. Browser-first, plugin-driven, and tuned for WebGL, Canvas, and modern web APIs.

TypeScript ECS Game Engine WebGL Three.js Bun
Cover image for Quantum Engine

Overview

Quantum Engine is a TypeScript Entity Component System designed for the browser. It is a Bun monorepo of 20 packages: a tiny ECS core plus optional plugins for rendering, physics, input, audio, animation, networking, UI, and scene editing, all wired together by a fluent App runtime with a schedule-based system executor and an event bus.

The goal was a Bevy-style architecture that runs natively on the web. Every package targets the browser (WebGL, Canvas, requestAnimationFrame), state lives in cache-friendly Structure-of-Arrays component storage, and the same plugin pattern that registers core systems also powers the Three.js renderer, the Rapier3D physics layer, and the scene editor.

Quantum Engine architecture: convenience presets (core, web, render, game, full) sit on top of a core ECS layer (entities, components, queries, systems, schedule, resources and events), which is extended by plugins (@quantum/time, transform, web, input, render, plus physics, audio, UI, networking, and more) that bind to platform integrations (web browser, input devices, GPU/WebGL, audio, storage, and network). A typical flow: create app from a preset, add systems, spawn entities, run the app loop.
Quantum Engine architecture: convenience presets (core, web, render, game, full) sit on top of a core ECS layer (entities, components, queries, systems, schedule, resources and events), which is extended by plugins (@quantum/time, transform, web, input, render, plus physics, audio, UI, networking, and more) that bind to platform integrations (web browser, input devices, GPU/WebGL, audio, storage, and network). A typical flow: create app from a preset, add systems, spawn entities, run the app loop.

Features

ECS core

  • Type-safe components with both Structure of Arrays (SoA) and Array of Structures (AoS) storage
  • Archetype-based queries with caching, BitSet component checks, and topological system ordering
  • Entity lifecycle with ID reuse and component lifecycle hooks
  • Resource manager for typed global state and an event bus for loose coupling between systems

Plugin architecture

Everything outside the core is a plugin. A plugin declares its dependencies, components, systems, and resources, and gets build, startup, and shutdown hooks. Plugins are hot-swappable, dependency-ordered, and composed through a fluent builder.

Convenience presets

@quantum/presets ships preset bundles so a typical app is one line:

ts
import { createWebApp } from '@quantum/presets'

const { app, canvas } = createWebApp()
app.addSystem(ScheduleLabel.Update, new MovementSystem())
app.run()

Presets cover the common cases: core (server / headless), web (2D canvas + input), render (Three.js), game (render + physics + animation + assets), and full (everything).

Rendering, physics, and assets

  • @quantum/render: Three.js integration with scene, camera, and renderer wired to the ECS
  • @quantum/physics: Rapier3D bindings, exposed as components and systems
  • @quantum/asset: async asset loading with cache and lifecycle integration
  • @quantum/animation, @quantum/audio, @quantum/spatial, @quantum/networking, @quantum/ui: additional plugins for the rest of a typical game stack

Scene editor

@quantum/editor adds picking, gizmos, and camera controls, and pairs with @quantum/scene for serialization, prefabs, and a scene builder API. The editor is itself an ECS app; it registers systems and resources just like any other plugin.

Tooling

  • Bun workspace with Turborepo for parallel builds and dependency-aware watching
  • Vitest for unit tests, Playwright for browser/component tests, mitata for benchmarks
  • TypeDoc + an Astro/Starlight docs site under apps/site
  • Per-package builds target the browser with external workspace deps and tree-shakeable ESM output

Architecture

plaintext
App
  ├── World          // entity + component storage and queries
  ├── ResourceManager // typed global state
  ├── Schedule       // Startup → PreUpdate → Update → PostUpdate → Render
  └── EventBus       // typed events between systems

Plugins layer on top: Time, Transform, Web, Input, Render, Physics, Asset,
Animation, Audio, UI, Spatial, Networking, Editor, Scene, Debug, ...

A typical frame walks the schedule once: time advances, input is sampled, gameplay systems run in Update, transforms and physics resolve in PostUpdate, and the renderer flushes in Render.

Quick start

ts
import { createWebApp } from '@quantum/presets'
import { defineComponent, createQuery, ScheduleLabel, System } from '@quantum/core'

const Position = defineComponent({ x: Float32Array, y: Float32Array }, { name: 'Position' })
const Velocity = defineComponent({ x: Float32Array, y: Float32Array }, { name: 'Velocity' })

class Movement extends System {
  update(world) {
    const q = createQuery().with(Position).with(Velocity).build()
    q.executeWithCallback(world, (_e, p, v) => {
      p.x += v.x
      p.y += v.y
    })
  }
}

const { app } = createWebApp()
app.addSystem(ScheduleLabel.Update, new Movement())
app.run()

Technology stack

  • TypeScript across a Bun monorepo of 20 @quantum/* packages plus tutorial and example apps
  • Browser-first build pipeline (ESM, external workspace deps, code splitting, source maps)
  • Three.js for 3D rendering, Rapier3D for physics, native Web APIs for input, audio, and timing
  • Turborepo for build orchestration; Vitest, Playwright, and mitata for tests and benchmarks
  • Astro + Starlight documentation site backed by TypeDoc-generated API references