Chapter 18 — Writing a Module
Part V — Building Modules
A guide to extending the engine.
Module Structure
Section titled “Module Structure”Every module exports a factory function that returns a ModuleDefinition:
export function createMyModule(config?: MyConfig): ModuleDefinition { return { id: 'my-module', register(ctx) { // register verbs // subscribe to events // register formulas }, init(world) { // set up initial state }, teardown(world) { // clean up }, };}Lifecycle
Section titled “Lifecycle”| Phase | Method | Purpose |
|---|---|---|
| Registration | register(ctx) | Wire event listeners, verbs, formulas |
| Initialization | init(world) | Set up module state in world |
| Teardown | teardown(world) | Clean up on engine shutdown |
Registering Verbs
Section titled “Registering Verbs”Verbs are player-facing actions. Register them during register():
ctx.verbs.register('meditate', (world, action) => { // resolve the action, produce events});Subscribing to Events
Section titled “Subscribing to Events”Listen for simulation events to react to changes:
ctx.events.on('combat.contact.hit', (event, world) => { // respond to combat hits});Registering Formulas
Section titled “Registering Formulas”Contribute calculations that other modules can use:
ctx.formulas.register('meditation-recovery', (entity, world) => { return entity.stats.will * 2;});Namespaced State
Section titled “Namespaced State”Store module-specific data in world.moduleState:
init(world) { world.moduleState['my-module'] = { activeMeditations: [] };}This keeps module state organized and prevents collisions between modules.