Minimap¶
Overview¶
The Minimap (src/client/ui/components/sidebar/Minimap.ts) displays a thumbnail of the map and allows clicking to jump the camera. It appears in two modes:
- Sidebar mode – inside the sidebar (classic layout)
- Overlay mode – top-right corner of the canvas (React layout,
useReactLayout: true)
In overlay mode, the minimap has a header with:
- Collapse/expand button (right side) – click to hide or show the map content (− / ▶)
- Drag handle – drag the header to reposition the minimap anywhere on the canvas (uses window.addEventListener for move/up so drag works when pointer leaves the canvas)
Persistence¶
Position and collapsed state are saved to sessionStorage under simu-game-minimap-overlay:
- Save: on drag end and on collapse/expand toggle
- Restore: in loadMinimap() when overlay mode (restoreOverlayState())
- Stored: { x, y, collapsed }
- sessionStorage = per-tab; clears when tab is closed
Click-to-jump implementation¶
Coordinate conversion (final approach)¶
Clicks are converted to tile coordinates using proportional position within the sprite's world bounds:
bounds = sprite.getBounds() // world-space AABB
relX = (globalX - bounds.x) / bounds.width // 0..1
relY = (globalY - bounds.y) / bounds.height
tileX = relX * mapDimensions.width
tileY = relY * mapDimensions.height
Why not toLocal()? Pixi has multiple coordinate spaces (canvas pixels, resolution, stage). toLocal() and manual formulas mixed these, causing wrong teleports (e.g. center click → bottom-right). Using getBounds() + proportional 0–1 avoids coordinate system mismatches.
Click source: We use Pixi's event.global (or event.globalX/event.globalY) – it matches the space used by getBounds().
Map intercepting clicks (overlay mode)¶
In overlay mode, the main map could intercept minimap clicks. Fixes:
- Minimap sprite
eventMode = 'static'-
hitArea = new Rectangle(0, 0, texture.width, texture.height)– full rect so transparent pixels also receive clicks -
Minimap container (overlay only)
eventMode = 'static'-
hitArea = Rectangle(...)covering the whole overlay – blocks map from hit-testing underneath -
MapInputHandler
- New
getExcludeOverlayBoundsdep – returns minimap rect in canvas space - On window
pointerup, if pointer is inside that rect → skip map click handling - GameScreen calls
isometricMap.setExcludeOverlayBounds(() => minimapContainer.getBounds())
Debug¶
Enable via:
Disable:
Logs: client coords, global coords, sprite bounds, relative %, tile coords.
Files¶
| File | Role |
|---|---|
Minimap.ts |
Minimap component, header (collapse/drag), click handling, viewport box, persistence |
GameScreen.ts |
Creates overlay minimap when useReactLayout, passes clientToCanvasCoords, sets setExcludeOverlayBounds |
MapInputHandler.ts |
getExcludeOverlayBounds – skips map processing when pointer over minimap |
IsometricMap.ts |
setExcludeOverlayBounds(getter) |
GameSidebar.tsx |
React sidebar – removed minimap spacer; speed controls moved up |
Previous attempts (for reference)¶
- clientToCanvasCoords – converts
(clientX, clientY)to canvas internal pixels; used for window pointerup, not for minimap coordinate conversion - canvasToStageCoords – converting canvas → stage pixels; assumption about stage size was wrong, caused incorrect coords
- toLocal() – depends on correct global/stage coords; mixing canvas pixels with stage caused ~2x error (center → bottom-right)