Simulation Context
Every handler receives a SimContext with access to the full simulation state.
API Reference
| Method | Description |
|---|---|
ctx.clock | Current simulation time |
ctx.schedule(type, time, payload) | Schedule a new event |
ctx.cancelEvent(event) | Cancel a scheduled event |
ctx.getEntity(id) | Get an entity by ID |
ctx.addEntity(entity) | Add an entity |
ctx.removeEntity(id) | Remove an entity |
ctx.getAllEntities() | Get all entities |
ctx.store | Global simulation store (typed as TStore) |
ctx.stats | Statistics collector (numeric metrics) |
ctx.random() | Seeded random number (0–1) |
ctx.dist | Context-bound distribution helper |
ctx.warmUpCompleted | Whether the warm-up period has ended |
ctx.log(level, message) | Log a message |
Global Store
The store is a typed, persistent object for accumulating custom data across handlers and hooks. Initialize it via options.store and access it as ctx.store.
type Events = { tick: { value: number } };
type Store = { count: number; total: number };
const sim = new SimulationEngine<Events, Store>({
store: { count: 0, total: 0 },
});
sim.on('tick', (event, ctx) => {
ctx.store.count++;
ctx.store.total += event.payload.value;
});
const result = sim.run();
console.log(result.store); // { count: ..., total: ... }Mutations happen in-place — no proxy or Immer wrapper. The framework does not enforce any schema on the store shape; that is your domain.
The store is deep-cloned via structuredClone, so reset() always restores the exact original state.
Lifecycle Hooks
sim.beforeEach((event, ctx) => { /* before each event */ });
sim.afterEach((event, ctx) => { /* after each event */ });
sim.onEnd((ctx) => { /* when simulation finishes */ });Last updated on