AGENT WORLD
A pixel-art town that runs on my real MCP stack. Each NPC is a service I use — Asana, Notion, n8n, Linear, Arc, Google Drive, Excalidraw, Granola, Claude Code — and when a task lands or a workflow fires, the matching NPC wakes up and walks to its quarter.
9 Sources → 9 Archetypes
Every tool in my stack maps to one NPC archetype. Real activity lands — a task, a page, a workflow run — and the matching agent wakes up and walks to its quarter.
From MCP to NPC
The town sits on top of my live MCP and automation stack. Work that happens in a tool runs through the adapter layer and shows up in the world as an NPC reaction.
notion, asana, make, second-brain — the layer where I actually work.
A new Asana task, a Notion page edit, a Drive upload, a Claude Code session.
Express + ws. Up to 6 live integrations (Asana, Notion, n8n, Linear, plus file watchers for Excalidraw and Claude Code). Mocks fall back when env tokens are missing.
Typed events only — source, type, data, timestamp. No game logic on the server.
SOURCE_TO_AGENT maps the event to an idle agent of matching type. assignTask() fires.
Specialized Agents
Procedural Buildings
Agent.ts Lines
State Machine States
Four states per agent
Every agent cycles through idle, alert, walking, and working — a real event turns into a roughly five-second scene you can watch. All four transitions sit in one Agent.ts class, 429 lines, no framework.
type AgentState = 'idle' | 'walking' | 'working' | 'alert';
// Event arrives → alert → walk → work → back to idle
assignTask(taskName: string, duration: number, destX: number, destY: number) {
this.pendingTask = { name: taskName, duration };
this.showAlert(); // state: 'alert'
setTimeout(() => this.walkTo(destX, destY), 600); // state: 'walking'
// On arrival: startWork() → state: 'working' + progress bar + bubble
// On finish: completeWork() → state: 'idle' + green particle burst
}Calls I'd defend
- →Phaser 3 over raw Canvas
It ships a sprite system, physics, and scene management. On raw Canvas I'd have rebuilt half of that myself.
- →The agents walk before they work
An event could flip a tile straight to "done" — but then there's nothing to see. The detour makes an Asana card closing something you watch happen, not a number that ticks up.
- →EventDispatcher is one source-to-archetype dictionary
9 sources map to 9 archetypes in one dictionary. The game scene never hears Asana or Notion — only Gildenläufer and Magier — so a new tool is one adapter and one line in the map.
- →Polling by default, webhooks when I want them
AdapterManager polls every 30s, so the server runs locally without tunnels. A POST /api/webhook endpoint gives n8n near-instant NPC reactions when I want them.