Quick Start

Build a working ECS application in 5 minutes.

Overview

This guide walks you through creating a simple movement system. By the end, you'll understand the core workflow of bitECS.

1. Create a World

A world is the container for all ECS data. Start by creating one:

import { createWorld } from 'bitecs'

const world = createWorld()
i
Worlds are independent - you can have multiple worlds running simultaneously.

2. Define Components

Components are data containers. Define them as objects with arrays:

// Position component (x, y coordinates)
const Position = {
  x: [] as number[],
  y: [] as number[],
}

// Velocity component (movement speed)
const Velocity = {
  x: [] as number[],
  y: [] as number[],
}

This Structure of Arrays (SoA) format stores all x values together and all y values together, which is more cache-efficient than storing each entity's data as a separate object.

3. Add Entities

Entities are just numbers. Create them and attach components:

import { addEntity, addComponent } from 'bitecs'

// Create an entity
const entity = addEntity(world)

// Add components
addComponent(world, entity, Position)
addComponent(world, entity, Velocity)

// Set initial values
Position.x[entity] = 100
Position.y[entity] = 100
Velocity.x[entity] = 2
Velocity.y[entity] = 1

4. Query & Update

Query for entities with specific components and update their data:

import { query } from 'bitecs'

// Find all entities with Position AND Velocity
const movingEntities = query(world, [Position, Velocity])

// Update each entity
for (const eid of movingEntities) {
  Position.x[eid] += Velocity.x[eid]
  Position.y[eid] += Velocity.y[eid]
}

5. Render & Loop

Add a simple render function and run everything in a game loop:

// Get canvas context
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')

// Render system - draw entities as circles
const renderSystem = () => {
  ctx.fillStyle = '#161616'
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  for (const eid of query(world, [Position])) {
    ctx.fillStyle = '#0f62fe'
    ctx.beginPath()
    ctx.arc(Position.x[eid], Position.y[eid], 4, 0, Math.PI * 2)
    ctx.fill()
  }
}

// Game loop
const loop = () => {
  movementSystem(world)
  renderSystem()
  requestAnimationFrame(loop)
}

loop()

Complete Example

quickstart.ts
1import { createWorld, addEntity, addComponent, query } from 'bitecs'
2
3// Components
4const Position = { x: [] as number[], y: [] as number[] }
5const Velocity = { x: [] as number[], y: [] as number[] }
6
7// World
8const world = createWorld()
9
10// Spawn entities
11for (let i = 0; i < 50; i++) {
12 const eid = addEntity(world)
13 addComponent(world, eid, Position)
14 addComponent(world, eid, Velocity)
15 Position.x[eid] = Math.random() * 400
16 Position.y[eid] = Math.random() * 300
17 Velocity.x[eid] = (Math.random() - 0.5) * 3
18 Velocity.y[eid] = (Math.random() - 0.5) * 3
19}
20
21// Movement system
22const movementSystem = () => {
23 for (const eid of query(world, [Position, Velocity])) {
24 Position.x[eid] += Velocity.x[eid]
25 Position.y[eid] += Velocity.y[eid]
26 if (Position.x[eid] < 0 || Position.x[eid] > 400) Velocity.x[eid] *= -1
27 if (Position.y[eid] < 0 || Position.y[eid] > 300) Velocity.y[eid] *= -1
28 }
29}
30
31// Render system
32const canvas = document.querySelector('canvas')
33const ctx = canvas.getContext('2d')
34
35const renderSystem = () => {
36 ctx.fillStyle = '#161616'
37 ctx.fillRect(0, 0, 400, 300)
38 ctx.fillStyle = '#0f62fe'
39 for (const eid of query(world, [Position])) {
40 ctx.beginPath()
41 ctx.arc(Position.x[eid], Position.y[eid], 4, 0, Math.PI * 2)
42 ctx.fill()
43 }
44}
45
46// Game loop
47const loop = () => {
48 movementSystem()
49 renderSystem()
50 requestAnimationFrame(loop)
51}
52
53loop()

Next Steps

Now that you understand the basics: