This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Hyperscape is a RuneScape-style MMORPG built on a custom 3D multiplayer engine. The project features a real-time 3D metaverse engine (Hyperscape) in a persistent world.
# Install dependencies
bun install
# Build all packages (required before first run)
bun run build
# Development mode with hot reload
bun run dev
# Start game server (production mode)
bun start # or: cd packages/server && bun run start
# Run all tests
npm test
# Lint codebase
npm run lint
# Clean build artifacts
npm run clean# Build individual packages
bun run build:shared # Core engine (must build first)
bun run build:client # Web client
bun run build:server # Game server
# Development mode for specific packages
bun run dev:shared # Shared package with watch mode
bun run dev:client # Client with Vite HMR
bun run dev:server # Server with auto-restart# Run all tests (uses Playwright for real gameplay testing)
npm test
# Run tests for specific package
npm test --workspace=packages/server
# Tests MUST use real Hyperscape instances - NO MOCKS ALLOWED
# Visual testing with screenshots and Three.js scene introspection# iOS
npm run ios # Build, sync, and open Xcode
npm run ios:dev # Sync and open without rebuild
npm run ios:build # Production build
# Android
npm run android # Build, sync, and open Android Studio
npm run android:dev # Sync and open without rebuild
npm run android:build # Production build
# Capacitor sync (copy web build to native projects)
npm run cap:sync # Sync both platforms
npm run cap:sync:ios # iOS only
npm run cap:sync:android # Android only# Generate API documentation (TypeDoc)
npm run docs:generate
# Start docs dev server (http://localhost:3402)
bun run docs:dev
# Build production docs
npm run docs:buildThis is a Turbo monorepo with packages:
packages/
├── shared/ # Core Hyperscape 3D engine
│ ├── Entity Component System (ECS)
│ ├── Three.js + PhysX integration
│ ├── Real-time multiplayer networking
│ └── React UI components
├── server/ # Game server (Fastify + WebSockets)
│ ├── World management
│ ├── SQLite/PostgreSQL persistence
│ └── LiveKit voice chat integration
├── client/ # Web client (Vite + React)
│ ├── 3D rendering
│ ├── Player controls
│ └── UI/HUD
├── physx-js-webidl/ # PhysX WASM bindings
├── asset-forge/ # AI asset generation (GPT-4, MeshyAI)
└── docs-site/ # Docusaurus documentation site
Critical: Packages must build in this order due to dependencies:
- physx-js-webidl - PhysX WASM (takes longest, ~5-10 min first time)
- shared - Depends on physx-js-webidl
- All other packages - Depend on shared
The turbo.json configuration handles this automatically via dependsOn: ["^build"].
The RPG is built using Hyperscape's ECS architecture:
- Entities: Game objects (players, mobs, items, trees)
- Components: Data containers (position, health, inventory)
- Systems: Logic processors (combat, skills, movement)
All game logic runs through systems, not entity methods. Entities are just data containers.
Important: Despite references to "Hyperscape apps (.hyp)" in development rules, .hyp files do not currently exist. This is an aspirational architecture pattern for future development.
Current Implementation: The RPG is built directly into packages/shared/src/ using:
- Entity Classes: PlayerEntity.ts, MobEntity.ts, ItemEntity.ts
- ECS Systems: Combat, inventory, skills, AI in src/systems/
- Components: Data containers for stats, health, equipment, etc.
Design Principle (from development rules):
- Keep RPG game logic conceptually isolated from core Hyperscape engine
- Use existing Hyperscape abstractions (ECS, networking, physics)
- Don't reinvent systems that Hyperscape already provides
- Separation of concerns: core engine vs. game content
NO any types are allowed - ESLint will reject them.
- Prefer classes over interfaces for type definitions
- Use type assertions when you know the type:
entity as Player - Share types from
types.tsfiles - don't recreate them - Use
import typefor type-only imports - Make strong type assumptions based on context (don't over-validate)
// ❌ FORBIDDEN
const player: any = getEntity(id);
if ('health' in player) { ... }
// ✅ CORRECT
const player = getEntity(id) as Player;
player.health -= damage;Don't create new files unless absolutely necessary.
- Revise existing files instead of creating
_v2.tsvariants - Delete old files when replacing them
- Update all imports when moving code
- Clean up test files immediately after use
- Don't create temporary
check-*.ts,test-*.mjs,fix-*.jsfiles
NO MOCKS - Use real Hyperscape instances with Playwright.
Every feature MUST have tests that:
- Start a real Hyperscape server
- Open a real browser with Playwright
- Execute actual gameplay actions
- Verify with screenshots + Three.js scene queries
- Save error logs to
/logs/folder
Visual testing uses colored cube proxies:
- 🔴 Players
- 🟢 Goblins
- 🔵 Items
- 🟡 Trees
- 🟣 Banks
- No TODOs or "will fill this out later" - implement completely
- No hardcoded data - use JSON files and general systems
- No shortcuts or workarounds - fix root causes
- Build toward the general case (many items, players, mobs)
- Data vs Logic: Never hardcode data into logic files
- RPG vs Engine: Keep RPG isolated from Hyperscape core
- Types: Define in
types.ts, import everywhere - Systems: Use existing Hyperscape systems before creating new ones
Before creating new abstractions, research existing Hyperscape systems:
- Check packages/shared/src/systems/
- Look for similar patterns in existing code
- Use Hyperscape's built-in features (ECS, networking, physics)
- Read entity/component definitions in
types/folders
Getting Systems:
const combatSystem = world.getSystem('combat') as CombatSystem;Entity Queries:
const players = world.getEntitiesByType('Player');Event Handling:
world.on('inventory:add', (event: InventoryAddEvent) => {
// Handle event - assume properties exist
});The dev server provides:
- Hot module replacement (HMR) for client
- Auto-rebuild and restart for server
- Watch mode for shared package
- Colored logs for debugging
Commands:
bun run dev # Core game (client + server + shared)
bun run dev:forge # AssetForge (standalone)
bun run docs:dev # Documentation site (standalone)All services have unique default ports to avoid conflicts:
| Port | Service | Env Var | Started By |
|---|---|---|---|
| 3333 | Game Client | VITE_PORT |
bun run dev |
| 3400 | AssetForge UI | ASSET_FORGE_PORT |
bun run dev:forge |
| 3401 | AssetForge API | ASSET_FORGE_API_PORT |
bun run dev:forge |
| 3402 | Docusaurus | (hardcoded) | bun run docs:dev |
| 5555 | Game Server | PORT |
bun run dev |
Zero-config local development: The defaults work out of the box. Just run bun run dev.
Package-specific .env files: Each package has its own .env.example with deployment documentation:
| Package | File | Purpose |
|---|---|---|
| Server | packages/server/.env.example |
Server deployment (Railway, Fly.io, Docker) |
| Client | packages/client/.env.example |
Client deployment (Vercel, Netlify, Pages) |
| AssetForge | packages/asset-forge/.env.example |
AssetForge deployment |
Common variables:
# Server (packages/server/.env)
DATABASE_URL=postgresql://... # Required for production
JWT_SECRET=... # Required for production
PRIVY_APP_ID=... # For Privy auth
PRIVY_APP_SECRET=... # For Privy auth
# Client (packages/client/.env)
PUBLIC_PRIVY_APP_ID=... # Must match server's PRIVY_APP_ID
PUBLIC_API_URL=https://... # Point to your server
PUBLIC_WS_URL=wss://... # Point to your server WebSocketSplit deployment (client and server on different hosts):
PUBLIC_PRIVY_APP_ID(client) must equalPRIVY_APP_ID(server)PUBLIC_WS_URLandPUBLIC_API_URLmust point to your server
This project uses Bun (v1.1.38+) as the package manager and runtime.
- Install:
bun install(NOTnpm install) - Run scripts:
bun run <script>orbun <file> - Some commands use
npmprefix for Turbo workspace filtering
- Runtime: Bun v1.1.38+
- Engine: Three.js 0.180.0, PhysX (WASM)
- UI: React 19.2.0, styled-components
- Server: Fastify, WebSockets, LiveKit
- Database: SQLite (local), PostgreSQL (production via Neon)
- Testing: Playwright, Vitest
- Build: Turbo, esbuild, Vite
- Mobile: Capacitor
# Clean everything and rebuild
npm run clean
rm -rf node_modules packages/*/node_modules
bun install
bun run buildPhysX is pre-built and committed. If it needs rebuilding:
cd packages/physx-js-webidl
./make.sh # Requires emscripten toolchain# Kill processes on common Hyperscape ports
lsof -ti:3333 | xargs kill -9 # Game Client
lsof -ti:5555 | xargs kill -9 # Game ServerSee Port Allocation section for full port list.
- Ensure server is not running before tests
- Check
/logs/folder for error details - Tests spawn their own Hyperscape instances
- Visual tests require headless browser support
- README.md - Full project documentation
- .cursor/rules/ - Detailed development rules
- packages/shared/ - Core engine source
- Game Design Document: See
.cursor/rules/gdd.mdc