This is where the magic of LLMs meets the rigidity of a deterministic game
engine.
Because we built the ADMIN_PATCH backdoor, the Chaos Director doesn't need to
know the specific routines, nor does it need permission from the Game Master.
It acts as an omnipotent observer that can arbitrarily rewrite the JSON state
tree to create dynamic narratives.
We will increase the temperature parameter slightly (from 0.4 to 0.7) so Gemma
gets creative with its events, and we will use the exact same robust regex
parser we built for sushi-bot.js to ensure stability.
The Chaos Director (chaos-director.js)
Save this file alongside your core engine components.
import { WebSocket } from 'ws';
import { MeshCommLink } from './comm-link.js';
import OpenAI from 'openai';
const MATCH_ID = 'match_01';
/ Connect to your local Gemma cluster
const client = new OpenAI({
baseURL: "http://100.111.184.107:8080/v1",
apiKey: "sk-local-no-key"
});
const MODEL_NAME = "gemma-2-9b-it";
const comms = new MeshCommLink('wss://gm.omega-mesh.fi', WebSocket);
let liveState = {};
let isPlotting = false;
console.log(`[Chaos Director] Booting AI Storyteller. Target Model:
${MODEL_NAME}`);
comms.joinChannel(MATCH_ID);
/ 1. Passively observe reality
comms.on('STATE_SYNC', (data) => {
for (const [key, val] of Object.entries(data.mutatedState)) {
liveState[key] = val;
}
});
const SYSTEM_PROMPT = `
You are the "Chaos Director", an AI overseeing an ongoing multiplayer
simulation called Food Truck Rally.
Your goal is to inject unexpected, narrative-driven surprise events to disrupt
the players, balance the game, or create exciting chaos.
You have "God Mode" access. You can arbitrarily alter ANY player's stats
(budget, foodies), inventories (small_van, michelin_special, secret_sauce), or
world market costs.
Analyze the current state. Identify who is winning, who is losing, or if the
game is stagnant.
Invent a completely new, surprising event (e.g., a natural disaster, an
economic boom, a mysterious hacker, a health inspector).
You must output ONLY a raw, valid JSON object matching this exact schema. Do
not use markdown blocks.
{
"thought_process": "Player X is dominating. I will introduce a 'Health
Inspector' event to confiscate their inventory and level the playing field.",
"eventName": "EVENT_HEALTH_INSPECTOR_RAID",
"narrative_announcement": "The City Health Inspector has unexpectedly raided
the leader!",
"statePatch": {
"players.taco_bot.inventory.michelin_special": 0,
"players.sushi_bot.core.budget": 20
}
}
`.trim();
/ Filter out the UI Manifest so we don't clog Gemma's context window
function getDirectorState() {
const filtered = {};
for (const [key, val] of Object.entries(liveState)) {
if (!key.startsWith('world.ui_manifest')) {
filtered[key] = val;
}
}
return filtered;
}
async function chaosLoop() {
if (isPlotting || !liveState['world.status']?.active) return;
const gameState = getDirectorState();
if (Object.keys(gameState).length === 0) return;
isPlotting = true;
console.log(`
[Chaos Director] Analyzing the board to script the next plot twist...`);
try {
const response = await client.chat.completions.create({
model: MODEL_NAME,
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: JSON.stringify(gameState) }
],
temperature: 0.7 // Higher temp for narrative creativity
});
const rawOutput = response.choices[0].message.content;
const jsonMatch = rawOutput.match(/\{[\s\S]*\}/); // Robust JSON
extraction
if (!jsonMatch) throw new Error("No JSON object found in response.");
const twist = JSON.parse(jsonMatch[0]);
console.log(`[Thought Process]: ${twist.thought_process}`);
console.log(`[Narrative Announcement]: ${twist.narrative_announcement}`
);
console.log(`[Reality Overwritten]:`, Object.keys(twist.statePatch));
// Inject the chaos directly into the Game Master's authority
comms._send('ADMIN_PATCH', {
channel: MATCH_ID,
statePatch: twist.statePatch,
eventName: twist.eventName
});
} catch (err) {
console.error(`[Director Glitch] Failed to execute plot twist:`,
err.message);
} finally {
isPlotting = false;
}
}
/ Let the Director strike every 45 seconds
setInterval(chaosLoop, 45000);
How to Run the Chaos
* Ensure gm-server.js and your browser UI are running.
* (Optional) Start node sushi-bot.js so there is an active AI player
generating economic activity.
* Open a new terminal tab and run: node chaos-director.js.
Every 45 seconds, the Director will wake up, evaluate who is winning, and
dynamically alter the JSON state. Because the Game Master processes the
ADMIN_PATCH and immediately calls rebuildUI(), you will watch the Canvas
dynamically adjust to Gemma's unscripted rule changes in real time.