Manifest-Driven Design
Hyperscape uses a manifest-driven architecture where all game content (NPCs, items, world areas) is defined in external data files rather than hardcoded in logic. This separation enables:
Easy content updates — Edit JSON, restart server
Community modding — No code changes required
AI generation — Generate content with Asset Forge
Clean separation — Data vs logic isolation
All manifests are loaded from world/assets/manifests/ at runtime by the DataManager.
Data Architecture
packages/shared/src/data/
├── DataManager.ts # Loads all manifests at runtime
├── npcs.ts # NPC helper functions (Map populated at runtime)
├── items.ts # Item helper functions (Map populated at runtime)
├── banks-stores.ts # Bank and shop definitions
├── world-areas.ts # Zone and biome definitions
├── world-structure.ts # World structure configuration
├── avatars.ts # Avatar/character options
├── skill-icons.ts # Skill UI icons
├── skill-unlocks.ts # Skill unlock requirements
├── playerEmotes.ts # Player emote animations
├── NoteGenerator.ts # Bank note generation
└── index.ts # Exports
Manifest Files Location
world/assets/manifests/
├── npcs.json # NPC and mob definitions
├── items/ # Item definitions by category
│ ├── weapons.json # Weapons (melee, ranged, magic)
│ ├── armor.json # Armor pieces (all combat styles)
│ ├── tools.json # Skilling tools
│ ├── resources.json # Gathered materials
│ ├── food.json # Consumable food
│ ├── ammunition.json # Arrows and ranged ammo
│ ├── runes.json # Magic runes
│ └── misc.json # Miscellaneous items
├── recipes/ # Crafting recipes by skill
│ ├── cooking.json # Cooking recipes
│ ├── firemaking.json # Firemaking recipes
│ ├── smelting.json # Ore smelting recipes
│ ├── smithing.json # Smithing recipes
│ ├── fletching.json # Fletching recipes (NEW)
│ ├── crafting.json # Crafting recipes (NEW)
│ ├── runecrafting.json # Runecrafting recipes (NEW)
│ └── tanning.json # Leather tanning recipes
├── gathering/ # Gathering skill data
│ ├── woodcutting.json # Tree data
│ ├── mining.json # Rock data
│ └── fishing.json # Fishing spot data
├── stations.json # Crafting stations (anvils, furnaces, ranges, banks)
├── quests.json # Quest definitions and progression
├── prayers.json # Prayer definitions
├── combat-spells.json # Combat spell definitions
├── tier-requirements.json # Equipment tier requirements
├── skill-unlocks.json # Skill progression milestones
└── ... (other manifests)
NPCs & Mobs
NPCs are loaded from JSON at runtime into the ALL_NPCS Map:
// From packages/shared/src/data/npcs.ts
export const ALL_NPCS : Map < string , NPCData > = new Map ();
NPC Data Structure
Each NPC has these properties (from types/entities/npc-mob-types.ts):
Property Type Description idstringUnique identifier namestringDisplay name category"mob" | "boss" | "quest" | "neutral"NPC type statsNPCStatsCombat stats (attack, strength, defense, health, ranged, level) dropsDropTableLoot table with rarity tiers spawnBiomesstring[]Biomes where NPC spawns modelPathstringPath to 3D model behavior"passive" | "aggressive"Combat behavior
Available 3D Models
NPCs :
/assets/models/
├── goblin/goblin_rigged.glb → Goblins
├── thug/thug_rigged.glb → Bandits
├── human/human_rigged.glb → Guards, knights, warriors, rangers
├── troll/troll_rigged.glb → Hobgoblins
├── imp/imp_rigged.glb → Dark warriors
├── cow/cow.vrm → Cows
├── dark-wizard/dark-wizard.vrm → Dark wizards
└── dark-ranger/dark-ranger.vrm → Dark rangers
Stations :
/assets/models/
├── anvil/anvil.glb → Smithing station
├── furnace/furnace.glb → Smelting station
├── cooking-range/cooking-range.glb → Cooking station
├── bank-chest/bank-chest.glb → Bank storage
├── prayer-alter/prayer-alter.glb → Prayer restoration
├── runecrafting-alter/runecrafting-alter.glb → Runecrafting station
└── firemaking-fire/firemaking-fire.glb → Fire model for firemaking
Fishing Tools :
/assets/models/
├── fishing-rod-base/fishing-rod-base-aligned.glb → Base fishing rod (aligned)
├── fishing-rod-base/fishing-rod-base.glb → Base fishing rod
├── fishing-rod-standard/fishing-rod-standard.glb → Standard fishing rod
└── bait-fishing-rod/bait-fishing-rod-aligned.glb → Bait fishing rod (aligned)
Equipment (Aligned Models) :
/assets/models/
├── hatchet-bronze/hatchet-bronze-aligned.glb → Bronze hatchet (aligned)
├── pickaxe-bronze/pickaxe-bronze-aligned.glb → Bronze pickaxe (aligned)
├── pickaxe-steel/pickaxe-steel-aligned.glb → Steel pickaxe (aligned)
├── pickaxe-mithril/pickaxe-mithril-aligned.glb → Mithril pickaxe (aligned)
├── sword-bronze/sword-bronze-aligned.glb → Bronze sword (aligned)
├── sword-steel/sword-steel-aligned.glb → Steel sword (aligned)
└── sword-mithril/sword-mithril-aligned.glb → Mithril sword (aligned)
Magic Staffs :
/assets/models/magic-staffs/
├── air-staff/
│ ├── air-staff.glb → Air staff
│ └── air-staff-aligned.glb → Air staff (aligned)
├── water-staff/
│ ├── water-staff.glb → Water staff
│ └── water-staff-aligned.glb → Water staff (aligned)
├── earth-staff/
│ ├── earth-staff.glb → Earth staff
│ └── earth-staff-aligned.glb → Earth staff (aligned)
└── fire-staff/
├── fire-staff.glb → Fire staff
└── fire-staff-aligned.glb → Fire staff (aligned)
Mining Rocks :
/assets/models/
├── copper-rock/copper-rock.glb → Copper ore rock
├── copper-rock/copper-rock-depleted.glb → Depleted copper rock
├── mithril-rock/mithril-rock.glb → Mithril ore rock
├── runite-rock/runite-rock.glb → Runite ore rock
└── runite-rock/runite-rock-depleted.glb → Depleted runite rock
Vegetation :
/assets/trees/
└── mushroom.glb → Giant mushroom (new)
NPC Helper Functions
// Get NPC by ID
getNPCById (npcId: string): NPCData | null
// Get NPCs by category
getNPCsByCategory (category: NPCCategory): NPCData[]
// Get NPCs by biome
getNPCsByBiome (biome: string): NPCData[]
// Get NPCs by level range
getNPCsByLevelRange (minLevel: number , maxLevel: number): NPCData[]
// Get combat NPCs (mob, boss, quest)
getCombatNPCs (): NPCData[]
// Get service NPCs (neutral)
getServiceNPCs (): NPCData[]
// Calculate drops with RNG
calculateNPCDrops (npcId: string): Array < { itemId : string; quantity : number } >
// Calculate combat level (OSRS formula)
calculateNPCCombatLevel (npc: NPCData): number
Spawn Constants
// From packages/shared/src/data/npcs.ts
export const NPC_SPAWN_CONSTANTS = {
GLOBAL_RESPAWN_TIME : 900000 , // 15 minutes per GDD
MAX_NPCS_PER_ZONE : 10 ,
SPAWN_RADIUS_CHECK : 5 , // Don't spawn if player within 5 meters
AGGRO_LEVEL_THRESHOLD : 5 , // Some NPCs ignore players above this
} as const ;
Items
Items are loaded from JSON into the ITEMS Map. Items are now organized into separate files by type for better organization:
// From packages/shared/src/data/items.ts
export const ITEMS : Map < string , Item > = new Map ();
Item Types & Organization
Type Description File "weapon"Combat weapons items/weapons.json"tool"Skilling tools items/tools.json"resource"Gathered materials (ores, logs, bars, raw fish) items/resources.json"consumable"Food that heals items/food.json"currency"Coins items/misc.json"junk"Burnt food, worthless items items/misc.json"misc"Everything else items/misc.json
Tier-Based Equipment
Items now use a centralized tier system defined in tier-requirements.json. Equipment references their tier (e.g., “bronze”, “steel”, “rune”) and the system looks up requirements automatically:
// Item with tier reference
{
"id" : "bronze_sword" ,
"tier" : "bronze" , // References tier-requirements.json
// ... other properties
}
Supported Tiers:
Melee : bronze, iron, steel, black, mithril, adamant, rune, dragon
Tools : Same as melee (with different skill requirements)
Ranged : leather, studded, green_dhide, blue_dhide, red_dhide, black_dhide
Magic : wizard, mystic, infinity, ahrims
Item Helper Functions
// Get item by ID
getItem (itemId: string): Item | null
// Get items by type
getItemsByType (type: ItemType): Item[]
// Get all weapons
getWeapons (): Item[]
// Get all armor
getArmor (): Item[]
// Get all tools
getTools (): Item[]
// Get all consumables
getConsumables (): Item[]
// Get all resources
getResources (): Item[]
// Get items by skill requirement
getItemsBySkill (skill: string): Item[]
// Get items by level requirement
getItemsByLevel (level: number): Item[]
Shop Items
// From packages/shared/src/data/items.ts
export const SHOP_ITEMS = [
"bronze_hatchet" ,
"fishing_rod" ,
"tinderbox" ,
"arrows" ,
];
Bank Notes
The system supports bank notes for stackable versions of items:
// From packages/shared/src/data/items.ts
export const NOTE_SUFFIX = "_note" ;
// Check if item can be noted
canBeNoted (itemId: string): boolean
// Get noted variant
getNotedItem (itemId: string): Item | null
// Get base item from note
getBaseItem (itemId: string): Item | null
// Check if ID is a noted item
isNotedItemId (itemId: string): boolean
Drop Tables
NPCs have tiered drop tables:
interface DropTable {
defaultDrop : {
enabled : boolean ;
itemId : string ;
quantity : number ;
};
always : Drop []; // 100% chance
common : Drop []; // High chance
uncommon : Drop []; // Medium chance
rare : Drop []; // Low chance
veryRare : Drop []; // Very low chance
}
interface Drop {
itemId : string ;
minQuantity : number ;
maxQuantity : number ;
chance : number ; // 0.0 - 1.0
}
Drop Calculation
// From packages/shared/src/data/npcs.ts
export function calculateNPCDrops ( npcId : string ) : Array <{ itemId : string ; quantity : number }> {
const npc = getNPCById (npcId);
const drops : Array <{ itemId : string ; quantity : number }> = [];
// Add default drop if enabled
if ( npc . drops . defaultDrop .enabled) {
drops . push ({
itemId : npc . drops . defaultDrop .itemId ,
quantity : npc . drops . defaultDrop .quantity ,
});
}
// Process all tiers with RNG
const processDrop = ( drop : Drop ) => {
if ( Math . random () < drop .chance) {
const quantity = Math . floor (
Math . random () * ( drop .maxQuantity - drop .minQuantity + 1 ) + drop .minQuantity
);
drops . push ({ itemId : drop .itemId , quantity });
}
};
npc . drops . always . forEach (processDrop);
npc . drops . common . forEach (processDrop);
npc . drops . uncommon . forEach (processDrop);
npc . drops . rare . forEach (processDrop);
npc . drops . veryRare . forEach (processDrop);
return drops;
}
World Areas
World areas define zones, biomes, and spawn points:
packages/shared/src/data/
├── world-areas.ts # Zone definitions
└── world-structure.ts # World layout
Zone Properties
Property Description idUnique zone identifier nameDisplay name biomeBiome type (forest, plains, etc.) difficulty0-3 difficulty level mobsNPCs that spawn here resourcesTrees, fishing spots, etc. isSafeWhether it’s a safe zone
Banks & Stores
// From packages/shared/src/data/banks-stores.ts
// Defines bank locations and shop inventories
Each starter town has:
Bank — Item storage facility
General Store — Basic equipment vendor
Stations
Crafting stations are interactive objects that enable processing skills like smithing, smelting, and cooking:
interface StationData {
type : string ; // "anvil" | "furnace" | "range" | "bank"
name : string ; // Display name
model : string ; // Path to 3D model
modelScale : number ; // Scale multiplier
modelYOffset : number ; // Vertical offset
examine : string ; // Examine text
}
Available Stations
Station Purpose Model Scale Y Offset Anvil Smith bars into equipment asset://models/anvil/anvil.glb0.5 0.2 Furnace Smelt ores into bars asset://models/furnace/furnace.glb1.5 1.0 Range Cook food with reduced burn chance asset://models/cooking-range/cooking-range.glb1.0 0.3 Bank Store items asset://models/bank-chest/bank-chest.glb0.5 0.10 Altar Restore prayer points asset://models/prayer-alter/prayer-alter.glb1.0 0.25
Station entities (Altar, Bank, Range) now load 3D models from the manifest system with automatic fallback to placeholder geometry if models are unavailable.
Station Model Loading
Station entities load 3D models from the manifest system using StationDataProvider:
// AltarEntity.ts, BankEntity.ts, RangeEntity.ts
const stationData = stationDataProvider . getStationData ( "altar" );
const modelPath = stationData ?.model ?? null ;
const modelScale = stationData ?.modelScale ?? 1.0 ;
const modelYOffset = stationData ?.modelYOffset ?? 0 ;
// Try to load 3D model first
if (modelPath && this . world .loader) {
try {
const { scene } = await modelCache . loadModel (modelPath , this .world);
this .mesh = scene;
this . mesh .name = `Altar_ ${ this . id } ` ;
// Scale the model from manifest
this . mesh . scale . set (modelScale , modelScale , modelScale);
// Offset Y position so model base sits on ground
this . mesh . position .y = modelYOffset;
// Enable shadows and set layer for raycasting
this . mesh . layers . set ( 1 );
this . mesh . traverse (( child ) => {
child . layers . set ( 1 );
if (child instanceof THREE . Mesh ) {
child .castShadow = true ;
child .receiveShadow = true ;
}
});
return ;
} catch (error) {
console . warn ( `[AltarEntity] Failed to load altar model, using placeholder:` , error);
}
}
// FALLBACK: Create placeholder geometry
const geometry = new THREE . BoxGeometry ( 0.9 , 0.8 , 0.9 );
const material = new THREE . MeshStandardMaterial ({
color : 0x9932cc , // Purple for altar
roughness : 0.5 ,
metalness : 0.3 ,
});
Station Models:
models/
├── anvil/
│ ├── anvil.glb # Optimized model (scale: 0.5, yOffset: 0.2)
│ ├── anvil_raw.glb # Raw model
│ ├── concept-art.png # Concept art
│ └── metadata.json # Model metadata
├── furnace/
│ ├── furnace.glb # Optimized model (scale: 1.5, yOffset: 1.0)
│ ├── furnace_raw.glb # Raw model
│ ├── concept-art.png # Concept art
│ └── metadata.json # Model metadata
├── cooking-range/
│ └── cooking-range.glb # Optimized model (scale: 1.0, yOffset: 0.3)
├── bank-chest/
│ └── bank-chest.glb # Optimized model (scale: 0.5, yOffset: 0.10)
└── prayer-alter/
├── prayer-alter.glb # Optimized model (scale: 1.0, yOffset: 0.25)
└── prayer-alter_raw.glb # Raw model
Fallback Colors:
Altar: Purple (0x9932cc)
Bank: Black (0x111111)
Range: Red (0xcc3333)
All fallback materials now use MeshStandardMaterial for consistent lighting behavior.
Crafting Stations
Stations are defined in stations.json:
Anvil - Used for smithing bars into equipment
Furnace - Used for smelting ores into bars
Range - Used for cooking food (reduces burn chance compared to fires)
Bank Booth - Used for accessing bank storage
Each station defines its 3D model, scale, position offset, and examine text.
Range Entity:
The range is a permanent cooking station that provides better burn rates than fires. Players can use raw food on ranges just like fires, but with reduced burn chance. Ranges are placed in starter towns and other settlements.
// RangeEntity extends InteractableEntity
// Location: packages/shared/src/entities/world/RangeEntity.ts
// Supports cooking with reduced burn rates per cooking.json stopBurnLevel.range
The tools.json manifest defines tool-specific properties:
Skill - Which skill the tool is used for
Tier - Tool tier (bronze, iron, steel, etc.)
Priority - Tool selection priority (higher = better)
Roll Ticks - For mining pickaxes, ticks between roll attempts
This metadata is separate from item definitions to keep tool mechanics centralized.
Skill Progression
Crafting Stations
Stations are defined in stations.json and represent interactive objects in the world used for processing skills:
interface Station {
type : string ; // "anvil" | "furnace" | "range" | "bank"
name : string ; // Display name
model : string | null ; // Path to 3D model
modelScale : number ; // Model scale multiplier
modelYOffset : number ; // Vertical position offset
examine : string ; // Examine text
}
Available Stations
Station Purpose Model Scale Y Offset Anvil Smithing bars into equipment models/anvil/anvil.glb0.5 0.2 Furnace Smelting ores into bars models/furnace/furnace.glb1.5 1.0 Cooking Range Cooking food (reduced burn chance) models/cooking-range/cooking-range.glb1.0 0.5 Bank Chest Accessing bank storage models/bank-chest/bank-chest.glb0.5 0.75 Altar Restoring prayer points models/prayer-alter/prayer-alter.glb1.0 0.25
Stations are placed in world areas and interact with the corresponding recipe manifests (recipes/smithing.json, recipes/smelting.json, etc.).
The tools.json manifest defines tool-specific properties separate from item definitions:
interface ToolMetadata {
itemId : string ; // References items/tools.json
skill : string ; // "woodcutting" | "mining" | "fishing"
tier : string ; // Tool tier
levelRequired : number ; // Minimum skill level
priority : number ; // Tool selection priority (higher = better)
rollTicks ?: number ; // Mining only: ticks between roll attempts
}
When multiple tools are available, the system selects the highest priority tool:
Woodcutting Hatchets :
Tool Priority Crystal 1 (best) Dragon 2 Rune 3 Adamant 4 Mithril 5 Steel 6 Iron 7 Bronze 8 (worst)
Mining Pickaxes (also includes rollTicks for mining speed):
Tool Priority Roll Ticks Crystal 1 3 Dragon 2 3 Rune 3 3 Adamant 4 4 Mithril 5 5 Steel 6 6 Iron 7 7 Bronze 8 8
Vegetation & Biomes
Vegetation Assets
The vegetation.json manifest defines procedural vegetation assets for world generation:
interface VegetationAsset {
id : string ; // Unique asset ID
model : string ; // Path to GLB model
category : string ; // Asset category
baseScale : number ; // Base scale multiplier
scaleVariation : [ number , number ]; // [min, max] scale variation
randomRotation : boolean ; // Randomize Y-axis rotation
weight : number ; // Spawn probability weight
maxSlope : number ; // Maximum terrain slope (0-1)
minSlope ?: number ; // Minimum terrain slope
alignToNormal : boolean ; // Align to terrain normal
yOffset : number ; // Vertical position offset
}
Vegetation Categories :
tree - Large trees
bush - Small bushes and shrubs
fern - Ground ferns
flower - Decorative flowers
grass - Grass patches
rock - Decorative rocks
fallen_tree - Fallen logs
mushroom - Giant mushrooms (added in recent update)
Biome Vegetation Layers
Biomes in biomes.json define procedural vegetation layers that reference vegetation assets:
interface VegetationLayer {
category : string ; // Matches vegetation.json categories
density : number ; // Spawn density
assets : string []; // Asset IDs (empty = all in category)
minSpacing : number ; // Minimum distance between instances
clustering : boolean ; // Group assets together
clusterSize ?: number ; // Size of clusters
noiseScale : number ; // Perlin noise scale
noiseThreshold : number ; // Noise threshold for spawning
avoidWater : boolean ; // Don't spawn in water
minHeight ?: number ; // Minimum terrain height
maxHeight ?: number ; // Maximum terrain height
}
Recent Updates :
Mushroom vegetation added to all biomes with varying densities (2-30)
Tree density reduced in plains biome (8 → 5)
Mushroom clustering varies by biome (cluster size 3-8)
Firemaking fire 3D model added (models/firemaking-fire/firemaking-fire.glb)
Recipe Manifests
Recipe manifests define crafting, processing, and production activities for artisan skills. All recipes follow a consistent structure with inputs, outputs, tools, level requirements, and XP rewards.
Fletching Recipes
The recipes/fletching.json manifest defines bow and arrow crafting:
interface FletchingRecipe {
output : string ; // Item ID of crafted item
outputQuantity : number ; // Number of items produced
category : string ; // Recipe category
inputs : Array <{ // Required materials
item : string ;
amount : number ;
}>;
tools : string []; // Required tools (e.g., "knife")
level : number ; // Fletching level required
xp : number ; // XP awarded
ticks : number ; // Time to craft (game ticks)
skill : "fletching" ;
}
Recipe Categories :
arrow_shafts - Knife + logs → arrow shafts (15-90 per log)
headless_arrows - Arrow shafts + feathers → headless arrows
shortbows - Knife + logs → unstrung shortbows
longbows - Knife + logs → unstrung longbows
stringing - Bowstring + unstrung bow → finished bow
arrows - Arrowtips + headless arrows → finished arrows
Crafting Recipes
The recipes/crafting.json manifest defines leather, armor, and jewelry crafting:
interface CraftingRecipe {
output : string ; // Item ID of crafted item
category : string ; // Recipe category
inputs : Array <{ // Required materials
item : string ;
amount : number ;
}>;
tools : string []; // Required tools (e.g., "needle", "chisel")
consumables : Array <{ // Consumable items (e.g., thread)
item : string ;
uses : number ; // Uses before consumed
}>;
level : number ; // Crafting level required
xp : number ; // XP awarded
ticks : number ; // Time to craft
station : string ; // Required station ("none" or "furnace")
}
Recipe Categories :
leather - Needle + thread + leather → leather armor
studded - Leather armor + steel studs → studded armor
dragonhide - Needle + thread + dragon leather → dragonhide armor
jewelry - Gold bar + gems + mould → jewelry (at furnace)
gem_cutting - Chisel + uncut gem → cut gem
Runecrafting Recipes
The recipes/runecrafting.json manifest defines rune crafting at altars:
interface RunecraftingRecipe {
runeType : string ; // Rune type identifier
runeItemId : string ; // Output rune item ID
levelRequired : number ; // Runecrafting level required
xpPerEssence : number ; // XP per essence used
essenceTypes : string []; // Accepted essence types
multiRuneLevels : number []; // Levels for multiple runes per essence
}
Rune Types :
Air (level 1, 5.0 XP) - Accepts rune essence or pure essence
Mind (level 2, 5.5 XP) - Accepts rune essence or pure essence
Water (level 5, 6.0 XP) - Accepts rune essence or pure essence
Earth (level 9, 6.5 XP) - Accepts rune essence or pure essence
Fire (level 14, 7.0 XP) - Accepts rune essence or pure essence
Chaos (level 35, 8.5 XP) - Requires pure essence only
Multi-Rune System : At specific level thresholds, players craft multiple runes per essence (e.g., 2 air runes at level 11, 3 at level 22, etc.)
Quests
Quests are defined in quests.json and provide structured objectives for players:
interface Quest {
id : string ; // Unique quest identifier
name : string ; // Display name
description : string ; // Quest description
difficulty : string ; // "novice" | "intermediate" | "experienced" | "master"
questPoints : number ; // Quest points awarded
replayable : boolean ; // Can be repeated
requirements : {
quests : string []; // Required completed quests
skills : Record < string , number >; // Required skill levels
items : string []; // Required items
};
startNpc : string ; // NPC ID to start quest
stages : QuestStage []; // Quest stages
onStart : {
items : Array <{ itemId : string ; quantity : number }>; // Items given on start
dialogue : string ; // Dialogue key
};
rewards : {
questPoints : number ; // Quest points
items : Array <{ itemId : string ; quantity : number }>; // Item rewards
xp : Record < string , number >; // Skill XP rewards
};
}
interface QuestStage {
id : string ; // Stage identifier
type : "dialogue" | "kill" | "gather" | "interact" ; // Stage type
description : string ; // Stage description
npcId ?: string ; // For dialogue stages
target ?: string ; // For kill/gather/interact stages
count ?: number ; // Required count
}
Available Quests
Quest Difficulty Quest Points Description Goblin Slayer Novice 1 Help Captain Rowan deal with the goblin threat Lumberjack’s First Lesson Novice 1 Help Forester Wilma gather and burn firewood Fresh Catch Novice 1 Help Fisherman Pete catch and cook fish Torvin’s Tools Novice 1 Help Torvin forge a set of bronze tools
Quest Stage Types
dialogue - Talk to an NPC
kill - Defeat a specific number of NPCs
gather - Collect items through skilling
interact - Use items or stations (cooking, smithing, etc.)
Adding New Content
Choose the right manifest
Items: Add to appropriate file in items/ directory
Gathering: Add to gathering/woodcutting.json, mining.json, or fishing.json
Recipes: Add to appropriate file in recipes/ directory
NPCs: Add to npcs.json
Follow existing patterns
Use the same structure as existing entries. For tiered equipment, specify the tier field.
Generate 3D model (optional)
Use Asset Forge to create a new model, or use existing models
Restart server
The DataManager loads manifests on startup
Test in game
Verify the new content appears correctly
Do NOT add game data directly to TypeScript files. Keep all content in JSON manifests for clean separation and easy modding.
Recent Changes
New Skills & Recipes (Week 5: Jan 31 - Feb 1, 2026)
Three new artisan skills added with complete OSRS-accurate recipe manifests:
Fletching : Arrow shafts, headless arrows, shortbows, longbows, bow stringing, arrow tipping (40+ recipes)
Crafting : Leather armor, studded armor, dragonhide armor, jewelry, gem cutting (25+ recipes)
Runecrafting : Air, mind, water, earth, fire, chaos runes with multi-rune level thresholds
New Assets :
Firemaking fire 3D model (models/firemaking-fire/firemaking-fire.glb)
Comprehensive armor manifest with 80+ armor pieces across all combat styles
Manifest Refactor (PR #3)
The manifest system was recently refactored for better scalability and organization:
Items split by type : Weapons, tools, resources, food, ammunition, runes, armor, and misc are now in separate files
Gathering resources : Woodcutting, mining, and fishing data moved to dedicated files
Recipe system : New recipes directory for smelting, smithing, cooking, firemaking, fletching, crafting, and runecrafting
Centralized requirements : tier-requirements.json provides OSRS-accurate level requirements
Skill unlocks : skill-unlocks.json documents progression milestones
New Vegetation (PR #4)
Mushroom vegetation added to biomes with configurable density, clustering, and spawn parameters.
GitHub Integration
The repository now includes Claude Code GitHub Actions for automated assistance:
.github/workflows/claude.yml - Responds to @claude mentions in issues and PRs
.github/workflows/claude-code-review.yml - Automated code review on pull requests
.github/workflows/update-docs.yml - Automatically updates documentation when manifests change
Detailed Documentation
NPC Data Structure Complete NPC schema, aggro types, drop tables, spawn constants, and helper functions.
Item Data Structure Item types, stats, requirements, equipment slots, noted items, and shop items.
Gathering & Crafting Woodcutting, mining, fishing, smelting, smithing, cooking, and firemaking systems.
Tier Requirements Centralized equipment and tool level requirements by tier.