Skip to main content

Crafting System

The Crafting skill allows players to create leather armor, dragonhide equipment, jewelry, and cut gems. The system implements OSRS-accurate mechanics with tick-based crafting, thread consumption, and movement/combat cancellation.
Crafting code lives in packages/shared/src/systems/shared/interaction/CraftingSystem.ts and TanningSystem.ts. Recipe data is in manifests/recipes/crafting.json and tanning.json.

Crafting Categories

Leather Crafting

Use needle on leather to open the crafting interface. Requires thread in inventory (5 uses per thread). Studded Leather:
Thread has 5 uses before being consumed. The system tracks uses in-memory during crafting sessions. When thread is depleted, a new thread is consumed from inventory.

Dragonhide Crafting

Use needle on dragon leather for high-level ranged armor. Requires thread in inventory.
Dragonhide armor requires both Crafting level AND Defence level to equip. For example, green d’hide body requires 63 Crafting to make and 40 Defence to wear.

Jewelry Crafting

Use furnace to craft jewelry from gold/silver bars. Requires specific mould in inventory (not consumed). Gold Jewelry: Sapphire Jewelry: Emerald Jewelry: Ruby Jewelry: Diamond Jewelry:
Jewelry crafting requires you to be near a furnace entity. The crafting interface filters recipes by the mould you have equipped (e.g., ring mould shows only rings).

Gem Cutting

Use chisel on uncut gems to create cut gems for jewelry.
When using chisel on a specific gem (e.g., uncut sapphire), the crafting interface auto-selects that gem and skips to quantity selection. This matches OSRS behavior.

Tanning System

Convert hides to leather at tanner NPCs for a coin fee. Tanning is instant (no XP granted). Tanning Mechanics:
  • Talk to tanner NPC to open tanning interface
  • Select hide type and quantity
  • Coins deducted from inventory
  • Hides instantly converted to leather
  • No XP granted (it’s a service, not a skill action)
Tanning is a prerequisite for dragonhide crafting. You must tan the hides before you can craft them into armor.

Crafting Mechanics

Thread Consumption

Thread is a consumable item with 5 uses:
Thread Lifecycle:
  1. Player starts crafting with thread in inventory
  2. Each craft consumes 1 use from the thread
  3. After 5 uses, thread is consumed and removed from inventory
  4. If no thread available, crafting stops with message
In-Memory Tracking:
  • Thread uses are tracked per crafting session
  • Server crash mid-batch resets the counter (acceptable trade-off)
  • Max exploitation: 4 free crafts per crash (thread has 5 uses)

Tick-Based Crafting

Crafting operates on the game’s 600ms tick system:
Timing Examples:
  • Leather gloves: 3 ticks = 1.8 seconds
  • Sapphire ring: 2 ticks = 1.2 seconds
  • Green d’hide body: 3 ticks = 1.8 seconds

Movement/Combat Cancellation

Crafting automatically cancels when the player:
  • Starts moving (clicks to walk)
  • Enters combat (attacks or is attacked)
This matches OSRS behavior where any action (movement, combat, banking) interrupts skilling activities.

Recipe Filtering

The crafting interface intelligently filters recipes based on context: Input Item Filtering:
  • Using needle on leather shows only leather recipes
  • Using needle on green dragon leather shows only green d’hide recipes
  • Using chisel on uncut sapphire shows only sapphire cutting
Station Filtering:
  • Furnace jewelry requires being near a furnace entity
  • Recipes filter by station: "furnace" vs station: "none"
Mould Filtering:
  • Jewelry recipes filter by equipped mould
  • Ring mould shows only rings
  • Necklace mould shows only necklaces
  • Amulet mould shows only amulets
  • Bracelet mould shows only bracelets
Auto-Select:
  • If only 1 recipe matches, it auto-selects and skips to quantity selection
  • Example: Chisel + uncut sapphire → immediately shows “How many?” prompt

Make-X Functionality

Players can craft multiple items in one session: Quantity Options:
  • 1, 5, 10: Quick-select buttons
  • All: Crafts maximum possible based on materials (sends -1 sentinel, server computes actual max)
  • X: Custom quantity with localStorage memory
Quantity Memory:
Server-Side Max Calculation:
  • Client sends -1 for “All” button
  • Server computes actual max based on available materials
  • Crafting stops when materials run out or target quantity reached

Crafting Flow

