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

# Skills & Progression

> RuneScape-style skill system with XP curves and leveling

# Skills & Progression

Hyperscape features a **skill-based progression system** where skills level independently through use. The XP formula and combat level calculation are authentic recreations of Old School RuneScape mechanics.

<Info>
  Skills are managed by `SkillsSystem` in `packages/shared/src/systems/shared/character/SkillsSystem.ts`.
</Info>

## Available Skills

### Combat Skills

| Skill            | Description                         | Training Methods            |
| ---------------- | ----------------------------------- | --------------------------- |
| **Attack**       | Melee accuracy                      | Combat (Accurate style)     |
| **Strength**     | Melee max hit                       | Combat (Aggressive style)   |
| **Defense**      | Damage reduction                    | Combat (Defensive style)    |
| **Constitution** | Maximum HP                          | All combat (always granted) |
| **Ranged**       | Ranged combat                       | Bow/crossbow attacks        |
| **Prayer**       | Protection prayers and combat buffs | Burying bones, using altars |

### Gathering Skills

| Skill           | Description          | Training Methods                 |
| --------------- | -------------------- | -------------------------------- |
| **Woodcutting** | Chop trees           | Using hatchet on trees           |
| **Mining**      | Mine ore             | Using pickaxe on rocks           |
| **Fishing**     | Catch fish           | Using fishing rod at spots       |
| **Agility**     | Movement and stamina | Walking/running across the world |

### Artisan Skills

| Skill            | Description                      | Training Methods                                    |
| ---------------- | -------------------------------- | --------------------------------------------------- |
| **Firemaking**   | Light fires                      | Using tinderbox on logs                             |
| **Cooking**      | Cook food                        | Using raw food on fires/ranges                      |
| **Smithing**     | Smelt bars and smith equipment   | Smelting ores at furnaces, smithing bars at anvils  |
| **Fletching**    | Create bows and arrows           | Using knife on logs, stringing bows, tipping arrows |
| **Crafting**     | Create leather armor and jewelry | Tanning hides, crafting leather, cutting gems       |
| **Runecrafting** | Create magic runes               | Using essence at runecrafting altars                |

### Support Skills

| Skill       | Description          | Training Methods        |
| ----------- | -------------------- | ----------------------- |
| **Agility** | Stamina regeneration | Moving around the world |

<Info>
  Smithing is a two-step process: first smelt ores into bars at a furnace, then smith bars into equipment at an anvil.
</Info>

### Support Skills

| Skill       | Description                         | Training Methods                            |
| ----------- | ----------------------------------- | ------------------------------------------- |
| **Prayer**  | Activate prayers for combat bonuses | Burying bones, using prayer at altars       |
| **Agility** | Stamina regeneration                | Moving through the world (1 XP per 2 tiles) |

<Info>
  Agility is unique - it trains passively as you move. Every 100 tiles traveled grants 50 XP (batched to prevent visual spam).
</Info>

***

## XP Formula

The XP table uses the authentic RuneScape formula. Level 92 represents the halfway point to 99 in total XP.

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// From SkillsSystem.ts
private generateXPTable(): void {
  this.xpTable = [0, 0]; // Levels 0 and 1

  for (let level = 2; level <= 99; level++) {
    const xp = Math.floor(level - 1 + 300 * Math.pow(2, (level - 1) / 7)) / 4;
    this.xpTable.push(Math.floor(this.xpTable[level - 1] + xp));
  }
}
```

### XP Requirements by Level

| Level | Total XP   | XP to Next     |
| ----- | ---------- | -------------- |
| 1     | 0          | 83             |
| 10    | 1,154      | 229            |
| 20    | 4,470      | 899            |
| 30    | 13,363     | 2,673          |
| 40    | 37,224     | 7,195          |
| 50    | 101,333    | 18,389         |
| 60    | 273,742    | 46,236         |
| 70    | 737,627    | 115,590        |
| 80    | 1,986,068  | 287,883        |
| 90    | 5,346,332  | 716,427        |
| 92    | 6,517,253  | \~50% of 99 XP |
| 99    | 13,034,431 | MAX            |

<Warning>
  **XP Cap**: Maximum XP per skill is 200,000,000 (200M). This matches OSRS.
</Warning>

***

## Level Calculations

### Get Level from XP

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
public getLevelForXP(xp: number): number {
  for (let level = 99; level >= 1; level--) {
    if (xp >= this.xpTable[level]) {
      return level;
    }
  }
  return 1;
}
```

### XP to Next Level

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
public getXPToNextLevel(skill: SkillData): number {
  if (skill.level >= 99) return 0;

  const nextLevelXP = this.getXPForLevel(skill.level + 1);
  return nextLevelXP - skill.xp;
}
```

### Progress Percentage

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
public getXPProgress(skill: SkillData): number {
  if (skill.level >= 99) return 100;

  const currentLevelXP = this.getXPForLevel(skill.level);
  const nextLevelXP = this.getXPForLevel(skill.level + 1);
  const progressXP = skill.xp - currentLevelXP;
  const requiredXP = nextLevelXP - currentLevelXP;

  return (progressXP / requiredXP) * 100;
}
```

***

## Combat Level

Combat level is calculated from combat skills using the OSRS formula. Prayer contributes to the base calculation.

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// From SkillsSystem.ts
public getCombatLevel(stats: StatsComponent): number {
  const defenseLevel = stats.defense?.level ?? 1;
  const hitpointsLevel = stats.constitution?.level ?? 10;
  const prayerLevel = stats.prayer?.level ?? 1;  // Prayer affects combat level
  const attackLevel = stats.attack?.level ?? 1;
  const strengthLevel = stats.strength?.level ?? 1;
  const rangedLevel = stats.ranged?.level ?? 1;
  const magicLevel = stats.magic?.level ?? 1;

  // Base = 0.25 × (Defense + Hitpoints + floor(Prayer / 2))
  const base = 0.25 * (defenseLevel + hitpointsLevel + Math.floor(prayerLevel / 2));

  // Melee = 0.325 × (Attack + Strength)
  const melee = 0.325 * (attackLevel + strengthLevel);

  // Ranged = 0.325 × floor(Ranged × 1.5)
  const rangedCalc = 0.325 * Math.floor(rangedLevel * 1.5);

  // Magic = 0.325 × floor(Magic × 1.5)
  const magicCalc = 0.325 * Math.floor(magicLevel * 1.5);

  // Combat Level = floor(Base + max(Melee, Ranged, Magic))
  return Math.floor(base + Math.max(melee, rangedCalc, magicCalc));
}
```

<Info>
  Prayer level contributes to combat level via the base calculation. Each Prayer level adds 0.125 to combat level (since it's divided by 2 then multiplied by 0.25).
</Info>

### Combat Level Examples

| Stats                         | Combat Level |
| ----------------------------- | ------------ |
| All 1s                        | 3            |
| 40 Atk/Str, 1 everything else | 32           |
| 60 Atk/Str/Def, 60 HP         | 66           |
| 99 all combat                 | 126          |

***

## Total Level

Total level is the sum of all skill levels.

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
public getTotalLevel(stats: StatsComponent): number {
  let total = 0;

  const skills = [
    "attack", "strength", "defense", "constitution", "ranged", "prayer",
    "woodcutting", "mining", "fishing", "firemaking", "cooking", "smithing", "crafting", "agility"
  ];

  for (const skill of skills) {
    const skillData = stats[skill];
    total += skillData?.level ?? 1;
  }

  return total;
}
```

### Maximum Total Level

With 15 skills at level 99: **1,485 total level**

<Info>
  Total level calculation includes: Attack, Strength, Defense, Constitution, Ranged, Prayer, Woodcutting, Mining, Fishing, Firemaking, Cooking, Smithing, Agility, Fletching, and Runecrafting.
</Info>

***

## XP Sources

### Combat XP

| Action                       | XP Per Damage |
| ---------------------------- | ------------- |
| Main skill (style-dependent) | 4.0           |
| Constitution (always)        | 1.33          |
| Controlled (per skill)       | 1.33          |

### XP Lamps

XP lamps are consumable items that grant XP to a skill of your choice:

```json theme={"theme":{"light":"github-light","dark":"css-variables"}}
{
  "id": "xp_lamp_1000",
  "name": "XP Lamp (1000 XP)",
  "type": "consumable",
  "useEffect": {
    "type": "xp_lamp",
    "xpAmount": 1000
  },
  "inventoryActions": ["Rub", "Drop", "Examine"]
}
```

**Usage:**

1. Right-click lamp in inventory → select "Rub"
2. Skill selection modal appears showing all skills with current levels
3. Select skill to receive XP
4. Lamp is consumed and XP is granted

**Security:**

* Server validates lamp exists at specified slot
* Server validates XP amount matches manifest definition
* Server validates skill ID is valid
* Rate limited to 3 requests/sec (shared with consume limiter)

<Info>
  XP lamps are commonly awarded as quest rewards, allowing players to choose which skill benefits from the quest.
</Info>

### Gathering XP

Gathering resources is now defined in `manifests/gathering/` with OSRS-accurate XP values:

**Woodcutting** (`gathering/woodcutting.json`):

| Tree         | Level | XP   | Variants                                                |
| ------------ | ----- | ---- | ------------------------------------------------------- |
| Fir          | 1     | 25   | 4 variants + LOD                                        |
| Pine         | 1     | 25   | 3 variants + LOD                                        |
| Birch        | 1     | 25   | 5 variants + LOD                                        |
| Bamboo       | 1     | 25   | 4 variants + LOD                                        |
| China Pine   | 1     | 25   | 4 variants + LOD                                        |
| Coconut Palm | 1     | 25   | 5 variants + LOD                                        |
| Desert Palm  | 1     | 25   | 5 variants + LOD                                        |
| Dead Tree    | 1     | 25   | 5 variants + LOD                                        |
| Cactus       | 1     | 25   | 8 variants + LOD                                        |
| Knotwood     | 1     | 25   | 4 variants + LOD (warm amber leaves #C4832A)            |
| Wind Pine    | 1     | 25   | 1 variant (tundra biome)                                |
| Oak          | 15    | 37.5 | 4 variants + LOD                                        |
| Maple        | 45    | 100  | 3 variants + LOD (vermillion red-orange leaves #D04838) |

<Note>
  The game now features 12 distinct tree types with 165 total model variants (55 base models × 3 LOD levels). Each tree type has multiple visual variants for environmental diversity. All tree models have been normalized to consistent root depths to prevent floating or sinking into terrain. Trees are now managed via TreeTypes.ts + woodcutting manifest instead of the vegetation system.
</Note>

**Mining** (`gathering/mining.json`):

| Ore        | Level | XP   | Success Rate (L1 → L99)          |
| ---------- | ----- | ---- | -------------------------------- |
| Copper/Tin | 1     | 17.5 | 39.5% → 100% (at L62)            |
| Iron       | 15    | 35   | 52% (at L15) → 100% (at L63)     |
| Coal       | 30    | 50   | 16.4% (at L30) → 39.5% (at L99)  |
| Mithril    | 55    | 80   | 11.7% (at L55) → 19.9% (at L99)  |
| Adamantite | 70    | 95   | 7.4% (at L70) → 10.2% (at L99)   |
| Runite     | 85    | 125  | 6.64% (at L85) → 7.42% (at L97+) |

<Info>
  Mining rocks **always deplete** after yielding one ore (OSRS-accurate). Success rate depends only on Mining level, not pickaxe tier. Pickaxe tier affects roll frequency (speed), not success chance.
</Info>

### Pickaxe Speed Bonuses

Dragon and Crystal pickaxes have a chance for bonus speed:

| Pickaxe     | Base Speed | Bonus Chance | Bonus Speed | Average Speed |
| ----------- | ---------- | ------------ | ----------- | ------------- |
| Bronze-Rune | 3-8 ticks  | -            | -           | 3-8 ticks     |
| Dragon      | 3 ticks    | 1/6 (16.7%)  | 2 ticks     | 2.83 ticks    |
| Crystal     | 3 ticks    | 1/4 (25%)    | 2 ticks     | 2.75 ticks    |

<Info>
  The bonus speed roll is server-authoritative to prevent client/server desyncs.
</Info>

***

## Agility System

Agility is a unique skill in Hyperscape that rewards exploration and movement. Unlike traditional RuneScape agility courses, it's trained passively by traversing the game world.

### Training Agility

**XP Gain:**

* 1 XP per 2 tiles traveled (both walking and running)
* XP is batched at 100 tiles = 50 XP to prevent visual spam
* XP drops appear every \~15 seconds while running, \~30 seconds while walking

**XP Rates:**

| Movement Type | Tiles/Second | XP/Minute | Time to Level 50 | Time to Level 99 |
| ------------- | ------------ | --------- | ---------------- | ---------------- |
| Walking       | 3.33         | \~100 XP  | \~17 hours       | \~2,000+ hours   |
| Running       | 6.67         | \~200 XP  | \~8.5 hours      | \~1,000+ hours   |

**Death Penalty:**

* Accumulated tiles toward next XP grant are lost on death (max \~50 XP lost)
* Earned XP is never lost
* Tile counter resets to 0 on death

**Logout Behavior:**

* Tile counter is not persisted (resets to 0 on logout)
* Earned XP is saved to database

<Warning>
  Teleportation does not grant Agility XP - only tiles traveled by walking/running count.
</Warning>

### Stamina System Integration

Agility directly affects stamina regeneration, while inventory weight affects stamina drain.

#### Weight-Based Stamina Drain

Carrying heavy items increases stamina drain while running:

**Formula:** `Drain Rate = Base Drain × (1 + Weight × 0.005)`

| Weight (kg) | Drain Multiplier | Drain/Second | Impact     |
| ----------- | ---------------- | ------------ | ---------- |
| 0           | 1.0×             | 2.0          | No penalty |
| 10          | 1.05×            | 2.1          | +5% drain  |
| 20          | 1.1×             | 2.2          | +10% drain |
| 40          | 1.2×             | 2.4          | +20% drain |
| 60          | 1.3×             | 2.6          | +30% drain |
| 100         | 1.5×             | 3.0          | +50% drain |

<Info>
  Weight is calculated server-side from your inventory and equipment, then synced to the client for stamina calculations.
</Info>

#### Agility-Based Stamina Regeneration

Higher Agility levels increase stamina regeneration:

**Formula:** `Regen Rate = Base Regen × (1 + Agility Level × 0.01)`

| Agility Level | Regen Multiplier | Idle Regen/Sec | Walking Regen/Sec |
| ------------- | ---------------- | -------------- | ----------------- |
| 1             | 1.01×            | 4.04           | 2.02              |
| 10            | 1.10×            | 4.40           | 2.20              |
| 25            | 1.25×            | 5.00           | 2.50              |
| 50            | 1.50×            | 6.00           | 3.00              |
| 75            | 1.75×            | 7.00           | 3.50              |
| 99            | 1.99×            | 7.96           | 3.98              |

**Base Stamina Rates:**

* Running: -2.0 stamina/second (modified by weight)
* Walking: +2.0 stamina/second (modified by agility)
* Idle: +4.0 stamina/second (modified by agility)

<Info>
  High Agility levels can offset the stamina drain penalty from heavy loads. A level 99 Agility player regenerates stamina nearly twice as fast as a level 1 player.
</Info>

### Agility Unlocks

| Level | Unlock                                     | Type    |
| ----- | ------------------------------------------ | ------- |
| 1     | Basic stamina regeneration (+1% per level) | Ability |
| 10    | +10% stamina regeneration                  | Ability |
| 25    | +25% stamina regeneration                  | Ability |
| 50    | +50% stamina regeneration                  | Ability |
| 75    | +75% stamina regeneration                  | Ability |
| 99    | Agility cape, +99% stamina regeneration    | Item    |

### Implementation Details

Agility is implemented across multiple systems:

**Server-Side** (`packages/server/src/systems/ServerNetwork/tile-movement.ts`):

* `TileMovementManager` tracks tiles traveled per player
* Batches XP grants at 100-tile threshold
* Resets tile counter on death

**Client-Side** (`packages/shared/src/entities/player/PlayerLocal.ts`):

* Stamina drain calculation uses `totalWeight` property
* Stamina regen calculation uses `skills.agility.level`
* Weight synced from server via `PLAYER_WEIGHT_CHANGED` event

**Database** (`packages/server/src/database/schema.ts`):

* `agilityLevel` and `agilityXp` columns in characters table
* Persisted on save, loaded on character selection

<Info>
  **Mining Mechanics**: Rocks always deplete after yielding one ore (100% depletion chance). Success rates are OSRS-accurate and depend only on Mining level, not pickaxe tier. Pickaxe tier affects roll frequency (speed) only. The bonus speed roll for Dragon/Crystal pickaxes is server-authoritative to prevent client/server desyncs.
</Info>

### Model Scale Normalization

Mining rocks (and all resources) now have normalized model scales to prevent "squished" or "stretched" appearance:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// From ModelCache.ts - normalizeScales()
// Detects and resets non-uniform scales in GLTF models
// Some 3D modeling tools export models with non-uniform scales on internal nodes
// (e.g., scale (2, 0.5, 1)) which causes distortion
scene.traverse((node) => {
  const s = node.scale;
  const isNonUniform = 
    Math.abs(s.x - s.y) > 0.001 ||
    Math.abs(s.y - s.z) > 0.001 ||
    Math.abs(s.x - s.z) > 0.001;

  if (isNonUniform) {
    node.scale.set(1, 1, 1);  // Reset to identity
    node.updateMatrix();
  }
});
```

<Info>
  This normalization runs once when a model is first loaded, before caching. All clones will have correct proportions.
</Info>

**Agility** (movement-based):

Agility is a unique skill that rewards exploration and world traversal:

| Training Method | XP Rate      | Notes                 |
| --------------- | ------------ | --------------------- |
| Walking         | \~100 XP/min | 2 tiles/tick movement |
| Running         | \~200 XP/min | 4 tiles/tick movement |

**XP Batching**: XP is granted every 100 tiles (50 XP) to prevent visual spam. This creates XP drops approximately every 15 seconds while running or 30 seconds while walking.

**Death Penalty**: Death resets your tile counter to 0, losing any accumulated progress toward the next XP grant (maximum \~50 XP lost).

**Benefits**:

* **Stamina Regeneration Bonus**: +1% regen per Agility level
  * Level 1: 1.01x regen (4.04/sec idle, 2.02/sec walking)
  * Level 50: 1.50x regen (6.00/sec idle, 3.00/sec walking)
  * Level 99: 1.99x regen (7.96/sec idle, 3.98/sec walking)

<Info>
  Agility does NOT affect combat level, matching OSRS design. It's purely a utility skill for stamina management.
</Info>

**Fishing** (`gathering/fishing.json`):

| Fish      | Level | XP  |
| --------- | ----- | --- |
| Shrimp    | 1     | 10  |
| Sardine   | 5     | 20  |
| Herring   | 10    | 30  |
| Trout     | 20    | 50  |
| Pike      | 25    | 60  |
| Salmon    | 30    | 70  |
| Lobster   | 40    | 90  |
| Swordfish | 50    | 100 |
| Shark     | 76    | 110 |

**Agility** (passive movement-based):

| Activity | XP Rate      | Notes            |
| -------- | ------------ | ---------------- |
| Walking  | \~100 XP/min | 1 XP per 2 tiles |
| Running  | \~200 XP/min | 1 XP per 2 tiles |

<Info>
  Agility XP is batched at 100 tiles (50 XP) to prevent visual spam. XP drops appear every \~15 seconds while running, \~30 seconds while walking.
</Info>

### Artisan XP

Processing recipes are defined in `manifests/recipes/` with OSRS-accurate XP values:

**Smelting** (`recipes/smelting.json`):

| Bar     | Level | Ores Required         | XP   | Success Rate |
| ------- | ----- | --------------------- | ---- | ------------ |
| Bronze  | 1     | 1 Copper + 1 Tin      | 6.2  | 100%         |
| Iron    | 15    | 1 Iron                | 12.5 | 50%          |
| Steel   | 30    | 1 Iron + 2 Coal       | 17.5 | 100%         |
| Mithril | 50    | 1 Mithril + 4 Coal    | 30   | 100%         |
| Adamant | 70    | 1 Adamantite + 6 Coal | 37.5 | 100%         |
| Rune    | 85    | 1 Runite + 8 Coal     | 50   | 100%         |

<Info>
  Iron ore has a 50% success rate when smelting - failed attempts consume the ore but grant no bar or XP.
</Info>

**Smithing** (`recipes/smithing.json`):

Smithing requires a hammer in inventory and access to an anvil. Recipes are organized by category:

*Weapons*:

| Item            | Level | Bars | XP   |
| --------------- | ----- | ---- | ---- |
| Bronze dagger   | 1     | 1    | 12.5 |
| Bronze sword    | 4     | 1    | 12.5 |
| Bronze scimitar | 5     | 2    | 25   |
| Iron sword      | 19    | 1    | 25   |
| Steel sword     | 34    | 1    | 37.5 |
| Mithril sword   | 54    | 1    | 50   |
| Adamant sword   | 74    | 1    | 62.5 |
| Rune sword      | 89    | 1    | 75   |

*Armor*:

| Item              | Level | Bars | XP    |
| ----------------- | ----- | ---- | ----- |
| Bronze platebody  | 18    | 5    | 62.5  |
| Iron platebody    | 33    | 5    | 125   |
| Steel platebody   | 48    | 5    | 187.5 |
| Mithril platebody | 68    | 5    | 250   |

*Tools*:

| Item           | Level | Bars | XP   |
| -------------- | ----- | ---- | ---- |
| Bronze hatchet | 1     | 1    | 12.5 |
| Bronze pickaxe | 1     | 1    | 12.5 |
| Iron hatchet   | 16    | 1    | 25   |
| Steel hatchet  | 31    | 1    | 37.5 |

<Info>
  Smithing recipes support "Make X" functionality - players can smith multiple items in one session. The system remembers the last custom quantity entered.
</Info>

**Cooking** (`recipes/cooking.json`):

| Food      | Level | XP  | Heals |
| --------- | ----- | --- | ----- |
| Shrimp    | 1     | 30  | 3 HP  |
| Sardine   | 1     | 40  | 3 HP  |
| Herring   | 5     | 50  | 5 HP  |
| Trout     | 15    | 70  | 7 HP  |
| Pike      | 20    | 80  | 8 HP  |
| Salmon    | 25    | 90  | 9 HP  |
| Lobster   | 40    | 120 | 12 HP |
| Swordfish | 45    | 140 | 14 HP |
| Shark     | 80    | 210 | 20 HP |

### Food Consumption Mechanics

Food consumption follows OSRS-accurate timing and combat integration:

**Eating Delay**:

* 3-tick (1.8s) cooldown between eating foods
* Managed by `EatDelayManager` (per-player tracking)
* Food consumed only after validation passes
* Message shown even at full health: "You eat the shrimp."

**Combat Integration**:

* Eating during combat adds 3-tick delay to attack cooldown
* OSRS rule: Only adds delay if weapon is **already on cooldown**
* If weapon is ready to attack, eating does NOT add delay
* Prevents eating from being used to delay attacks strategically

**Server-Authoritative Flow**:

```
Client → useItem packet → Server validates → INVENTORY_USE event →
InventorySystem validates item exists → ITEM_USED → PlayerSystem validates eat delay →
Consume item + heal + attack delay
```

**Security Features**:

* Rate limiting (3 requests/sec)
* Input validation (slot bounds, item ID mismatch detection)
* Heal amount capped at 99 HP (prevents manifest exploits)
* Server-side eat delay enforcement

<Info>
  Food is consumed even at full health (OSRS-accurate). The eat delay and attack delay still apply.
</Info>

**Firemaking** (`recipes/firemaking.json`):

| Logs     | Level | XP    |
| -------- | ----- | ----- |
| Normal   | 1     | 40    |
| Oak      | 15    | 60    |
| Willow   | 30    | 90    |
| Teak     | 35    | 105   |
| Maple    | 45    | 135   |
| Mahogany | 50    | 157.5 |
| Yew      | 60    | 202.5 |
| Magic    | 75    | 303.8 |

**Fletching** (`recipes/fletching.json`):

Fletching is a three-stage process: creating arrow shafts, crafting unstrung bows, and finishing products.

*Arrow Shafts* (Knife + Logs):

| Logs   | Level | Shafts | XP |
| ------ | ----- | ------ | -- |
| Normal | 1     | 15     | 5  |
| Oak    | 15    | 30     | 10 |
| Willow | 30    | 45     | 15 |
| Maple  | 45    | 60     | 20 |
| Yew    | 60    | 75     | 25 |
| Magic  | 75    | 90     | 30 |

*Shortbows* (Knife + Logs, then String):

| Bow             | Level | XP (Cut) | XP (String) | Total XP |
| --------------- | ----- | -------- | ----------- | -------- |
| Shortbow        | 5     | 5        | 5           | 10       |
| Oak shortbow    | 20    | 16.5     | 16.5        | 33       |
| Willow shortbow | 35    | 33.3     | 33.3        | 66.6     |
| Maple shortbow  | 50    | 50       | 50          | 100      |
| Yew shortbow    | 65    | 67.5     | 67.5        | 135      |
| Magic shortbow  | 80    | 83.3     | 83.3        | 166.6    |

*Longbows* (Knife + Logs, then String):

| Bow            | Level | XP (Cut) | XP (String) | Total XP |
| -------------- | ----- | -------- | ----------- | -------- |
| Longbow        | 10    | 10       | 10          | 20       |
| Oak longbow    | 25    | 25       | 25          | 50       |
| Willow longbow | 40    | 41.5     | 41.5        | 83       |
| Maple longbow  | 55    | 58.3     | 58.3        | 116.6    |
| Yew longbow    | 70    | 75       | 75          | 150      |
| Magic longbow  | 85    | 91.5     | 91.5        | 183      |

*Arrows* (Arrowtips + Headless Arrows):

| Arrow   | Level | XP (per 15) |
| ------- | ----- | ----------- |
| Bronze  | 1     | 19.5        |
| Iron    | 15    | 37.5        |
| Steel   | 30    | 75          |
| Mithril | 45    | 112.5       |
| Adamant | 60    | 150         |
| Rune    | 75    | 187.5       |

**Crafting** (`recipes/crafting.json`):

*Leather Armor* (Needle + Thread):

| Item              | Level | Leather | XP   |
| ----------------- | ----- | ------- | ---- |
| Leather gloves    | 1     | 1       | 13.8 |
| Leather boots     | 7     | 1       | 16.3 |
| Leather cowl      | 9     | 1       | 18.5 |
| Leather vambraces | 11    | 1       | 22   |
| Leather body      | 14    | 1       | 25   |
| Leather chaps     | 18    | 1       | 27   |
| Coif              | 38    | 1       | 37   |

*Dragonhide Armor* (Needle + Thread):

| Item                   | Level | Dragon Leather | XP  |
| ---------------------- | ----- | -------------- | --- |
| Green d'hide vambraces | 57    | 1              | 62  |
| Green d'hide chaps     | 60    | 2              | 124 |
| Green d'hide body      | 63    | 3              | 186 |

*Jewelry* (Gold Bar + Gem at Furnace):

| Item               | Level | Materials                | XP  |
| ------------------ | ----- | ------------------------ | --- |
| Gold ring          | 5     | 1 gold bar               | 15  |
| Amulet of accuracy | 8     | 1 gold bar               | 30  |
| Amulet of strength | 50    | 1 gold bar + ruby        | 85  |
| Amulet of power    | 70    | 1 gold bar + diamond     | 100 |
| Amulet of glory    | 80    | 1 gold bar + dragonstone | 150 |
| Amulet of fury     | 90    | 1 gold bar + onyx        | 165 |

*Gem Cutting* (Chisel):
**Crafting** (`recipes/crafting.json`):

*Leather Armor*:

| Item              | Level | XP   |
| ----------------- | ----- | ---- |
| Leather Gloves    | 1     | 13.8 |
| Leather Boots     | 7     | 16.3 |
| Leather Cowl      | 9     | 18.5 |
| Leather Vambraces | 11    | 22   |
| Leather Body      | 14    | 25   |
| Leather Chaps     | 18    | 27   |
| Coif              | 38    | 37   |

*Studded Armor*:

| Item          | Level | XP |
| ------------- | ----- | -- |
| Studded Body  | 41    | 40 |
| Studded Chaps | 44    | 42 |

*Dragonhide Armor*:

| Item                   | Level | XP  |
| ---------------------- | ----- | --- |
| Green D'hide Vambraces | 57    | 62  |
| Green D'hide Chaps     | 60    | 124 |
| Green D'hide Body      | 63    | 186 |

*Jewelry*:

| Item               | Level | XP  |
| ------------------ | ----- | --- |
| Gold Ring          | 5     | 15  |
| Amulet of Accuracy | 8     | 30  |
| Amulet of Strength | 50    | 85  |
| Amulet of Power    | 70    | 100 |
| Amulet of Glory    | 80    | 150 |
| Amulet of Fury     | 90    | 165 |

*Gem Cutting*:

| Gem         | Level | XP    |
| ----------- | ----- | ----- |
| Sapphire    | 20    | 50    |
| Emerald     | 27    | 67.5  |
| Ruby        | 34    | 85    |
| Diamond     | 43    | 107.5 |
| Dragonstone | 55    | 137.5 |
| Onyx        | 67    | 167.5 |

**Runecrafting** (`recipes/runecrafting.json`):

Runecrafting creates magic runes from essence at runecrafting altars:

| Rune  | Level | XP/Essence | Essence Types | Multi-Rune Levels                  |
| ----- | ----- | ---------- | ------------- | ---------------------------------- |
| Air   | 1     | 5.0        | Rune/Pure     | 11, 22, 33, 44, 55, 66, 77, 88, 99 |
| Mind  | 2     | 5.5        | Rune/Pure     | 14, 28, 42, 56, 70, 84, 98         |
| Water | 5     | 6.0        | Rune/Pure     | 19, 38, 57, 76, 95                 |
| Earth | 9     | 6.5        | Rune/Pure     | 26, 52, 78                         |
| Fire  | 14    | 7.0        | Rune/Pure     | 35, 70, 95                         |
| Chaos | 35    | 8.5        | Pure only     | 74                                 |

<Info>
  **Multi-Rune Levels**: At certain levels, you craft multiple runes per essence. For example, at level 11 Runecrafting, you craft 2 air runes per essence instead of 1. Chaos runes require pure essence and cannot be crafted with regular rune essence.
</Info>

**Agility** (Movement-based):

| Activity | XP Rate      | Notes                           |
| -------- | ------------ | ------------------------------- |
| Walking  | \~100 XP/min | 2 tiles/tick × 1 XP per 2 tiles |
| Running  | \~200 XP/min | 4 tiles/tick × 1 XP per 2 tiles |

<Info>
  Agility XP is batched at 100 tiles = 50 XP to prevent visual spam. Death resets accumulated tiles (not earned XP).
</Info>

***

## Level Requirements

Skills gate access to equipment and activities. Requirements are now centralized in `tier-requirements.json` and `skill-unlocks.json`.

### Tier-Based Equipment Requirements

Equipment now uses a tier system that automatically looks up requirements:

**Melee Weapons & Armor** (Attack/Defence):

| Tier        | Level |
| ----------- | ----- |
| Bronze/Iron | 1     |
| Steel       | 5     |
| Black       | 10    |
| Mithril     | 20    |
| Adamant     | 30    |
| Rune        | 40    |
| Dragon      | 60    |

**Tools** (Woodcutting/Mining):

| Tier        | Attack | Woodcutting | Mining |
| ----------- | ------ | ----------- | ------ |
| Bronze/Iron | 1      | 1           | 1      |
| Steel       | 5      | 6           | 6      |
| Mithril     | 20     | 21          | 21     |
| Adamant     | 30     | 31          | 31     |
| Rune        | 40     | 41          | 41     |
| Dragon      | 60     | 61          | 61     |

### Gathering Resource Requirements

Defined in `gathering/*.json`:

**Woodcutting**:

| Tree     | Level |
| -------- | ----- |
| Normal   | 1     |
| Oak      | 15    |
| Willow   | 30    |
| Teak     | 35    |
| Maple    | 45    |
| Mahogany | 50    |
| Yew      | 60    |
| Magic    | 75    |

**Mining**:

| Ore        | Level |
| ---------- | ----- |
| Copper/Tin | 1     |
| Iron       | 15    |
| Coal       | 30    |
| Mithril    | 55    |
| Adamantite | 70    |
| Runite     | 85    |

### Mining Success Rates (OSRS-Accurate)

Mining success rates depend **only on Mining level**, not pickaxe tier. Pickaxe tier affects roll frequency (speed) only.

The formula uses linear interpolation between low and high values:

```
P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256
```

| Ore        | Success at Min Level | Success at L99 | Notes             |
| ---------- | -------------------- | -------------- | ----------------- |
| Copper/Tin | \~39.5% (L1)         | 100% (L62+)    | Beginner-friendly |
| Iron       | \~52% (L15)          | 100% (L63+)    | Fast training     |
| Coal       | \~16.4% (L30)        | \~39.5% (L99)  | Slow but valuable |
| Mithril    | \~11.7% (L55)        | \~19.9% (L99)  | Very slow         |
| Adamantite | \~7.4% (L70)         | \~10.2% (L99)  | Rare              |
| Runite     | \~6.64% (L85)        | \~7.42% (L97+) | Extremely rare    |

<Warning>
  **Rock Depletion**: Mining rocks ALWAYS deplete after yielding one ore (100% chance). This matches OSRS behavior. The only exception would be Mining gloves (not currently implemented).
</Warning>

### Pickaxe Speed Bonuses

Pickaxe tier determines roll frequency (ticks between attempts):

| Pickaxe | Roll Ticks | Speed     | Special Bonus                         |
| ------- | ---------- | --------- | ------------------------------------- |
| Bronze  | 8          | Slowest   | None                                  |
| Iron    | 7          | Slow      | None                                  |
| Steel   | 6          | Medium    | None                                  |
| Mithril | 5          | Fast      | None                                  |
| Adamant | 4          | Faster    | None                                  |
| Rune    | 3          | Very fast | None                                  |
| Dragon  | 3          | Very fast | 1/6 chance for 2-tick roll (avg 2.83) |
| Crystal | 3          | Very fast | 1/4 chance for 2-tick roll (avg 2.75) |

<Info>
  **Dragon/Crystal Pickaxe Bonus**: These pickaxes have a chance to trigger a faster roll. The server rolls this randomly and applies it deterministically to prevent client/server desyncs.
</Info>

**Fishing**:

| Fish      | Level |
| --------- | ----- |
| Shrimp    | 1     |
| Sardine   | 5     |
| Herring   | 10    |
| Trout     | 20    |
| Pike      | 25    |
| Salmon    | 30    |
| Lobster   | 40    |
| Swordfish | 50    |
| Shark     | 76    |

### Processing Recipe Requirements

Defined in `recipes/*.json`:

**Smelting**: Levels 1-85 (Bronze to Rune bars)
**Smithing**: Levels 1-91 (Bronze to Rune equipment)
**Cooking**: Levels 1-80 (Shrimp to Shark)
**Firemaking**: Levels 1-75 (Normal to Magic logs)

### Smithing Requirements

| Item              | Smithing Level | Bars Required             |
| ----------------- | -------------- | ------------------------- |
| Bronze Bar        | 1              | 1 copper ore + 1 tin ore  |
| Iron Bar          | 15             | 1 iron ore (50% success)  |
| Steel Bar         | 30             | 1 iron ore + 2 coal       |
| Mithril Bar       | 50             | 1 mithril ore + 4 coal    |
| Adamant Bar       | 70             | 1 adamantite ore + 6 coal |
| Rune Bar          | 85             | 1 runite ore + 8 coal     |
| Bronze Equipment  | 1              | 1-5 bronze bars           |
| Iron Equipment    | 15             | 1-5 iron bars             |
| Steel Equipment   | 30             | 2-5 steel bars            |
| Mithril Equipment | 50             | 2-5 mithril bars          |
| Adamant Equipment | 70             | 3-5 adamant bars          |
| Rune Equipment    | 85             | 3-5 rune bars             |

***

## Agility System

Agility is a unique skill that trains passively through movement and affects stamina mechanics.

### Movement XP

Agility XP is granted based on tiles traveled:

`typescript\n// From TileMovementManager.ts\nconst AGILITY_TILES_PER_XP_GRANT = 100;  // Tiles needed before XP is granted\nconst AGILITY_XP_PER_GRANT = 50;         // XP granted per threshold\n\n// Effective rate: 1 XP per 2 tiles traveled\n`\n\n**XP Rates**:\n| Movement Type | Tiles/Tick | Tiles/Second | XP/Minute |\n|---------------|------------|--------------|------------|\n| Walking | 2 | 3.33 | \~100 XP |\n| Running | 4 | 6.67 | \~200 XP |\n\n**Batching System**:\n- XP is granted every 100 tiles (50 XP)\n- Prevents visual spam (XP drop every \~15s running, \~30s walking)\n- Overflow is preserved (walking 150 tiles = 50 XP + 50 tiles remaining)\n- Death resets tile counter to 0 (small penalty)\n- Logout/disconnect clears tile counter (max \~50 XP lost)\n\n<Warning>\nTeleportation does NOT grant Agility XP - only walking/running movement counts.\n</Warning>\n\n### Weight-Based Stamina Drain\n\nCarrying weight affects stamina drain while running:\n\n`typescript\n// From PlayerLocal.ts\nconst WEIGHT_DRAIN_MODIFIER = 0.005;  // +0.5% drain per kg carried\n\nconst weightMultiplier = 1 + totalWeight * WEIGHT_DRAIN_MODIFIER;\nconst drainRate = BASE_STAMINA_DRAIN * weightMultiplier;\n`\n\n**Weight Impact Table**:\n| Weight (kg) | Drain Multiplier | Drain/Second |\n|-------------|------------------|--------------|\n| 0 | 1.0x | 2.0 |\n| 10 | 1.05x | 2.1 |\n| 20 | 1.1x | 2.2 |\n| 40 | 1.2x | 2.4 |\n| 60 | 1.3x | 2.6 |\n| 100 | 1.5x | 3.0 |\n\n<Info>\nWeight is calculated server-side from inventory items and synced to the client via `PLAYER_WEIGHT_CHANGED` events.\n</Info>\n\n### Agility-Based Stamina Regeneration\n\nAgility level increases stamina regeneration:\n\n`typescript\n// From PlayerLocal.ts\nconst AGILITY_REGEN_MODIFIER = 0.01;  // +1% regen per agility level\n\nconst agilityMultiplier = 1 + agilityLevel * AGILITY_REGEN_MODIFIER;\nconst regenRate = BASE_STAMINA_REGEN * agilityMultiplier;\n`\n\n**Agility Regen Bonus Table**:\n| Agility Level | Regen Multiplier | Idle Regen/Sec | Walk Regen/Sec |\n|---------------|------------------|----------------|----------------|\n| 1 | 1.01x | 4.04 | 2.02 |\n| 10 | 1.10x | 4.40 | 2.20 |\n| 25 | 1.25x | 5.00 | 2.50 |\n| 50 | 1.50x | 6.00 | 3.00 |\n| 75 | 1.75x | 7.00 | 3.50 |\n| 99 | 1.99x | 7.96 | 3.98 |\n\n**Base Stamina Rates**:\n- Running: -2.0 stamina/second (affected by weight)\n- Walking: +2.0 stamina/second (affected by agility)\n- Idle: +4.0 stamina/second (affected by agility)\n\n### Agility Unlocks\n\nFrom `skill-unlocks.json`:\n\n| Level | Unlock |\n|-------|--------|\n| 1 | Basic stamina regeneration (+1% per level) |\n| 10 | +10% stamina regeneration |\n| 25 | +25% stamina regeneration |\n| 50 | +50% stamina regeneration |\n| 75 | +75% stamina regeneration |\n| 99 | Agility cape, +99% stamina regeneration |\n\n### Progression Example\n\nAt running speed (200 XP/min):\n- **Level 2** (83 XP): \~25 seconds\n- **Level 10** (1,154 XP): \~6 minutes\n- **Level 50** (101,333 XP): \~8.5 hours\n- **Level 99** (13M XP): \~1,000+ hours\n\n---

## Anti-Exploit Protections

### Resource Spam Click Prevention

The gathering system prevents duplicate harvesting when players spam-click resources:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// From ResourceSystem.ts
const existingSession = this.activeGathering.get(playerId);
if (existingSession) {
  // If already gathering this EXACT resource, silently ignore (prevents duplicate rewards)
  if (existingSession.resourceId === resource.id) {
    return;
  }
  // If switching to a DIFFERENT resource, cancel the old session first
  this.cancelGatheringForPlayer(playerId, "switch_resource");
}
```

**Protection Features**:

* Duplicate gather requests for the same resource are silently ignored
* Prevents timer resets and duplicate drops
* Allows switching to different resources (cancels old session first)
* Guard clause executes after resource resolution for accurate comparison

<Info>
  This fix prevents the spam-click exploit where players could reset gathering timers by rapidly clicking the same resource.
</Info>

### Noted Items Tool Validation

Noted items (bank notes) cannot be used as skilling tools:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// From ToolUtils.ts
export function itemMatchesToolCategory(
  itemId: string,
  category: string,
): boolean {
  // Noted items are bank notes - cannot be used as tools
  if (isNotedItemId(itemId)) {
    return false;
  }
  // ... rest of validation
}
```

**Affected Tools**:

* Pickaxes (mining)
* Hatchets/axes (woodcutting)
* Fishing rods, nets, harpoons (fishing)

<Warning>
  Noted items must be un-noted at a bank before they can be equipped or used for skilling.
</Warning>

***

## Skill Guide Panel

The Skill Guide Panel is an OSRS-style interface that shows what you unlock at each level for any skill.

### Opening the Guide

Click any skill in the Skills Panel to open its guide. The panel displays:

* **All unlocks** with level requirements
* **Visual indicators** for unlocked (green checkmark) vs locked (lock icon) items
* **Next unlock** highlighted with gold accent and "NEXT" badge
* **Progress tracking**: "X of Y unlocks achieved"
* **Type badges**: Item vs ability unlocks with color coding

### Features

* **Scrollable list** for skills with many unlocks (Prayer has 29!)
* **Keyboard support**: ESC key or click outside to close
* **Loading states**: Spinner during data fetch
* **Server-authoritative**: Unlock data fetched from `/api/data/skill-unlocks`

<Info>
  The guide helps you plan your progression by showing exactly what you'll unlock at each level milestone.
</Info>

## Skill Events

The system emits events for UI updates and logging:

| Event                  | Data                                        | Description          |
| ---------------------- | ------------------------------------------- | -------------------- |
| `SKILLS_XP_GAINED`     | `playerId`, `skill`, `amount`               | XP added to skill    |
| `SKILLS_LEVEL_UP`      | `entityId`, `skill`, `oldLevel`, `newLevel` | Level increased      |
| `SKILLS_UPDATED`       | `playerId`, `skills`                        | Skills state changed |
| `SKILLS_MILESTONE`     | `entityId`, `skill`, `milestone`            | Milestone reached    |
| `COMBAT_LEVEL_CHANGED` | `entityId`, `oldLevel`, `newLevel`          | Combat level changed |
| `TOTAL_LEVEL_CHANGED`  | `entityId`, `oldLevel`, `newLevel`          | Total level changed  |

***

## Milestones

Special milestones trigger events and messages:

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
const commonMilestones = [
  { level: 50, name: "Halfway", message: "Halfway to mastery!" },
  { level: 92, name: "Half XP", message: "Halfway to 99 in XP!" },
  { level: 99, name: "Mastery", message: "Skill mastered!" },
];

// Attack-specific milestones
const attackMilestones = [
  { level: 40, name: "Rune Weapons", message: "You can now wield rune weapons!" },
  { level: 60, name: "Dragon Weapons", message: "You can now wield dragon weapons!" },
];
```

***

## API Reference

### Grant XP

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// Grant XP via event system (recommended)
skillsSystem.grantXP(entityId, "woodcutting", 25);

// Direct internal grant (used by external handlers)
skillsSystem.addXPInternal(entityId, skill, amount);
```

### Check Requirements

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// Check if entity meets skill requirements
const canEquip = skillsSystem.meetsRequirements(entity, {
  attack: 40,
  defense: 40,
});
```

### Set Level (Admin)

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// Directly set skill level (for admin commands)
skillsSystem.setSkillLevel(entityId, "attack", 99);
```

### Reset Skill

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// Reset skill to level 1
skillsSystem.resetSkill(entityId, "attack");
```

***

## Skill Unlocks & Guide Panel

The `skill-unlocks.json` manifest documents what players unlock at each level. This data powers the in-game Skill Guide Panel.

### Skill Guide Panel (OSRS-Style)

Players can click any skill in the Skills Panel to open an OSRS-style guide showing all unlocks:

**Features:**

* Click any skill icon to open guide
* Shows all unlocks with level requirements
* Visual distinction between unlocked (green ✓) and locked (🔒) items
* Next unlock highlighted with progress indicator
* Scrollable list for skills with many unlocks
* Type badges (item/ability) with color coding
* ESC key or click outside to close

**Implementation:**

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
// packages/client/src/game/panels/SkillGuidePanel.tsx
interface SkillGuidePanelProps {
  visible: boolean;
  skillLabel: string;
  skillIcon: string;
  playerLevel: number;
  unlocks: readonly SkillUnlock[];
  isLoading: boolean;
  onClose: () => void;
}
```

**Data source:**

* Fetched from server API: `GET /api/data/skill-unlocks`
* Returns all skill unlocks from `skill-unlocks.json` manifest
* Cached in client state after initial fetch

**Example unlocks:**

* **Attack 1**: Bronze weapons, Iron weapons
* **Attack 5**: Steel weapons
* **Attack 40**: Rune weapons
* **Attack 60**: Dragon weapons
* **Woodcutting 15**: Oak trees
* **Mining 30**: Coal
* **Cooking 40**: Lobster
* **Smithing 50**: Mithril bar
* **Prayer 1-77**: 29 different prayers

<Info>
  The guide panel handles British/American spelling differences automatically (defence → defense) for consistent display.
</Info>

### Skill Guide Panel

**New in v1.0:** Players can click any skill in the Skills Panel to open an OSRS-style guide showing all unlocks.

**Features:**

* Click any skill icon to open its guide
* Shows all unlocks with level requirements
* Visual distinction between unlocked (green ✓) and locked (🔒) items
* Highlights next unlock with progress indicator
* Scrollable list for skills with many unlocks
* Type badges (item vs ability)
* Matches OSRS UI theme

**Implementation:**

* Component: `packages/client/src/game/panels/SkillGuidePanel.tsx`
* Data source: `/api/data/skill-unlocks` endpoint
* Fetched once at Skills Panel mount
* Cached in component state

**API Endpoint:**

```typescript theme={"theme":{"light":"github-light","dark":"css-variables"}}
GET /api/data/skill-unlocks

Response:
{
  "attack": [
    { "level": 1, "description": "Bronze weapons", "type": "item" },
    { "level": 40, "description": "Rune weapons", "type": "item" },
    { "level": 60, "description": "Dragon weapons", "type": "item" }
  ],
  "woodcutting": [
    { "level": 1, "description": "Normal trees", "type": "item" },
    { "level": 15, "description": "Oak trees", "type": "item" }
  ]
}
```

**User Experience:**

1. Open Skills Panel (default keybind)
2. Click any skill icon (e.g., Attack ⚔️)
3. Skill Guide Panel opens showing all unlocks
4. Green checkmarks indicate achieved unlocks
5. Lock icons indicate future unlocks
6. Next unlock is highlighted with "➤ X more levels to unlock..."
7. Close with X button, ESC key, or click outside

**Unlock Types:**

* `item` - Equipment, resources, or craftable items (blue badge)
* `ability` - Passive bonuses, prayers, or unlocked actions (purple badge)
* `area` - Accessible locations or zones
* `quest` - Quest requirements
* `activity` - Minigames or special activities

## Manifest-Driven Design

All skill-related data is now defined in JSON manifests:

* **`tier-requirements.json`** - Equipment level requirements by tier
* **`skill-unlocks.json`** - What unlocks at each level
* **`gathering/*.json`** - Resource nodes, yields, and XP
* **`recipes/*.json`** - Processing recipes and XP

This allows easy content updates without code changes and enables community modding.

***

## Agility Skill System

The Agility skill is unique - it trains passively through movement and affects stamina mechanics.

### Training Agility

**XP Gain**: 1 XP per 2 tiles traveled (batched at 100 tiles = 50 XP)

| Movement Type | Tiles/Tick | XP/Minute | Time to 99    |
| ------------- | ---------- | --------- | ------------- |
| Walking       | 2          | \~100 XP  | \~2,000 hours |
| Running       | 4          | \~200 XP  | \~1,000 hours |

**XP Batching**: To prevent visual spam, XP is granted in batches of 50 XP every 100 tiles. This creates XP drops every \~15 seconds while running or \~30 seconds while walking.

**Death Penalty**: On death, accumulated tiles toward the next XP grant are lost (max 50 XP lost). Earned XP is never lost.

**Teleportation**: Does not grant Agility XP (no tiles traversed).

### Weight-Based Stamina Drain

Carrying heavy items increases stamina drain while running:

**Formula**: `Drain Rate = Base Drain × (1 + Weight × 0.005)`

| Weight (kg) | Drain Multiplier | Drain/Second |
| ----------- | ---------------- | ------------ |
| 0           | 1.0x             | 2.0          |
| 10          | 1.05x            | 2.1          |
| 20          | 1.1x             | 2.2          |
| 40          | 1.2x             | 2.4          |
| 60          | 1.3x             | 2.6          |
| 100         | 1.5x             | 3.0          |

**Weight Calculation**: Total weight is calculated server-side from inventory items and equipment, then synced to the client for stamina calculations.

### Agility-Based Stamina Regeneration

Higher Agility levels increase stamina regeneration:

**Formula**: `Regen Rate = Base Regen × (1 + Agility Level × 0.01)`

| Agility Level | Regen Multiplier | Idle Regen/Sec | Walk Regen/Sec |
| ------------- | ---------------- | -------------- | -------------- |
| 1             | 1.01x            | 4.04           | 2.02           |
| 10            | 1.10x            | 4.40           | 2.20           |
| 25            | 1.25x            | 5.00           | 2.50           |
| 50            | 1.50x            | 6.00           | 3.00           |
| 75            | 1.75x            | 7.00           | 3.50           |
| 99            | 1.99x            | 7.96           | 3.98           |

**Base Rates**:

* Running: 2 stamina/second drain (no regen)
* Walking: 2 stamina/second regen
* Idle: 4 stamina/second regen

### Agility Unlocks

| Level | Unlock                                     |
| ----- | ------------------------------------------ |
| 1     | Basic stamina regeneration (+1% per level) |
| 10    | +10% stamina regeneration                  |
| 25    | +25% stamina regeneration                  |
| 50    | +50% stamina regeneration                  |
| 75    | +75% stamina regeneration                  |
| 99    | Agility cape, +99% stamina regeneration    |

***

## Skill Guide Panel

Players can click any skill in the Skills Panel to view a detailed guide showing all unlocks for that skill.

**Features**:

* Shows all unlocks with level requirements
* Visual distinction between unlocked (green checkmark) and locked (lock icon) items
* Highlights the next unlock the player is working toward
* Scrollable list for skills with many unlocks (Prayer has 29!)
* Type indicators (item vs ability)

**Implementation**: The panel fetches unlock data from `/api/data/skill-unlocks` endpoint, which serves the `skill-unlocks.json` manifest.

***

## Related Documentation

* [Combat System](/wiki/game-systems/combat)
* [Movement System](/wiki/game-systems/movement)
* [Data Manifests Overview](/wiki/data/overview)
* [Item Data Structure](/wiki/data/items)
* [NPC Data Structure](/wiki/data/npcs)
