Overview
Hyperscape uses manifest-driven design where game content is defined in TypeScript data files rather than hardcoded in logic. This enables content creation without modifying game systems.Design Philosophy
Separation of Concerns
| Layer | Responsibility |
|---|---|
| Manifests | Content definitions (what exists) |
| Systems | Game logic (how things work) |
| Entities | Runtime instances |
Benefits
- Content creators can add items, NPCs, areas without deep coding
- Designers iterate quickly on balance
- Developers focus on systems, not data
- Modders can extend content easily
Manifest Files
Manifests are JSON files that define game content. They are stored inpackages/server/world/assets/manifests/ and served from the CDN in production.
Manifest Loading
Development:- Manifests loaded from local filesystem:
packages/server/world/assets/manifests/ - Assets cloned from HyperscapeAI/assets via Git LFS during
bun install - CDN fetching skipped if local manifests exist (allows local modifications)
- Local CDN serves assets at
http://localhost:8080
- Manifests fetched from CDN at server startup:
PUBLIC_CDN_URL/manifests/ - Cached locally in
packages/server/world/assets/manifests/ - Only re-fetched if content changes (HTTP ETag validation)
- Assets served directly from Cloudflare R2 CDN (no local clone)
- Frontend served from Cloudflare Pages (separate from game server)
- Set
CI=trueorSKIP_ASSETS=trueto skip asset download - Set
SKIP_MANIFESTS=trueorNODE_ENV=testto allow starting without manifests - Useful for unit tests that don’t need full game content
Fetch Implementation
ThefetchManifestsFromCDN function in packages/server/src/startup/config.ts handles manifest synchronization:
Manifest Directory Structure
All manifests are inworld/assets/manifests/:
| File | Content |
|---|---|
npcs.json | Mobs and NPCs |
items/ | Equipment, resources, consumables (split by category) |
banks-stores.json | Shop inventories |
world-areas.json | Zones and regions |
avatars.json | Character models |
quests.json | Quest definitions with stages and rewards |
tier-requirements.json | Equipment level requirements by tier |
skill-unlocks.json | What unlocks at each skill level (served via /api/data/skill-unlocks) |
gathering/ | Resource gathering data (woodcutting, mining, fishing) |
recipes/ | Processing recipes (cooking, firemaking, smelting, smithing, fletching, crafting, runecrafting) |
stations.json | World station configurations (anvils, furnaces, ranges, banks, altars) |
prayers.json | Prayer definitions with bonuses and drain rates |
quests.json | Quest definitions with stages, requirements, and rewards |
ammunition.json | Arrow types with ranged strength bonuses |
runes.json | Magic runes and elemental staff configurations |
combat-spells.json | Combat spell definitions (Strike and Bolt tiers) |
duel-arenas.json | Duel arena configurations and spawn points |
model-bounds.json | Auto-generated model footprints (build-time only) |
The
skill-unlocks.json manifest is served to clients via the /api/data/skill-unlocks API endpoint for use in the Skill Guide Panel UI.Manifest Structure
NPCs (npcs.json)
NPC data is loaded from JSON manifests at runtime by DataManager:
NPC definitions are in
world/assets/manifests/npcs.json, not hardcoded in TypeScript.Items Directory
Items are now organized into separate JSON files by category for better maintainability:items.json format.
Tools (tools.json)
Tools include atool object specifying skill, priority, and optional bonus mechanics:
Tool Properties
| Pickaxe | Roll Ticks | Bonus Chance | Bonus Ticks | Avg Speed |
|---|---|---|---|---|
| Bronze | 8 | - | - | 8 ticks |
| Rune | 3 | - | - | 3 ticks |
| Dragon | 3 | 1/6 (0.167) | 2 | 2.83 ticks |
| Crystal | 3 | 1/4 (0.25) | 2 | 2.75 ticks |
Tools with
equipSlot: "weapon" can be equipped and used for combat. The tier system automatically derives level requirements from tier-requirements.json.Inventory Actions
Items can define explicitinventoryActions for OSRS-accurate context menus:
| Action | Use Case | Example Items |
|---|---|---|
| Eat | Food items | Shrimp, Lobster, Shark |
| Drink | Potions | Strength potion, Attack potion |
| Wield | Weapons, shields | Bronze sword, Wooden shield |
| Wear | Armor | Bronze platebody, Leather body |
| Bury | Bones | Bones, Big bones, Dragon bones |
| Use | Tools, misc | Tinderbox, Hammer, Logs |
| Drop | Any item | (always available) |
| Examine | Any item | (always available) |
inventoryActions is not specified, the system falls back to type-based detection using item-helpers.ts.
Gathering Resources (gathering/)
gathering/woodcutting.json - Trees and log yields:
Mining Depletion: Rocks always deplete after one ore (
depleteChance: 1.0). The depletedModelPath and depletedModelScale define the visual appearance of depleted rocks.Gathering Resources
Resource gathering data is split by skill for better organization:Processing Recipes
Processing recipes are organized by skill:Station Configurations
World stations (anvils, furnaces, ranges, banks, altars) are configured instations.json:
modelScale and modelYOffset properties control the visual appearance of stations in the world.
Stations (stations.json)
Defines crafting stations and interactive objects in the world:
- Anvil — Smith bars into equipment
- Furnace — Smelt ores into bars
- Range — Cook food with reduced burn chance
- Bank — Store items
- Altar — Restore prayer points
Manifest Loading
Server-Side Loading
The server loads manifests in two ways depending on the environment: Production/CI:- Root:
biomes.json,npcs.json,prayers.json,stations.json, etc. - Items:
items/food.json,items/weapons.json,items/tools.json, etc. - Gathering:
gathering/fishing.json,gathering/mining.json, etc. - Recipes:
recipes/cooking.json,recipes/smithing.json, etc.
- Manifests cached locally in
world/assets/manifests/ - HTTP cache headers:
max-age=300, must-revalidate(5 minutes) - Compares content before writing to avoid unnecessary disk I/O
- Logs warnings for failed fetches
- Falls back to existing local manifests if CDN unavailable
- Throws error only if no manifests exist at all (prevents broken startup)
Client-Side Loading
The client fetches manifests from CDN via DataManager:DataManager
TheDataManager class loads all manifests and populates runtime data structures. Smithing, cooking, and other processing skills use recipe manifests:
Smelting Recipe (recipes/smelting.json):
recipes/smithing.json):
Tier Requirements (tier-requirements.json)
Defines level requirements by equipment tier:
Prayers (prayers.json)
Defines prayer bonuses, drain rates, and conflicts:
id— Unique prayer ID (lowercase, underscores, max 64 chars)name— Display namedescription— Effect description for tooltipicon— Emoji icon for UIlevel— Required Prayer level (1-99)category— “offensive”, “defensive”, or “utility”drainEffect— Drain rate (higher = faster drain)bonuses— Combat stat multipliers (attackMultiplier, strengthMultiplier, defenseMultiplier)conflicts— Array of prayer IDs that conflict with this prayer
Prayer bonuses are multipliers applied to base stats. A value of 1.05 means +5%, 1.10 means +10%.
Station Configuration (stations.json)
Defines world stations with 3D models:
Data Providers
Manifest Distribution
Development vs Production
Hyperscape uses different manifest loading strategies for development and production: Development (Local):- Manifests loaded from
packages/server/world/assets/manifests/ - Assets cloned via Git LFS during
bun install - CDN serves from local Docker nginx container
- Manifests fetched from CDN at server startup
- Cached locally in
packages/server/world/assets/manifests/ - Assets served from Cloudflare R2
CDN Manifest Fetching
The server automatically fetches manifests from the CDN on startup:- Production/CI: Always fetches from CDN to ensure latest data
- Development: Skips fetch if local manifests exist (allows local development)
- Caching: Compares content before writing to avoid unnecessary disk I/O
- Fallback: Uses existing local manifests if CDN fetch fails
- Update game content by deploying new manifests to CDN
- No server redeployment needed for content changes
- Server always has latest game data
- Reduces deployment size (manifests not bundled in Docker image)
This architecture allows content updates (new items, NPCs, balance changes) to be deployed by updating manifests on the CDN, without requiring server redeployment or downtime.
DataManager
TheDataManager class in packages/shared/src/data/DataManager.ts loads all manifests from JSON files and populates runtime data structures:
Manifest Loading
DataManager supports two loading modes:- Filesystem (server-side): Loads from
packages/server/world/assets/manifests/ - CDN (client-side): Fetches from
PUBLIC_CDN_URL/manifests/
CDN Manifest Fetching
The server automatically fetches manifests from the CDN at startup:| Environment | Behavior |
|---|---|
| Development | Skips fetch if local manifests exist (allows local editing) |
| Production | Always fetches latest from CDN (ensures consistency) |
| Staging | Always fetches from staging CDN bucket |
| Test | Skips fetch if SKIP_MANIFESTS=true or NODE_ENV=test |
- Root:
npcs.json,stores.json,world-areas.json,prayers.json,skill-unlocks.json, etc. - Items:
items/weapons.json,items/tools.json,items/resources.json,items/food.json,items/misc.json - Gathering:
gathering/woodcutting.json,gathering/mining.json,gathering/fishing.json - Recipes:
recipes/cooking.json,recipes/firemaking.json,recipes/smelting.json,recipes/smithing.json
- Manifests cached in
packages/server/world/assets/manifests/ - Content comparison: Only changed files are written to disk
- HTTP cache headers: 5-minute cache with revalidation
- Startup logs:
X fetched, Y updated, Z failed
This architecture allows updating game content by uploading new manifests to R2 without redeploying the server. The server will fetch the latest manifests on next restart.
Adding Content
Development Workflow
Choose the right manifest
Determine which manifest file to edit based on content type:
- Items:
manifests/items/weapons.json,tools.json,resources.json,food.json, ormisc.json - NPCs/Mobs:
manifests/npcs.json - Gathering Resources:
manifests/gathering/woodcutting.json,mining.json, orfishing.json - Processing Recipes:
manifests/recipes/cooking.json,firemaking.json,smelting.json, orsmithing.json - Stations:
manifests/stations.json - World Areas:
manifests/world-areas.json
Edit manifest locally
Add your content following the existing structure. Use tier-based requirements for equipment:
Deploy to staging
- Commit changes to a feature branch
- Create PR and merge to
stagingbranch - GitHub Actions uploads manifests to R2 staging bucket
- Railway redeploys staging server
- Server fetches updated manifests from staging CDN
- Items:
manifests/items/weapons.json,tools.json,resources.json,food.json, ormisc.json - NPCs/Mobs:
manifests/npcs.json - Gathering Resources:
manifests/gathering/woodcutting.json,mining.json, orfishing.json - Processing Recipes:
manifests/recipes/cooking.json,firemaking.json,smelting.json, orsmithing.json - Stations:
manifests/stations.json - Quests:
manifests/quests.json - World Areas:
manifests/world-areas.json
-
Upload new manifest to R2:
- Restart the server (Railway dashboard or API)
- Server fetches latest manifests from R2 on startup
Validation
Manifests are JSON files validated at runtime by DataManager:- Schema validation: Invalid fields logged as warnings
- Duplicate detection: Duplicate item IDs across files cause errors
- Reference checking: Invalid itemId/npcId references caught at runtime
- Atomic loading: Items directory loads all files or falls back to legacy format
Data Providers
The manifest system uses specialized data providers for efficient lookups:| Provider | Purpose | Manifest Source |
|---|---|---|
ProcessingDataProvider | Cooking, firemaking, smelting, smithing recipes | recipes/*.json |
TierDataProvider | Equipment level requirements by tier | tier-requirements.json |
StationDataProvider | Station models and configurations | stations.json |
DataManager | Central loader for all manifests | All manifests |
PrayerDataProvider Usage
Access prayer definitions at runtime:- Loaded by
DataManagerat startup - Validates prayer ID format, bonuses, and conflicts
- Builds optimized lookup tables by level and category
- Provides type-safe access methods
StationDataProvider Usage
Access station configurations at runtime:- Models loaded via
ModelCachewith transform baking modelYOffsetraises model so base sits on ground- Graceful fallback to blue box placeholder if model fails
- Shadows and raycasting layers configured automatically
Quests (quests.json)
The quests.json manifest defines quest content with stages, requirements, and rewards:
id— Unique quest identifiername— Display name shown in quest logdescription— Brief quest summarydifficulty— Quest difficulty:novice,intermediate,experienced,masterquestPoints— Quest points awarded on completionreplayable— Whether quest can be repeated after completionrequirements— Prerequisites to start the questquests— Required completed questsskills— Minimum skill levels (e.g.,{"woodcutting": 15})items— Required items in inventory
startNpc— NPC ID to start the queststages— Ordered list of quest objectivestype— Stage type:dialogue,kill,gather,interactdescription— Objective description shown to playertarget— Target entity/item IDcount— Required count for completion
onStart— Items and dialogue triggered when quest startsrewards— Quest completion rewardsquestPoints— Quest points awardeditems— Item rewardsxp— Skill XP rewards (e.g.,{"attack": 100})
- dialogue — Talk to an NPC
- kill — Defeat a specific number of enemies
- gather — Collect resources (woodcutting, mining, fishing)
- interact — Use items or interact with objects
Quest progress is tracked server-side. Players can view active and completed quests in the quest log interface.
Prayers (prayers.json)
The prayers.json manifest defines OSRS-accurate prayer abilities with stat bonuses and drain mechanics:
id— Unique prayer identifiername— Display name shown in prayer bookdescription— Effect description for tooltipicon— Icon asset path for prayer book UIlevel— Prayer level required to unlockcategory— Prayer type:offensive,defensive, orutilitydrainEffect— Drain rate (higher = faster drain)bonuses— Stat multipliers applied when activeattackMultiplier— Attack bonus (e.g., 1.05 = +5%)strengthMultiplier— Strength bonusdefenseMultiplier— Defense bonus
conflicts— Array of prayer IDs that cannot be active simultaneously
- Offensive — Attack and strength bonuses (Burst of Strength, Clarity of Thought)
- Defensive — Defense bonuses (Thick Skin, Rock Skin, Steel Skin)
- Utility — Special effects (future: Protect from Melee, Rapid Heal)
Prayer drain rates follow OSRS formulas. The
drainEffect value determines how quickly prayer points deplete while the prayer is active.Quests (quests.json)
Defines multi-stage quests with objectives, requirements, and rewards:
id— Unique quest identifier (snake_case)name— Display name shown in quest journaldescription— Quest summarydifficulty—novice,intermediate,experienced,masterquestPoints— Quest points awarded on completionreplayable— Whether quest can be repeated (typically false)requirements— Prerequisites to start questquests— Array of quest IDs that must be completedskills— Skill level requirements (e.g.,{ "attack": 10 })items— Required items in inventory
startNpc— NPC ID that starts the queststages— Array of quest objectivesonStart— Items granted when quest starts (optional)rewards— Rewards granted on completion
dialogue— Talk to NPC (auto-completes via dialogue system)kill— Kill specific mob type (target: mob type,count: number)gather— Gather items (target: item ID,count: number)interact— Interact with entities (target: entity type,count: number)
Security: Quest IDs are validated with isValidQuestId() to prevent injection attacks. Max length: 64 characters, pattern: `^[a-z][a-z0-9_]---
title: “Manifest-Driven Design”
description: “Data-driven content through TypeScript manifest files”
icon: “file-json”
Overview
Hyperscape uses manifest-driven design where game content is defined in TypeScript data files rather than hardcoded in logic. This enables content creation without modifying game systems.Design Philosophy
Separation of Concerns
| Layer | Responsibility |
|---|---|
| Manifests | Content definitions (what exists) |
| Systems | Game logic (how things work) |
| Entities | Runtime instances |
Benefits
- Content creators can add items, NPCs, areas without deep coding
- Designers iterate quickly on balance
- Developers focus on systems, not data
- Modders can extend content easily
Manifest Files
All manifests are inworld/assets/manifests/:
| File | Content |
|---|---|
npcs.json | Mobs and NPCs |
items/ | Equipment, resources, consumables (split by category) |
banks-stores.json | Shop inventories |
world-areas.json | Zones and regions |
avatars.json | Character models |
tier-requirements.json | Equipment level requirements by tier |
skill-unlocks.json | What unlocks at each skill level |
gathering/ | Resource gathering data (woodcutting, mining, fishing) |
recipes/ | Processing recipes (cooking, firemaking, smelting, smithing) |
stations.json | World station configurations (anvils, furnaces, ranges) |
prayers.json | Prayer definitions with bonuses and drain rates |
quests.json | Quest definitions with stages, requirements, and rewards |
model-bounds.json | Auto-generated model footprints (build-time only) |
Manifest Structure
NPCs (npcs.json)
NPC data is loaded from JSON manifests at runtime by DataManager:
NPC definitions are in
world/assets/manifests/npcs.json, not hardcoded in TypeScript.Items Directory
Items are now organized into separate JSON files by category for better maintainability:items.json format.
Tools (tools.json)
Tools include atool object specifying skill, priority, and optional bonus mechanics:
Tool Properties
| Pickaxe | Roll Ticks | Bonus Chance | Bonus Ticks | Avg Speed |
|---|---|---|---|---|
| Bronze | 8 | - | - | 8 ticks |
| Rune | 3 | - | - | 3 ticks |
| Dragon | 3 | 1/6 (0.167) | 2 | 2.83 ticks |
| Crystal | 3 | 1/4 (0.25) | 2 | 2.75 ticks |
Tools with
equipSlot: "weapon" can be equipped and used for combat. The tier system automatically derives level requirements from tier-requirements.json.Inventory Actions
Items can define explicitinventoryActions for OSRS-accurate context menus:
| Action | Use Case | Example Items |
|---|---|---|
| Eat | Food items | Shrimp, Lobster, Shark |
| Drink | Potions | Strength potion, Attack potion |
| Wield | Weapons, shields | Bronze sword, Wooden shield |
| Wear | Armor | Bronze platebody, Leather body |
| Bury | Bones | Bones, Big bones, Dragon bones |
| Use | Tools, misc | Tinderbox, Hammer, Logs |
| Drop | Any item | (always available) |
| Examine | Any item | (always available) |
inventoryActions is not specified, the system falls back to type-based detection using item-helpers.ts.
Gathering Resources (gathering/)
gathering/woodcutting.json - Trees and log yields:
Mining Depletion: Rocks always deplete after one ore (
depleteChance: 1.0). The depletedModelPath and depletedModelScale define the visual appearance of depleted rocks.Gathering Resources
Resource gathering data is split by skill for better organization:Processing Recipes
Processing recipes are organized by skill:Station Configurations
World stations (anvils, furnaces, ranges, banks) are configured instations.json:
modelScale and modelYOffset properties control the visual appearance of stations in the world.
Terrain Flattening
Stations can optionally flatten terrain underneath for level building surfaces:| Property | Type | Default | Description |
|---|---|---|---|
flattenGround | boolean | false | Enable terrain flattening under this station |
flattenPadding | number | 0.3 | Extra meters around footprint to flatten |
flattenBlendRadius | number | 0.5 | Meters over which to blend from flat to procedural terrain |
- Station footprint calculated from model bounds × scale
- Flat zone created with dimensions:
(footprint + padding × 2) - Terrain height sampled at station center position
- Smoothstep blending (t² × (3 - 2t)) creates natural transitions
- Spatial indexing using terrain tiles (100m) for O(1) lookup
Terrain flattening ensures stations sit on level ground even on hills or slopes, improving visual quality and preventing floating/clipping issues.
Stations (stations.json)
Defines crafting stations and interactive objects in the world:
type— Station identifier (anvil, furnace, range, bank, altar)name— Display namemodel— Path to 3D model assetmodelScale— Scale multiplier for the modelmodelYOffset— Vertical position offsetexamine— Text shown when examining the stationflattenGround— Whether to flatten terrain under the stationflattenPadding— Radius of flattened area around stationflattenBlendRadius— Blend radius for smooth terrain transition
- Anvil — Smith bars into equipment
- Furnace — Smelt ores into bars
- Range — Cook food with reduced burn chance
- Bank — Store items
- Altar — Restore prayer points
DataManager
Smithing, cooking, and other processing skills use recipe manifests: Smelting Recipe (recipes/smelting.json):
recipes/smithing.json):
Tier Requirements (tier-requirements.json)
Defines level requirements by equipment tier:
Station Configuration (stations.json)
Defines world stations with 3D models:
Data Providers
DataManager
TheDataManager class in packages/shared/src/data/DataManager.ts loads all manifests from JSON files and populates runtime data structures:
Manifest Loading
DataManager supports two loading modes:- Filesystem (server-side): Loads from
packages/server/world/assets/manifests/ - CDN (client-side): Fetches from
http://localhost:8080/assets/manifests/
Adding Content
World Areas with Station Spawns (world-areas.json)
World areas now support data-driven station spawning:
type— Station type (bank, anvil, furnace, range, altar)position— [x, y, z] coordinates in world spacerotation— Optional quaternion rotation
- Reads
stationsfield from WorldArea definitions - Spawns station entities at configured positions
- Replaces hardcoded station spawning in EntityManager
- Uses
getStationsInArea()helper for querying
Step 1: Choose the Right Manifest
Determine which manifest file to edit based on content type:- Items:
manifests/items/weapons.json,tools.json,resources.json,food.json, ormisc.json - NPCs/Mobs:
manifests/npcs.json - Gathering Resources:
manifests/gathering/woodcutting.json,mining.json, orfishing.json - Processing Recipes:
manifests/recipes/cooking.json,firemaking.json,smelting.json, orsmithing.json - Stations:
manifests/stations.json(station types and models) - World Areas:
manifests/world-areas.json(station spawn locations) - Quests:
manifests/quests.json(quest definitions)
Step 2: Edit Manifest
Add your content following the existing structure. Use tier-based requirements for equipment:Step 3: Restart Server
Manifests are loaded at server startup. Restart to apply changes:Step 4: Verify
Check the game to ensure content appears correctly. Use the Skills panel to verify level requirements.Validation
Manifests are JSON files validated at runtime by DataManager:- Schema validation: Invalid fields logged as warnings
- Duplicate detection: Duplicate item IDs across files cause errors
- Reference checking: Invalid itemId/npcId references caught at runtime
- Atomic loading: Items directory loads all files or falls back to legacy format
Data Providers
The manifest system uses specialized data providers for efficient lookups:| Provider | Purpose | Manifest Source |
|---|---|---|
ProcessingDataProvider | Cooking, firemaking, smelting, smithing recipes | recipes/*.json |
TierDataProvider | Equipment level requirements by tier | tier-requirements.json |
StationDataProvider | Station models and configurations | stations.json |
DataManager | Central loader for all manifests | All manifests |
StationDataProvider Usage
Access station configurations at runtime:- Models loaded via
ModelCachewith transform baking modelYOffsetraises model so base sits on ground- Graceful fallback to blue box placeholder if model fails
- Shadows and raycasting layers configured automatically
Quests (quests.json)
The quests.json manifest defines quest content with multi-stage progression, requirements, and rewards:
id— Unique quest identifiername— Display name shown in quest journaldescription— Brief quest summarydifficulty— Quest difficulty (novice, intermediate, experienced, master, grandmaster)questPoints— Quest points awarded on completionreplayable— Whether quest can be repeated after completionrequirements— Prerequisites to start the questquests— Required completed questsskills— Required skill levels (e.g.,{"woodcutting": 15})items— Required items in inventory
startNpc— NPC ID that starts the queststages— Array of quest stages in orderonStart— Items given and dialogue triggered when quest startsrewards— Items, XP, and quest points awarded on completion
dialogue— Talk to an NPCkill— Kill a specific number of NPCs/mobsgather— Collect items through gathering skillsinteract— Interact with objects or process items
- Goblin Slayer — Combat tutorial (kill 15 goblins)
- Lumberjack’s First Lesson — Woodcutting and firemaking tutorial
- Fresh Catch — Fishing and cooking tutorial
- Torvin’s Tools — Mining, smelting, and smithing tutorial
Quest progress is tracked server-side. Each stage must be completed in order before advancing to the next stage.
Prayers (prayers.json)
The prayers.json manifest defines OSRS-accurate prayer abilities with stat bonuses and drain mechanics:
id— Unique prayer identifiername— Display name shown in prayer bookdescription— Effect description for tooltipicon— Icon asset path for prayer book UIlevel— Prayer level required to unlockcategory— Prayer type:offensive,defensive, orutilitydrainEffect— Drain rate (higher = faster drain)bonuses— Stat multipliers applied when activeattackMultiplier— Attack bonus (e.g., 1.05 = +5%)strengthMultiplier— Strength bonusdefenseMultiplier— Defense bonus
conflicts— Array of prayer IDs that cannot be active simultaneously
- Offensive — Attack and strength bonuses (Burst of Strength, Clarity of Thought)
- Defensive — Defense bonuses (Thick Skin, Rock Skin, Steel Skin)
- Utility — Special effects (future: Protect from Melee, Rapid Heal)
Prayer drain rates follow OSRS formulas. The
drainEffect value determines how quickly prayer points deplete while the prayer is active.Model Bounds (model-bounds.json)
The model-bounds.json manifest contains pre-calculated bounding box data for all 3D models in the game. This data is used for spatial calculations, collision detection, and tile-based placement:
bounds— Minimum and maximum coordinates of the model’s bounding boxdimensions— Calculated width (x), height (y), and depth (z) of the modelfootprint— Tile-based footprint for placement (width × depth in tiles)generatedAt— Timestamp of when bounds were calculatedtileSize— Base tile size used for footprint calculations (typically 1.0)
- Placement Validation — Ensure entities fit within available space
- Collision Detection — Fast AABB checks for physics and interactions
- Tile Occupancy — Calculate which tiles an entity occupies
- Spatial Queries — Optimize raycasting and proximity checks
Best Practices
- Use descriptive IDs:
bronze_swordnotsword1 - Follow naming conventions: snake_case for IDs
- Organize by category: Use the directory structure (items/, recipes/, gathering/)
- Test after changes: Verify in-game before committing
- Keep data flat: Avoid deep nesting in manifest structures
- Use tier system: Leverage TierDataProvider for equipment requirements instead of hardcoding
- Validate JSON: Use a JSON validator before committing to catch syntax errors
Manifest Loading Order
DataManager loads manifests in this order:- Tier requirements (
tier-requirements.json) - Needed for item normalization - Model bounds (
model-bounds.json) - Needed for station footprint calculation - Items (
items/directory oritems.jsonfallback) - NPCs (
npcs.json) - Gathering resources (
gathering/*.json) - Recipe manifests (
recipes/*.json) - Skill unlocks (
skill-unlocks.json) - Prayers (
prayers.json) - Quests (
quests.json) - Stations (
stations.json) - Uses model bounds for footprints - World areas (
world-areas.json) - Stores (
stores.json)
Build-Time Manifests
Model Bounds Extraction
Themodel-bounds.json manifest is auto-generated during build:
- Scans
world/assets/models/**/*.glbfiles - Parses glTF position accessor min/max values
- Calculates bounding boxes and footprints at scale 1.0
- Writes to
world/assets/manifests/model-bounds.json
StationDataProviderloads this manifest at startup- Combines model bounds ×
modelScalefromstations.json - Calculates final collision footprint for each station type
- No manual footprint configuration needed
Quests (quests.json)
Defines multi-stage quests with requirements and rewards:
dialogue— Talk to an NPCkill— Kill specific mobs (with count)gather— Gather resources (with count)interact— Interact with objects (with count)craft— Craft items (with count)
novice— Beginner questsintermediate— Medium difficultyexperienced— Advanced questsmaster— Expert-level quests