Files
dflike/CLAUDE.md
root 513d35e0e5 docs: update CLAUDE.md and README.md to reflect current project state
Fix stale values (test count, cooldown constants, system execution order),
add missing subsystems (LLM, desires, pickup, invention, persistence),
and document newer features (thirst, productivity, day/night cycle,
industry/crafting, LLM configuration).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:01:44 +00:00

9.0 KiB

CLAUDE.md

Project

Multiplayer NPC simulation game (Dwarf Fortress-inspired). Server-authoritative ECS architecture.

Structure

  • shared/ -- Types and constants (no runtime code)
  • server/ -- Node.js + Socket.io game server with ECS
    • server/src/llm/ -- LLM integration (backstory, narration, invention, thought generation)
    • server/src/services/ -- Runtime services (logging)
    • server/src/config/ -- Config and tuning values (relationship, industry, runtime constants)
  • client/ -- Phaser 3 + TypeScript renderer
  • chars/ -- Character sprite assets (do not modify)
  • saves/ -- SQLite save files (gitignored, one .db per region)
  • docs/plans/ -- Design and implementation docs

Commands

  • npm install -- install all workspace dependencies
  • npm -w server run dev -- start server (port 3001), loads existing save or creates new world
  • npm -w server run dev -- --new-world -- start server with fresh world (overwrites save)
  • npm -w server run test -- run server tests
  • npm -w server run test:watch -- run server tests in watch mode
  • npm -w client run dev -- start client dev server (port 3000)
  • npm -w client run build -- build client for production
  • npx -w shared tsc -- rebuild shared types (required after modifying shared/src/)

Tooling

  • ESM modules throughout ("type": "module")
  • Server: tsx (runtime), vitest (tests), better-sqlite3 (persistence)
  • Client: vite (bundler), Phaser 3
  • Shared: compiled to shared/dist/ (auto-built)

Key Entry Points

Core:

  • server/src/main.ts -- server startup, --new-world flag, graceful shutdown (SIGINT/SIGTERM)
  • server/src/game/GameLoop.ts -- tick loop orchestration, save/load integration
  • shared/src/types.ts -- protocol types
  • shared/src/constants.ts -- game constants (incl. portrait slots, folder mapping)

Persistence:

  • server/src/persistence/database.ts -- SQLite connection, schema creation, migration runner
  • server/src/persistence/saveManager.ts -- orchestrates periodic saves, shutdown saves, load-on-startup
  • server/src/persistence/worldSerializer.ts -- save/load map tiles and metadata
  • server/src/persistence/entitySerializer.ts -- save/load entities, components, relationships, bonds
  • server/src/persistence/eventSerializer.ts -- save/load narration, memory, stockpile, invention events

Spawner:

  • server/src/spawner/appearanceGenerator.ts -- NPC appearance + portrait feature generation
  • server/src/spawner/nameGenerator.ts -- NPC name generation
  • server/src/spawner/statGenerator.ts -- 3d6 stat generation for NPCs

Stats & Social:

  • server/src/systems/statHelpers.ts -- getEffectiveStat (base + modifiers, clamped 3-18)
  • server/src/systems/statModifierSystem.ts -- modifier decay and needs-based modifiers
  • server/src/systems/socialSystem.ts -- NPC social interaction phases and stat integration
  • server/src/systems/relationshipSystem.ts -- relationship delta calculation and despawn handling
  • server/src/systems/relationshipHelpers.ts -- classify, getPartnerCap, getFriendCap, getEffectiveClassification
  • server/src/systems/bondRegistry.ts -- mutual bond tracking between NPCs
  • server/src/config/relationshipConfig.ts -- tuning values for relationship system (config-driven)

Industry & Crafting:

  • server/src/systems/industrySystem.ts -- craft/build/gather decision tree
  • server/src/systems/craftingSystem.ts -- input consumption, timer, output production
  • server/src/systems/buildingSystem.ts -- structure creation with build progress
  • server/src/systems/dropoffSystem.ts -- stockpile item deposit
  • server/src/systems/pickupSystem.ts -- stockpile item retrieval for crafting
  • server/src/industry/recipeRegistry.ts -- recipe registry with seed recipes
  • server/src/config/industryConfig.ts -- tuning values for gathering, crafting, building

LLM & AI:

  • server/src/llm/llmService.ts -- LLM client abstraction and request queuing
  • server/src/llm/backstoryGenerator.ts -- NPC backstory and desire generation
  • server/src/llm/narrationService.ts -- narration text generation
  • server/src/llm/eventMemoryService.ts -- event memory management for LLM context
  • server/src/systems/inventionSystem.ts -- LLM-driven recipe invention
  • server/src/systems/thoughtSystem.ts -- NPC thought generation for followed entities
  • server/src/systems/desireGeneratorSystem.ts -- LLM-driven desire generation
  • server/src/systems/desireFulfillmentSystem.ts -- desire progress tracking and completion

