# Project: FreeExile PoE2-Style Procedural Tile Map System Overhaul

## Architecture
- **Server Procedural Generation Layer**:
  - `server/world/wilderness_map_generator.py`: Generates organic open-world tile maps from `(zone_id, seed, biome_id)` for wilderness zones ($60 \times 45$ up to $120 \times 90$) with winding main path, 2–3 encounter zones, 1–2 rewarded dead ends, sealed boss gate, 1–3 POIs, and guaranteed 8-tile radius safe floor clearing at spawn.
  - `server/world/map_binary_serializer.py`: Compact binary serializer encoding map grids into `Uint8Array` byte streams (16-byte fixed header + POI table + encounter table + 1-byte/tile payload).
  - `server/world/map_data_types.py`: Unified `TileType` enumeration with 20 codes (0–19: VOID, FLOOR, WALL, obstacles, PATH, DENSE_TERRAIN, POI, ENCOUNTER_LOW/MED/HIGH, WATER).
  - `server/world/procedural_map_engine.py`: Procedural map facade routing dungeon vs wilderness generation.
  - `server/world/zone_engine.py`: Server-authoritative spawn validation enforcing tile passability and safe haven purity.
- **Client Tile Rendering & Caching Layer**:
  - `client/webapp/js/engine/tile_map_renderer.js`: Viewport frustum culling, $16 \times 16$ tile chunk pre-rendering via active LRU `OffscreenCanvas` pool (3–4 instances to strictly guarantee $\le 8\text{ MB}$ RAM on mobile), dirty flag chunk re-baking, and draw call limitation $\le (viewport_W / TILE_W + 5) \times (viewport_H / TILE_H + 5)$.
  - `client/webapp/js/engine/world_renderer.js`: Replaces legacy hardcoded math formulas with data-driven tile map rendering, preserving Map Device, Waypoint safe rings, and interactive props.
  - `client/webapp/js/engine/iso_math.js`: 2:1 isometric coordinate projection ($1 \text{ world unit} = 1 \text{ tile}$, $tx = \lfloor wx \rfloor, ty = \lfloor wy \rfloor$).
- **Collision & Boss Gate Layer**:
  - `client/webapp/js/engine/collision_engine.js`: `isPositionBlocked(wx, wy, radius)` tile lookup blocking `WALL`, `CHASM`, `WATER`, and locked `BOSS_GATE`, with 2-axis sliding physics (`resolveMovementWithSliding`).
  - `client/webapp/js/engine/boss_gate_controller.js`: Manages Boss Gate barrier locking, kill counter threshold verification, tile mutation to `FLOOR`, and visual seal rune rendering.
- **Fog of War & Minimap HUD Layer**:
  - `client/webapp/js/ui/war_fog.js`: Multi-state Fog of War matrix (`window.fogGrid`, $0=\text{UNEXPLORED}$, $1=\text{EXPLORED\_FOGGED}$, $2=\text{VISIBLE}$), 8-tile radius line-of-sight reveal, and `localStorage` persistence (`fe_fog_${zone_id}_${seed}`).
  - `client/webapp/js/ui/war_fog_renderer.js`: Offscreen fog shroud canvas layer with dynamic entity culling for unexplored/fogged monsters.
  - `client/webapp/js/ui/minimap_hud.js`: Dedicated $120 \times 80\text{px}$ canvas Minimap in top-right HUD with biome terrain and colored markers (Player=White, Waypoint=Green, Boss Gate=Red, POI=Yellow).
- **Encounter Zone & Monster System Layer**:
  - `client/webapp/js/engine/monster_system.js`: Terrain-anchored pack spawning dynamically distributed inside `ENCOUNTER_*` tile clusters, POI scripted ambush wave triggers, and kill tracking.
  - `client/webapp/js/engine/grid_pathfinder.js`: Lightweight BFS/A* grid pathfinder for monster chase navigation around walls and obstacles.
  - `client/webapp/js/data/wilderness_zone_packs.js`: Refactored encounter zone pack definitions.
- **Testing & Tooling**:
  - `tests/unit/test_tile_collision.py`: Unit test suite ($\ge 10$ test cases) for tile collision, wall sliding, and boss gate locking.
  - `tests/e2e/test_poe2_map_system_e2e.py`: End-to-end requirement-driven test suite (Tiers 1–4).
  - `tools/perf/map_render_benchmark.js`: Mobile rendering benchmark script validating average FPS $\ge 30$, draw calls $\le 4$, and RAM $\le 8\text{ MB}$.

