Skip to main content
Glama

Elmridge — an AI town sim

A browser town-simulation game built with three.js: a small economy runs day and night, citizens hold jobs, buy food, chat, sleep, and get unhappy when the bakery runs out of bread. Two AI surfaces sit on top:

  1. An MCP server — any MCP-capable agent (Claude, Hermes, …) gets 25 tools to observe and puppet the town: spawn citizens, assign jobs, move people, set policies, build houses, trigger festivals, or rewrite the schedule.

  2. TypeSafe Jev (“System One”) — an optional LLM decision layer on the OpenRouter-compatible endpoint that steers every citizen once per game hour with typed, confidence-gated choices.

Elmridge by day Elmridge at night Citizen detail card

Quick start

npm install
npm start          # game on http://localhost:8080

Drag to orbit, scroll to zoom, click a citizen to open their card. Keys: space pause · 1/2/3 → 1×/2×/4× · H help · Esc deselect.

Related MCP server: onyx MCP

Let AI play with the town (MCP)

The stdio MCP server (src/server/mcp-server.js) bridges to the running game over WebSocket:

# Hermes
hermes mcp add sim-game --command node --args C:/path/to/sim-game/src/server/mcp-server.js

# Claude Desktop / any MCP client
{
  "mcpServers": {
    "sim-game": {
      "command": "node",
      "args": ["C:/path/to/sim-game/src/server/mcp-server.js"]
    }
  }
}

25 tools, all listed in scripts/mcp-test.js:

group

tools

read

get_town get_characters get_character get_buildings get_economy get_events get_ai

people

spawn_character set_job move_character set_activity release_character set_need give_money give_food

world

build demolish set_policy set_time set_speed select announce trigger_event

AI layer

set_ai ask_jev

Actions stream into the UI as “🤖 AI · tool ✓” chips, so you can watch an agent work in real time. select also highlights the citizen in the scene.

TypeSafe Jev decision layer

Set an OpenRouter API key on the game server, then ask your agent to call set_ai:

OPENROUTER_API_KEY=sk-or-… npm start

Once enabled, once per game hour the world state is flattened into a dense text snapshot and every citizen is asked a typed System One question ({ _action: choice, _content: noul, … }). Answers above the confidence gate (0.5) become visible directives: the citizen leaves their schedule, walks somewhere, eats, socialises, or idles — and the HUD card shows the directive with its confidence. ask_jev exposes the raw passthrough for free-form queries. Costs/tokens are tracked (get_ai). Without a key the layer stays offline and the game runs exactly the same.

The key is read from the environment or from %LOCALAPPDATA%/hermes/.env (never printed), so this repo ships with no secrets.

The simulation

Everything tick-based in src/sim/ runs headless and deterministic (seeded mulberry32) — the browser is only a viewer.

  • Jobs — mayor, farmer, baker, merchant, craftsman, bartender, unemployed. Jobs have wages, workplaces, opening hours, and production recipes.

  • Economy — taxes fund the treasury, wages and unemployment pay push coins back out; shops adjust prices daily toward a target sales rate; farms wholesale vegetables to the bakery each morning; treasury pays wages (partial-pay keeps everyone afloat in a shortfall).

  • Needs — hunger, energy, social, morale. Citizens eat at home, buy meals at the market, collapse from hunger, and cheer at festivals.

  • Day cycle — 100 ms ticks, sunrise/sunset lighting, lamps and windows at night, sleep at home, dawn commutes.

All balance numbers (wages, prices, opening hours, build costs, Jev cadence) live in one file: src/sim/config.js.

Stability check: 20 simulated days from seed 1337 end with 0 deaths, 0 broke citizens, treasury 500 → 485.

Tests

npm test           # both suites
# or individually:
node scripts/check.js      # 52 headless assertions: economy, jobs, needs,
                           # commands, events, Jev layer (mocked System One)
node scripts/mcp-test.js   # boots the game, real MCP handshake, all 25 tools

Layout

src/sim/        world, grid/A*, characters, economy, Jev layer  (no I/O)
src/server/     static+WS server · stdio MCP bridge
client/         three.js scene, HUD, websocket client
scripts/        check.js · mcp-test.js
screenshots/    README images

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers