# Handoff Report — Client Map Explorer

## 1. Observation

1. **`client/webapp/js/engine/world_renderer.js` lines 12–28**:
   ```javascript
   const camObj = (typeof camera !== 'undefined' && camera) ? camera : (typeof window !== 'undefined' ? window.camera : null);
   const camWx = (camObj && Number.isFinite(camObj.wx)) ? Math.round(camObj.wx) : 0;
   const camWy = (camObj && Number.isFinite(camObj.wy)) ? Math.round(camObj.wy) : 0;
   const tileRadius = Math.ceil(Math.max(viewport.clientWidth, viewport.clientHeight) / (TILE_H * 2)) + 2;
   for (let x = camWx - tileRadius; x <= camWx + tileRadius; x++) {
     for (let y = camWy - tileRadius; y <= camWy + tileRadius; y++) {
       const pt = worldToIso(x, y);
       if (pt.x < -TILE_W || pt.x > viewport.clientWidth + TILE_W || pt.y < -TILE_H || pt.y > viewport.clientHeight + TILE_H) continue;
       let tileImg = ASSETS['tile_grass'];
       if (Math.abs(x - y) <= 1) tileImg = ASSETS['tile_stone'];
       else if (Math.hypot(x - 5, y - (-3)) < 3.2) tileImg = ASSETS['tile_water'];
       if (tileImg && tileImg.complete) {
         ctx.drawImage(tileImg, pt.x - TILE_W / 2, pt.y - TILE_H / 2, TILE_W, TILE_H);
       }
     }
   }
   ```
   Observed that tiles are generated purely from math formulas (`Math.abs(x - y) <= 1`, `Math.hypot(...) < 3.2`) with $2,025$ loop iterations per frame on a 1280×720 viewport. Followed by a static 1440×960 image `vltk1_terrain` at lines 30–40.

2. **`client/webapp/js/engine/iso_math.js` lines 94–153**:
   - `TILE_W = 64`, `TILE_H = 32`.
   - `worldToIso(wx, wy, wz = 0)` projects via `(relWx - relWy) * 32 + cx` and `(relWx + relWy) * 16 + cy`.
   - `isoToWorld(screenX, screenY)` inverts back to `relWx = (sx/32 + sy/16)/2`, `relWy = (sy/16 - sx/32)/2`.
   - `updateCamera` (lines 98–125) smooths camera tracking with exponential lerp (`followSpeed = 6.5`, `deadzone = 0.35`) clamped to zone bounds.

3. **`client/webapp/js/engine/collision_engine.js` lines 88–179**:
   - `isPositionBlocked(wx, wy, radius = 0.35, isDodge = false)` checks boundary clamping against `ZONE_BOUNDS`, sanctuary water radius, and `mapProps` solid footprints. It currently has NO tile grid checks.
   - `resolveMovementWithSliding` (lines 148–179) performs smooth 2-axis (X-then-Y) movement decomposition when obstructed, delegating all obstacle checks to `isPositionBlocked`.

4. **`client/webapp/js/engine/monster_system.js` & `wilderness_zone_packs.js`**:
   - In `wilderness_zone_packs.js` lines 8–47, monster packs have hardcoded coordinates: e.g. `wx: 9.5, wy: -4.5`.
   - In `monster_system.js` lines 255–259:
     ```javascript
     const step = dt * 1.8;
     m.wx += ((player.wx - m.wx) / distToPlayer) * step;
     m.wy += ((player.wy - m.wy) / distToPlayer) * step;
     ```
     Monsters move directly in a straight line toward the player without any tile collision checks, phasing through walls.

5. **`client/webapp/index.html` lines 26–178**:
   - The top header has a left status card, center telemetry island, and right action buttons.
   - The area immediately below the top header on the right side (`top-12 right-3`) is clear of UI elements and provides an ideal location for the 120×80px Minimap canvas container.
   - `#modal-container` and `#overlay-pause` exist for modal and overlay mounting.

6. **Server Baseline & Existing Tests**:
   - `server/world/procedural_map_engine.py` (396 lines) and `map_data_types.py` (176 lines) already define `TileType` (VOID=0, FLOOR=1, WALL=2, etc.) and `ProceduralMapEngine`.
   - `pytest tests/unit/test_war_fog_and_procedural_map.py` passes 20/20 unit tests in 0.82s.

---

## 2. Logic Chain

1. **Terrain Replacement Feasibility**:
   - From Observation 1 and 2, 1 world unit equals 1 isometric tile (`TILE_W=64, TILE_H=32`).
   - Therefore, integer coordinates `tx = Math.floor(wx)`, `ty = Math.floor(wy)` map 1:1 to tile grid indices.
   - Replacing lines 12–40 of `world_renderer.js` with tile grid lookups (`window.currentMapGrid[ty * width + tx]`) requires no changes to the camera or projection mathematics in `iso_math.js`.