Client-Side Flow

  1. Trigger Interaction: Player uses needle/chisel on item, or clicks furnace
  2. Send Interact Packet: craftingSourceInteract with triggerType and inputItemId
  3. Receive Recipe List: Server sends CRAFTING_INTERFACE_OPEN with filtered recipes
  4. Select Recipe: Player chooses item and quantity
  5. Send Craft Request: processingCrafting with recipeId and quantity
  6. Receive Updates: CRAFTING_COMPLETE events as items are crafted

Server-Side Flow

Crafting Session Lifecycle


Performance Optimizations

The crafting system includes several optimizations to reduce server load:

Consolidated Inventory Scans

Problem: Original implementation scanned inventory 4 times per craft tick (once for tools, inputs, consumables, and interact handler). Solution: Single getInventoryState() call per tick:
Impact: Reduced from 4 inventory scans to 1 per tick per active crafter.

Reusable Arrays

Problem: Array.from(this.activeSessions) allocated a new array every tick. Solution: Collect completed IDs first, then process:

Once-Per-Tick Processing

Problem: Update loop could be called multiple times per tick. Solution: Guard clause with lastProcessedTick:

Security Features

Rate Limiting

Crafting interact requests are rate-limited to prevent inventory scan spam:
Limits:
  • 5 requests per second per player
  • Prevents malicious clients from spamming inventory fetches

Audit Logging

All craft completions are logged for security monitoring:
Logged Data:
  • Player ID
  • Recipe ID and output item
  • Materials consumed
  • XP awarded
  • Batch progress (e.g., “3 of 10”)

Item ID Generation

Crafted items use monotonic counters to prevent ID collisions:
Protection: Prevents Date.now() collisions when multiple crafts complete in the same millisecond.

Input Validation

All crafting requests validate:
  • triggerType must be “needle”, “chisel”, or “furnace”
  • inputItemId length capped at 64 characters
  • quantity bounded to 1-10,000 range
  • Recipe ID validated against manifest

Crafting Events

The crafting system emits events for UI and logging:

UI Components

CraftingPanel

The crafting panel displays available recipes grouped by category: Categories:
  • Leather
  • Studded
  • Dragonhide
  • Jewelry
  • Gem Cutting
Features:
  • Recipe cards with icons, level requirements, XP, materials
  • Color-coded level requirements (green = can craft, red = too low)
  • Quantity selector (1, 5, 10, All, X)
  • Auto-select for single recipes
  • Make-X memory in localStorage

TanningPanel

The tanning panel shows available hides with costs: Features:
  • Hide list with icons and inventory counts
  • Cost per hide in gold pieces
  • Quantity selector (1, 5, 10, All, X)
  • Make-X memory in localStorage

API Reference

ProcessingDataProvider

The data provider loads and indexes crafting recipes:

CraftingSystem

The crafting system manages active crafting sessions:

Testing

The crafting system has comprehensive test coverage: Unit Tests (CraftingSystem.test.ts - 658 lines):
  • Recipe filtering by station and inputItemId
  • Crafting lifecycle (start, complete, schedule next)
  • Level/material/tool/consumable validation
  • Movement and combat cancellation
  • Concurrent crafting prevention
  • Tick-based update loop
  • Unique item ID generation
  • Thread consumption tracking
Data Tests (ProcessingDataProvider.test.ts):
  • Manifest loading and parsing
  • Recipe lookup functions
  • Category grouping
  • Input item validation
  • Tanning recipe validation
Missing E2E Tests: The crafting system currently lacks Playwright integration tests. These should be added to verify the full flow: use needle on leather → panel opens → select recipe → craft completes → XP awarded.

Manifest Structure

crafting.json

Fields:
  • output: Item ID of crafted item
  • category: UI grouping (leather, studded, dragonhide, jewelry, gem_cutting)
  • inputs: Materials consumed (item ID + amount)
  • tools: Required tools in inventory (not consumed)
  • consumables: Items with limited uses (e.g., thread with 5 uses)
  • level: Crafting level required
  • xp: XP granted per item (float values for OSRS accuracy, rounded at DB boundary)
  • ticks: Time in game ticks (600ms per tick)
  • station: Required station (“none” or “furnace”)

tanning.json

Fields:
  • input: Hide item ID
  • output: Leather item ID
  • cost: Coin cost per hide
  • name: Display name