cruxVM Runtime
The deterministic simulation engine that brings worlds to life.
Overview
cruxVM is the runtime engine that executes world simulations. It guarantees deterministic execution — the same inputs always produce the same outputs.
Deterministic
Same IR + seed = identical results every time
Fast
Optimized for thousands of ticks per second
Edge-Ready
Works in browsers, Node.js, and edge runtimes
Extensible
Add custom actions and conditions
Creating a VM
Create a VM instance with validated cruxIR. The VM clones the initial state, so you can safely reset to the original.
import { CruxVM } from '@cruxos/vm';
import { validate } from '@cruxos/ir';
// Validate IR first
const result = validate(worldJson);
if (!result.success) {
throw new Error('Invalid IR');
}
// Create VM
const vm = new CruxVM(result.data);
// Run simulation
const output = vm.run(100); // Run 100 ticks
console.log(`Executed: ${output.ticksExecuted} ticks`);
console.log(`Events: ${output.events.length}`);
console.log(`Final state:`, output.finalState);Configuration Options
const vm = new CruxVM(ir, {
maxTicks: 1000, // Maximum ticks to run
onTick: (state) => { // Called after each tick
console.log(`Tick ${state.tick}`);
},
onEvent: (event) => { // Called when events occur
console.log(`Event: ${event.type}`);
}
});Tick Execution
Each tick follows a precise execution order to ensure determinism.
Clear Events
Previous tick's events are cleared
Sort Rules
Rules sorted by priority (higher first)
Execute Rules
For each rule: select agents → check conditions → run actions
Deliver Messages
Move outbox → inbox for all agents
Increment Tick
Advance tick counter, call onTick callback
// Execute single ticks manually
for (let i = 0; i < 10; i++) {
vm.tick();
console.log(`After tick ${i}: ${vm.getState().agents.length} agents`);
}
// Or use run() for multiple ticks
const result = vm.run(100);State Access
Access the current world state and query agents.
// Get full state
const state = vm.getState();
console.log(`Current tick: ${state.tick}`);
console.log(`Agents: ${state.agents.length}`);
// Find specific agent
const agent = vm.getAgent('visitor_1');
console.log(`Position: (${agent.position.x}, ${agent.position.y})`);
// Find agents by type
const visitors = vm.getAgentsByType('visitor');
console.log(`${visitors.length} visitors in the world`);
// Emit custom event
vm.emit('custom_event', { data: 'value' }, 'source_id', 'target_id');
// Reset to initial state
vm.reset();Deterministic RNG
cruxVM uses a seeded pseudo-random number generator. The same seed always produces the same sequence of random numbers.
Using Math.random() breaks determinism. Always use the VM's RNG.
const rng = vm.getRNG();
// Random float [0, 1)
const float = rng.next();
// Random integer in range [min, max]
const roll = rng.range(1, 6);
// Random float in range [min, max)
const percent = rng.rangeFloat(0, 100);
// Random choice from array
const direction = rng.choice(['north', 'south', 'east', 'west']);
// Shuffle array (in place)
const items = ['a', 'b', 'c'];
rng.shuffle(items);RNG Algorithm
cruxVM uses a Mulberry32 PRNG — fast, deterministic, and with good statistical properties. The 32-bit seed is set from the world metadata.
Actions
Actions are functions that modify agent state. They receive a context object with everything needed for deterministic execution.
interface ActionContext {
agent: Agent; // Current agent
rng: DeterministicRNG; // Random number generator
zones: Zone[]; // All zones
agents: Agent[]; // All agents
globals: Record; // Global variables
params: Record; // Rule parameters
tick: number; // Current tick
emit: (type, data?) => void; // Emit event
}Built-in Actions
wander Random movement within bounds
speed: numbermove_toward Move toward a target position
target: {x, y}, speed: numberset_state Update agent state properties
Any key-value pairsdeplete_energy Reduce agent's energy
amount: numberrest Recover energy and set resting state
recovery: numberfly_random Random flight within bounds
speed, maxX, maxY: numberCustom Actions
import { registerAction } from '@cruxos/vm';
registerAction('teleport', (ctx) => {
const { agent, params, rng } = ctx;
// Teleport to random position
agent.position.x = rng.range(0, params.maxX);
agent.position.y = rng.range(0, params.maxY);
// Emit event
ctx.emit('teleported', {
to: { x: agent.position.x, y: agent.position.y }
});
});Conditions
Conditions are expressions that evaluate against agent state to determine if a rule should execute.
Supported Operators
| Operator | Description | Example |
|---|---|---|
== | Equal | mood == "happy" |
!= | Not equal | status != "dead" |
> | Greater than | energy > 50 |
< | Less than | health < 20 |
>= | Greater or equal | level >= 5 |
<= | Less or equal | age <= 100 |
&& | Logical AND | alive && energy > 0 |
|| | Logical OR | flying || swimming |
{
"condition": "energy >= 30 && resting != true && mood == \"happy\""
}Condition Context
Conditions can access:
agent.state.*— Agent's state properties (directly by name)globals.*— Global world variablestick— Current tick number- Zone proximity (via custom conditions)