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
Inheritance
Overrides
Creating Prefabs
Use addPrefab() to create a prefab entity. Prefabs are special entities that serve as templates:
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 componentset() helper requires onSet observers to work. See Inheritance Setup below for the full setup, or the Observers page for details.IsA Relation
The built-in IsA relation establishes inheritance between an entity and a prefab:
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 prefabWhen 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.
| Concept | Description |
|---|---|
| Prefab | Template entity created with addPrefab() |
| Instance | Entity with IsA(prefab) relation |
| Inheritance | Automatic - bitECS walks the IsA chain |
| Override | Setting 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:
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:
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:
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`)
}IsA(prefab) to find instances, not the prefab.Prefab Hierarchies
Prefabs can inherit from other prefabs, creating inheritance hierarchies:
// 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
Specialization
Runtime Flexibility
Memory Efficient
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!