- TypeScript 95.6%
- Shell 2%
- JavaScript 1.9%
- HTML 0.3%
- Dockerfile 0.2%
|
Some checks are pending
Test Suite / test (push) Waiting to run
- Add new character body base entity type with yellow body and cyan head - Include 32 sprite frames: idle and walk animations in 4 directions (e,n,s,w) - Update placeholder generator to create char_body_base sprites - Rebuild sprite atlas (expanded to 512px width to accommodate new frames) |
||
|---|---|---|
| .forgejo/workflows | ||
| apps | ||
| assets | ||
| benchmarks | ||
| build_docs | ||
| infra | ||
| packages | ||
| results-optimized-20260306-160317 | ||
| scripts | ||
| tests | ||
| worlds/default | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| BENCHMARK_SUMMARY.md | ||
| bun.lock | ||
| bunfig.toml | ||
| CLAUDE.md | ||
| package.json | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| TEST_SUITE_FINAL_SUMMARY.md | ||
| TEST_SUITE_PHASE2_COMPLETE.md | ||
| TEST_SUITE_PHASE3_COMPLETE.md | ||
| TEST_SUITE_STATUS.md | ||
| TESTING_GUIDE.md | ||
| tsconfig.base.json | ||
AI-agent MMORPG Sandbox
A monorepo for building an AI-agent-driven isometric MMORPG. Features real-time simulation, WebSocket broadcasting, and a PixiJS-based world viewer.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ ASSET ENGINE (packages/asset-engine) │
│ ┌─────────┐ ┌─────────────┐ ┌─────────┐ ┌───────────┐ │
│ │ sources │ -> │ normalizer │ -> │ packer │ -> │ atlas │ │
│ │ (png) │ │ (quantize) │ │ (layout)│ │ .png │ │
│ └─────────┘ └─────────────┘ └─────────┘ └───────────┘ │
│ │ │
│ v │
│ ┌───────────┐ │
│ │ atlas.json│ │
│ └───────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────────┐
│ WORLD VIEWER (apps/web) │
│ ┌──────────────┐ ┌─────────────┐ ┌───────────────┐ │
│ │ AssetManager │ -> │ Isometric │ -> │ PixiJS Stage │ │
│ │ (load atlas) │ │ Renderer │ │ (tiles+ents) │ │
│ └──────────────┘ └─────────────┘ └───────────────┘ │
│ ^ ^ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ Placeholder │ │ Camera │ │
│ │ Fallback │ │ (pan/zoom) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
^
│
┌─────────────────────────────────────────────────────────────────┐
│ SIM SERVER (apps/sim) │
│ ┌──────────────┐ ┌─────────────┐ ┌───────────────┐ │
│ │ Tick Loop │ -> │ Entity │ -> │ WebSocket │ │
│ │ (8 ticks/s) │ │ Manager │ │ Broadcast │ │
│ └──────────────┘ └─────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Packages
| Package | Description |
|---|---|
packages/asset-engine |
Sprite atlas generation (placeholders, normalization, packing) and Asset Forge pipeline |
packages/world-terrain-generator |
Procedural world generation with biomes, rivers, POIs, roads, and props |
packages/schemas |
JSON schemas for actions and events |
packages/shared |
Shared types and utilities (ULID, types) |
Apps
| App | Port | Description |
|---|---|---|
apps/sim |
3001 | Game simulation server with REST + WebSocket |
apps/web |
3000 | Next.js world viewer with PixiJS rendering |
apps/orchestrator |
3002 | NPC/Director service (placeholder) |
Quick Start
Prerequisites
- bun (recommended) or pnpm
- Node.js 20+
Development
# Install dependencies
bun install
# Start all servers (builds shared package, generates assets if needed)
./scripts/servers.sh start
# Or manually:
# Terminal 1: Sim server
cd apps/sim && bun run src/index.ts
# Terminal 2: Web viewer
cd apps/web && bun run dev
Server Management
./scripts/servers.sh start # Start sim + web servers
./scripts/servers.sh stop # Stop all servers
./scripts/servers.sh restart # Restart servers
./scripts/servers.sh status # Show status and health checks
Access
- World Viewer: http://localhost:3000
- Sim Health: http://localhost:3001/health
- World View API: http://localhost:3001/api/world/view
Asset Pipeline
Generate Placeholder Sprites
cd packages/asset-engine
bun run src/cli.ts placeholders
Creates 77 placeholder sprites in assets/:
- 9 tile types (grass, dirt, water, water_shallow, water_very_shallow, beach, forest, rock, road, stone)
- 2 entity types with 32 animation frames each
- 4 props (tree, chest, rock, shrub)
Build Sprite Atlas
The sprite atlas must be rebuilt whenever you modify or add assets:
cd packages/asset-engine
bun run src/cli.ts build
Outputs to apps/web/public/assets/:
atlas.png- Packed sprite sheetatlas.json- Manifest with frames, anchors, animations
When to rebuild:
- After adding new sprites to
assets/ - After modifying existing sprites (e.g., updating tree graphics)
- After generating placeholder sprites
After rebuilding: Do a hard refresh in your browser to clear the cache:
- Chrome/Firefox:
Ctrl+Shift+R(Windows/Linux) orCmd+Shift+R(Mac) - Or clear your browser cache and refresh
The atlas packs all sprites from assets/ into a single texture for efficient rendering.
Asset Forge (AI-Generated Sprites)
The Asset Forge is a 3-stage pipeline for generating pixel-isometric sprites:
cd packages/asset-engine
bun run forge # Generate sprites using the forge pipeline
Features:
- Style profiles (palette, outline, lighting)
- Templates (canvas sizes, anchors)
- 3-stage pipeline: Render → Conform → Normalize
- Automatic scoring and quality validation
- Atlas export with manifest
See packages/asset-engine/README_FORGE.md for details.
World Generation
The world terrain generator creates procedural, deterministic worlds with biomes, rivers, POIs, and roads.
Quick Start
# Generate a world
./scripts/worldgen.sh generate myworld 64x64
# List generated worlds
./scripts/worldgen.sh list
# Validate a world
./scripts/worldgen.sh validate myworld
# Rebuild assets with all tile types
./scripts/worldgen.sh rebuild-assets
World Generation Features
- 9 Tile Types: grass, dirt, water, water_shallow, beach, forest, rock, road, stone
- 3 POI Types: villages (spawn points), ruins (dungeons), caves
- River System: Downhill tracing from high elevation
- Road Network: A* pathfinding connecting POIs
- Prop Scattering: Trees, rocks, shrubs based on biome density
- Deterministic: Same seed produces identical worlds
Worldgen Script Commands
| Command | Description |
|---|---|
generate [seed] [size] |
Generate a new world (default: 64x64) |
validate <world> |
Validate a world package |
list |
List generated worlds |
rebuild-assets |
Rebuild atlas with all tile types |
help |
Show help |
Generated World Structure
worlds/<seed>/
├── metadata.json # World metadata (id, seed, version, dimensions)
├── tilemap.json # Tile data (w, h, data[])
├── pois.json # Points of interest
├── props.json # Scattered props (trees, rocks, etc.)
└── roads.json # Roads connecting POIs
Sim Server Integration
The sim server automatically loads the world specified by WORLD_SEED:
# Use default world
WORLD_SEED=default bun run src/index.ts
# Use custom world
WORLD_SEED=myworld bun run src/index.ts
API Endpoints
Sim Server (port 3001)
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check with current tick |
/api/entity/:ent_id |
GET | Get entity card |
/api/world/view |
GET | Get world snapshot |
/api/bots/act |
POST | Submit action (move, etc.) |
/ws/world |
WS | Subscribe to map events |
WebSocket Protocol
Subscribe:
{
"type": "subscribe_map",
"shard_id": "shard_01",
"bbox": [0, 0, 63, 63],
"zoom": 4,
"lod": 0,
"after_tick": 0
}
Events received:
{
"type": "map_events",
"events": [
{
"type": "entity_moved",
"tick": 123,
"data": {
"ent_id": "ent_demo",
"from": [5, 5],
"to": [6, 5]
}
}
]
}
Entity Visual Fields
Entities include rendering metadata:
{
ent_id: string;
kind: string;
sprite_id: string; // e.g., "villager_a", "villager_b"
anim: string; // "idle" or "walk"
facing: string; // "s", "e", "n", "w"
x: number;
y: number;
}
World Viewer Features
- Isometric rendering with diamond tiles
- Camera controls: Pan (drag), Zoom (scroll wheel, 1x-4x)
- Entity rendering with placeholder fallbacks
- Real-time updates via WebSocket
- Smooth interpolation during entity movement
Color Palette (16 colors)
Based on fantasy console aesthetics:
#1a1c2c #5d275d #b13e53 #ef7d57
#ffcd75 #a7f070 #38b764 #257179
#29366f #3b5dc9 #41a6f6 #73eff7
#f4f4f4 #94b0c2 #566c86 #333c57
Development Notes
Bun Import Requirements
Bun requires import type for type-only imports:
// Correct
import type { ArtSpec } from "./types.js";
import { DEFAULT_ART_SPEC } from "./types.js";
// Incorrect (causes runtime errors)
import { ArtSpec, DEFAULT_ART_SPEC } from "./types.js";
PixiJS v8 API Changes
- Use
fill({ color: 0x38b764 })instead offill(0x38b764) - Application init is async:
await app.init({ ... }) - Textures use source objects
React StrictMode
The GameViewer component handles StrictMode double-invocation with:
initializedRefguard- Proper cleanup with
cancelledflag - Safe app destruction with try/catch
Docker (Production)
cd infra
docker compose up -d --build
Services:
- Postgres (events/snapshots)
- Redis (pubsub/caches)
- Nginx reverse proxy (TLS-ready)
Project Structure
ai-agent-mmo-sandbox/
├── apps/
│ ├── sim/ # Game simulation server
│ ├── web/ # Next.js world viewer
│ └── orchestrator/ # NPC/Director (placeholder)
├── packages/
│ ├── asset-engine/ # Sprite atlas generation
│ ├── world-terrain-generator/ # Procedural world generation
│ ├── schemas/ # JSON schemas
│ └── shared/ # Shared types
├── assets/ # Source sprites (generated)
├── worlds/ # Generated world packages
├── scripts/ # Utility scripts
│ ├── servers.sh # Server management
│ └── worldgen.sh # World generation helper
└── infra/ # Docker Compose setup
License
MIT