> ## Documentation Index
> Fetch the complete documentation index at: https://hyperscape-ai-mintlify-docs-update.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Development Setup

> Local development workflow, hot reload, and debugging

## Development Commands

### Core Commands

| Command               | Description                           |
| --------------------- | ------------------------------------- |
| `bun run dev`         | Start game (client + server + shared) |
| `bun run dev:elizaos` | Game + ElizaOS AI agents              |
| `bun run dev:all`     | Everything: game + AI + AssetForge    |
| `bun run build`       | Build all packages                    |
| `bun start`           | Start production server               |

### Package-Specific

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
# From package.json scripts
bun run dev:client    # Client only (port 3333)
bun run dev:server    # Server only (port 5555)
bun run dev:shared    # Shared package with watch mode
bun run dev:turbo     # Turbo-based dev (excludes asset-forge)
bun run dev:reset     # Clean + rebuild + dev (nuclear option)

# Server build tasks
cd packages/server
bun run extract-bounds  # Generate model-bounds.json from GLB files
bun run build           # Build server (runs extract-bounds automatically)

# Asset Forge (in packages/asset-forge/)
cd packages/asset-forge
bun run dev           # Frontend (Vite) + Backend (Elysia) concurrently
bun run dev:frontend  # Vite only
bun run dev:backend   # Elysia API only
```

### Build Pipeline

The server package includes automated tasks for collision footprint extraction:

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
# Extract model bounds (auto-runs during build)
bun run extract-bounds
```

This scans `world/assets/models/**/*.glb` and generates `world/assets/manifests/model-bounds.json` with bounding box data for automatic collision footprint calculation.

**Turbo Caching:**

* Only re-runs when GLB files or script changes
* Outputs cached between builds
* Configured in `packages/server/turbo.json`

### Circular Dependency Handling

The build system handles circular dependencies between packages using resilient build patterns:

```typescript theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
// From packages/procgen/package.json and packages/plugin-hyperscape/package.json
// Use 'tsc || echo' pattern so build exits 0 even with circular dep errors
"build": "tsc || echo 'Build completed with warnings'"
```

**Circular Dependencies:**

* `@hyperscape/shared` ↔ `@hyperscape/procgen` (shared imports from procgen, procgen peer-depends on shared)
* `@hyperscape/shared` ↔ `@hyperscape/plugin-hyperscape` (similar circular dependency)

**Build Strategy:**

* When turbo runs a clean build, tsc fails because the other package's `dist/` doesn't exist yet
* The `|| echo` pattern allows the build to exit 0 even with circular dep errors
* Packages still produce partial output which is sufficient for downstream consumers
* Shared package always uses `--skipLibCheck` in declaration generation to handle circular dependencies

<Info>
  This is a known limitation of the current architecture. The packages produce working output despite TypeScript errors during clean builds.
</Info>

## Port Allocation

| Port | Service        | Started By            |
| ---- | -------------- | --------------------- |
| 3333 | Game Client    | `bun run dev`         |
| 5555 | Game Server    | `bun run dev`         |
| 8080 | Asset CDN      | `bun run dev`         |
| 5432 | PostgreSQL     | Docker (auto)         |
| 4001 | ElizaOS API    | `bun run dev:elizaos` |
| 3400 | AssetForge UI  | `bun run dev:forge`   |
| 3401 | AssetForge API | `bun run dev:forge`   |

## Hot Reload

The dev server provides:

* **Client**: Vite HMR for instant updates
* **Server**: Auto-restart on file changes
* **Shared**: Watch mode with rebuild

## Asset Management

Hyperscape uses a **separate assets repository** to keep the main codebase lightweight and prevent manifest divergence.

### Asset Repository Structure

* **Main repo** (`HyperscapeAI/hyperscape`): Code only, no asset files
* **Assets repo** (`HyperscapeAI/assets`): All game content (manifests, models, textures, audio) (\~200MB with Git LFS)

<Info>
  **Change (Feb 2026)**: Manifests are now sourced exclusively from the assets repo. The main repo no longer tracks any asset files, including JSON manifests.
</Info>

### Local Development

Assets are automatically cloned during `bun install`:

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
# Automatic (runs during bun install)
# See scripts/ensure-assets.mjs

