template
Import from @pierre/ecs/template.
EntityTemplate
Section titled “EntityTemplate”Defined in src/template.ts. Engine-agnostic — no knowledge of
specific component types.
interface EntityTemplate { readonly name: string; readonly components?: Readonly<Record<string, unknown>>; readonly tags?: readonly string[];}- name — Human-readable identifier (e.g.
"orc","healPotion") - components — Keys are registered
ComponentDefnames, values are component data - tags — Registered
TagDefnames to add to the entity
World.spawn()
Section titled “World.spawn()”world.spawn(template: EntityTemplate, overrides?: Record<string, unknown>): EntityId- Creates a new entity via
world.createEntity() - Iterates
template.components— resolves each store by name viastoreByName, shallow-merges with matching override, callsstore.set() - Iterates
template.tags— resolves each tag store viatagByName, callsstore.add() - Throws if a component or tag name is not registered
Overrides
Section titled “Overrides”Pass runtime data (e.g. position) that varies per spawn call:
world.spawn(orcTemplate, { positions: { x: 5, y: 10 } });Override values are spread over the template’s component data, so partial overrides work.
Caveats
Section titled “Caveats”- Shallow merge only — Nested structures cannot be partially
overridden. Overriding a single field inside
equipmentsrequires passing the entireequipmentsobject. - Runtime validation — Component/tag name typos (e.g.
renderablevsrenderables) are caught at spawn time, not compile time. This is a trade-off for dynamic registration. - Template names — Must be unique within each template array.
Duplicate names cause
find()to return the first match silently.
composeTemplates()
Section titled “composeTemplates()”composeTemplates(...templates: readonly EntityTemplate[]): EntityTemplateCombines multiple templates into one so content layers (race + class + archetype + variant) can be expressed as plain data without ad-hoc builders.
name— taken from the last template.components— shallow-merged by component name; later inputs win for any component they redeclare. Nested values are replaced wholesale (no deep merge).tags— unioned across all inputs, de-duplicated, preserving first-seen order.- Throws if called with zero templates; never mutates its inputs.
const orc = composeTemplates(baseCreature, orcRace, meleeArchetype, { name: 'orcChieftain', components: { fighter: { hp: 30, attack: 6 } }, tags: ['elite'],});world.spawn(orc, { positions: { x: 5, y: 10 } });See also
Section titled “See also”- Component Store - where template components land.
- EcsWorld -
world.spawn(template, overrides)is the consumer entry point.