From 87f68044b45e7de62f1f93ca9a5f3394aefb79a1 Mon Sep 17 00:00:00 2001 From: jedarden Date: Thu, 23 Apr 2026 00:30:46 -0400 Subject: [PATCH] =?UTF-8?q?feat(replay):=20add=20fog-of-war=20perspective?= =?UTF-8?q?=20toggle=20and=20minimap=20per=20=C2=A77.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add perspective dropdown (Omniscient + per-player) that filters the replay view to a single player's fog of war, hiding cells/bots outside their vision radius. Add minimap canvas in the corner showing the full grid with walls, energy, cores, bots, fog overlay, and a viewport rectangle. Clicking the minimap pans the main canvas and zooms in. Co-Authored-By: Claude Opus 4.7 --- web/index.html | 26 +++++++- web/src/main.ts | 9 ++- web/src/pages/replay.ts | 14 +++- web/src/replay-viewer.ts | 138 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 4 deletions(-) diff --git a/web/index.html b/web/index.html index 5ae0ef1..595bfba 100644 --- a/web/index.html +++ b/web/index.html @@ -214,6 +214,27 @@ font-family: monospace; } + /* Minimap (§7.3) */ + .minimap-container { + position: absolute; + bottom: 16px; + right: 16px; + border: 2px solid #475569; + border-radius: 6px; + overflow: hidden; + box-shadow: 0 4px 12px rgba(0,0,0,0.5); + opacity: 0.85; + transition: opacity 0.2s; + z-index: 10; + } + .minimap-container:hover { + opacity: 1; + } + #minimap-canvas { + display: block; + cursor: crosshair; + } + /* Transcript panel styles (§15.3) */ .transcript-panel { position: fixed; @@ -360,9 +381,12 @@
-
+
Load a replay file to view
+
+ +
diff --git a/web/src/main.ts b/web/src/main.ts index c3f4382..e704315 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -40,6 +40,12 @@ let transcriptViewModeValue: 'all' | 'window' | 'recent' = 'all'; // Initialize viewer let viewer = new ReplayViewer(canvas, { cellSize: 16 }); +// Wire up minimap canvas (§7.3) +const minimapCanvas = document.getElementById('minimap-canvas') as HTMLCanvasElement; +if (minimapCanvas) { + viewer.setMinimapCanvas(minimapCanvas); +} + // Enable controls when replay is loaded function enableControls(): void { playBtn.disabled = false; @@ -92,7 +98,7 @@ function updateMatchInfo(replay: Replay): void { } // Update fog of war options - fogSelect.innerHTML = ''; + fogSelect.innerHTML = ''; replay.players.forEach((player, idx) => { const option = document.createElement('option'); option.value = String(idx); @@ -196,6 +202,7 @@ cellSizeSelect.addEventListener('change', () => { viewer = new ReplayViewer(canvas, { cellSize: size }); viewer.onTurnChange = () => { updateUI(); updateEventLog(); updateTranscriptHighlight(); }; viewer.onPlayStateChange = (playing) => { playBtn.textContent = playing ? 'Pause' : 'Play'; }; + if (minimapCanvas) viewer.setMinimapCanvas(minimapCanvas); loadReplay(replay); } }); diff --git a/web/src/pages/replay.ts b/web/src/pages/replay.ts index e762281..93f664f 100644 --- a/web/src/pages/replay.ts +++ b/web/src/pages/replay.ts @@ -64,6 +64,9 @@ function initReplayViewerWithClass(ReplayViewerClass: any, initialUrl?: string):
Load a replay file to view
+
+ +
@@ -177,7 +180,7 @@ function initReplayViewerWithClass(ReplayViewerClass: any, initialUrl?: string):