---

## Feature Inventory
| # | Feature | Description | Milestone | Source |
|---|---------|-------------|-----------|--------|
| 1 | Seed-based Procedural Map Generation | Wilderness layout generation with rooms, paths, and biomes | M1 | ORIGINAL_REQUEST §R1 |
| 2 | Compact Uint8Array Serialization | 1-byte/cell contiguous row-major binary wire format | M1 | ORIGINAL_REQUEST §R1 |
| 3 | Spawn Safe Area Floor Guarantee | Radius 8.0 clearing of pure FLOOR around player spawn | M1 | ORIGINAL_REQUEST §R1 |
| 4 | Guaranteed Sinuous Main Path | Main path from spawn to boss gate with sinuosity $\ge 1.25$ | M1 | ORIGINAL_REQUEST §R1 |
| 5 | Encounter Zones Classification | 2–3 dense encounter clusters (LOW/MEDIUM/HIGH) along path | M1 | ORIGINAL_REQUEST §R1 |
| 6 | Rewarded Dead-End Carving | 1–2 branching dead ends with loot cache / mini events | M1 | ORIGINAL_REQUEST §R1 |
| 7 | Isolated Boss Gate & Sealed Arena | Exactly 1 BOSS_GATE tile on sealed arena perimeter | M1 | ORIGINAL_REQUEST §R1 |
| 8 | Point of Interest (POI) Placement | 1–3 POI tiles distributed in branching chambers | M1 | ORIGINAL_REQUEST §R1 |
| 9 | Client Map Grid Ingestion | Client `window.currentMapGrid` and `getTileAt(tx, ty)` API | M1 | ORIGINAL_REQUEST §R1 |
| 10 | Viewport Frustum Culling | Tile bounding box culling based on camera with 2-tile padding | M2 | ORIGINAL_REQUEST §R2 |
| 11 | Draw Call Budget Enforcement | Draw calls $\le (viewport_W / TILE_W + 5) \times (viewport_H / TILE_H + 5)$ | M2 | ORIGINAL_REQUEST §R2 |
| 12 | 16x16 Chunk OffscreenCanvas Cache | $16 \times 16$ tile chunk pre-rendering via OffscreenCanvas | M2 | ORIGINAL_REQUEST §R2 |
| 13 | Chunk Dirty Flag Mutation | Re-render chunk only when internal tile state changes | M2 | ORIGINAL_REQUEST §R2 |
| 14 | Unified Tile Sprite Sheet Atlas | Unified sprite atlas texture with procedural color fallback | M2 | ORIGINAL_REQUEST §R2 |
| 15 | Mobile RAM Budget Compliance | Tile data + chunk cache $\le 8\text{ MB}$ via 3–4 LRU chunk pool | M2 | ORIGINAL_REQUEST §R2 |
| 16 | Legacy Math Terrain Deprecation | Replaces hardcoded math in `world_renderer.js` | M2 | ORIGINAL_REQUEST §R2 |
| 17 | Tile-Level Blocked Position Check | `isPositionBlocked(wx, wy)` checks tile passability | M3 | ORIGINAL_REQUEST §R3 |
| 18 | Dual-Axis Smooth Wall Sliding | 2-axis sliding physics preserved along tile walls | M3 | ORIGINAL_REQUEST §R3 |
| 19 | Terrain Speed Modifiers | +20% on PATH, -30% on DENSE_TERRAIN and MUD_POOL | M3 | ORIGINAL_REQUEST §R3 |
| 20 | Monster AI Grid Pathfinding | BFS/A* pathfinder for monster chase around tile walls | M3 | ORIGINAL_REQUEST §R3 |
| 21 | Boss Gate Condition & Breach Event | Boss Gate locked until kill threshold; mutates to FLOOR | M3 | ORIGINAL_REQUEST §R3 |
| 22 | Boss Gate Visual Seal Rune | Rotating glowing purple/gold seal rune at locked gate | M3 | ORIGINAL_REQUEST §R3 |
| 23 | Server-Side Spawn Validation | `zone_engine.py` validates monster spawn against tile grid | M3 | ORIGINAL_REQUEST §R3 |
| 24 | Client-Side Fog of War Matrix | `window.fogGrid` with 0=UNEXPLORED, 1=EXPLORED, 2=VISIBLE | M4 | ORIGINAL_REQUEST §R4 |
| 25 | 8-Tile Radius Fog Reveal | Real-time 8-tile radius reveal around player | M4 | ORIGINAL_REQUEST §R4 |
| 26 | Fog Persistence in LocalStorage | Persists fog under `fe_fog_${zone_id}_${seed}` | M4 | ORIGINAL_REQUEST §R4 |
| 27 | Fog Overlay Canvas Rendering | Solid black, 55% tint, and entity suppression in fog | M4 | ORIGINAL_REQUEST §R4 |
| 28 | Dedicated 120x80 Minimap HUD | $120 \times 80\text{px}$ canvas in top-right HUD | M4 | ORIGINAL_REQUEST §R4 |
| 29 | Minimap Marker Color Encoding | Player(white), Waypoint(green), Boss Gate(red), POI(yellow)| M4 | ORIGINAL_REQUEST §R4 |
| 30 | Terrain-Anchored Monster Spawning | Packs spawn inside designated `ENCOUNTER_*` tile clusters | M5 | ORIGINAL_REQUEST §R5 |
| 31 | Scripted POI Wave Ambush | Stepping within 1 tile of POI triggers scripted wave | M5 | ORIGINAL_REQUEST §R5 |
| 32 | Boss Gate Proximity Lore Popup | Lore popup displayed when player within 3 tiles of gate | M5 | ORIGINAL_REQUEST §R5 |
| 33 | Zone Encounter Progress Tracker | `window.zoneEncounterProgress` tracks pack kills | M5 | ORIGINAL_REQUEST §R5 |
| 34 | Unit Test Suite Preservation | All 894 existing unit tests continue to pass | M6 | ORIGINAL_REQUEST §AC |
| 35 | Waypoint Safe Radius Preservation | 8.0-unit immortal safe zone, 2%/s healing, monster leashing | M6 | ORIGINAL_REQUEST §AC |
| 36 | Pause Game Controller Preservation | ESC / Settings modal pause freezes loop and shows overlay | M6 | ORIGINAL_REQUEST §AC |

---

## Milestones
| # | Name | Scope | Dependencies | Status |
|---|------|-------|-------------|--------|
| E2E | E2E Testing Track | Requirement-driven test suite (Tiers 1–4), test runner, and `TEST_READY.md` publication | none | DONE |
| M1 | Procedural Tile Map Pipeline (Server to Client) | `wilderness_map_generator.py`, `map_binary_serializer.py`, `map_data_types.py` expansion, and client grid loader | none | DONE |
| M2 | Mobile-Optimized Tile Rendering | `tile_map_renderer.js`, SAT diamond culling, LRU chunk cache, benchmark script | M1 | DONE |
| M3 | Tile Collision & Boss Gate Logic | `collision_engine.js` tile checks, smooth sliding, `boss_gate_controller.js`, `test_tile_collision.py` | M1 | DONE |
| M4 | Fog of War & Minimap HUD | `war_fog.js`, `war_fog_renderer.js`, `minimap_hud.js`, HUD mounting in `index.html` | M2 | DONE |
| M5 | Encounter Zone Architecture | `monster_system.js`, `grid_pathfinder.js`, terrain pack spawning, POI wave ambush, lore popup | M1, M3 | DONE |
| M6 | Final Verification & Adversarial Hardening | 100% E2E test pass (Tiers 1–4), Tier 5 adversarial hardening, 894 unit tests regression check | E2E, M2, M3, M4, M5 | DONE |

---

## Interface Contracts
### Server Binary Serialization ↔ Client Ingestion
- Wire Format:
  - Byte 0–1: Magic `0x4645` ("FE")
  - Byte 2: Version `1`
  - Byte 3: Biome Code
  - Byte 4–5: Width $W$ (uint16 LE)
  - Byte 6–7: Height $H$ (uint16 LE)
  - Byte 8–9: Spawn $X, Y$ (uint8 each)
  - Byte 10–11: Boss Gate $X, Y$ (uint8 each)
  - Byte 12: POI Count $K$
  - Next $K \times 3$ bytes: $(x, y, type)$ per POI
  - Byte $13 + 3K$: Encounter Zone Count $E$
  - Next $E \times 5$ bytes: $(minX, minY, maxX, maxY, tier)$ per zone
  - Remaining $W \times H$ bytes: Flat row-major tile types (`Uint8Array`)
