Skip to main content

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):
PropertyTypeDescription
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

TypeDescriptionFile
"weapon"Combat weaponsitems/weapons.json
"tool"Skilling toolsitems/tools.json
"resource"Gathered materials (ores, logs, bars, raw fish)items/resources.json
"consumable"Food that healsitems/food.json
"currency"Coinsitems/misc.json
"junk"Burnt food, worthless itemsitems/misc.json
"misc"Everything elseitems/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

PropertyDescription
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

StationPurposeModelScaleY Offset
AnvilSmith bars into equipmentasset://models/anvil/anvil.glb0.50.2
FurnaceSmelt ores into barsasset://models/furnace/furnace.glb1.51.0
RangeCook food with reduced burn chanceasset://models/cooking-range/cooking-range.glb1.00.3
BankStore itemsasset://models/bank-chest/bank-chest.glb0.50.10
AltarRestore prayer pointsasset://models/prayer-alter/prayer-alter.glb1.00.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

Tool Metadata

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

StationPurposeModelScaleY Offset
AnvilSmithing bars into equipmentmodels/anvil/anvil.glb0.50.2
FurnaceSmelting ores into barsmodels/furnace/furnace.glb1.51.0
Cooking RangeCooking food (reduced burn chance)models/cooking-range/cooking-range.glb1.00.5
Bank ChestAccessing bank storagemodels/bank-chest/bank-chest.glb0.50.75
AltarRestoring prayer pointsmodels/prayer-alter/prayer-alter.glb1.00.25
Stations are placed in world areas and interact with the corresponding recipe manifests (recipes/smithing.json, recipes/smelting.json, etc.).

Tool Metadata

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
}

Tool Priority System

When multiple tools are available, the system selects the highest priority tool: Woodcutting Hatchets:
ToolPriority
Crystal1 (best)
Dragon2
Rune3
Adamant4
Mithril5
Steel6
Iron7
Bronze8 (worst)
Mining Pickaxes (also includes rollTicks for mining speed):
ToolPriorityRoll Ticks
Crystal13
Dragon23
Rune33
Adamant44
Mithril55
Steel66
Iron77
Bronze88

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

QuestDifficultyQuest PointsDescription
Goblin SlayerNovice1Help Captain Rowan deal with the goblin threat
Lumberjack’s First LessonNovice1Help Forester Wilma gather and burn firewood
Fresh CatchNovice1Help Fisherman Pete catch and cook fish
Torvin’s ToolsNovice1Help 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

1

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
2

Follow existing patterns

Use the same structure as existing entries. For tiered equipment, specify the tier field.
3

Generate 3D model (optional)

Use Asset Forge to create a new model, or use existing models
4

Restart server

The DataManager loads manifests on startup
5

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