Skip to content

caasi/town-zero

Repository files navigation

town-zero

A multiplayer real-time ecosystem simulation .io game with LLM-driven NPCs. Players coexist with autonomous NPC villagers and monsters in a persistent world. Village destruction = defeat; cooperation is possible but betrayal is allowed.

Getting Started

Prerequisites

  • Node.js 22+
  • pnpm 10+

Install

pnpm install

Run

# Start the server (builds shared types automatically, port 2567)
pnpm run dev:server

# In another terminal, start the client (port 3000)
pnpm run dev:client

Open http://localhost:3000 in your browser.

Build

pnpm run build

Test

pnpm run test

Current State

Working: Full game loop running. Server simulation wired into Colyseus GameRoom with state sync, player commands, vision updates, death notifications, and NPC dialogue. Canvas 2D client renders the world with fog of war, client-side movement prediction (Gambetta reconciliation), HUD, trade modal, and reconnection handling. 434 tests across server and client.

Next: Wire LLM scheduler into GameRoom tick for NPC decision-making.

Controls

  • WASD -- Move
  • Q -- Attack nearest enemy
  • E -- Interact (talk to NPC / trade with merchant)
  • G -- Gather resource at current tile
  • T -- Deposit resources at settlement

How It Works

Players join a 40x40 grid world containing a village and a monster den. Each is a settlement with population, inventory, structures, and territory.

  • NPCs are driven by LLM calls (natural language prompt in, structured JSON commands out) or fall back to a simple rule-based bot controller.
  • Players send commands via keyboard. Disconnected players are seamlessly taken over by bots until they reconnect.
  • Agents gather resources, deposit them at settlements, operate production facilities, trade with merchants, and fight enemies.
  • Fog of war limits each agent's vision to a Manhattan-distance radius. Agents must be adjacent to share map memory with allies.

Simulation Loop (8 ticks/s = 125ms)

  1. Consume one InputFrame per alive agent from inputQueue (player) or planBacklog (bot/LLM); execute via executeFrame (direction → turn-before-move, action → instant effect)
  2. Bot controller decides for idle bot agents → fills planBacklog
  3. Production facilities convert raw materials to food
  4. Agents consume food (starvation causes HP loss and death)
  5. Merchant spawning and movement
  6. Vision update (per-agent MapMemory)
  7. Memory merge between adjacent same-faction agents

Tech Stack

  • Monorepo: pnpm workspaces (shared/, server/, client/)
  • Server: Colyseus 0.17 (@colyseus/core + @colyseus/ws-transport + @colyseus/schema v4)
  • Client: Canvas 2D renderer + @colyseus/sdk + Vite
  • Testing: Vitest (434 tests)
  • Language: TypeScript (strict, ES2022)

Project Structure

shared/          # Types, constants, InputFrame definitions
server/
  src/
    simulation/  # Grid, Agent, Settlement, ExecuteFrame, Resources, Vision, Tick
    ai/          # LLM prompt builder, response parser, scheduler, bot controller
    dialogue/    # Dialogue tree engine, LLM gate, tree data
    map/         # Map generator
    rooms/       # Colyseus GameRoom, schemas, sync, validation, vision
client/
  src/
    main.ts      # Game loop, HUD, overlays, connection management
    network.ts   # Colyseus connection with timeout and reconnect handling
    renderer.ts  # Canvas 2D renderer (terrain, entities, fog overlay)
    camera.ts    # Player-centered viewport with edge clamping
    fog.ts       # Three-tier fog of war (visible / explored / unknown)
    input.ts     # WASD movement + action keys, per-tick input sequencing
    display.ts   # Movement prediction, server reconciliation, lerped rendering
    types.ts     # Client-side type definitions
docs/            # Design spec and implementation plan

License

See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors