Prefabs

Create reusable entity templates with automatic inheritance.

Overview

Prefabs are template entities that other entities can inherit from. When an entity uses the IsA relation with a prefab, it automatically inherits component data through observers.

Templates

Define entity archetypes once, instantiate many times.

Inheritance

Instances inherit component values from their prefab.

Overrides

Instances can override inherited values with their own.

Creating Prefabs

Use addPrefab() to create a prefab entity. Prefabs are special entities that serve as templates:

creating.ts
import { addPrefab, addComponent, set } from 'bitecs'

// Create a prefab (template entity)
const EnemyPrefab = addPrefab(world)

// Add components with default values
addComponent(world, EnemyPrefab, set(Health, { value: 100 }))
addComponent(world, EnemyPrefab, set(Speed, { value: 5 }))
addComponent(world, EnemyPrefab, set(Damage, { value: 10 }))

// Prefabs can have any components
addComponent(world, EnemyPrefab, Enemy)  // Tag component
i
The set() helper requires onSet observers to work. See Inheritance Setup below for the full setup, or the Observers page for details.
i
Prefabs are excluded from regular queries by default. They only serve as templates for other entities.

IsA Relation

The built-in IsA relation establishes inheritance between an entity and a prefab:

isa.ts
import { addEntity, addComponent, IsA } from 'bitecs'

// Create an instance that inherits from EnemyPrefab
const goblin = addEntity(world)
addComponent(world, goblin, IsA(EnemyPrefab))

// goblin now inherits Health, Speed, Damage from EnemyPrefab
// Reading Health.value[goblin] returns 100 (inherited)

// Override specific values
Health.value[goblin] = 50  // Now goblin has 50 health

// Speed and Damage still inherited from prefab
How Inheritance Works

When you call getComponent() on an instance, bitECS automatically walks up the IsA chain to find inherited values. You just needonGet/onSet observers for data storage.

ConceptDescription
PrefabTemplate entity created with addPrefab()
InstanceEntity with IsA(prefab) relation
InheritanceAutomatic - bitECS walks the IsA chain
OverrideSetting data on instance stores locally

Inheritance Setup

Inheritance is automatic with the IsA relation. You just needonSet and onGet observers to define how data is stored and retrieved:

inheritance.ts
import { observe, onGet, onSet } from 'bitecs'

const Health = { value: [] as number[] }

// Store data when set() is called
observe(world, onSet(Health), (eid, params) => {
  Health.value[eid] = params.value
})

// Return data when getComponent() is called
observe(world, onGet(Health), (eid) => ({
  value: Health.value[eid]
}))

With these observers in place, instances automatically inherit from their prefab. When you read from an instance, bitECS walks the IsA chain for you.

Multiple Components

Set up observers for each component that needs data storage:

helper.ts
const Health = { value: [] as number[] }
const Speed = { value: [] as number[] }
const Position = { x: [] as number[], y: [] as number[] }

// Simple helper to set up both observers
const withStore = (component: any) => {
  observe(world, onSet(component), (eid, params) => {
    for (const key in params) {
      component[key][eid] = params[key]
    }
  })

  observe(world, onGet(component), (eid) => {
    const result: any = {}
    for (const key in component) {
      result[key] = component[key][eid]
    }
    return result
  })
}

withStore(Health)
withStore(Speed)
withStore(Position)

Querying Instances

Query for all instances of a prefab using the IsA relation:

querying.ts
import { query, IsA } from 'bitecs'

// Find all entities that are instances of EnemyPrefab
const enemies = query(world, [IsA(EnemyPrefab)])

// Find all enemies with Position (includes inherited components)
const positionedEnemies = query(world, [IsA(EnemyPrefab), Position])

// Process all enemy instances
for (const enemy of enemies) {
  // getComponent respects inheritance via onGet
  const health = getComponent(world, enemy, Health)
  console.log(`Enemy ${enemy} has ${health.value} health`)
}
!
Prefab Queries
Remember that prefabs themselves are excluded from regular queries. Use IsA(prefab) to find instances, not the prefab.

Prefab Hierarchies

Prefabs can inherit from other prefabs, creating inheritance hierarchies:

hierarchies.ts
// Base enemy prefab
const EnemyPrefab = addPrefab(world)
addComponent(world, EnemyPrefab, set(Health, { value: 100 }))
addComponent(world, EnemyPrefab, set(Speed, { value: 5 }))

// Specialized prefabs inherit from base
const GoblinPrefab = addPrefab(world)
addComponent(world, GoblinPrefab, IsA(EnemyPrefab))
addComponent(world, GoblinPrefab, set(Speed, { value: 8 }))  // Override speed

const OgrePrefab = addPrefab(world)
addComponent(world, OgrePrefab, IsA(EnemyPrefab))
addComponent(world, OgrePrefab, set(Health, { value: 500 }))  // Override health
addComponent(world, OgrePrefab, set(Speed, { value: 2 }))    // Slower

// Instances inherit full chain
const goblin = addEntity(world)
addComponent(world, goblin, IsA(GoblinPrefab))
// goblin inherits: Health=100 (from EnemyPrefab), Speed=8 (from GoblinPrefab)

const ogre = addEntity(world)
addComponent(world, ogre, IsA(OgrePrefab))
// ogre inherits: Health=500, Speed=2 (both from OgrePrefab)

Template Reuse

Define common attributes once in base prefabs.

Specialization

Override specific values in derived prefabs.

Runtime Flexibility

Instances can further override any inherited value.

Memory Efficient

Inherited values aren't duplicated per instance.
!
Deep prefab hierarchies can impact performance due to chain lookups. Keep hierarchies shallow (2-3 levels) for best performance.

Common Patterns

Component Bundles

Use prefabs to group common component combinations:

// Renderable bundle
const RenderablePrefab = addPrefab(world)
addComponent(world, RenderablePrefab, Position)
addComponent(world, RenderablePrefab, Sprite)
addComponent(world, RenderablePrefab, Visible)

// Physics bundle
const PhysicsPrefab = addPrefab(world)
addComponent(world, PhysicsPrefab, Position)
addComponent(world, PhysicsPrefab, Velocity)
addComponent(world, PhysicsPrefab, Collider)
addComponent(world, PhysicsPrefab, Mass)

// Entity with both bundles
const player = addEntity(world)
addComponent(world, player, IsA(RenderablePrefab))
addComponent(world, player, IsA(PhysicsPrefab))  // Can have multiple IsA!

Next Steps

Continue Learning