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

# Data Manifests Overview

> Manifest-driven content system for NPCs, items, and world areas

## 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

<Info>
  All manifests are loaded from `world/assets/manifests/` at runtime by the `DataManager`.
</Info>

***

## 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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                                                     |
| ------------- | ----------------------------------------- | --------------------------------------------------------------- |
| `id`          | `string`                                  | Unique identifier                                               |
| `name`        | `string`                                  | Display name                                                    |
| `category`    | `"mob" \| "boss" \| "quest" \| "neutral"` | NPC type                                                        |
| `stats`       | `NPCStats`                                | Combat stats (attack, strength, defense, health, ranged, level) |
| `drops`       | `DropTable`                               | Loot table with rarity tiers                                    |
| `spawnBiomes` | `string[]`                                | Biomes where NPC spawns                                         |
| `modelPath`   | `string`                                  | Path to 3D model                                                |
| `behavior`    | `"passive" \| "aggressive"`               | Combat behavior                                                 |

### Available 3D Models

**Mobs** (`models/mobs/`):

```
├── goblin/
│   ├── goblin.vrm                → Goblin (VRM format)
│   ├── goblin_rigged.glb         → Goblin (GLB format)
│   └── animations/
│       ├── running.glb           → Running animation
│       └── walking.glb           → Walking animation
├── dark-ranger/
│   └── dark-ranger.vrm           → Dark ranger
└── dark-wizard/
    └── dark-wizard.vrm           → Dark wizard
```

**NPCs** (`models/npcs/`):

```
├── banker/banker.vrm             → Banker
├── captain-rowan/captain-rowan.vrm → Captain Rowan
├── fisherman-pete/fisherman-pete.vrm → Fisherman Pete
├── forester-wilma/forester-wilma.vrm → Forester Wilma
├── shopkeeper/shopkeeper.vrm     → Shopkeeper
├── tanner-ellis/tanner-ellis.vrm → Tanner Ellis
└── torvin/torvin.vrm             → Torvin
```

