Skip to content

Chapter 18 — Writing a Module

Part V — Building Modules

A guide to extending the engine.

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
},
};
}
PhaseMethodPurpose
Registrationregister(ctx)Wire event listeners, verbs, formulas
Initializationinit(world)Set up module state in world
Teardownteardown(world)Clean up on engine shutdown

Verbs are player-facing actions. Register them during register():

ctx.verbs.register('meditate', (world, action) => {
// resolve the action, produce events
});

Listen for simulation events to react to changes:

ctx.events.on('combat.contact.hit', (event, world) => {
// respond to combat hits
});

Contribute calculations that other modules can use:

ctx.formulas.register('meditation-recovery', (entity, world) => {
return entity.stats.will * 2;
});

Store module-specific data in world.moduleState:

init(world) {
world.moduleState['my-module'] = { activeMeditations: [] };
}

This keeps module state organized and prevents collisions between modules.