Config & Services:

  • server/src/config/runtimeConstants.ts -- runtime-adjustable game constants
  • server/src/services/logService.ts -- structured logging service

Client:

  • client/src/main.ts -- Phaser game bootstrap
  • client/src/scenes/GameScene.ts -- main game scene (camera/avatar/follow modes)
  • client/src/sprites/CharacterCompositor.ts -- sprite layer compositing
  • client/src/sprites/PortraitCompositor.ts -- portrait layer compositing (data URL output)
  • client/src/ui/NpcInfoPanel.ts -- follow-mode NPC info panel (HTML/CSS overlay)

Key Conventions

  • ECS components are plain data objects, systems are pure functions
  • Server owns all game state; clients are renderers
  • Character sprites are 48x48 per frame, 6 cols x 4 rows spritesheet layout
  • Compositing: skins + accessories layered in z-order, cached as single textures
  • Portraits: skin-specific layers composited client-side, exported as data URLs for HTML panel
  • Portrait assets are in chars/baseman/accessories/portraits/ organized by skin folder (skin01-07)
  • Sprite skin shape00_skinXX maps to portrait folder skin{XX+1}, base file skin{XX}.png
  • Shared types ensure client/server protocol agreement
  • Systems run in order: statModifier -> needsDecay -> npcBrain -> social -> relationship -> desireFulfillment -> desireGenerator -> industry -> pickup -> gathering -> crafting -> building -> dropoff -> movement -> thought -> invention
  • Follow mode shows EarthBound-styled NPC info panel with live-updating needs bars and stats
  • NPC stats use 3d6 generation (range 3-18, bell curve): 5 physical (STR/DEX/CON/INT/PER) + 5 personality (SOC/COU/CUR/EMP/TMP)
  • Stats have transient modifiers (needs-based permanent + event-based decaying); effective value = base + modifiers, clamped 3-18
  • Base stats are floats (drift slowly from experience); getEffectiveStat floors to int for gameplay use
  • Wire protocol sends effective (computed) stats only; modifiers stay server-side
  • Relationships: per-NPC Map<EntityId, RelationshipData> component, lazy-initialized on first encounter
  • Relationship values range -100 to 100, classified into tiers (Partner/Friend/Acquaintance/Stranger/Wary/Rival/Enemy/Nemesis)
  • Relationship deltas use diminishing returns and blended asymmetry (30% shared + 70% individual outcome)
  • Stats influence relationships: empathy (positive gain), temperament (negative loss), sociability (friend cap + bonus)
  • Partner cap: default 1, poly (2) requires sociability 15+ AND empathy 14+; friend cap scales with sociability
  • Despawned strong relationships (|value| >= 20) persist as memories; weak ones fade and get cleaned up
  • SocialSystem emits lastOutcome on SocialState; relationshipSystem consumes and clears it
  • NPC info panel has Status/Relations tabs; relationships tab shows tier-grouped sliders with colored markers
  • All relationship tuning values in server/src/config/relationshipConfig.ts (designed for future admin UI)
  • Industry system decides craft/build/gather based on inventory and existing structures
  • RecipeRegistry singleton holds seed recipes (craft_wooden_axe, craft_hammer, build_stockpile, build_workbench)
  • Crafting: 40 tick base, dexterity modifier; consumes inputs, produces output item
  • Building: creates structure entity with buildProgress 0→1; structures have type (stockpile/workshop) + subtype + inventory
  • After gathering, NPCs drop off items at nearest completed stockpile via 'dropoff' goal
  • Movement pauses during gathering, crafting, and building (same skip pattern)
  • World persistence uses SQLite (better-sqlite3) with single file per region at saves/default.db
  • Event data (narration, memory, stockpile, inventions) is written to DB immediately on occurrence
  • Entity state (NPCs, structures, relationships, bonds) is batch-saved every 30 seconds
  • Graceful shutdown (Ctrl-C) triggers final save before exit
  • On startup, loads from existing save or generates fresh world; --new-world flag forces fresh
  • Schema versioning via schema_version in metadata table; migration runner for future schema changes
  • In-memory event buffers (50 entries) are caches over full DB history; populated from DB on startup
  • Map tiles stored fully in DB (not regenerated from seed); decoupled from map generator
  • Entity IDs preserved across save/load via World.createEntityWithId(); nextId counter restored
  • Components with Map types (inventory, pairCooldowns, structure.inventory) serialize via Object.fromEntries/new Map
  • Transient state (movement paths, active social interactions, NPC goals) reset on load; NPCs resume from idle
  • Player entities are not persisted; players reconnect fresh