# Manual sync (if needed)
bun run assets:sync
```

The `ensure-assets.mjs` script:

1. Checks if `packages/server/world/assets/` exists
2. If missing, clones `HyperscapeAI/assets` repository
3. **Local dev**: Full clone with LFS for models/textures/audio (\~200MB)
4. **CI/Production**: Shallow clone without LFS (manifests only, \~1MB)

### CI/CD Asset Handling

In CI environments, assets are cloned without LFS (manifests only):

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
# From scripts/ensure-assets.mjs
if (process.env.CI === 'true') {
  // Shallow clone without LFS (manifests only)
  git clone --depth 1 https://github.com/HyperscapeAI/assets.git
  # Manifests are in assets/manifests/ directory
} else {
  // Full clone with LFS for local development
  git clone https://github.com/HyperscapeAI/assets.git
  # Includes models/, textures/, audio/ with Git LFS
}
```

<Warning>
  The entire `packages/server/world/assets/` directory is gitignored. **Never commit asset files to the main repository.** All game content lives in the [HyperscapeAI/assets](https://github.com/HyperscapeAI/assets) repository.
</Warning>

### Asset Updates

When assets are updated in the assets repository:

1. Pull latest assets: `bun run assets:sync`
2. Manifests and models are automatically updated
3. Restart server to reload manifests

**Benefits of Separate Assets Repo:**

* Single source of truth for all game content
* Prevents manifest divergence between repos
* Reduces main repo size (no binary commits)
* Cleaner git history
* Easier asset updates (PR to assets repo, not main repo)
* CI gets manifests without downloading large binary files

### Manifest Files

All manifest JSON files are sourced from the assets repo:

```
HyperscapeAI/assets/
├── manifests/
│   ├── items/
│   │   ├── weapons.json
│   │   ├── tools.json
│   │   ├── resources.json
│   │   ├── food.json
│   │   ├── armor.json
│   │   ├── ammunition.json
│   │   └── runes.json
│   ├── gathering/
│   │   ├── woodcutting.json
│   │   ├── mining.json
│   │   └── fishing.json
│   ├── recipes/
│   │   ├── smelting.json
│   │   ├── smithing.json
│   │   ├── cooking.json
│   │   └── firemaking.json
│   ├── npcs.json
│   ├── stores.json
│   ├── world-areas.json
│   ├── biomes.json
│   ├── vegetation.json
│   ├── combat-spells.json
│   ├── duel-arenas.json
│   ├── tier-requirements.json
│   └── skill-unlocks.json
├── models/          # 3D models (GLB/VRM)
├── textures/        # Texture files
└── audio/           # Music and sound effects
```

**Manifest Loading:**
The server's `DataManager` loads manifests from `packages/server/world/assets/manifests/` which is populated by cloning the assets repo.

## Docker Services

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
bun run cdn:up      # Start CDN container
bun run cdn:down    # Stop CDN container
```

<Info>
  The CDN starts automatically with `bun run dev`. Only run manually if using services separately.
</Info>

## Testing

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
npm test                              # Run all tests
npm test --workspace=packages/server  # Test specific package
npm test --workspace=packages/client  # Client E2E tests
```

<Warning>
  Tests use real Hyperscape instances with Playwright—no mocks allowed. The server must not be running before tests.
</Warning>

### E2E Journey Tests (NEW - February 2026)

Comprehensive end-to-end tests validate the complete player journey from login to gameplay:

**Test File**: `packages/client/tests/e2e/complete-journey.spec.ts`

<Steps>
  <Step title="Login Flow">
    Full authentication and character selection
  </Step>

  <Step title="Loading Screen">
    Uses `waitForLoadingScreenHidden` helper for reliable test synchronization
  </Step>

  <Step title="Spawn">
    Character spawns in world with proper initialization
  </Step>

  <Step title="Walk">
    Movement and pathfinding validation
  </Step>

  <Step title="Screenshot Comparison">
    Utilities to verify game is rendering correctly
  </Step>
</Steps>

**Key Features**:

* **Real Browser Testing**: Uses Playwright with actual WebGPU rendering (no mocks)
* **Screenshot Comparison**: Visual regression testing to verify rendering
* **Loading Screen Detection**: Reliable synchronization helpers
* **Full Gameplay Flow**: Tests complete user journey, not isolated features

**Test Utilities**:

```typescript theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
// From packages/client/tests/e2e/utils/visualTesting.ts

// Wait for loading screen to disappear
await waitForLoadingScreenHidden(page);

// Take screenshot for comparison
await page.screenshot({ path: 'test-output/gameplay.png' });

// Verify game is rendering (not black screen)
const isRendering = await verifyGameRendering(page);
expect(isRendering).toBe(true);
```

**Running Journey Tests**:

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
cd packages/client
npm test -- complete-journey.spec.ts
```

### Test Stability Improvements

Recent commits improved test reliability:

* **GoldClob Fuzz Tests**: 120s timeout for randomized invariant tests (4 seeds × 140 operations)
* **Precision Fixes**: Use larger amounts (10000n) to avoid gas cost precision issues
* **Dynamic Import Timeout**: 60s timeout for EmbeddedHyperscapeService beforeEach hooks
* **Anchor Test Configuration**: Use localnet instead of devnet for free SOL in `anchor test`
* **CI Build Order**: Build impostors/procgen before shared (dependency fix)

## Linting

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
npm run lint        # Lint codebase
npm run typecheck   # TypeScript type checking
```

## GitHub Actions

The repository includes automated workflows for code quality and documentation:

### Claude Code Integration

* **`.github/workflows/claude.yml`** - Responds to `@claude` mentions in issues and PRs for automated assistance
* **`.github/workflows/claude-code-review.yml`** - Automated code review on pull requests
* **`.github/workflows/update-docs.yml`** - Automatically updates documentation when manifest files change

To use Claude Code:

1. Comment `@claude` in any issue or PR
2. Claude will analyze the context and provide assistance
3. For code reviews, Claude automatically reviews new PRs

<Info>
  Requires `CLAUDE_CODE_OAUTH_TOKEN` and `MINTLIFY_API_KEY` secrets to be configured in repository settings.
</Info>

## Code Quality Improvements (February 2026)

### Type Safety Audit (commit d9113595)

Eliminated explicit `any` types in core game logic:

**Files Updated:**

* `tile-movement.ts` - Removed 13 any casts by properly typing BuildingCollisionService
* `proxy-routes.ts` - Replaced any with proper types (unknown, Buffer | string, Error)
* `ClientGraphics.ts` - Added safe cast after WebGPU verification

**Remaining any types:**

* TSL shader code (ProceduralGrass.ts) - @types/three limitation
* Browser polyfills (polyfills.ts) - intentional mock implementations
* Test files - acceptable for test fixtures

### Memory Leak Fix (commit 3bc59db)

Fixed memory leak in InventoryInteractionSystem using AbortController:

```typescript theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
// Before: 9 event listeners never removed
world.on('inventory:add', handler);

// After: Proper cleanup with AbortController
const abortController = new AbortController();
world.on('inventory:add', handler, { signal: abortController.signal });

// Cleanup on system destroy
abortController.abort();
```

### Dead Code Removal (commit 7c3dc985)

Removed 3,098 lines of dead code:

* Deleted `PacketHandlers.ts` (never imported, completely unused)
* Updated audit TODOs to reflect actual codebase state
* ServerNetwork is already decomposed into 30+ modules (not 116K lines)
* ClientNetwork handlers are intentional thin wrappers (not bloated)

### Build System Fixes

**TypeScript Override Conflict (commit 113a85a):**

Removed conflicting TypeScript overrides from root `package.json`. The build system now relies on workspace protocol and Turbo's dependency resolution.

**Windows Environment Variables (commit 3b7665d):**

Fixed native app builds on Windows by conditionally supplying secrets:

```yaml theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
env:
  TAURI_SIGNING_PRIVATE_KEY: ${{ needs.prepare.outputs.is_release == 'true' && secrets.TAURI_SIGNING_PRIVATE_KEY || '' }}
```

**Linux/Windows Desktop Builds (commit f19a7042):**

Fixed unsigned builds for Linux and Windows:

```yaml theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
# Before: --bundles app (macOS-only, caused Linux/Windows to fail)
# After: --no-bundle (works on all platforms)
tauri build --no-bundle
```

**CI Workflow Matrix Reference (commit a095ba1):**

Removed invalid matrix reference from job-level condition. Matrix variables are only available during job execution, not at job scheduling time.

## Common Workflows

### Adding a New Feature

1. Make changes in `packages/shared/src/`
2. Hot reload applies automatically
3. Test in browser at localhost:3333

### Updating Game Content

1. Edit manifest files in `world/assets/manifests/`
2. Restart server to reload manifests
3. Documentation updates automatically via GitHub Actions

### Debugging Server

1. Check terminal output for errors
2. Server logs show WebSocket activity
3. Database queries logged in dev mode

### Clean Rebuild

```bash theme={"theme":{"light":"github-light","dark":"tokyo-night"}}
bun run clean
rm -rf node_modules packages/*/node_modules
bun install
bun run build
```
