Skip to main content

Latest Releases

This changelog syncs automatically with GitHub Releases. Subscribe via RSS for updates.
Terrain System Refactor & Duel Arena Polish
February 2026

🏔️ Terrain Height Parameter Refactoring (commit e54476f)

Extracted all terrain generation constants to single source of truth for consistency between main thread and web workers:
  • TerrainHeightParams.ts: New centralized parameter file
    • All noise layer definitions (continent, ridge, hill, erosion, detail)
    • Island configuration (radius, falloff, base elevation)
    • Pond configuration (radius, depth, center position)
    • Coastline noise parameters for irregular shorelines
    • Mountain boost configuration
  • Worker Code Generation: buildGetBaseHeightAtJS() function
    • Injects TypeScript constants into inline worker string
    • Ensures worker heights match main thread exactly
    • Prevents parameter drift between threads
  • Synchronized Parameters: TerrainSystem imports constants directly
    • Worker receives same values via code injection
    • Eliminates manual synchronization errors
    • Single source of truth for all terrain generation

⚡ Terrain Worker Performance Optimization (commit ef54a70)

Moved height and normal computation to web workers for 63x reduction in main-thread noise evaluations:
  • Worker Height Computation: Full height calculation in worker threads
    • Synced noise weights to match TerrainSystem (hillScale 0.012→0.02, persistence 0.5→0.6)
    • Added shoreline adjustment to worker (calculateBaseSlopeAt, adjustHeightForShoreline)
    • Worker heights now fully correct for tiles without flat zones
  • Worker Normal Computation: Normals computed in worker via overflow grid
    • (resolution+2)² overflow grid with centered finite differences
    • Eliminates ~16,384 noise calls per tile on main thread
    • 63x reduction in noise evaluations for normal calculation
  • Conditional Fallback: Main-thread recomputation only for tiles with flat zones
    • Tiles without flat zones use worker data directly (zero noise calls)
    • Tiles overlapping buildings/stations recompute on main thread
    • Ensures flat zone heights are respected in final geometry
  • Performance Impact: Terrain generation now runs in parallel across CPU cores
    • Main thread free for rendering and input handling
    • Smooth frame rates during terrain streaming

🎮 Duel Arena Gameplay Fixes (commit 5e5c7c9)

Resolved 6 critical bugs affecting agent duel gameplay:
  • 2H Sword Attack Timing: DuelCombatAI now attacks every weapon-speed cycle
    • Previously waited for re-engagement interval between attacks
    • Seeds first tick to attack immediately (startCombat() has no auto-attack)
    • Fixes slow 2H weapon attacks in duels
  • Teleport During Fight: Health restore now has quiet parameter
    • Skips PLAYER_RESPAWNED/PLAYER_SET_DEAD events during fight-start HP sync
    • Added suppressEffect flag to teleportPlayer/teleportToArena
    • Prevents visual teleport effects during proximity corrections
  • Stale Avatars: endCycle() chains cleanup→delay→new cycle via .finally()
    • INTER_CYCLE_DELAY_MS ensures proper cleanup before next cycle
    • Cleanup always teleports both agents to lobby
    • Prevents avatars stuck in arena between cycles
  • FIGHT Text Display: CountdownOverlay stays mounted 2.5s into FIGHTING phase
    • Fade-out animation (opacity + scale)
    • Ensures “FIGHT” text visible at combat start
  • Arena Fences: Replaced solid walls with fence posts + rails
    • Better visibility into arena
    • Maintains collision boundaries
  • Health Bars: Inline HP sync in handleEntityDamaged
    • updateContestantHp called before every broadcast
    • Eliminates health bar desync during combat

🎨 Duel Arena Visual Enhancements

Lit Torches with Fire Particles (commit cef09c5)

  • Torch Placement: Torches at all 4 corners of each arena
    • PointLights with flicker animation
    • “torch” glow preset (6 riseSpread particles per torch)
    • Tight 0.08 spread for concentrated flame effect
  • Preset-Aware Respawn: Particle spread varies by preset type
    • Torch particles use tight spread
    • Other presets use default spread values

Procedural Stone Tile Texture (commit f8c585e)

  • Arena Floor Texture: Canvas-generated sandstone tile pattern
    • Replaces flat-colored arena floors
    • OSRS medieval aesthetic
    • Each arena gets unique randomized texture
    • Grout lines, color variation, and speckle noise
    • Procedurally generated per arena for variety

🔧 Build System Improvements

Circular Dependency Resilience (commit 5666ece)

  • Build Resilience: procgen and plugin-hyperscape builds now handle circular deps
    • Both packages have circular dependencies with @hyperscape/shared
    • Used ‘tsc || echo’ pattern so build exits 0 even with circular dep errors
    • Packages still produce partial output sufficient for downstream consumers
    • Prevents clean build failures when dist/ doesn’t exist yet

CI Test Reliability

  • Benchmark Thresholds (commit 98ebfa7): Relaxed NPCTickProcessor thresholds for CI variance
  • Geometry Validation (commit 04248b7): Increased timeout to 120s for CI
  • Intensive Generation Tests (commit 832286c): Increased timeouts for procgen tests
  • Vitest Timeout (commit 7e4d2cc): Global timeout increase to fix CI flakiness
  • RoadNetworkSystem Performance (commit 474d29d): Fixed flaky performance test
  • Manifest Validation (commit aa1ea2d, 1f4551c, 6f1d3a7): Fixed invalid manifest JSONs causing DataManager errors
    • Corrected .gitignore manifest negation
    • Fixed JSON syntax errors in manifest files
    • Ensures CI tests have valid data

🚀 Deployment & Infrastructure

Vast.ai GPU Server Deployment

  • Python 3.11+ Support (commit 621ae67): Upgraded to bookworm-slim for vastai-sdk compatibility
  • PEP 668 Compliance (commit d9e9111): Added —break-system-packages for pip3 on Debian 12
  • CLI Package (commit 781f3d7): Installed vastai CLI package and reverted to binary invocation
  • SSH Key Generation (commit 3ce7d64): Ensured vastai CLI on PATH and generated SSH keys in Docker
  • US-Based Filtering (commit 48bd8e7): Filter for US-based machines for lower latency
  • CUDA Docker Image (commit c6540358): Switched from KVM to standard CUDA image
  • Runtime Environment (commit dc9b475): Inject all runtime env vars into provisioned game server

CI/CD Enhancements

  • Foundry Installation (commit 8083993): Install Foundry for MUD contracts tests
  • Playwright Dependencies (commit 59204671): Added playwright deps and ffmpeg for streaming
  • DNS Configuration (commit fd172485): Overwrite resolv.conf with Google DNS instead of appending
  • Build Chain (commit cbcbb2f, f0d2fae): Added all internal packages to build chain including decimation
  • Asset Checks (commit 87b3c1a): Added git-lfs for asset checks
  • Native Modules (commit bd2aad9): Added build-essential for native module compilation on minimal Docker images
  • Declaration Generation (commit eb722bb): Always use —skipLibCheck for circular dependency handling
  • CI Environment (commit 28bf9fb): Set CI=true to skip asset download in production
  • CORS Configuration (commit 7256b07, fb3b9cd): Allow all origins and add CORS max-age for betting app
Melee Weapon Overhaul & Combat Pathfinding
February 2026