- Client API: `window.currentMapGrid`, `window.getTileAt(tx: number, ty: number): number`.

### TileMapRenderer ↔ CanvasRenderer
- `TileMapRenderer.init(mapGrid: Uint8Array, width: number, height: number, biomeId: string) -> void`
- `TileMapRenderer.render(ctx: CanvasRenderingContext2D, camera: Object, viewport: Object) -> void`
- `TileMapRenderer.markChunkDirty(tx: number, ty: number) -> void`
- `TileMapRenderer.getMemoryUsage() -> number` (bytes $\le 8\text{ MB}$)

### CollisionEngine ↔ TileMap & BossGate
- `CollisionEngine.isPositionBlocked(wx: number, wy: number, radius?: number, isDodge?: boolean) -> boolean`
- `CollisionEngine.resolveMovementWithSliding(curWx: number, curWy: number, moveDistX: number, moveDistY: number, radius?: number) -> { wx: number, wy: number, isSliding: boolean }`

### WarFog & Minimap ↔ WorldRenderer & Game Loop
- `WarFog.updatePlayerVision(playerWx: number, playerWy: number, radius?: number) -> void`
- `WarFog.getFogState(tx: number, ty: number) -> number` (0=UNEXPLORED, 1=EXPLORED, 2=VISIBLE)
- `MinimapHUD.render(playerWx: number, playerWy: number) -> void`

### MonsterSystem ↔ EncounterZones & BossGate
- `MonsterSystem.initZoneMonsters(zoneId: string, mapGrid: Uint8Array, encounterZones: Array) -> void`
- `MonsterSystem.onPackDefeated(packId: string, zoneId: string) -> void`: Increments kill count, triggers Boss Gate breach if threshold reached.

---

## Code Layout & Boundaries
- `server/world/wilderness_map_generator.py` [NEW, owned by M1 Worker, $\le 320$ lines]
- `server/world/map_binary_serializer.py` [NEW, owned by M1 Worker, $\le 160$ lines]
- `server/world/map_data_types.py` [MODIFIED, owned by M1 Worker, $\le 220$ lines]
- `server/world/procedural_map_engine.py` [MODIFIED, owned by M1 Worker, $\le 450$ lines]
- `server/world/zone_engine.py` [MODIFIED, owned by M3 Worker, $\le 490$ lines]
- `client/webapp/js/engine/tile_map_renderer.js` [NEW, owned by M2 Worker, $\le 320$ lines]
- `client/webapp/js/engine/world_renderer.js` [MODIFIED, owned by M2 Worker, $\le 450$ lines]
- `client/webapp/js/engine/collision_engine.js` [MODIFIED, owned by M3 Worker, $\le 320$ lines]
- `client/webapp/js/engine/boss_gate_controller.js` [NEW, owned by M3 Worker, $\le 200$ lines]
- `tests/unit/test_tile_collision.py` [NEW, owned by M3 Worker, $\le 300$ lines]
- `client/webapp/js/ui/war_fog.js` [MODIFIED / EXTENDED, owned by M4 Worker, $\le 300$ lines]
- `client/webapp/js/ui/war_fog_renderer.js` [MODIFIED / EXTENDED, owned by M4 Worker, $\le 250$ lines]
- `client/webapp/js/ui/minimap_hud.js` [NEW, owned by M4 Worker, $\le 280$ lines]
- `client/webapp/index.html` [MODIFIED, owned by M4 Worker, $\le 250$ lines]
- `client/webapp/js/engine/monster_system.js` [MODIFIED, owned by M5 Worker, $\le 480$ lines]
- `client/webapp/js/engine/grid_pathfinder.js` [NEW, owned by M5 Worker, $\le 220$ lines]
- `client/webapp/js/data/wilderness_zone_packs.js` [MODIFIED, owned by M5 Worker, $\le 350$ lines]
- `tools/perf/map_render_benchmark.js` [NEW, owned by M2 Worker, $\le 200$ lines]
- `tests/e2e/test_poe2_map_system_e2e.py` [NEW, owned by E2E Testing Worker, $\le 450$ lines]
