Introduction

A flexible toolkit for data-oriented design in game development.

What is bitECS?

bitECS is a high-performance Entity Component System (ECS) library for JavaScript and TypeScript. It offers core ECS concepts without imposing strict rules onto your architecture:

  • Entities are numerical IDs
  • Component stores can be anything
  • No formal concept of systems, only queries

What is ECS?

Entity Component System is an architectural pattern that favors composition over inheritance. It separates data (components) from behavior (systems) and uses entities as identifiers that link components together.

Entity

A unique ID that groups components together. In bitECS, entities are just numbers.

Component

Pure data containers with no behavior. Define what an entity has, not what it does.

System

Functions that operate on entities matching specific component patterns.

Core Principles

JavaScript runs in a JIT-compiled environment, and performance characteristics vary across engines (V8, SpiderMonkey, JavaScriptCore). Data-oriented design helps, but only goes so far in JS. bitECS embraces this by leaving component storage agnostic—you choose the backing store that works best for your use case and target runtime.

  • Structure of Arrays (SoA) - Store component data in arrays indexed by entity ID. Generally faster than objects and significantly more memory-efficient.
  • Function pipelines - Implement systems as composable functions that can be reordered and profiled independently.
  • Agnostic storage - Use TypedArrays, regular arrays, or custom stores. Optimize where profiling shows you need it.
  • ZAII - Zero As Initial Initialization. Design around zero being the default state.
!
Storage Options

Choose the backing store that fits your needs:

  • TypedArrays - Zero garbage collection. Required for SharedArrayBuffer multithreading.
  • Regular arrays - Flexible, lower memory than objects, minimal GC pressure.
  • Array of Structures (AoS) - Objects per entity. Familiar API, but more memory at scale.

Both SoA (Position.x[eid]) and AoS (Position[eid].x) work with bitECS—just matters which side of the brackets the dot is on. We encourage SoA for memory efficiency, but the choice is yours.

Example

Here's a complete example showing the core concepts:

game.ts
1import { createWorld, addEntity, addComponent, query } from 'bitecs'
2
3// Define components as objects with arrays
4const Position = {
5 x: [] as number[],
6 y: [] as number[],
7}
8
9const Velocity = {
10 x: [] as number[],
11 y: [] as number[],
12}
13
14// Create a world
15const world = createWorld()
16
17// Add an entity to the world
18const entity = addEntity(world)
19
20// Add components to entity
21addComponent(world, entity, Position)
22addComponent(world, entity, Velocity)
23
24// Set initial values
25Position.x[entity] = 0
26Position.y[entity] = 0
27Velocity.x[entity] = 1
28Velocity.y[entity] = 1
29
30// Define a system that moves entities
31const moveSystem = (world) => {
32 for (const eid of query(world, [Position, Velocity])) {
33 Position.x[eid] += Velocity.x[eid]
34 Position.y[eid] += Velocity.y[eid]
35 }
36}
37
38// Game loop
39const loop = () => {
40 moveSystem(world)
41 requestAnimationFrame(loop)
42}
43
44loop()

What's New in 0.4

Version 0.4 is a complete TypeScript rewrite with significant new features:

Relationships

First-class entity relationships with optional data storage, auto-removal, and exclusive targeting.

Observers

Subscribe to component changes with onAdd, onRemove, onSet, and onGet hooks.

Prefabs

Define reusable entity templates with inheritance through the IsA relation.

Query Operators

And, Or, Not operators for complex queries, plus hierarchy traversal.
i
See the Migration Guide if you're upgrading from 0.3.x.