# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview HikeMap is a location-based RPG web application with trail/GPS track editing capabilities. Players walk in the real world to explore, battle monsters, and level up their characters. The frontend is a single-page application in `index.html` with a Node.js/Express backend in `server.js`. ## Development ### Docker (Recommended) ```bash docker-compose up -d ``` Access at http://localhost:880 ### Local Development ```bash npm install node server.js ``` Then open http://localhost:8080 ## Architecture ### File Structure | File | Purpose | |------|---------| | `index.html` | Frontend SPA (CSS, HTML, JavaScript) | | `server.js` | Express API server, WebSocket handling | | `database.js` | SQLite database layer (better-sqlite3) | | `animations.js` | Combat/monster animation definitions | | `docker-compose.yml` | Container configuration | | `hikemap.db` | SQLite database (auto-created) | | `SKILLS.md` | Complete skills documentation | ### Asset Directories | Directory | Purpose | |-----------|---------| | `mapgameimgs/monsters/` | Monster sprites (50px and 100px versions) | | `mapgameimgs/bases/` | Home base icons | | `mapgameimgs/skills/` | Custom skill icons (uploaded via admin) | | `mapgameimgs/cacheicons/` | Geocache type icons | | `mapgamemusic/` | Background music tracks | | `sfx/` | Sound effects (combat, spawns, etc.) | ### Key Libraries - **Frontend**: MapLibre GL JS 4.1.0 (WebGL vector maps), Turf.js (geospatial math) - **Backend**: Express, better-sqlite3, jsonwebtoken, ws (WebSocket) - **Note**: Codebase has Leaflet compatibility shims for gradual migration --- ## RPG System ### Core Concepts **Character Creation**: - Player chooses Race (Human, Elf, Dwarf, Halfling) and Class (Trail Runner) - Race provides stat bonuses, Class determines skills and growth **Stats**: | Stat | Description | |------|-------------| | HP | Health points - reach 0 and you die | | MP | Mana points - used for skills | | ATK | Attack power | | DEF | Defense (reduces damage taken) | | Accuracy | Hit chance modifier | | Dodge | Evasion chance | **Home Base**: - Set by player, 20-meter radius (`HOME_BASE_RADIUS`) - 3x HP regeneration when at home - Required to respawn after death - Skill loadout can only be changed at home **Fog of War**: - Canvas-based overlay that hides unexplored areas - Two reveal zones: homebase radius and player explore radius - Geocaches only visible/interactable in revealed areas - Multipliers can modify reveal radius (via utility skills) - Hard-edged cutout (no gradient layers) **Virtual Movement Mode**: - Developer/testing feature for moving without real GPS - WASD/arrow keys move virtual position on map - Winch tethering system: walking away from virtual position reels it back - Prevents unlimited virtual exploration - real GPS movement matters - Toggle via developer tools panel ### Combat System **Monster Spawning**: - Monsters spawn while walking (configurable distance) - No spawns within home base radius - Multiple monsters can accumulate (entourage) - Spawn sound effect plays when monster appears (`sfx/` directory) **Combat Flow**: 1. Player taps monster to engage 2. Turn-based combat with skill selection 3. Hit/miss calculated per skill accuracy 4. XP awarded on victory 5. Death sends player to respawn state **Damage Formula**: ```javascript damage = (skillPower * playerATK / 100) - enemyDEF hitChance = skillAccuracy + (attackerAccuracy - 90) - defenderDodge ``` **Animation System** (`animations.js`): - Separate file defines all combat animations - Player animations: `attack`, `skill`, `miss`, `death` - Monster animations: `attack`, `skill`, `miss`, `death`, `idle`, `bouncy`, various flips - Each animation has: `duration`, `loop`, `easing`, `keyframes` - Combat timing syncs damage with animation "hit" moment (500ms delay) - Skills can override default animation via `animation` field ### Skill System **Skill Tiers**: Skills unlock at level milestones (2, 3, 4, 5, 6, 7) **Skill Types**: - `damage`: Deal damage to enemies - `heal`: Restore HP - `buff`: Temporary stat boosts (defense, accuracy) - `utility`: Out-of-combat effects (MP regen boost) - `status`: Apply effects like poison **Loadout System**: - On level-up: ALL offered skills unlock, player picks one to activate - `unlockedSkills`: Everything learned - `activeSkills`: Currently equipped (one per tier) - Swap active skills at home base only See `SKILLS.md` for complete skill reference. **Custom Skill Icons**: - Upload via admin panel (`/admin.html`) - Stored in `mapgameimgs/skills/` directory - Database field: `skills.icon` stores filename - Falls back to emoji if no custom icon set ### Classes **Trail Runner** (currently the only class): | Base Stat | Value | Per Level | |-----------|-------|-----------| | HP | 100 | +10 | | MP | 50 | +5 | | ATK | 12 | +2 | | DEF | 8 | +1 | | Accuracy | 90 | - | | Dodge | 15 | - | ### Races | Race | HP | MP | ATK | DEF | |------|-----|-----|-----|-----| | Human | +5 | +5 | +0 | +0 | | Elf | -5 | +15 | +0 | -2 | | Dwarf | +15 | -5 | +0 | +3 | | Halfling | -5 | +0 | +2 | +5 | ### Monsters **Current Monster Types**: | Monster | Level Range | Notes | |---------|-------------|-------| | Moop | 1-5 | Basic enemy | | Fancy Moop | 1-5 | Higher ATK | | Fanciest Moop | 3-5 | Stronger variant | | Sub Par Moop | 1-1 | Very weak, tutorial enemy | *MOOP = Matter Out Of Place (litter-themed enemies)* --- ## Database Schema (database.js) ### Key Tables **Users & Auth**: - `users`: id, username, password_hash, is_admin, created_at **RPG Stats**: - `rpg_stats`: player_id, name, race, class, level, xp, hp, maxHp, mp, maxMp, atk, def, home_base_lat/lng, unlocked_skills, active_skills, is_dead, home_base_icon **Skills**: - `skills`: id, name, description, type, mp_cost, base_power, accuracy, hit_count, target, status_effect - `class_skills`: Links skills to classes with unlock_level and choice_group - `class_skill_names`: Class-specific skill renames **Monsters**: - `monster_types`: id, name, icon, base_hp/atk/def, xp_reward, level scaling, dialogues **Buffs**: - `player_buffs`: Active buffs with expiry times (e.g., Second Wind) ### Important Methods ```javascript // database.js key methods db.getRpgStats(userId) // Get player stats db.saveRpgStats(userId, stats) // Save player stats db.resetUserProgress(userId) // Admin: reset player db.swapActiveSkill(userId, tier, newSkillId) // Swap loadout ``` --- ## API Endpoints (server.js) ### Authentication | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/auth/register` | Create account | | POST | `/api/auth/login` | Login, returns JWT | ### RPG | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/user/has-character` | Check if character exists | | POST | `/api/user/character` | Create character | | GET | `/api/user/rpg-stats` | Get player stats | | PUT | `/api/user/rpg-stats` | Save player stats | | POST | `/api/user/swap-skill` | Swap active skill (at home) | | POST | `/api/user/activate-buff` | Activate utility skill | | GET | `/api/user/buffs` | Get active buffs | ### Game Data | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/skills` | All skills | | GET | `/api/classes` | All classes with skills | | GET | `/api/monster-types` | All monster types | | GET | `/api/spawn-settings` | Monster spawn config | ### Admin | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/admin/reset-progress/:userId` | Reset player | | POST | `/api/admin/reset-homebase/:userId` | Clear home base | | PUT | `/api/admin/spawn-settings` | Update spawn config | --- ## Frontend Structure (index.html) ### Line Ranges (approximate) | Lines | Content | |-------|---------| | 1-3000 | CSS styles | | 3000-3700 | HTML structure | | 3700-4500 | Constants, state, skill definitions | | 4500-10000 | Map, track editing, geocaches | | 10000-11000 | Character creation, sheet | | 11000-12000 | Stats management, saving | | 12000-13500 | Combat system, monsters | ### Key State Variables ```javascript // RPG State playerStats // Player RPG data combatState // Active combat info monsterEntourage // Spawned monsters statsLoadedFromServer // Prevents stale saves pendingSkillChoice // Level-up skill selection // GPS & Virtual Movement userLocation // Current position (real or virtual) realGpsPosition // Actual GPS coordinates testPosition // Virtual position when in test mode gpsTestMode // Virtual movement enabled flag previousWinchRealGps // Winch system - tracks real GPS for tethering // Fog of War fogCanvas // Canvas element for fog overlay fogCtx // 2D context for fog drawing fogSystemReady // Flag indicating fog can render exploreRadiusMultiplier // Skill-modified explore radius homebaseRadiusMultiplier // Skill-modified homebase radius ``` ### Key Functions ```javascript // RPG & Combat initializePlayerStats(username) // Load from server savePlayerStats() // Save to server showSkillChoiceModal(level) // Level-up skill pick swapSkillFromHomebase(tier, id) // Change loadout startCombat(monsters) // Begin combat useSkill(skillId) // Execute skill in combat // Fog of War updateFogOfWar() // Redraw fog overlay isInRevealedArea(lat, lng) // Check if location visible initFogOfWar() // Create fog canvas // Virtual Movement & Winch enableVirtualMovement() // Enter virtual GPS mode disableVirtualMovement() // Return to real GPS simulateGpsPosition() // Update map with virtual position applyWinchTether(newRealPosition) // Reel in virtual when walking away // Animations (from animations.js) getAnimation(animationId) // Get animation definition getAnimationList() // List monster animations getPlayerAnimationList() // List player animations ``` --- ## Data Persistence **Server-Authoritative Model**: 1. On page load, fetch stats from server 2. `statsLoadedFromServer` flag prevents premature saves 3. Auto-save every 30 seconds after initial load 4. `beforeunload` uses `sendBeacon` for reliable final save 5. localStorage used as read-only backup **Critical**: Never save to server until `statsLoadedFromServer = true` --- ## Common Tasks ### Adding a New Skill 1. Insert into `skills` table (database.js or admin panel) 2. Add to `class_skills` with unlock_level and choice_group 3. Optionally add class rename in `class_skill_names` 4. Add icon/calculate function in `SKILLS` constant if special behavior needed ### Adding a New Class 1. Insert into `classes` table 2. Create `class_skills` entries for skill progression 3. Add `class_skill_names` for thematic renames 4. Update `getClassIcon()` for display ### Adding a New Monster 1. Insert into `monster_types` via admin panel or database 2. Set level range, stats, dialogues 3. Optionally add to `monster_skills` for special abilities --- ## Troubleshooting ### Docker: Restart vs Rebuild Most source files are **volume-mounted** in `docker-compose.yml`, so changes are reflected without rebuilding. **Action required by file type:** | File | Action | Notes | |------|--------|-------| | `index.html` | **Rebuild container** | Volume mount may not sync live | | `admin.html` | **Rebuild container** | Volume mount may not sync live | | `service-worker.js` | **Rebuild container** + bump cache version | Volume mount may not sync live | | `server.js` | **Rebuild container** | Volume mount may not sync live | | `database.js` | **Rebuild container** | Volume mount may not sync live | | `mapgameimgs/*` | Browser refresh | Volume-mounted | | `mapgamemusic/*` | Browser refresh | Volume-mounted | | `sfx/*` | Browser refresh | Volume-mounted | | `hikemap.db` | Nothing | Volume-mounted, persists outside container | **IMPORTANT**: Despite being volume-mounted, code files (`index.html`, `server.js`, etc.) often require a container rebuild to reflect changes. Always rebuild when in doubt. **Files requiring full rebuild** (`docker-compose up -d --build`): | File | Why Rebuild? | |------|--------------| | `package.json` | New npm dependencies need installing | | `Dockerfile` | Build process changes | | `manifest.json` | Not volume-mounted | | `icon-*.png` | Not volume-mounted | | `.env` | Not volume-mounted | | `.well-known/*` | Not volume-mounted | | `default.kml` | Not volume-mounted | | `docker-compose.yml` | Container config changes | **Commands:** ```bash # Restart container (fast - for server.js/database.js changes) docker restart hikemap_hikemap_1 # Full rebuild (slow - only when needed) docker-compose up -d --build # If rebuild fails with volume errors: docker ps -a | grep hike # Find container ID docker rm docker-compose up -d --build ``` ### Cache Issues After server-side changes, users may need to clear browser cache: 1. Increment `CACHE_NAME` version in `service-worker.js` 2. Hard refresh in browser (Ctrl+Shift+R) 3. Or clear site data in browser DevTools ### Common Issues **"Changes not appearing after edit"** - Client files (html/js): Just refresh browser - Server files (server.js, database.js): Run `docker restart hikemap_hikemap_1` - Did you bump the service worker cache version? **"API returns old data"** - Check container is running: `docker ps | grep hike` - Restart container: `docker restart hikemap_hikemap_1` - Check container logs: `docker logs hikemap_hikemap_1` **"Database changes lost after rebuild"** - The `hikemap.db` file is mounted as a volume and persists - Schema changes are applied via migrations in `database.js` on startup