Overview
The @hyperscape/shared package is the core Hyperscape engine, providing:
- Entity Component System (ECS)
- Three.js 3D rendering
- PhysX physics simulation
- Real-time networking
- React UI components
- Game data manifests
Package Location
packages/shared/
├── src/
│ ├── components/ # ECS components
│ ├── constants/ # Game constants
│ ├── core/ # Core engine classes
│ ├── data/ # Game manifests (npcs, items, etc.)
│ ├── entities/ # Entity definitions
│ │ ├── player/ # PlayerEntity, PlayerLocal, PlayerRemote
│ │ ├── npc/ # MobEntity, NPCEntity
│ │ ├── world/ # World entities
│ │ └── managers/ # Entity managers
│ ├── extras/ # Additional utilities
│ ├── libs/ # External integrations
│ ├── nodes/ # Scene graph nodes
│ ├── physics/ # PhysX wrapper
│ ├── platform/ # Platform detection
│ ├── runtime/ # Game loop
│ ├── systems/ # ECS systems
│ │ ├── client/ # Client-only systems
│ │ ├── server/ # Server-only systems
│ │ └── shared/ # Shared systems (combat, economy, etc.)
│ ├── types/ # TypeScript types
│ └── utils/ # Helper functions
├── index.ts # Server exports
└── index.client.ts # Client exports
Rendering
WebGPU with WebGL Fallback
The shared package includes renderer factory utilities for creating renderers with automatic fallback:
// From src/utils/rendering/RendererFactory.ts
import { createRenderer, isWebGPURenderer, getRendererBackend } from '@hyperscape/shared';
// Create renderer (WebGPU preferred, WebGL fallback)
const renderer = await createRenderer({
antialias: true,
powerPreference: "high-performance",
});
// Check backend
const isWebGPU = isWebGPURenderer(renderer); // true or false
const backend = getRendererBackend(renderer); // "webgpu" or "webgl"
Renderer Features:
- Automatic WebGPU detection and fallback to WebGL
- Works in WKWebView (Tauri), older Safari, and browsers without WebGPU
- Configurable shadow maps and post-processing
- Max anisotropy detection
Environment System:
- Auto exposure for day/night cycle (mimics eye adaptation)
- Cascaded shadow maps (WebGPU) or single directional shadows (WebGL)
- Dynamic ambient lighting based on time of day
- Fog color transitions
Key Exports
Entity Hierarchy
The entity system follows a clear inheritance pattern:
// From packages/shared/src/entities/Entity.ts (lines 26-38)
// Entity (base class)
// ├── InteractableEntity (can be interacted with)
// │ ├── ResourceEntity (trees, rocks, fishing spots)
// │ ├── ItemEntity (ground items)
// │ └── NPCEntity (dialogue, shops)
// ├── CombatantEntity (can fight)
// │ ├── PlayerEntity (base player)
// │ │ ├── PlayerLocal (client-side local player)
// │ │ └── PlayerRemote (client-side remote players)
// │ └── MobEntity (enemies)
// └── HeadstoneEntity (player death markers)
| Export | Purpose |
|---|
Entity | Base entity class with components, physics, networking |
CombatantEntity | Combat-capable entities with health, damage |
InteractableEntity | Objects players can interact with |
PlayerEntity | Server-side player with full stats, inventory |
PlayerLocal | Client-side local player with input handling |
PlayerRemote | Client-side representation of other players |
MobEntity | NPCs and hostile mobs with AI states |
HeadstoneEntity | Death marker for item retrieval |
Systems (Shared)
Located in src/systems/shared/:
| Category | Systems |
|---|
character/ | Character stats, equipment, skills, inventory |
combat/ | Combat mechanics, damage, death, aggro |
death/ | Death handling, respawn, safe zones |
economy/ | Banks, shops, trading, loot |
entities/ | Entity lifecycle, spawning, resource management |
interaction/ | Player-world interactions, dialogue, processing |
movement/ | Tile-based movement, collision, pathfinding |
presentation/ | Visual rendering, particles, music |
progression/ | Quest system, achievements |
tick/ | Game tick processing, NPC AI |
world/ | Terrain generation, flat zones, biomes, vegetation |
Collision System
The movement system includes a unified collision matrix for OSRS-accurate tile blocking:
// From packages/shared/src/systems/shared/movement/
export { CollisionMatrix } from './CollisionMatrix';
export { CollisionFlag, CollisionMask } from './CollisionFlags';
export { EntityOccupancyMap } from './EntityOccupancyMap';
export { TileSystem } from './TileSystem';
Key Exports:
| Export | Purpose |
|---|
CollisionMatrix | Zone-based collision storage (8×8 tile zones) |
CollisionFlag | Bitmask flags (BLOCKED, WATER, OCCUPIED, walls) |
CollisionMask | Combined masks (BLOCKS_WALK, BLOCKS_MOVEMENT) |
EntityOccupancyMap | Entity tracking facade over CollisionMatrix |
tilesWithinRangeOfFootprint | Multi-tile interaction range checks |
Usage:
import { CollisionMatrix, CollisionMask } from '@hyperscape/shared';
const collision = new CollisionMatrix();
// Check if tile is walkable
if (!collision.hasFlags(x, z, CollisionMask.BLOCKS_WALK)) {
// Safe to move
}
// Add blocking for a tree
collision.addFlags(x, z, CollisionFlag.BLOCKED);
Data Manifests
Game content is defined in TypeScript files in src/data/:
| File | Purpose |
|---|
DataManager.ts | Runtime loader for manifests |
npcs.ts | NPC/mob definitions with drops, stats |
items.ts | Item definitions with stats, requirements |
world-areas.ts | Zone configuration |
banks-stores.ts | Shop inventories and bank locations |
avatars.ts | VRM avatar options |
playerEmotes.ts | Emote animation URLs |
world-structure.ts | World layout and spawn points |
equipment-stats.json | Equipment bonuses |
equipment-requirements.json | Level requirements |
NPC data is loaded from JSON manifests at runtime by DataManager.
Add new NPCs in world/assets/manifests/npcs.json.
Skill Unlocks API
The skill unlocks system provides functions for querying what players unlock at each level:
import {
getAllSkillUnlocks,
getUnlocksAtLevel,
getUnlocksUpToLevel,
loadSkillUnlocks,
type SkillUnlock
} from '@hyperscape/shared';
// Load from manifest (called by DataManager)
loadSkillUnlocks(manifest);
// Get all unlocks for a skill
const attackUnlocks = getAllSkillUnlocks()["attack"];
// Get unlocks at specific level
const level40Unlocks = getUnlocksAtLevel("attack", 40);
// Returns: [{ level: 40, description: "Rune weapons", type: "item" }]
// Get all unlocks up to level
const unlockedSoFar = getUnlocksUpToLevel("attack", 45);
Defence/Defense Normalization:
The system automatically handles British/American spelling:
// skill-unlocks.json uses "defence" (OSRS-accurate)
// UI uses "defense" (codebase convention)
// Both work - normalization happens at load time
const defenceUnlocks = getAllSkillUnlocks()["defence"]; // Works
const defenseUnlocks = getAllSkillUnlocks()["defense"]; // Also works
This allows the manifest to use OSRS-accurate British spelling while the codebase uses American spelling consistently.
Entry Points
Server (index.ts)
Exports for server-side usage:
import {
Entity,
DataManager,
PlayerEntity,
MobEntity
} from '@hyperscape/shared';
Client (index.client.ts)
Exports for client-side usage:
import {
Entity,
PlayerLocal,
PlayerRemote
} from '@hyperscape/shared/client';
Dependencies
| Package | Version | Purpose |
|---|
three | 0.181.0 | 3D rendering |
@pixiv/three-vrm | 3.4.3 | VRM avatar support |
@hyperscape/physx-js-webidl | workspace | Physics |
react | ^19.2.0 | UI components |
fastify | ^5.0.0 | HTTP server (server builds) |
livekit-client | ^2.9.9 | Voice chat |
Recent Changes
Terrain Flattening System (PR #644)
The terrain system now supports flat zones under stations for proper building placement:
- FlatZone interface — Defines rectangular flat areas with smooth blending
- Spatial indexing — O(1) flat zone lookup using terrain tiles
- Manifest-driven — Stations configure
flattenGround, flattenPadding, flattenBlendRadius
- Dynamic registration —
registerFlatZone(), unregisterFlatZone(), getFlatZoneAt()
See Terrain System for details.
Equipment System Fixes (PR #641)
Atomic equip/unequip operations prevent item duplication:
- Transaction locks prevent race conditions
- Order of operations — Remove from inventory FIRST (equip), clear equipment FIRST (unequip)
- Rollback on failure — Restores state if operation fails
- New helper methods —
hasSpace(), hasItemAtSlot(), removeItemDirect(), addItemDirect()
Building
cd packages/shared
bun run build # Production build
bun run dev # Watch mode with auto-rebuild
Shared must be built before other packages that depend on it. Turbo handles this automatically.
Key Patterns
ECS Architecture
All game logic uses Entity Component System. See ECS Concepts.
Manifest-Driven Data
Game content defined in src/data/. See Manifests.
Type Safety
Strong TypeScript typing throughout—no any types allowed. ESLint enforces this rule.
Dual Entry Points
index.ts: Server-side exports (includes Fastify, database utilities)
index.client.ts: Client-side exports (browser-compatible)