2. **Tile Collision & Smooth Sliding**:
   - From Observation 3, character movement and wall sliding are completely driven by `resolveMovementWithSliding`, which relies solely on `isPositionBlocked(wx, wy)`.
   - By adding tile lookup `(floor(wx), floor(wy))` and radial boundary checks in `isPositionBlocked`, character movement instantly gains full tile-level collision and smooth wall-sliding without requiring changes to player input or physics loops.

3. **Fog of War & Masking Dynamic Entities**:
   - From Observation 1 and 4, `entity_renderer.js` sorts and draws monsters.
   - By reading `window.fogGrid[mobTy * width + mobTx]`, any monster in `UNEXPLORED` (0) or `EXPLORED_FOGGED` (1) can be skipped during rendering, fulfilling the requirement that monsters are invisible in fogged areas without leaking state.

4. **Mobile RAM Footprint & Chunk Cache**:
   - In a $120 \times 90$ map, caching all 48 chunks of $16 \times 16$ tiles in `OffscreenCanvas` ($1024 \times 512 \times 4$ bytes = 2.0 MB each) would require 96 MB of RAM, violating the 8 MB mobile budget.
   - However, on mobile viewports (e.g. $844 \times 390$ or $1280 \times 720$), at most 2–4 chunks are visible at any time.
   - Implementing an LRU active chunk pool of 3–4 `OffscreenCanvas` instances consumes only $6.0 \text{ to } 7.2 \text{ MB}$, strictly meeting the $\le 8 \text{ MB}$ limit while reducing canvas draw calls per frame by $> 98\%$.

5. **Encounter Progression & Boss Gate Logic**:
   - From Observation 4, monster kills already execute `target.hp <= 0` in `combat_skills.js`.
   - Hooking pack elimination into `window.zoneEncounterProgress[zoneId]` allows automatic state mutation of the `BOSS_GATE` tile from blocked (10) to walkable floor (1) when kill thresholds are satisfied.

---

## 3. Caveats

1. **Safe Haven Zones**: `zone_boundless_sanctuary` and `zone_player_hideout` contain custom interactive props (Map Device, Vạn Giới Giới Môn, Waypoint). These zones should either retain their existing visual props or be mapped to a clean sanctuary tile layout so existing interactive coordinates remain valid.
2. **Sprite Sheet Assets**: If custom tile sprites are not yet bundled into an image atlas, the tile renderer must include robust procedural canvas fallbacks (colored isometric diamonds with biome styling) so the game renders cleanly regardless of asset availability.
3. **Network Binary Transport**: When streaming tile grids over WebSocket, transmitting as a raw binary buffer (`Uint8Array`) requires protocol support on the WebSocket client handler (`ws.binaryType = 'arraybuffer'`) or a lightweight base64 fallback.

---

## 4. Conclusion

The client codebase is well-structured and ready for tile-based procedural map rendering:
- The isometric projection math in `iso_math.js` perfectly supports $1 \text{ world unit} = 1 \text{ tile}$.
- The collision architecture in `collision_engine.js` allows seamless injection of tile passability checks into `isPositionBlocked` while preserving smooth wall-sliding.
- The HUD structure in `index.html` has clear space at `top-12 right-3` for the 120×80 Minimap canvas and `top-16` for the Boss Gate lore popup.
- An LRU-bounded chunk cache pool of 3–4 `OffscreenCanvas` instances guarantees the $\le 8 \text{ MB}$ RAM budget and drops draw calls to 2–4 per frame.

---

## 5. Verification Method

1. **Procedural Map Test Suite**:
   ```bash
   pytest tests/unit/test_war_fog_and_procedural_map.py
   ```
   *Expected*: All 20 tests pass.
2. **New Tile Collision Unit Tests**:
   Once implemented, execute:
   ```bash
   pytest tests/unit/test_tile_collision.py
   ```
   *Expected*: $\ge 10$ test cases covering WALL collision, FLOOR walkability, BOSS_GATE locked/unlocked states, and boundary clamps, all passing.
3. **Map Render Performance Benchmark**:
   ```bash
   node tools/perf/map_render_benchmark.js
   ```
   *Expected*: Average FPS $\ge 30$, draw calls $\le 4$ per frame, and memory consumption $\le 8 \text{ MB}$.
4. **Invalidation Conditions**:
   - If total chunk memory exceeds 8 MB (indicating unconstrained canvas allocation without LRU eviction).
   - If player clips or phases through `WALL` or locked `BOSS_GATE` tiles.
   - If monsters in `EXPLORED_FOGGED` tiles remain visible on screen.
