World

A World is the container for all ECS data - entities, components, and queries.

Overview

A world is the top-level container for all ECS data. Entities are created within a world, and data is queried based on the existence and shape of entities in that world. Each world is completely independent of all others.

Isolated

Each world has its own entities, components, and query state.

Lightweight

Worlds are cheap to create. Use multiple for different game states.

Extensible

Add custom context data directly to your world object.

Creating a World

Create a new world with createWorld():

basic.ts
import { createWorld, addEntity, addComponent } from 'bitecs'

const world = createWorld()

// Add entities and components
const eid = addEntity(world)
addComponent(world, eid, Position)

console.log(eid)  // 1

Custom Context

Pass an object to createWorld() to use as a custom context. The same reference is returned, so you can access your data directly on the world:

context.ts
const context = {
  time: {
    then: 0,
    delta: 0,
  },
  input: {
    keys: new Set<string>(),
  },
  renderer: null as CanvasRenderingContext2D | null,
}

const world = createWorld(context)

// world === context is true!
console.log(world === context)  // true

// Access your data in systems
const timeSystem = (world) => {
  const now = performance.now()
  world.time.delta = now - world.time.then
  world.time.then = now
}

const inputSystem = (world) => {
  if (world.input.keys.has('Space')) {
    // Handle jump...
  }
}
Why Custom Context?

Custom context keeps all game state in one place. Instead of passing delta time, input state, or renderer references separately to each system, attach them to the world. Systems only need one parameter.

Common Context Patterns

patterns.ts
// Game loop timing
const world = createWorld({
  time: { delta: 0, elapsed: 0, frame: 0 }
})

// Physics configuration
const world = createWorld({
  physics: { gravity: 9.8, friction: 0.1 }
})

// External references
const world = createWorld({
  canvas: document.querySelector('canvas'),
  assets: new Map(),
  audio: new AudioContext(),
})

Multiple Worlds

Worlds are independent. Use multiple worlds to separate game states or run parallel simulations:

multiple.ts
// Separate worlds for different purposes
const gameWorld = createWorld({ scene: 'game' })
const uiWorld = createWorld({ scene: 'ui' })
const physicsWorld = createWorld({ scene: 'physics' })

// Each has its own entities
addEntity(gameWorld)   // 1 (in gameWorld)
addEntity(uiWorld)     // 1 (in uiWorld - independent!)
addEntity(gameWorld)   // 2 (in gameWorld)
!
Use Cases for Multiple Worlds
  • UI vs Game - Keep UI entities separate from game entities
  • Level Streaming - Load next level in background world, then swap
  • Multiplayer Rooms - Each game room or match runs in its own world

Shared Entity Index

By default, each world has its own entity ID space. If you need multiple worlds to share entity IDs (e.g., entities that exist in multiple worlds), create a shared index:

shared-index.ts
import { createWorld, createEntityIndex, addEntity } from 'bitecs'

// Create a shared entity index
const entityIndex = createEntityIndex()

// Create worlds that share the same entity ID space
const worldA = createWorld(entityIndex)
const worldB = createWorld(entityIndex)

// Entity IDs are unique across ALL worlds using this index
addEntity(worldA) // 1
addEntity(worldB) // 2
addEntity(worldA) // 3

Shared vs Separate Entity IDs

// Without shared index (default) - IDs can collide!
const w1 = createWorld()
const w2 = createWorld()
console.log(addEntity(w1), addEntity(w2))  // 1, 1 (same IDs!)

// With shared index - IDs are unique across worlds
const index = createEntityIndex()
const w3 = createWorld(index)
const w4 = createWorld(index)
console.log(addEntity(w3), addEntity(w4))  // 1, 2 (unique IDs)

Combine custom context with a shared entity index - pass them in any order:

// Both work identically
createWorld({ data: 1 }, entityIndex)
createWorld(entityIndex, { data: 1 })
!
If you're using global components (defined outside any world) with multiple worlds, you must use a shared entity index. Otherwise, entity IDs may collide and overwrite each other's data.

Entity Versioning

Enable versioning to detect stale entity references after an entity is removed and its ID recycled:

versioning.ts
import { createEntityIndex, withVersioning, getId, getVersion } from 'bitecs'

// Enable versioning with 8 bits for version (default)
const index = createEntityIndex(withVersioning())

// Or specify custom version bits
const index = createEntityIndex(withVersioning(16))

const world = createWorld(index)

const eid = addEntity(world)
console.log(getId(index, eid))       // 1 (base ID)
console.log(getVersion(index, eid))  // 0 (first version)

removeEntity(world, eid)
const newEid = addEntity(world)      // Reuses ID 1

console.log(getId(index, newEid))       // 1 (same base ID)
console.log(getVersion(index, newEid))  // 1 (incremented version)

World Utilities

Functions for inspecting and managing worlds:

FunctionDescription
resetWorld(world)Clear all entities, keep component registrations
deleteWorld(world)Completely delete a world and free resources
getWorldComponents(world)Get all registered components
getAllEntities(world)Get array of all entity IDs
utilities.ts
import {
  resetWorld,
  deleteWorld,
  getWorldComponents,
  getAllEntities
} from 'bitecs'

// Get all entity IDs currently in the world
const entities = getAllEntities(world)
console.log(`World has ${entities.length} entities`)

// Get all registered components
const components = getWorldComponents(world)
console.log(`${components.length} components registered`)

// Reset world - removes all entities, keeps registrations
resetWorld(world)
console.log(getAllEntities(world).length)  // 0

// Completely delete when done
deleteWorld(world)

Next Steps

Continue Learning

  • Entities - Create and manage entities within a world
  • Components - Add data to your entities
  • Queries - Find entities by their components
  • Systems - Process entities each frame