UI structure¶
Overview¶
The app uses a React + PixiJS hybrid: React renders screens (Menu, New Game, Settings) and the game layout shell; PixiJS renders the isometric map inside a canvas. Entry point: src/client/react/main.tsx → App.tsx → init() from main.ts. When useReactLayout: true (default), the game screen shows only the map in Pixi; sidebar and footer are React components. GameBridge (GameUIApi) exposes IsometricMap API to React; StorageDriver abstracts localStorage/sessionStorage for persistence.
Screens¶
| Screen | Path | Description |
|---|---|---|
| Menu | react/screens/MenuScreen.tsx |
Main menu, New Game, Settings |
| New Game | react/screens/NewGameScreen.tsx |
Configure map, start game |
| Loading | react/screens/LoadingScreen.tsx |
Loading progress (React) |
| Singleplayer | Pixi + GameFooter + GameOverlays |
Map full width, footer + overlays |
| Settings | react/screens/SettingsScreen.tsx |
Tabs: Game, Graphics, Audio |
| Coming Soon | react/screens/ComingSoonScreen.tsx |
Placeholder for multiplayer |
Navigation¶
- NavigationManager – uses
window.location.hash(#menu,#singleplayer,#settings/graphics) - ScreenStateManager – persists last screen in
localStorage - NavigationManager.onNavigate(screen, callback) – register listeners per screen
- NavigationManager.navigateTo(screen, pushToHistory, tab) – navigate
Game screen layout¶
Legacy (sidebar): Sidebar left ⅕, GameArea center, Footer bottom.
React layout (default): Sidebar removed; map full width; footer fixed at bottom; overlays float above map.
┌─────────────────────────────────────────────────────────┐
│ GameArea (map, full width) │ Menu │ FPS │ Mini │
│ │Speed │ Dev │ map │
│ Overlays: Menu, Speed, Dev, FPS, ├──────┴─────┴──────┤
│ Minimap, SelectionPanel (draggable) │ SelectionPanel │
├──────────────────────────────────────┴───────────────────┤
│ Footer (fixed height ~220px) │
│ Tabs: Order manager | Colonists | Jobs │
└─────────────────────────────────────────────────────────┘
GameArea¶
- Wraps IsometricMap (map, camera, zones, objects, jobs)
- Handles map click → object selection, area selection
- Passes selection to sidebar via
handleObjectSelection(objectData, panelType) - Shows TileSelectorModal for tile-based actions
- Right-click (PPM) on map: context menu (object actions e.g. Chop/Mine, or "Move here" / "Run here" when colonist is selected). Orders from this menu are assigned to the selected colonist.
- selectedColonistId – set when colonist is selected (from map click or footer list); required for right-click "Move here" / "Run here". In React layout,
GameOverlays.onSelectionChangecallssetSelectedColonistIdfortype: 'citizen', and clears it when selection changes or panel closes.
Sidebar¶
- Position: Left, ⅕ of screen width
- Content: Menu button, Minimap, SpeedControls, single panel slot
- Panels (one visible at a time):
| Panel | Type | Shows when |
|---|---|---|
| InfoPanel | citizen |
Colonist selected |
| WorkshopPanel | workshop |
Workshop/structure selected |
| ObjectPanel | object |
Tree, stone, resource selected |
| ZonePanel | zone |
Zone selected (also as overlay) |
| AreaSelectionPanel | area-selection |
Area selection mode active |
- Zone overlay – ZonePanel content drawn above sidebar when a zone is selected
- Dev panel – Tile selector, place colonist (toggle via DEV button)
Footer¶
- Position: Bottom, ~18% of height
- Tabs: Order manager, Colonists, Jobs
- Order manager – CategoriesPanel (¼) + OrdersGrid (¾) for placing orders
- Colonists – ColonistsPanel (list of colonists)
- Jobs – JobsPanel (pending jobs)
Panels¶
| Panel | Purpose |
|---|---|
| InfoPanel | Colonist: name, skills, needs, job preferences, body parts |
| WorkshopPanel | Structure: production, recipes |
| ObjectPanel | Object: name, actions (chop, mine) |
| ZonePanel | Zone: type, remove, storage summary |
| AreaSelectionPanel | Area selection: confirm/cancel, bounds |
| CategoriesPanel | Order categories (Orders, Structures, etc.) |
| OrdersGrid | Order buttons (Chop, Mine, etc.) |
| ColonistsPanel | Colonist list, select → InfoPanel |
| JobsPanel | Pending jobs list |
| Minimap | Small map overview, click to move camera |
| SpeedControls | 1x, 2x, 3x game speed |
Generic components¶
In components/generic/:
- Panel – rounded rect background
- Button, Checkbox, Toggle, Slider, Dropdown
- Tooltip – hover tooltip
- ProgressBar, Separator
- Modal – overlay modal
- TabButton – tab-style button
- FPSCounter – fps display
React layout (useReactLayout)¶
When useReactLayout is true (default):
- Sidebar removed – map occupies full width; Pixi GameArea has
sidebarWidth: 0 - Footer – React
GameFooterat bottom (Order manager, Colonists, Jobs tabs) - Overlays – React
GameOverlaysrenders draggable panels above the map (pointer-events: noneon wrapper, panels useautowhere needed) - GameBridge –
onGameReady(api)passesGameUIApito React; selection events viaonSelectionChange, map actions viaexecuteAction,setColonistJobAllowed, etc. - Canvas reparenting – on Singleplayer, canvas moves into
centerRef; on other screens, intofullscreenRef
Overlays (DraggableOverlayPanel)¶
| Overlay | storageKey | Resizable | Purpose |
|---|---|---|---|
| MenuOverlay | (fixed) | no | Menu button (top-left) |
| MinimapOverlay | simu-game-minimap | yes | Map thumbnail, click-to-jump; resize handle |
| FpsOverlay | simu-game-fps | no | FPS counter |
| ZoomOverlay | simu-game-zoom | no | Zoom ± buttons |
| SpeedOverlay | simu-game-speed | no | 1x, 2x, 3x speed |
| DevOverlay | simu-game-dev | no | Tile selector, Place colonist, Clear tile, etc. |
| SelectionPanelOverlay | simu-game-selection-panel | yes | Colonist/Zone/Object/Area panel (draggable, closable) |
- Position/size/collapsed persisted via StorageDriver (sessionStorage by default)
DraggableOverlayPanel– header with label, drag handle, collapse (−/▶), optional close (X), optional resize handle
Minimap¶
- Sidebar mode: Inside sidebar, below menu button
- Overlay mode (React layout): Top-right of canvas; header with collapse/drag; position + collapsed state persisted in sessionStorage
- Implementation:
getBounds()+ proportional position; hitArea blocks map clicks - See minimap.md for full technical details
Z-index (GameScreen)¶
- GameArea: 1
- Sidebar: 100
- Zone overlay: 200
- Minimap overlay (React): 5000
- FPS counter: 9999
- Tooltip: 10000
UIScaleManager¶
- Single instance, scales fonts/boxes/images for accessibility
onScaleChange(callback)– when scale changes,createGameUIis re-run- Panel sizes (sidebar width, footer height) stay fixed; internal elements scale
StorageDriver¶
src/client/storage/StorageDriver.ts– abstractsgetItem(key),setItem(key, val)for persistence- Default:
localStorage(orsessionStoragefor minimap overlay) - Used by: minimap position, overlay positions, UI scale, session data
- Swappable via
setStorageDriver()ininit()
Key files (React layout)¶
| File | Role |
|---|---|
react/main.tsx |
Entry, mounts App in #root |
react/App.tsx |
Layout, init(), screen routing, canvas reparent |
GameBridge.ts |
GameUIApi, SelectionEvent types |
react/game/GameFooter.tsx |
Order manager, Colonists, Jobs tabs |
react/game/overlays/GameOverlays.tsx |
Overlay container, selection → panel |
react/game/overlays/DraggableOverlayPanel.tsx |
Generic draggable panel |
react/game/panels/*.tsx |
ColonistPanel, ZonePanel, ObjectPanel, AreaSelectionPanel |