⚔️ Melee Weapon System Overhaul (PR #894)

Major weapon categorization update with shortsword rename, 2H weapon support, and batch export workflow:
  • Shortsword Rename: Generic sword items renamed to shortsword across entire codebase
    • Item IDs: bronze_swordbronze_shortsword, iron_swordiron_shortsword, etc.
    • Display names updated: “Bronze Sword” → “Bronze Shortsword”
    • All tests updated (72 files changed with 1888 additions, 522 deletions)
    • Affects: inventory, bank, duel, quest, smithing, and combat systems
  • 2H Sword Combat Emotes: New two-handed weapon animations
    • 2h_idle stance emote for idle state
    • 2h_slash attack emote for combat
    • Full client pipeline integration with emote system
    • Weapon-aware idle emote reset (2H weapons return to 2h_idle instead of idle)
  • Weapon Type Expansion: New weapon categories in WeaponType enum
    • SHORTSWORD: One-handed short blades (bronze, iron, steel, mithril, adamant, rune)
    • LONGSWORD: One-handed long blades (future content)
    • SCIMITAR: Curved one-handed blades (future content)
    • 2H_SWORD: Two-handed great swords (future content)
  • Combat Animation Mapping: All melee weapon types now map to sword_swing animation
    • Unified animation system in CombatAnimationManager
    • Consistent attack visuals across weapon types
    • Replaces weapon-specific animation routing
  • Weapon Style Configuration: Updated size and proportion constants
    • MIN_WEAPON_SIZES: Shortsword 0.35m, Longsword 0.5m, Scimitar 0.45m, 2H Sword 0.8m
    • MAX_WEAPON_SIZES: Shortsword 2.0m, Longsword 3.0m, Scimitar 2.5m, 2H Sword 4.5m
    • BASE_WEAPON_PROPORTIONS: Shortsword 45% of height, Longsword 65%, Scimitar 55%, 2H Sword 90%
Asset Forge Batch Workflow (Equipment Viewer):
  • Batch Apply Fitting: Apply fitting configuration to all weapons of same subtype
    • New /api/assets/batch-apply-fitting endpoint
    • Applies hyperscapeAttachment metadata to multiple assets in one operation
    • Updates position, rotation, scale, grip point, and avatar height for all selected weapons
    • Progress overlay with current asset name and completion percentage
  • Batch Review & Export: Step through weapons and export aligned GLBs
    • New batch review mode with navigation bar (prev/next/skip)
    • Visual mesh swapping without reloading transforms (preserves fitting)
    • Export current weapon or export all remaining weapons
    • Progress tracking with green checkmarks for exported weapons
    • Auto-advance to next un-exported weapon after export
  • Weapon Subtype Grouping: Equipment list now groups weapons by subtype
    • Collapsible sections: Shortswords, Longswords, Scimitars, 2H Swords, etc.
    • Chevron icons for expand/collapse
    • Counts displayed per group
  • Geometry Normalization: Advanced transform flattening for batch consistency
    • flattenSceneTransforms(): Bakes all intermediate node transforms into mesh geometry
    • Eliminates GLTF hierarchy differences between weapons
    • Axis alignment: Rotates geometry so longest axis matches reference weapon
    • Flip detection: Uses vertex centroid bias to detect 180° flips
    • Position alignment: Shifts bbox center to match reference weapon
    • Ensures consistent grip offset across all weapons in batch
  • Swap Equipment Content: New swapEquipmentContent() method on EquipmentViewerRef
    • Replaces visual mesh without touching transforms
    • Preserves normalization state (grip offset, bbox center, longest axis)
    • Enables batch review without full reload
    • Maintains scale, rotation, and position from original weapon
  • Save Aligned GLB: New /api/assets/:id/save-aligned endpoint
    • Saves aligned (fitted) GLB model to server
    • Updates metadata.json with alignedModelPath and alignedAt timestamp
    • Returns relative path for download
  • UI Components:
    • BatchProgressOverlay: Simple spinner for batch apply fitting
    • BatchReviewBar: Navigation bar with prev/next/export controls
    • Progress dots showing current weapon and export status
    • Export All button with remaining count
    • Done button to exit review mode

🎯 OSRS-Accurate Combat Pathfinding (PR #886)

BFS primary pathfinding with multi-destination search and line-of-sight validation:
  • BFS as Primary Pathfinder: Player movement now uses BFS instead of naive diagonal-first
    • Eliminates visible diagonal zigzag when walking to attack targets
    • Matches OSRS “smartpathing” behavior
    • Optimal paths around obstacles
    • findPath() now calls findBFSPath() directly (no naive fallback)
  • Multi-Destination BFS: New findPathToAny() method for combat
    • Generates ALL valid attack tiles (melee cardinal, ranged/magic with LoS)
    • Terminates at first valid tile reached
    • Naturally finds shortest path to closest reachable position
    • No need to pre-pick “best” tile with heuristics
  • Line of Sight: Ranged and magic attacks now require LoS
    • Bresenham line trace against BLOCKS_RANGED collision flags
    • Prevents attacking through walls when in Chebyshev range
    • hasLineOfSight() function in TileSystem.ts
    • Used by both pathfinding and attack validation
  • Valid Tile Generation: New helper functions
    • getValidRangedTiles(): All tiles in range with LoS to target
    • getValidMeleeTiles(): Cardinal tiles for range 1, Chebyshev for range 2+
    • Pre-filters tiles before pathfinding for efficiency
  • NPC Chase Pathfinding: NPCs still use naive diagonal pathing
    • findNaivePath() exposed publicly for ChasePathfinding.ts
    • Enables safespotting mechanics (OSRS-accurate)
    • Players use BFS, mobs use naive (intentional difference)
  • Pending Attack Manager: Updated range checks with LoS validation
    • Ranged/magic attacks verify LoS before executing
    • Melee attacks use cardinal-only for range 1
    • Prevents attacks through walls
  • Collision Masks: New BLOCKS_RANGED mask
    • Combines BLOCK_LOS and BLOCKED flags
    • Used for LoS checks in combat and pathfinding
  • Testing: All 608 combat tests pass (1 pre-existing unrelated failure)
Breaking Changes:
  • Ranged and magic attacks now require line of sight (cannot attack through walls)
  • Player movement paths may differ from previous naive diagonal-first behavior

🗺️ Quest Minimap Icons (PR #885)

Quest-state-aware icons on minimap for quest giver NPCs:
  • Quest Icon System: Blue icons for quest NPCs
    • Blue ”!” for available quests (not started)
    • Blue ”?” for in-progress quests
    • Icons disappear when all quests completed
  • NPC Quest Configuration: New questIds field in NPCEntityConfig
    • Array of quest IDs the NPC offers
    • Passed through spawn → network → client pipeline
    • Minimap fetches quest statuses from server
  • Quest Status Sync: Client requests quest statuses for minimap
    • New getQuestStatuses network message
    • Server responds with status map (not_started, in_progress, completed)
    • Minimap updates icons based on quest state
  • Service Detection Fix: Fixed broken NPC service detection in Minimap
    • services is string[], not { types: string[] }
    • Also fixes bank/shop icon detection
    • Proper type casting for service array
  • Icon Rendering: Quest icons drawn with filled circle and symbol
    • ”!” symbol for available quests
    • ”?” symbol for in-progress quests
    • Cyan color (#00ffff) for visibility

🔧 Instant Item & Coin Pickup (PR #888)

Visually instant pickup by deferring database persistence:
  • Item Pickup: Ground entity removed before database write
    • addItem() now accepts silent flag to skip DB persist and emit
    • pickupItem() adds to memory, removes ground entity, emits update, THEN awaits DB persist
    • Player sees instant feedback while persistence is still guaranteed
    • No item loss or duplication risk (pickup lock held throughout)
  • Coin Pickup: Same responsive pattern for coins
    • addCoins() now accepts skipPersist flag
    • Coin ground entity removed before database write
    • persistCoinsImmediate() made public for manual persistence
    • Coin persist happens after removal, still guaranteed before lock release
  • Performance Impact: Eliminates 500ms+ database round-trip blocking visual feedback
  • Security: DB persist still awaited (not fire-and-forget), pickup lock prevents races
  • Testing: All 58 inventory tests pass (pickup, moveItem, transactionLock, coinPersistence, coinPouch)

🎒 Stackable Equipment Merge (PR #887)

Direct quantity merge when equipping same stackable item already equipped:
  • Optimization: Arrows (or other stackables) that match equipped slot merge directly
    • Eliminates unequip → inventory → re-equip cycle
    • Prevents brief inventory flash showing combined count before equip
    • Adds quantity directly to equipped stack
  • Same-Type Detection: isSameStackableMerge flag checks:
    • Item is stackable
    • Slot already has an item
    • Item IDs match (String comparison for safety)
  • Conditional Unequip: Only unequip if NOT a same-type stackable merge
    • Different item or empty slot → unequip current item first
    • Same stackable → merge quantity directly
  • Code Path: Simplified equipment flow with early merge detection
    • Reduces network packets and database writes
    • Improves responsiveness for arrow equipping

🐛 Multiplayer Sync Fixes (PR #884)

Mob position desync and stuck combat rotation fixes:
  • Combat Rotation Clearing: Clear inCombatRotation flag on movement start in TileInterpolator
    • Was never cleared, causing mobs to keep combat-facing after combat ended
    • Mobs now return to normal AI-driven rotation when moving
  • Mob Rotation Routing: Only route entityModified to setCombatRotation for players, not mobs
    • Mobs handle combat rotation locally in MobEntity.clientUpdate()
    • Prevents server rotation packets from conflicting with client-side mob AI
  • Damage Splat Positioning: Prefer entity visual position over server position
    • Damage splats appear where mob visually is (interpolated position)
    • Fixes splats appearing at server position during client interpolation
  • Movement Packet Optimization: Replace redundant entityModified with emote on tileMovementEnd
    • Reduces packet duplication
    • Cleaner network protocol
  • Movement Cancellation Fix: cancelMovement sends tileMovementEnd instead of entityModified
    • Client TileInterpolator properly stops interpolating old path
    • Fixes visual desync when movement is cancelled
Mob Combat & Multiplayer Fixes
February 2026

⚔️ Mob Magic & Ranged Attacks (PR #826)

Mobs can now use magic and ranged attacks with full projectile support and visual weapon attachments:
  • Attack Type Configuration: NPC manifest fields for combat type
    • attackType: \"melee\" (default), \"ranged\", or \"magic\"
    • spellId: Required for magic mobs (e.g., \"wind_strike\", \"fire_bolt\")
    • arrowId: Required for ranged mobs (e.g., \"bronze_arrow\", \"iron_arrow\")
    • heldWeaponModel: Optional weapon GLB (bow, staff) attached to hand bone
    • combatRange: Attack range in tiles (1 for melee, 7-10 for ranged/magic)
  • Combat Handler Routing: Mobs route through same handlers as players
    • MagicAttackHandler - Mob magic path with infinite runes, no equipment bonuses
    • RangedAttackHandler - Mob ranged path with infinite arrows, no equipment bonuses
    • Separate damage calculation using mob’s magic or ranged stat from manifest
    • Players can still use prayer bonuses to defend against mob attacks
  • Projectile System: Spell and arrow projectiles for mobs
    • OSRS-accurate hit delays based on distance
    • Element-based spell visuals (air, water, earth, fire)
    • Arrow projectiles with metal-colored tips
    • Launch delays: 600ms for spells, 400ms for arrows
    • Shared emitMagicProjectile() and emitRangedProjectile() methods
  • Visual Weapon Attachment: Held weapons on mob VRM avatars
    • Static weapon cache shares GLB scenes across mob instances
    • clone(true) for per-mob instances with shared geometry/materials
    • Proper cleanup on world teardown via clearWeaponCache()
    • Supports Asset Forge V1 and V2 attachment metadata
    • Deduplicates concurrent fetches via _pendingLoads map
    • Prevents weapon attachment to destroyed mobs via _destroyed flag
  • Animation System: Attack-type-specific emotes
    • Magic mobs: SPELL_CAST animation
    • Ranged mobs: RANGE animation
    • Melee mobs with weapons: SWORD_SWING animation
    • Emote matching switched from substring to exact equality (more robust)
  • Auto-Attack Integration: Tick-based follow-up attacks
    • weaponType stored in combat state for auto-attack routing
    • CombatTickProcessor routes by stored weapon type
    • Retaliation uses correct attack type (magic/ranged mobs retaliate with projectiles)
    • Mob retaliators resolve weapon type from config for proper handler routing
  • Shared Utilities: prepareMobAttack() in AttackContext.ts
    • Consolidates entity resolution, range checks, cooldown, animation
    • Eliminates ~150 lines of duplication between magic and ranged handlers
    • Returns validated MobAttackContext or null
    • Accepts preResolved parameter to avoid redundant entity lookups
  • Constants: New combat constants in CombatConstants.ts
    • MAGIC_RANGE: 10 - Magic attack range in tiles
    • SPELL_LAUNCH_DELAY_MS: 600 - Spell cast animation wind-up
    • ARROW_LAUNCH_DELAY_MS: 400 - Arrow draw animation wind-up
  • Testing: 996 lines of integration tests
    • Magic/ranged attack routing and projectile emission
    • Missing spellId/arrowId graceful handling with console warnings
    • Out-of-range rejection
    • Event-carried vs NPC-data spell/arrow resolution
    • Auto-attack tick paths for both magic and ranged
    • Default-to-melee fallback when attackType missing

🔄 Multiplayer Sync Fixes (PR #875, #882, #884)

Critical fixes for multiplayer synchronization affecting remote player rendering and combat:
  • Position Sync Fix (PR #875, #882): Remote players now face correct direction
    • Sync base.quaternion in PlayerRemote to fix sideways-facing players
    • Force transform update after async avatar load to prevent T-pose ghosts
    • Position and animate remote avatar before making visible (prevents 1-frame flash at origin)
    • Update spatial index after teleport/respawn so sendToNearby reaches players at new location
    • Broadcast authoritative position to all players on join
    • Fixes invisible combat movement in duels (players couldn’t see opponent moving)
  • Equipment Visibility on Load (PR #875): Equipment now appears when VRM loads
    • Added getAvatar() helper to resolve VRM from both PlayerLocal and PlayerRemote
    • Subscribe to AVATAR_LOAD_COMPLETE to replay cached equipment when VRM loads
    • Re-send equipment on socket reconnect (packets lost during disconnect)
    • Send existing players’ equipment to joiner and broadcast joiner’s equipment
    • Use all 11 EQUIPMENT_SLOT_NAMES instead of hardcoded 6 slots
    • Gate equipment UI_UPDATE to local player only (prevents duplicate UI updates)
  • PvP Ranged XP Fix (PR #875): Ranged attacks now grant correct XP in duels
    • Detect weapon type (bow/crossbow/staff) in PlayerDeathSystem for PvP kills
    • Previously used player’s melee attack style, incorrectly granting Strength XP for ranged kills
    • Now matches MobEntity logic: inspect actual weapon type for XP calculation
    • Fixes ranged attacks incorrectly granting Strength XP in duels
  • Mob Position Desync Fix (PR #884): Mobs no longer get stuck facing combat direction
    • Clear inCombatRotation flag on movement start in TileInterpolator
    • Only route entityModified to setCombatRotation for players, not mobs
    • Mobs handle combat rotation locally in MobEntity.clientUpdate()
    • Prefer entity visual position over server position in DamageSplatSystem
    • Replace redundant entityModified with emote on tileMovementEnd packet
    • Fix cancelMovement to send tileMovementEnd instead of entityModified

🛡️ Duel Health Restore Fix (PR #875)

Fixed critical bug where duel losers could get stuck in arena with frozen physics:
  • Split Health Restores: Individual try/catch blocks for winner and loser
    • Previously both restorePlayerHealth calls were in single try/catch
    • If winner’s restore triggered exception in any PLAYER_RESPAWNED handler, loser’s restore was skipped
    • Left loser with frozen physics, isDying=true, and no playerRespawned/playerSetDead packets
    • playerTeleport still arrived (separate try/catch) but client couldn’t act on it
  • Error Isolation: Each restore individually wrapped, matching teleport pattern
    • Winner restore failure no longer affects loser
    • Both players guaranteed to receive health restoration
    • Prevents players stuck in arena unable to move or respawn
Trading System & UI Polish
February 2026

🤝 Player-to-Player Trading (PR #850)

Complete trading system with OSRS-style two-screen confirmation flow:
  • Trade Panel Integration: TradePanel wired into modal system
    • Trade event handlers in useModalPanels hook (trade, tradeUpdate, tradeConfirm, tradeClose)
    • Rendered in InterfaceModals following DuelPanel pattern
    • Server emits UI_UPDATE events with trade data
    • TradePanel component already built, now fully connected
  • Trade Flow: Request → Offer Screen → Confirm Screen → Complete
    • Screen 1: Add/remove items, accept offers
    • Screen 2: Final confirmation with value totals
    • Both players must accept on each screen
    • Acceptance resets when either player modifies offer
  • UI Components:
    • TradePanel.tsx - Main trade window with two screens
    • TradeRequestModal.tsx - Incoming trade request modal
    • components/TradeSlot.tsx - Individual trade offer slots
    • components/InventoryMiniPanel.tsx - Inventory grid for item selection
    • modals/QuantityPrompt.tsx - Offer-X quantity input
    • hooks/useRemovedItemTracking.ts - Anti-scam tracking for removed items
  • Anti-Scam Features:
    • Wealth transfer indicators (value difference warnings)
    • Removed item tracking (highlights items opponent removed)
    • Screen 2 shows final offer values
    • Both players must re-accept after any modification
  • Network Events: trade, tradeUpdate, tradeConfirm, tradeClose
    • Server-authoritative trade state management
    • Real-time offer synchronization
    • Proximity validation (2-tile range)
    • Interface blocking during trade

🎨 Visual Polish

  • Mob Sword Swing Animation (PR #848): Mobs with held weapons use sword_swing emote
    • Guards with bronze swords now play proper sword swing animation
    • Replaces default punch animation for melee mobs with weapons
    • Checks for heldWeaponModel in mob config
  • Duel Stake Icons (PR #846): Item icons in duel stake panels
    • Replaced truncated text names with actual ItemIcon rendering
    • Staked items in inventory appear dimmed (40% opacity)
    • Visual indicator for offered items
  • Arrow Projectile Spawn (PR #845): Fixed arrow spawn position
    • Arrows now spawn at bow position instead of player center
    • Offset 1.2 units forward toward target
    • Height adjusted to upper torso level (1.4m)
    • Prevents arrows appearing to come from inside player’s head
  • Equipment Panel Icons (PR #825): Shows actual item icons instead of SVG placeholders
    • Uses ItemIcon component with proper asset URLs
    • Consistent with inventory panel styling

🗺️ Minimap Visual Upgrade (PR #830)

RS3/OSRS-accurate minimap with location icons and improved color scheme:
  • Dot Color Update: Swapped to RS3 standard colors
    • White: Players (was green/blue)
    • Yellow: NPCs and mobs (was red)
    • Red: Ground items (was yellow)
    • White square: Local player (was green circle)
  • Destination Marker: Red flag icon (RS3-style)
    • Thin pole with filled triangle flag
    • Replaces previous red dot marker
    • More visible and distinctive
  • Location Icons: Custom icons for key locations
    • Bank: Gold coin ($) symbol
    • Shop: Open bag icon
    • Prayer Altar: White cross
    • Runecrafting Altar: Purple circle with “R”
    • Anvil: Dark anvil silhouette
    • Furnace: Orange circle with flame
    • Cooking Range: Brown circle with steam
    • Fishing Spot: Cyan circle with fish
    • Mining Rock: Brown circle with pickaxe
    • Tree: Green circle
    • Quest NPC: Cyan circle with ”?”
  • Icon Detection: Automatic subtype detection
    • Station types (bank, furnace, anvil, range, altar)
    • NPC service types (bank, shop, quest)
    • Resource types (fishing_spot, mining_rock, tree)
  • Size Hierarchy: Compact dots (6px) for entities, larger icons (12px) for locations
  • Implementation: drawMinimapIcon() function with switch-based rendering
    • Returns true if icon drawn, false for default dot fallback
    • Clean filled glyphs with 1px dark outline
    • ~8px icon size for readability

🗄️ Database Performance Fix (PR #823)

Inventory write coalescing to prevent connection pool starvation:
  • Write Coalescing: Collapses concurrent inventory writes
    • At most 2 DB transactions per player (one active + one queued)
    • Latest snapshot wins (intermediate states discarded)
    • All waiting callers resolve when batch completes
  • Performance Impact:
    • Before: 100 fletching completions = 200 sequential transactions
    • After: 100 fletching completions = 2 transactions per player
    • Eliminates “200 pending operations” warnings
    • Prevents game freezes during batch crafting
  • Graceful Shutdown: Orphaned waiters rejected on DatabaseSystem.destroy()
  • Code Changes:
    • Replaced inventoryWriteLocks with inventoryWriteActive + inventoryWriteQueued
    • Removed redundant getPlayerAsync checks (repository handles missing players)
    • Recursive drain of queued batches after active write completes

🎥 Client Rendering Fixes (PR #829)

Camera and post-processing improvements:
  • Camera Initialization Fix: Camera now faces behind player on fresh load
    • Changed theta from 0 to Math.PI in spherical coordinates
    • Fixes backwards movement controls on first spawn
    • Applied to both initial state and reset camera method
  • Post-Processing Color Grading Fix: LUT intensity zeroed when disabled
    • Prevents color grading from leaking into outline-only rendering
    • Entity highlights now work correctly with post-processing disabled
    • Rendering routes through composer even when post-processing is off
    • intensityUniform.value = 0 when LUT is “none”

🌐 Website Updates (PR #822)

  • Gold Token Page: Refactored into section components
    • TokenHero, ValueProps, HowItWorks, OpenSource, GoldCTA
    • Error boundaries and loading states
    • SEO improvements with opengraph images
    • Accessibility enhancements (semantic HTML, ARIA labels)
  • Solana Wallet Integration: Updated dependencies
    • @privy-io/react-auth to 3.13.1
    • @privy-io/server-auth to 1.32.5
    • @solana-mobile/wallet-standard-mobile for MWA support
    • Multi-chain wallet detection (Saga and Seeker devices)
  • Code Review: Updated to Claude Opus 4.6
Mob Projectile Attacks & Performance Fixes
February 2026

⚔️ Mob Magic & Ranged Attacks (PR #826)

Mobs can now use magic and ranged attacks, not just melee:
  • Attack Type Configuration: NPC manifest fields for combat type
    • attackType: "melee" (default), "ranged", or "magic"
    • spellId: Required for magic mobs (e.g., "wind_strike", "fire_bolt")
    • arrowId: Required for ranged mobs (e.g., "bronze_arrow", "iron_arrow")
    • heldWeaponModel: Optional weapon GLB (bow, staff) attached to hand bone
  • Combat Handler Routing: Mobs route through same handlers as players
    • MagicAttackHandler - Mob magic path with infinite runes
    • RangedAttackHandler - Mob ranged path with infinite arrows
    • Separate damage calculation for mobs (no equipment bonuses)
    • Uses mob’s magic or ranged stat from NPC manifest
  • Projectile System: Spell and arrow projectiles for mobs
    • OSRS-accurate hit delays based on distance
    • Element-based spell visuals (air, water, earth, fire)
    • Arrow projectiles with metal-colored tips
    • Launch delays: 600ms for spells, 400ms for arrows
  • Visual Weapon Attachment: Held weapons on mob VRM avatars
    • Static weapon cache shares GLB scenes across mob instances
    • clone(true) for per-mob instances with shared geometry
    • Proper cleanup on world teardown via clearWeaponCache()
    • Supports Asset Forge V1 and V2 attachment metadata
  • Animation System: Attack-type-specific emotes
    • Magic mobs: SPELL_CAST animation
    • Ranged mobs: RANGE animation
    • Melee mobs: COMBAT or SWORD_SWING animation
    • Emote matching switched from substring to exact equality
  • Auto-Attack Integration: Tick-based follow-up attacks
    • weaponType stored in combat state for auto-attack routing
    • CombatTickProcessor routes by stored weapon type
    • Retaliation uses correct attack type (magic/ranged mobs retaliate with projectiles)
  • Shared Utilities: prepareMobAttack() in AttackContext.ts
    • Consolidates entity resolution, range checks, cooldown, animation
    • Eliminates duplication between magic and ranged handlers
    • Returns validated MobAttackContext or null
  • Constants: New combat constants in CombatConstants.ts
    • MAGIC_RANGE: 10 - Magic attack range in tiles
    • SPELL_LAUNCH_DELAY_MS: 600 - Spell cast animation wind-up
    • ARROW_LAUNCH_DELAY_MS: 400 - Arrow draw animation wind-up
  • Testing: 996 lines of integration tests
    • Magic/ranged attack routing and projectile emission
    • Missing spellId/arrowId graceful handling
    • Out-of-range rejection
    • Event-carried vs NPC-data spell/arrow resolution
    • Auto-attack tick paths for both magic and ranged

🗺️ Minimap Visual Upgrade (PR #830)

RS3/OSRS-accurate minimap with location icons and improved color scheme:
  • Dot Color Update: Swapped to RS3 standard colors
    • White: Players (was green/blue)
    • Yellow: NPCs and mobs (was red)
    • Red: Ground items (was yellow)
    • White square: Local player (was green circle)
  • Destination Marker: Red flag icon (RS3-style)
    • Thin pole with filled triangle flag
    • Replaces previous red dot marker
    • More visible and distinctive
  • Location Icons: Custom icons for key locations
    • Bank: Gold coin ($) symbol
    • Shop: Open bag icon
    • Prayer Altar: White cross
    • Runecrafting Altar: Purple circle with “R”
    • Anvil: Dark anvil silhouette
    • Furnace: Orange circle with flame
    • Cooking Range: Brown circle with steam
    • Fishing Spot: Cyan circle with fish
    • Mining Rock: Brown circle with pickaxe
    • Tree: Green circle
    • Quest NPC: Cyan circle with ”?”
  • Icon Detection: Automatic subtype detection
    • Station types (bank, furnace, anvil, range, altar)
    • NPC service types (bank, shop, quest)
    • Resource types (fishing_spot, mining_rock, tree)
  • Size Hierarchy: Compact dots (6px) for entities, larger icons (12px) for locations
  • Implementation: drawMinimapIcon() function with switch-based rendering
    • Returns true if icon drawn, false for default dot fallback
    • Clean filled glyphs with 1px dark outline
    • ~8px icon size for readability

🎨 Visual Polish

  • Mob Sword Swing Animation (PR #848): Mobs with held weapons use sword_swing emote
    • Guards with bronze swords now play proper sword swing animation
    • Replaces default punch animation for melee mobs with weapons
    • Checks for heldWeaponModel in mob config
  • Duel Stake Icons (PR #846): Item icons in duel stake panels
    • Replaced truncated text names with actual ItemIcon rendering
    • Staked items in inventory appear dimmed (40% opacity)
    • Visual indicator for offered items
  • Arrow Projectile Spawn (PR #845): Fixed arrow spawn position
    • Arrows now spawn at bow position instead of player center
    • Offset 1.2 units forward toward target
    • Height adjusted to upper torso level (1.4m)
    • Prevents arrows appearing to come from inside player’s head
  • Equipment Panel Icons (PR #825): Shows actual item icons instead of SVG placeholders
    • Uses ItemIcon component with proper asset URLs
    • Consistent with inventory panel styling

🗄️ Database Performance Fix (PR #823)

Inventory write coalescing to prevent connection pool starvation:
  • Write Coalescing: Collapses concurrent inventory writes
    • At most 2 DB transactions per player (one active + one queued)
    • Latest snapshot wins (intermediate states discarded)
    • All waiting callers resolve when batch completes
  • Performance Impact:
    • Before: 100 fletching completions = 200 sequential transactions
    • After: 100 fletching completions = 2 transactions per player
    • Eliminates “200 pending operations” warnings
    • Prevents game freezes during batch crafting
  • Graceful Shutdown: Orphaned waiters rejected on DatabaseSystem.destroy()
  • Code Changes:
    • Replaced inventoryWriteLocks with inventoryWriteActive + inventoryWriteQueued
    • Removed redundant getPlayerAsync checks (repository handles missing players)
    • Recursive drain of queued batches after active write completes

🎥 Client Rendering Fixes (PR #829)

Camera and post-processing improvements:
  • Camera Initialization Fix: Camera now faces behind player on fresh load
    • Changed theta from 0 to Math.PI in spherical coordinates
    • Fixes backwards movement controls on first spawn
    • Applied to both initial state and reset camera method
  • Post-Processing Color Grading Fix: LUT intensity zeroed when disabled
    • Prevents color grading from leaking into outline-only rendering
    • Entity highlights now work correctly with post-processing disabled
    • Rendering routes through composer even when post-processing is off
    • intensityUniform.value = 0 when LUT is “none”

🎨 UI Improvements

  • Equipment Panel Icons (PR #825): Shows actual item icons instead of SVG placeholders
    • Uses ItemIcon component with proper asset URLs
    • Consistent with inventory panel styling
    • Fallback to placeholder only when icon missing

🌐 Website Updates (PR #822)

  • Gold Token Page: Refactored into section components
    • TokenHero, ValueProps, HowItWorks, OpenSource, GoldCTA
    • Error boundaries and loading states
    • SEO improvements with opengraph images
    • Accessibility enhancements (semantic HTML, ARIA labels)
  • Solana Wallet Integration: Updated dependencies
    • @privy-io/react-auth to 3.13.1
    • @privy-io/server-auth to 1.32.5
    • @solana-mobile/wallet-standard-mobile for MWA support
    • Multi-chain wallet detection (Saga and Seeker devices)
  • Code Review: Updated to Claude Opus 4.6
Combat Polish & Visual Upgrades
February 2026

⚔️ Combat System Improvements

Persistent Combat Follow (PR #737)

OSRS-accurate continuous target tracking during combat:
  • Target Movement Detection: Tracks last known target tile per attacker
    • Pre-computes follow path when target moves (even if in range)
    • Zero-delay pursuit when target steps out of range
    • Prevents stutter pattern where players stand still until target escapes
  • Race Condition Fixes:
    • Clears action queue when clicking new target (prevents ground-click override)
    • Stops active follow when switching targets
    • Stops remaining walk path when entering combat range
  • Memory Management: lastCombatTargetTile map cleaned up on combat end/disengage

Combat Rotation System (PR #732)

Players now automatically face their combat target during ranged/magic attacks:
  • Face Target Event: COMBAT_FACE_TARGET network packet
    • Server emits when attack is processed
    • Client rotates player toward target
    • Essential for stationary ranged/magic attacks
  • Rotation Clearing: Proper cleanup when combat ends
    • Clears rotation when target dies
    • Clears rotation when player starts moving
    • Prevents facing dead targets or old combat directions

Staff Melee/Magic XP (PR #734)

OSRS-accurate staff combat mechanics:
  • Dual Combat Styles: Staves/wands now have both melee and magic styles
    • Melee (no spell): Bash/Pound/Focus grant Attack/Strength/Defense XP
    • Magic (with spell): Autocast grants Magic XP
  • XP Grant Logic: Validates attack style to prevent wrong XP type
  • Autocast Panel: Selecting autocast style automatically opens Spells panel
  • Weapon Styles: Updated for STAFF and WAND: ["accurate", "aggressive", "defensive", "autocast"]

🎨 Visual Enhancements

Spell Projectile Upgrade (PR #722)

Multi-layer spell projectiles with WebGPU-compatible rendering:
  • Multi-Layer Structure: Outer glow + core orb + orbiting sparks (bolt-tier)
  • Impact Burst Particles: 4-6 particles burst outward on spell hit
  • WebGPU Compatibility: DataTextures with color baked into pixels
  • Visual Tuning: Increased spell sizes and glow intensity
    • Strike spells: 0.25 → 0.5 size, glow 0.3-0.5 → 0.7
    • Bolt spells: 0.35 → 0.7 size, glow 0.5 → 0.8
  • Trail System: Element-colored billboard meshes replace white sprites

Bow Models & Arrow Sizing (PR #719)

  • Bow Models: All bow items now display 3D models when equipped
  • Arrow Size Reduction: Length 0.6 → 0.35, width 0.15 → 0.08 for better scale

Ground Item Snapping (PR #718)

  • Bbox Snapping: Automatic bottom-of-model alignment to terrain
  • Ground Offset System: New groundOffset and modelScale item properties
  • Fire Models: Fires now sit flush on terrain using bbox calculation
  • Ashes Spawn: Fires spawn ashes when they burn out (OSRS-accurate)

🔧 Firemaking Improvements (PR #736)

OSRS-accurate firemaking behavior:
  • Movement Stopping: Player movement automatically stopped before lighting
  • Movement Cancellation: Lighting cancelled if player moves (0.5 unit threshold)
  • Fire Placement: Fire spawns at cached start position, not current position
  • Network Events: New FIRE_LIGHTING_CANCELLED event

🐛 Bug Fixes

  • Mob Respawn (PR #729): Mobs respawn at random spawn point instead of death location
  • UI Theme (PR #701): Fixed quest log black background, aligned all panel colors
  • Mobile Breakpoint (PR #701): Aligned with breakpoints.md (640px)
  • Test Fixes (PR #701): Updated 4078 tests to match current implementation
Artisan Skills & Visual Upgrades
February 2026

🎨 Three New Artisan Skills

Complete implementation of Crafting, Fletching, and Runecrafting with OSRS-accurate mechanics:

Crafting Skill (PR #698)

  • Leather Armor: Needle + thread + leather for basic armor
    • 6 leather items: gloves, boots, cowl, vambraces, body, chaps
    • Thread consumption system (5 uses per thread)
    • Levels 1-18 for full leather set
  • Dragonhide Armor: High-level ranged gear from dragon leather
    • Green d’hide vambraces (L57), chaps (L60), body (L63)
    • Requires needle + thread + dragon leather
  • Jewelry Crafting: Gold bars + gems at furnaces
    • Requires specific moulds (ring, necklace, amulet, bracelet)
    • Moulds not consumed (permanent tools)
    • 12 jewelry items from gold rings to diamond bracelets
  • Gem Cutting: Chisel + uncut gems
    • 4 gem types: sapphire, emerald, ruby, diamond
    • Levels 20-43 for all gems
  • Tanning System: Convert hides to leather at tanner NPCs
    • Cowhide → leather (1 gp)
    • Dragon hides → dragon leather (20 gp)
    • Instant conversion, no XP granted
  • UI Features:
    • Category grouping (leather, studded, dragonhide, jewelry, gem_cutting)
    • Auto-select when only one recipe matches input item
    • Make-X with quantity memory (localStorage)
    • Thread usage tracking (5 uses before consumption)
  • Database: New craftingLevel and craftingXp columns (migration 0029)
  • Testing: 19 unit tests covering crafting lifecycle, cancellation, and edge cases

Fletching Skill (PR #699)

  • Arrow Crafting: Multi-output arrow production
    • Arrow shafts: 15 per log (knife + logs)
    • Headless arrows: 15 per action (arrow shafts + feathers)
    • Finished arrows: 15 per action (headless arrows + arrowtips)
    • Bronze, Iron, Steel, Mithril, Adamant arrows
  • Bow Crafting: Shortbows and longbows
    • Unstrung bows: knife + logs
    • Strung bows: unstrung bow + bowstring (item-on-item)
    • 5 wood types: normal, oak, willow, maple, yew
  • Item-on-Item Interactions: Stringing bows and assembling arrows
    • Client interaction handler with raycast routing
    • Server network handler with target validation
    • Packet definition for secondary item ID
  • Multi-Output Support: outputQuantity field in recipes
    • 15 arrow shafts per log
    • 15 arrows per arrowtip set
    • Quantity selection refers to actions, not output items
  • UI Features:
    • Category grouping (arrow_shafts, shortbows, longbows, stringing, arrows)
    • Output quantity display (e.g., “Arrow shafts (x15)”)
    • Auto-select for single-recipe interactions
    • Make-X with quantity memory
  • Database: New fletchingLevel and fletchingXp columns (migration 0030)
  • Smithing Integration: 6 arrowtip recipes (15 per bar) added to smithing
  • Testing: 19 unit tests covering fletching system and multi-output recipes

Runecrafting Skill (PR #703)

  • Instant Conversion: Click altar to convert ALL essence in inventory
    • No tick delay (instant crafting)
    • Server-authoritative runeType validation
  • Two Essence Types:
    • Rune essence: basic runes only (air, mind, water, earth, fire, body)
    • Pure essence: all runes (includes cosmic, chaos, nature, law, death)
  • Multi-Rune Crafting: Higher levels grant bonus runes per essence
    • Air runes: 2x at L11, 3x at L22, up to 10x at L99
    • Mind runes: 2x at L14, 3x at L28, up to 8x at L98
    • Water runes: 2x at L19, 3x at L38, up to 6x at L95
    • Earth runes: 2x at L26, 3x at L52, 4x at L78
    • Fire runes: 2x at L35, 3x at L70
  • Altar Entities: RunecraftingAltarEntity with mystical particle effects
    • Per-altar rune type (air altar, water altar, fire altar, etc.)
    • Color-coded particle systems (4 layers: pillar, wisps, sparks, base)
    • Mesh-aware particle spawning from actual geometry vertices
    • Billboard particles with camera-facing orientation
  • Database: New runecraftingLevel and runecraftingXp columns (migration 0031)
  • Testing: 19 unit tests covering runecrafting system, multipliers, and validation

🔥 Visual Improvements

Fire Models (PR #715)

  • GLB Fire Model: Replaced orange cube placeholder with 3D fire model
    • Model path: fire.glb with scale 1.0
    • Proper lighting and shadows
  • Billboard Particle System: Realistic flame effects
    • 4 particle layers: pillar, wisps, sparks, base
    • Color-baked glow textures for WebGPU compatibility
    • Mesh-aware particle spawning from actual geometry
    • Camera-facing billboards with quaternion copy
    • Additive blending for glow effects
  • Particle State Management: Efficient per-particle tracking
    • Typed arrays for particle properties (ages, lifetimes, angles, speeds)
    • Reusable geometry (shared CircleGeometry for all particles)
    • Surface point sampling from fire model mesh
    • Bounding box calculation for spawn area
  • Performance: Particles added to world.stage.scene (not entity node)
    • Registered with world.setHot() for frame updates
    • Proper cleanup in destroy() method

Ground Item Snapping (PR #718)

  • Bbox-Snap to Terrain: Items now align to ground using bounding box
    • Calculates bbox.min.y and offsets mesh position
    • Compensates for GroundItemSystem’s 0.2m terrain offset
    • Named constant: GROUND_ITEM_TERRAIN_OFFSET = 0.2
    • Applies to all ground items and fire models
  • Grounded Items: Items with groundOffset ≤ 0 use bbox snapping
    • No floating animation for grounded items
    • Prevents clipping through terrain
    • Consistent placement across all item types
  • Documentation: Clarified groundOffset behavior in ItemEntity.ts

Mining Rock Materials (PR #710)

  • PBR Materials: Realistic rock appearance with metalness=0
    • Prevents overly shiny/metallic rocks
    • Proper roughness values for stone
  • Depleted Rock Alignment: Bbox snapping for depleted rock models
    • Ensures stumps/depleted rocks sit flush with ground
    • Consistent with active rock placement

Headstone Model (PR #710)

  • GLB Model: Replaced placeholder box with headstone.glb
    • Proper 3D gravestone model
    • Scale and positioning for visibility

🎮 UI Enhancements

Skill Guide Panel (PR #711)

  • Click-to-Open: Click skill icon in skills panel to open guide
    • Shows all unlocks for that skill sorted by level
    • Visual indicators: ✓ unlocked, ➤ next, 🔒 locked
    • Progress tracking (X/Y unlocked)
    • Levels to next unlock display
  • Client-Side Loading: Unlock data loaded from skill-unlocks.json manifest
    • No server round-trip required
    • Instant panel opening
    • Cached unlock data per skill
  • ModalWindow Integration: Consistent styling with other modals
    • Themed colors and spacing
    • Scrollable unlock list
    • Loading state with spinner
  • Unlock Types: item, ability, area, quest, activity
    • Type badges with color coding
    • Next unlock highlighted with “NEXT” badge

🐛 Bug Fixes

  • Fishing Spots (PR #712): Aligned water threshold to 9.0m so spots spawn at shoreline instead of underwater
  • Gathering Emote (PR #713): Prevented gathering animation from playing when player lacks required tool
    • Tool validation before emote trigger
    • Prevents visual desync

🧹 Code Cleanup

  • Dead Code Removal (PR #715): Removed unused ProcessingSystemBase, FiremakingSystem, and CookingSystem
    • Legacy systems replaced by unified ProcessingSystem
    • Reduced codebase complexity
F2P Ranged & Magic Combat
January 2026

⚔️ Ranged Combat System

Complete implementation of OSRS-style ranged combat with bows and arrows:
  • Ranged Weapons: Shortbow, Oak shortbow, Willow shortbow, Maple shortbow
  • Ammunition: Bronze, Iron, Steel, Mithril, and Adamant arrows
    • Arrows equipped in new ammo slot
    • 100% consumption rate (no Ava’s device yet)
    • Arrow strength bonuses affect damage
  • Combat Styles: Accurate (+3 Ranged), Rapid (-1 tick speed), Longrange (+2 range, Ranged+Defense XP)
  • Damage Calculation: OSRS-accurate formulas with equipment bonuses
    • Effective Ranged = floor(rangedLevel × prayer) + styleBonus + 8
    • Max Hit = floor(0.5 + effectiveRanged × (arrowStrength + 64) / 640)
  • Projectile System: 3D arrow meshes with arc trajectories
    • OSRS-accurate hit delay: 1 + floor((3 + distance) / 6)
    • Arrows rotate to face travel direction
    • Metal-colored arrow tips based on arrow type
  • Attack Range: 10 tiles (Chebyshev distance)
  • XP Distribution: 4 XP per damage to Ranged, 1.33 XP to Constitution

✨ Magic Combat System

Complete implementation of F2P magic with Strike and Bolt spells:
  • Spells Panel: New spellbook UI with spell grid
    • Click to select autocast spell
    • Right-click for context menu (Autocast/Cast)
    • Element-colored spell icons with glow effects
    • Level requirements displayed
  • Combat Spells: 8 F2P spells across 2 tiers
    • Strike: Wind (L1, 2 dmg), Water (L5, 4 dmg), Earth (L9, 6 dmg), Fire (L13, 8 dmg)
    • Bolt: Wind (L17, 9 dmg), Water (L23, 10 dmg), Earth (L29, 11 dmg), Fire (L35, 12 dmg)
  • Rune System: Air, Water, Earth, Fire, Mind, and Chaos runes
    • Runes consumed on each cast
    • Elemental staves provide infinite runes (Staff of Air/Water/Earth/Fire)
  • Staffless Casting: Can cast spells without a staff (OSRS-accurate)
    • Staff provides magic attack bonus and infinite runes
    • Spells work with any weapon or no weapon
  • Combat Styles: Accurate (+3 Magic), Longrange (+2 range, Magic+Defense XP), Autocast
  • Damage Calculation: OSRS-accurate formulas
    • Effective Magic = floor(magicLevel × prayer) + styleBonus + 8
    • Max Hit = spell base damage (no equipment modifiers in F2P)
    • Magic Defense = floor(0.7 × magicLevel + 0.3 × defenseLevel) for players
  • Projectile Visuals: Colored spell orbs with element-specific effects
    • OSRS-accurate hit delay: 1 + floor((1 + distance) / 3)
    • Spell trails with glow and pulse effects
  • Database: New magicLevel, magicXp, and selectedSpell columns
  • XP Distribution: Base spell XP + (2 × damage) to Magic, 1.33 XP per damage to Constitution

🎯 Combat System Enhancements

  • Attack Type Detection: Automatic detection of MELEE/RANGED/MAGIC from equipped weapon or selected spell
  • Pathfinding Updates: Ranged/magic use Chebyshev distance, melee uses cardinal-only for range 1
  • Pending Attack Manager: Updated to support all three attack types with appropriate range checks
  • Equipment Panel: New ammo slot for arrows (top-right position)
  • Menu Bar: Added Spells button (🔮) to menu bar
  • Combat Panel: Updated with icons for Rapid, Longrange, and Autocast styles
  • Timestamp Validation: Required timestamp validation on all combat packets (prevents replay attacks)

🧪 Testing

  • Unit Tests: Comprehensive tests for ranged/magic damage calculators
  • Integration Tests: Full combat flow testing for all three attack types
  • Type Guards: Event payload validation throughout combat handlers
Duel Arena System
January 2026

⚔️ Player vs Player Dueling

Complete OSRS-style duel arena system with rules negotiation and stakes:
  • Duel Flow: Challenge → Rules → Stakes → Confirm → Countdown → Fight → Result
  • Challenge System: Walk to player and send duel challenge (like trading)
    • 30-second timeout for acceptance
    • Distance-based cancellation (15 tiles)
    • Clickable chat messages for acceptance
  • Rules Screen: 10 combat rule toggles
    • No Ranged, No Melee, No Magic, No Special Attack
    • No Prayer, No Potions, No Food, No Movement, No Forfeit
    • Equipment slot restrictions (11 slots)
    • Both players must accept to proceed
  • Stakes Screen: Item staking with anti-scam features
    • Left-click to stake 1, right-click for quantity menu
    • Value imbalance warnings
    • Opponent modification warnings
    • Both players must accept to proceed
  • Confirmation Screen: Final read-only review
    • Shows all rules, equipment restrictions, and stakes
    • Both players must accept to start
  • Arena System: 6 arenas in 2×3 grid layout
    • Arena pooling with automatic reservation
    • Collision walls prevent escape during combat
    • Flattened terrain for fair combat
    • Forfeit pillars for surrendering (if allowed)
  • Combat Resolution: Winner receives all stakes
    • Death or forfeit determines winner
    • Automatic health restoration
    • Teleport to lobby after duel
    • Disconnect handling with 30-second timeout
  • UI Components:
    • DuelPanel with screen transitions
    • DuelChallengeModal for incoming challenges
    • DuelCountdown overlay (3-2-1-FIGHT)
    • DuelResultModal showing items won/lost
    • DuelHUD during combat with opponent health

🏗️ Architecture

  • DuelSystem: Main orchestrator for duel state machine
  • DuelSessionManager: Session CRUD operations
  • PendingDuelManager: Challenge tracking and timeouts
  • ArenaPoolManager: Arena reservation and collision
  • DuelCombatResolver: Combat resolution and stake transfers
  • Audit Logging: Economic tracking for all duel outcomes

🧪 Testing

  • 1,066 lines of DuelSystem unit tests
  • 456 lines of PendingDuelManager tests
  • 233 lines of ArenaPoolManager tests
  • Full coverage of state machine transitions and edge cases
Security & Type Safety
January 2026

🔒 Security Enhancements

Comprehensive security improvements across authentication and input validation:
  • Secure Token Storage: Configurable auth storage (localStorage, sessionStorage, or memory)
    • AuthStorageType enum for storage selection
    • Memory-only mode for maximum security
    • Proper cleanup on logout (clears all storage types)
  • URL Parameter Validation: Removed authToken from URL params (security vulnerability)
    • BREAKING: Tokens must now be passed via postMessage, not URL
    • Schema-based validation for embedded config parameters
    • Prevents token exposure in browser history and server logs
  • CSP Violation Monitoring: Content-Security-Policy violation event handling
    • Throttled reporting to prevent flooding
    • Report-URI endpoint for security monitoring
    • Documented CSP directives and security implications
  • Async Token Provider: Fresh token retrieval for API calls
    • Registered with API client for automatic token refresh
    • Prevents stale token usage
  • Timestamp Validation: Required on all combat packets
    • ±30 second window for replay attack prevention
    • Missing timestamps now rejected (was optional)
  • Type Guards: Comprehensive event payload validation
    • isUIUpdateEvent, isPlayerStatsData, isSkillsUpdateEvent
    • isPrayerPointsChangedEvent, isPrayerStateSyncEvent
    • Runtime validation at system boundaries

🎨 UI/UX Improvements

  • Viewport Scaling: Proportional panel resize on viewport changes
    • ViewportScaler component for design resolution-based scaling
    • Grid snapping utility for window alignment
    • Left/right column panel scaling with proper stacking
  • Minimap Overhaul:
    • Independent width/height resizing (no longer forced square)
    • Extracted MinimapOverlayControls component
    • Fixed pip desync using cached projection-view matrices
    • Default zoom set to 10 for better visibility
  • Panel Layout Redesign: Right column flush stacking
    • Minimap (top) → gap → Combat → Skills → Inventory → Menubar (bottom)
    • Consistent panel widths (235px) for alignment
    • No overlaps, touching edges
  • Combat Panel: Attack style buttons changed from 2×2 grid to 1×3 row for better mobile UX

⚡ Performance Optimizations

  • Object Pooling: Memory optimization utilities
    • ArrayPool for reusable temporary arrays
    • EventDataPool for pooled event objects
    • PositionPool for position reuse
    • withPooledArray helper for scoped pool usage
  • Notification Helpers: Convenient error handling functions
    • showErrorNotification, showNetworkErrorNotification, showSuccessNotification
    • Consistent error logging with console output

🧪 Testing

  • Security Tests: URL parameter validation, error boundaries
  • E2E Test Utilities: Entity introspection, visual testing helpers
    • getEntitiesByType, getPlayerInventory, getPlayerEquipment, getPlayerSkills
    • clickAtWorldPosition for world coordinate input simulation
  • Unit Tests: Expanded test patterns in vitest config
Collision System & UI Improvements
January 2026

🎯 Static Tile Collision System

Production-quality OSRS-accurate collision system for static world objects and entities:
  • CollisionMatrix: Zone-based collision storage with bitmask flags
    • World divided into 8×8 tile zones (Int32Array[64] = 256 bytes per zone)
    • Lazy allocation: zones created on first write
    • Memory efficient: 1000×1000 tile world = ~4MB
    • O(1) tile lookups with zero allocations in hot paths
  • Collision Flags: OSRS-accurate bitmask flags
    • Static objects: BLOCKED, WATER, STEEP_SLOPE
    • Entity occupancy: OCCUPIED_PLAYER, OCCUPIED_NPC
    • Directional walls: 8 directions for future dungeons/buildings
    • Combined masks: BLOCKS_WALK, BLOCKS_MOVEMENT, BLOCKS_RANGED
  • Automatic Footprint Detection: Build-time model bounds extraction
    • New extract-model-bounds.ts script parses GLB files
    • Extracts bounding boxes from glTF position accessors
    • Generates model-bounds.json manifest automatically
    • Footprints calculated from model dimensions × scale
    • Turbo caching avoids rebuilding when models unchanged
  • Multi-Tile Entities: Stations and large resources occupy multiple tiles
    • Furnaces, anvils, banks support 2×2 footprints
    • Center-based registration (footprint centered on entity position)
    • OSRS-style interaction from any adjacent tile
    • tilesWithinRangeOfFootprint() for multi-tile range checks
  • Pathfinding Integration: Mobs and players respect collision
    • BFSPathfinder checks CollisionMatrix for static objects
    • Safespotting: players can hide behind trees/rocks
    • Depleted resources remain solid (stumps block movement)
  • Network Synchronization: Zone-based collision sync
    • Base64 serialization for efficient network transport
    • Only allocated zones sent to clients
    • getZonesInRadius() for area-based sync
  • Testing: 1,118 lines of comprehensive unit tests
    • CollisionMatrix: zone allocation, flag operations, negative coordinates
    • CollisionFlags: bitmask uniqueness, directional walls
    • TileSystem: multi-tile footprint calculations

💰 Coin Pouch Withdrawal System

RS3-style money pouch with secure withdrawal to inventory:
  • Money Pouch: Protected coin storage (characters.coins column)
    • Doesn’t use inventory slots
    • Separate from physical coin items
    • Displayed in inventory panel footer
  • Withdrawal Flow: Pouch → inventory as stackable coins item
    • Click coin pouch to open withdrawal modal
    • Enter amount or use preset buttons
    • Coins added to existing stack or new inventory slot
    • Server-authoritative with atomic database transactions
  • Security Features:
    • Rate limiting: 10 requests/second with auto-cleanup
    • Timestamp validation: prevents replay attacks (±30s window)
    • Input validation: positive integers, max 2.1B coins
    • Overflow protection: prevents MAX_COINS stack overflow
    • Row-level locking: FOR UPDATE in transactions
    • Audit logging: tracks large withdrawals (≥1M coins)
  • UI Components:
    • Extracted CoinPouch component with keyboard accessibility
    • Hoisted styles prevent re-render allocations
    • CoinAmountModal reused from bank system
    • Enter/Space key support for accessibility
  • Error Handling: Graceful inventory sync with fallback
    • Transaction commits before sync
    • Sync failures logged but don’t fail withdrawal
    • Players can relog to resync if needed
  • Testing: 32 comprehensive unit tests
    • Input validation (NaN, Infinity, negative, overflow)
    • Insufficient coins, inventory full, stack overflow
    • New stack creation, existing stack updates
    • Atomicity simulation

🎨 Hover Tooltips & Click-to-Unequip

RS3-style hover tooltips and improved equipment interaction:
  • Hover Tooltips: Item stats on hover (equipment and inventory)
    • Shows item name, bonuses (attack/defense/strength), and quantity
    • Portal-based rendering avoids z-index issues
    • Suppressed when context menu is open
    • Separate from targeting mode tooltips
  • Click-to-Unequip: Direct equipment slot clicks unequip items
    • Removed modal popup (faster workflow)
    • Sends unequipItem packet directly to server
    • Consistent with OSRS/RS3 behavior
  • Context Menu Coordination: Smart tooltip suppression
    • contextmenu:close event dispatched on menu close
    • Hover tooltips re-enabled after menu closes
    • Memory leak fix: uses ref instead of state setter for event dispatch
  • Code Quality: Extracted tooltip rendering functions
    • renderItemHoverTooltip() and renderEquipmentHoverTooltip()
    • Improved testability and maintainability
    • Eliminated 80+ line IIFEs in JSX

🗺️ Walk Here Context Menu

OSRS-style terrain interaction with right-click menu:
  • Terrain Context Menu: Right-click empty terrain shows “Walk here”
    • Separate from entity context menus
    • Includes “Cancel” option
    • Uses same ContextMenuAction structure
  • Type Safety: New ContextMenuTargetType union
    • Separates entity types from UI menu types
    • InteractableEntityType remains strict (entities only)
    • ContextMenuTargetType = InteractableEntityType | "terrain"
    • Prevents semantic type errors
  • Null Handling: ContextMenuController.showMenu() accepts null target
    • Terrain clicks pass null for target
    • Synthetic values used for menu display

🐛 Bug Fixes & Improvements

  • Fishing Animation: Restored fishing emote instead of idle placeholder (#554)
  • Store Transactions: Wrapped with executeInventoryTransaction to prevent race conditions (#553)
  • Bank Stacking: Stackable base items now stack when withdrawing from bank (#553)
    • Removed 28-item withdrawal limit for stackable items
    • Coins, ores, logs, fish now stack properly
  • Mob Combat Animations: Fixed idle/walk emotes overriding combat animations (#544)
    • Added isPriorityEmote() and isCombatEmote() helper methods
    • Death animation timing consolidated to tick-based constant (7 ticks)
    • Moved emoteMap to instance constant (performance optimization)
  • Nametag Removal: Removed overhead nametags for OSRS accuracy (#547)
    • Cleaned up orphaned nametag files and JSDoc references

🧪 Test Suite Maintenance

  • Vitest Imports: Fixed incorrect bun:test imports → vitest
  • Stale Assertions: Updated hardcoded counts to match current implementation
    • Item counts: 82→86 base items, 17→19 tools, 35→36 resources
    • Combat timeout: 8→17 ticks (now uses COMBAT_CONSTANTS)
    • Food count: 11→12 types
  • Performance Thresholds: Adjusted for CI environment variance
    • Heap growth: 500KB→5000KB (allows GC timing variance)
    • Scaling ratios: 10x→50x (allows parallel test contention)
    • Added documentation of observed values (local vs CI)
  • Mock Fixes: Added missing entities.players to mock worlds
Asset System Updates
January 2026

📦 Asset System Enhancements

New manifest additions and improvements to the asset pipeline:
  • Model Bounds Manifest: New model-bounds.json with pre-calculated bounding boxes for all 3D models
    • Contains bounds (min/max coordinates), dimensions (x/y/z), and tile footprints
    • Used for spatial calculations, collision detection, and placement validation
    • Auto-generated from actual model geometry
    • Covers 50+ models including tools, weapons, armor, resources, NPCs, and stations
  • Fishing Content: Complete fishing system with tools and spots
    • New models: fishing-rod-base and fishing-rod-standard
    • 7 fishing spots with OSRS-accurate catch rates (net, bait, fly, cage, harpoon, monkfish, shark)
    • Catch rate formulas with catchLow and catchHigh values for level-based success
    • Secondary requirements (bait, feathers) for certain fishing methods
  • Mining Expansion: Additional ore rocks with depleted states
    • Copper rock with depleted model variant
    • Mithril rock model added
    • Runite rock with depleted variant
    • All rocks include proper model paths and scale values
  • Crafting Stations: 3D models for smithing and smelting
    • Anvil model (anvil.glb) with scale 0.5 and yOffset 0.2
    • Furnace model (furnace.glb) with scale 1.5 and yOffset 1.0
    • Station manifest updated with proper model paths and positioning
Combat & Food System
January 2026

🛡️ Combat Session Management

OSRS-accurate behavior where being attacked closes bank/store/dialogue interfaces:
  • Session Interruption: Bank, store, and dialogue UIs automatically close when player is attacked
  • OSRS-Accurate: Even splash attacks (0 damage) interrupt banking - being in combat matters
  • Server-Authoritative: Server sends close packets with reason: "combat"
  • Defensive Guards: Malformed events handled gracefully (missing targetId/targetType)
  • Session Close Reasons: Added "combat" to SessionCloseReason type
  • Testing: 342 lines of comprehensive unit tests covering all session types and edge cases

⚡ Performance Optimizations

Raycast proxy optimization for fast entity click detection:
  • Raycast Proxy: Invisible capsule meshes for instant click detection on NPCs and mobs
  • Performance Gain: Avoids expensive VRM SkinnedMesh raycast (~700-1800ms per click)
  • Implementation: Proxy added directly to THREE.Scene, bypasses Node system
  • VRM Optimization: Disabled raycast on all VRM/GLB meshes (child.raycast = () => {})
  • Constants: Centralized RAYCAST_PROXY constants (radius, height, segments, Y-offset)
  • Memory Management: Proper cleanup in destroy() methods

🍖 Food Consumption & Healing System

OSRS-accurate food consumption with 3-tick eat delay and combat integration:
  • Eat Delay: 3-tick (1.8s) cooldown between eating foods
  • Combat Integration: Eating during combat adds 3-tick attack delay (only if already on cooldown)
  • Server-Authoritative: All validation happens server-side with comprehensive security
    • Rate limiting (3 requests/second)
    • Input validation (slot bounds, item ID mismatch detection)
    • Exploit prevention (MAX_HEAL_AMOUNT: 99 caps healing)
    • Consume-after-check (food only removed after validation passes)
  • OSRS Behavior: Food consumed even at full health, message format: “You eat the shrimp.”
  • Event-Driven Health: Client health bars now use PLAYER_HEALTH_UPDATED events (eliminates race conditions)
  • New Classes: EatDelayManager for per-player cooldown tracking
  • Testing: 30 unit tests covering eat delay and combat integration

⛏️ Mining System Improvements

OSRS-accurate mining mechanics with correct depletion and success rates:
  • 100% Rock Depletion: Rocks always deplete after yielding one ore (OSRS-accurate)
  • Accurate Success Rates: Updated to match OSRS wiki formulas
    • Copper/Tin: ~39.5% at L1, 100% at L62
    • Iron: ~52% at L15, 100% at L63
    • Coal: ~16.4% at L30, ~39.5% at L99
    • Runite: ~6.64% at L85, ~7.42% at L97+
  • Pickaxe Bonuses: Dragon/Crystal pickaxe bonus speed implemented
    • Dragon: 1/6 chance for 2-tick roll (avg 2.83 ticks)
    • Crystal: 1/4 chance for 2-tick roll (avg 2.75 ticks)
    • Server-side roll for determinism (prevents client/server desync)
  • Model Scale Fix: Normalized non-uniform scales in GLTF models (fixes “squished” rocks)
  • Depleted Models: Generalized depleted model swapping for all resource types

🎨 Context Menu Enhancements

Continued improvements to OSRS-style context menus:
  • Centralized Constants: All context menu colors now use CONTEXT_MENU_COLORS from GameConstants.ts
  • Consistency: Eliminated hardcoded color values across all interaction handlers
  • Resource Colors: Resources now use cyan (object color) instead of yellow (NPC color) for OSRS accuracy
  • Performance: Added useMemo and useCallback for render optimization in InventoryPanel
  • Testing: 333 lines of tests for InventoryActionDispatcher

🐛 Bug Fixes

  • UI Border Conflicts: Fixed border shorthand conflicts in SettingsPanel and CombatPanel (#510)
  • Noted Tools: Noted items now correctly rejected as valid tools for skilling (#508)
  • Quaternion Normalization: Fixed squished resources by using config.rotation.w instead of hardcoded 1 (#507)
  • Auto-Retaliate Guards: Added server guards to prevent client-side rotation conflicts (#511)
  • Bank Placeholders: Fixed unique constraint violation on “release all placeholders” using two-phase slot update (#502)

🎮 UX Improvements

  • F5 Debug Toggle: Added F5 keybind to toggle FPS debug panel (matches Minecraft) (#505)
  • Invalid Target Feedback: “Nothing interesting happens.” message when using item on invalid target
  • Cancel Option: OSRS-style Cancel option always shown last in context menus
  • Debug Panel: F5 or backslash key now toggles FPS/performance stats
Smithing & Manifest System
January 2026

⚒️ Smithing Skill System

Complete implementation of the Smithing skill with OSRS-accurate mechanics:
  • Smelting: Convert ores into bars at furnaces
    • 6 bar types: Bronze, Iron, Steel, Mithril, Adamant, Rune
    • Iron ore has 50% success rate (OSRS-accurate)
    • Coal requirements for higher-tier bars
    • Tick-based timing (4 ticks per bar)
  • Smithing: Convert bars into equipment at anvils
    • 40+ smithable items across weapons, armor, and tools
    • Requires hammer in inventory
    • Organized by category in UI
    • “Make X” functionality with quantity memory
  • Database: New smithingLevel and smithingXp columns
  • Manifests: New recipes/smelting.json and recipes/smithing.json

🎨 OSRS-Style Context Menus

Authentic context menu system with colored entity names:
  • Color Coding: Orange for items (#ff9040), yellow for NPCs (#ffff00), cyan for objects (#00ffff)
  • Inventory Actions: Manifest-driven actions with heuristic fallback
    • Items can define inventoryActions array
    • First action becomes left-click default
    • Supported: Eat, Drink, Wield, Wear, Bury, Use, Drop, Examine
  • Centralized Dispatching: InventoryActionDispatcher eliminates code duplication
  • Item Helpers: Type detection utilities (isFood, isPotion, isBone, usesWield, usesWear)
  • Cancel Option: Always shown last (OSRS standard)

🏗️ Manifest Architecture Improvements

  • Items Directory: Items split into 5 category files (weapons, tools, resources, food, misc)
  • Gathering Manifests: Separate files for woodcutting, mining, fishing
    • Complete fishing spot definitions with OSRS-accurate catch rates
    • Mining rocks with 3D model paths and depleted states
  • Recipe Manifests: Dedicated files for cooking, firemaking, smelting, smithing
  • Station Manifests: 3D models and configs for anvils, furnaces, ranges
    • Anvil model with scale 0.5 and yOffset 0.2
    • Furnace model with scale 1.5 and yOffset 1.0
  • Tier System: Centralized tier-requirements.json for equipment levels
  • Skill Unlocks: skill-unlocks.json defines what unlocks at each level
  • Atomic Loading: All category files must exist or system falls back to legacy format

🎣 New 3D Models

  • Fishing Tools: Base and standard fishing rod models with metadata
  • Mining Rocks: Copper, mithril, and runite ore rocks with depleted variants
  • Stations: Anvil and furnace models for crafting

🔧 Data Providers

New specialized providers for efficient data access:
  • ProcessingDataProvider: Cooking, firemaking, smelting, smithing recipes
  • TierDataProvider: Equipment level requirements by tier
  • StationDataProvider: Station models and configurations
  • Pre-allocated Buffers: Memory optimization for inventory counting

🐛 Bug Fixes

  • Resource Spam Fix: Prevent duplicate harvesting on spam-click (#494)
  • Equipment System: Tools with equipSlot: "weapon" can now be equipped (hatchets, pickaxes)
  • Firemaking: Level requirement validation added
  • Cooking: Level requirement check before starting action

📊 Testing

  • 843 new test lines: Comprehensive coverage for inventory actions and item helpers
  • Unit Tests: InventoryActionDispatcher (333 lines), item-helpers (510 lines)
  • Integration Tests: ProcessingDataProvider, skill unlocks, data integrity
v0.1.0
Initial Release

🎮 Core Features

  • Tick-based Combat — Authentic OSRS-style 600ms tick combat system
  • AI Agents — ElizaOS integration with 17 actions and 6 state providers
  • Skill System — 11 skills: Combat (Attack, Strength, Defense, Constitution, Ranged, Prayer), Gathering (Woodcutting, Fishing, Mining), Artisan (Firemaking, Cooking, Smithing)
  • Economy — Banks, shops, inventory, and loot system

🏗️ Architecture

  • Turbo monorepo with 7 packages
  • Three.js + PhysX WASM for 3D physics
  • Fastify + WebSocket multiplayer
  • React 19 + Vite client

📦 Packages

  • @hyperscape/shared — Core 3D engine
  • @hyperscape/server — Game server
  • @hyperscape/client — Web client
  • @hyperscape/plugin-hyperscape — ElizaOS plugin
  • @hyperscape/physx-js-webidl — PhysX bindings
  • 3d-asset-forge — AI asset generation
View release on GitHub

Subscribe