**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
├── bamboo_01.glb - bamboo_04.glb (+ LOD variants) → Bamboo trees
├── birch_01.glb - birch_05.glb (+ LOD variants)   → Birch trees with white bark
├── cactus01.glb - cactus08.glb (+ LOD variants)   → Desert cacti
├── chinaPine_01.glb - chinaPine_04.glb (+ LOD)    → China pine trees
├── coconut_01.glb - coconut_05.glb (+ LOD)        → Coconut palms
├── dead_01.glb - dead_06.glb (+ LOD variants)     → Dead/withered trees
├── fir_01.glb - fir_04.glb (+ LOD variants)       → Fir trees
├── knotwood_01.glb - knotwood_04.glb (+ LOD)      → Knotwood trees (warm amber leaves #C4832A)
├── maple_01.glb - maple_03.glb (+ LOD variants)   → Maple trees (vermillion red-orange leaves #D04838)
├── oak_01.glb - oak_04.glb (+ LOD variants)       → Oak trees
├── palm_01.glb - palm_05.glb (+ LOD variants)     → Desert palms
└── pine_01.glb - pine_03.glb (+ LOD variants)     → Pine trees
```

**Miscellaneous Items** (`models/misc/`):

```
├── bones/bones.glb               → Bones (mob drop)
├── coin-pile/coin-pile.glb       → Coin pile
├── ashes/ashes.glb               → Ashes
├── firemaking-fire/firemaking-fire.glb → Fire model for firemaking
└── headstone/headstone.glb       → Headstone
```

<Note>
  Tree models include LOD (Level of Detail) variants for performance optimization. Each tree type has multiple variants (e.g., `fir_01.glb`, `fir_01_lod1.glb`, `fir_01_lod2.glb`) for different viewing distances. All tree models have been normalized to consistent root depths to prevent floating or sinking into terrain.
</Note>

### NPC Helper Functions

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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                       |
| ------------ | --------------------------------- |
| `id`         | Unique zone identifier            |
| `name`       | Display name                      |
| `biome`      | Biome type (forest, plains, etc.) |
| `difficulty` | 0-3 difficulty level              |
| `mobs`       | NPCs that spawn here              |
| `resources`  | Trees, fishing spots, etc.        |
| `isSafe`     | Whether it's a safe zone          |

***

## Banks & Stores

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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.glb`                 | 0.5   | 0.2      |
| **Furnace** | Smelt ores into bars               | `asset://models/furnace/furnace.glb`             | 1.5   | 1.0      |
| **Range**   | Cook food with reduced burn chance | `asset://models/cooking-range/cooking-range.glb` | 1.0   | 0.3      |
| **Bank**    | Store items                        | `asset://models/bank-chest/bank-chest.glb`       | 0.5   | 0.10     |
| **Altar**   | Restore prayer points              | `asset://models/prayer-alter/prayer-alter.glb`   | 1.0   | 0.25     |

<Note>
  Station entities (Altar, Bank, Range) now load 3D models from the manifest system with automatic fallback to placeholder geometry if models are unavailable.
</Note>

### Station Model Loading

Station entities load 3D models from the manifest system using `StationDataProvider`:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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.

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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.glb`                 | 0.5   | 0.2      |
| **Furnace**       | Smelting ores into bars            | `models/furnace/furnace.glb`             | 1.5   | 1.0      |
| **Cooking Range** | Cooking food (reduced burn chance) | `models/cooking-range/cooking-range.glb` | 1.0   | 0.5      |
| **Bank Chest**    | Accessing bank storage             | `models/bank-chest/bank-chest.glb`       | 0.5   | 0.75     |
| **Altar**         | Restoring prayer points            | `models/prayer-alter/prayer-alter.glb`   | 1.0   | 0.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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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**:

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

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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
}
```

**Recent maxSlope Updates** (March 2026):

* **Tundra**: 0.8 → 1.8 (increased for terraced terrain)
* **Forest**: 0.8 → 1.5 (increased for landscape features)
* **Canyon**: 0.6 → 2.5 (increased for steep canyon walls)

**Vegetation Categories**:

* `tree` - Large trees (oak, willow, maple, yew, magic, fir, knotwood, dead, wind\_pine)
* `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)

**Tree Types**:

* **Oak, Willow, Yew, Magic** - Standard woodcutting trees with multiple model variants
* **Maple** - Autumn trees with warm vermillion red-orange leaves (#D04838)
* **Fir** - Coniferous trees for forest biomes
* **Knotwood** - Trees with warm amber-colored leaves (#C4832A)
* **Dead** - Barren trees for tundra/canyon biomes
* **Wind Pine** - Specialized pine tree for tundra biome (single model variant)

### Model Bounds System

The `model-bounds.json` manifest provides pre-calculated bounding boxes and footprints for 3D models:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
interface ModelBounds {
  id: string;                    // Model identifier
  assetPath: string;             // Path to GLB model
  bounds: {
    min: { x: number; y: number; z: number; };
    max: { x: number; y: number; z: number; };
  };
  dimensions: {
    x: number;                   // Width in meters
    y: number;                   // Height in meters
    z: number;                   // Depth in meters
  };
  footprint: {
    width: number;               // Grid footprint width
    depth: number;               // Grid footprint depth
  };
}
```

**Purpose:**

* Pre-calculated bounds avoid runtime model loading for collision detection
* Footprint data used for station placement and terrain flattening
* Enables efficient spatial queries without loading full 3D models
* Generated automatically from model files with 1-meter tile size

The model bounds system is used by the terrain flattening system to calculate station footprints and by the collision system for efficient spatial queries.

### Biomes

The `biomes.json` manifest defines terrain biomes with vegetation, mobs, and environmental properties:

**Available Biomes:**

* **Plains** - Open grasslands with gentle rolling hills (difficulty 0)
* **Forest** - Dense woodland with abundant trees (difficulty 1)
* **Valley** - Low-lying areas between hills (difficulty 0)
* **Mountains** - High elevation rocky peaks (difficulty 2)
* **Tundra** - Frozen wasteland with ice and snow (difficulty 3)
* **Desert** - Arid wasteland with sand dunes (difficulty 2)
* **Lakes** - Water bodies and fishing spots (difficulty 0)
* **Swamp** - Murky wetlands with twisted vegetation (difficulty 1)
* **Canyon** - Red-rock canyon lands with terraced mesas (difficulty 2, NEW)

### Biome Vegetation Layers

Biomes in `biomes.json` define procedural vegetation layers that reference vegetation assets:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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**:

* **165 tree model variants** added across 12 tree types (bamboo, birch, cactus, chinaPine, coconut, dead, fir, knotwood, maple, oak, palm, pine) with 3 LOD levels each
* **Tree model depth normalization**: All fir variants aligned to fir\_03's minY (-59.46), all maple variants aligned to maple\_01's minY (-114.76) to prevent floating
* **Maple tree recoloring**: Leaves changed to warm vermillion red-orange (#D04838)
* **Knotwood tree recoloring**: Leaves changed from golden-yellow to warm amber (#C4832A)
* **Terrain biome textures** added for TerrainShader rendering (grass, dirt, cliff, desert, snow variants)
* **Woodcutting manifest updated**: Replaced 8 generic trees with 12 new tree types using `modelVariants` arrays
* **Biomes manifest updated**: Removed stale `tree1` vegetation layers (trees now managed via TreeTypes.ts + woodcutting manifest)
* **Wind Pine tree type** added for tundra biome (split from dead tree variants)
* 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`)
* Tree model scales adjusted for better visual proportions (March 2026)
* Fir and maple model root depths normalized to prevent floating (March 2026)
  * All fir variants aligned to fir\_03's minY (-59.46)
  * All maple variants aligned to maple\_01's minY (-114.76)

***

## 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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
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

<Steps>
  <Step title="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`
  </Step>

  <Step title="Follow existing patterns">
    Use the same structure as existing entries. For tiered equipment, specify the `tier` field.
  </Step>

  <Step title="Generate 3D model (optional)">
    Use Asset Forge to create a new model, or use existing models
  </Step>

  <Step title="Restart server">
    The DataManager loads manifests on startup
  </Step>

  <Step title="Test in game">
    Verify the new content appears correctly
  </Step>
</Steps>

<Warning>
  Do NOT add game data directly to TypeScript files. Keep all content in JSON manifests for clean separation and easy modding.
</Warning>

## 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

<CardGroup cols={2}>
  <Card title="NPC Data Structure" icon="users" href="/wiki/data/npcs">
    Complete NPC schema, aggro types, drop tables, spawn constants, and helper functions.
  </Card>

  <Card title="Item Data Structure" icon="box-open" href="/wiki/data/items">
    Item types, stats, requirements, equipment slots, noted items, and shop items.
  </Card>

  <Card title="Gathering & Crafting" icon="hammer" href="/wiki/game-systems/skills">
    Woodcutting, mining, fishing, smelting, smithing, cooking, and firemaking systems.
  </Card>

  <Card title="Tier Requirements" icon="shield" href="/wiki/data/items">
    Centralized equipment and tool level requirements by tier.
  </Card>
</CardGroup>
