--- description: Architecture, visuals, and integration logic for the HubScreen component - the persistent main menu of the campaign globs: src/ui/screens/HubScreen.js alwaysApply: false --- # **HubScreen Component Rule** The HubScreen is the persistent "Main Menu" of the campaign where the player manages resources, units, and mission selection. It is a **View** that consumes data from the **GameStateManager** singleton. ## **Integration Architecture** ### **Data Sources** - **Wallet:** `gameStateManager.persistence.loadProfile().currency` (or similar cached state) - **Roster:** `gameStateManager.rosterManager.getDeployableUnits()` - **Unlocks:** Derived from `gameStateManager.missionManager.completedMissions` ### **Navigation Flow** 1. **Entry:** GameStateManager switches state to `STATE_META_HUB`. `index.html` mounts `` 2. **Mission Selection:** - User clicks "Mission Board" - `` mounts `` overlay - `` emits `mission-selected` 3. **Squad Assembly:** - `` catches event - Transitions to `STATE_TEAM_BUILDER` (passing the selected Mission ID) 4. **Deployment:** - TeamBuilder emits `embark` - GameStateManager handles embark (starts GameLoop) ## **Visual Layout (The "Dusk Camp")** Style: 2.5D Parallax or Static Art background with UI overlays. Theme: A makeshift military camp at twilight. Torches, magical lanterns, supplies piled high. ### **A. The Stage (Background)** - **Image:** `assets/images/ui/hub_bg_dusk.png` covers 100% width/height - **Hotspots:** Invisible, clickable divs positioned absolutely over key art elements - _The Tent (Barracks):_ `top: 40%, left: 10%, width: 20%`. Hover: Glows Blue - _The Table (Missions):_ `top: 60%, left: 40%, width: 20%`. Hover: Glows Gold - _The Wagon (Market):_ `top: 50%, left: 80%, width: 15%`. Hover: Glows Green ### **B. Top Bar (Status)** - **Left:** Game Logo - **Right:** Resource Strip - `[💎 450 Shards] [⚙️ 12 Cores] [Day 4]` ### **C. Bottom Dock (Navigation)** - A row of large, labeled buttons acting as redundant navigation - `[BARRACKS] [MISSIONS] [MARKET] [RESEARCH] [SYSTEM]` - **State:** Buttons are disabled/greyed out if the facility is locked ### **D. Overlay Container (Modal Layer)** - A centralized div with a semi-transparent backdrop (`rgba(0,0,0,0.8)`) where sub-screens (Barracks, MissionBoard) are rendered without leaving the Hub ## **TypeScript Interfaces** ```typescript // src/types/HubInterfaces.ts export interface HubState { wallet: { aetherShards: number; ancientCores: number; }; rosterSummary: { total: number; ready: number; injured: number; }; unlocks: { market: boolean; research: boolean; }; activeOverlay: "NONE" | "BARRACKS" | "MISSIONS" | "MARKET" | "SYSTEM"; } export interface HubEvents { // Dispatched when the player wants to leave the Hub context entirely "request-team-builder": { detail: { missionId: string }; }; "save-and-quit": void; } ``` ## **Implementation Requirements** ### **Component Structure** Create `src/ui/screens/HubScreen.js` as a LitElement: 1. **Imports:** Import `gameStateManager` singleton and `html`, `css`, `LitElement` 2. **State:** Define properties for `wallet`, `unlocks`, and `activeOverlay` 3. **Lifecycle:** In `connectedCallback`, read `gameStateManager.persistence` to populate wallet/unlocks 4. **Layout:** - Background img covering host - Absolute divs for Hotspots - Flexbox header for Resources - Flexbox footer for Dock Buttons - Centered div for Overlays 5. **Logic:** - `_openOverlay(type)`: Sets state - `_closeOverlay()`: Sets state to NONE - `_onMissionSelected(e)`: Dispatches `request-team-builder` to window/parent 6. **Lazy Loading:** Use dynamic imports inside the `render()` method ## **Conditions of Acceptance (CoA)** **CoA 1: Live Data Binding** - On mount (`connectedCallback`), the component must fetch wallet and roster data from `gameStateManager` - The Top Bar must display the correct currency values **CoA 2: Hotspot & Dock Sync** - Clicking the "Mission Table" hotspot OR the "Missions" dock button must perform the same action: setting `activeOverlay = 'MISSIONS'` **CoA 3: Overlay Management** - When `activeOverlay` is `'MISSIONS'`, the `` component must be rendered in the Overlay Container - Clicking "Close" or "Back" inside an overlay must set `activeOverlay = 'NONE'` **CoA 4: Mission Handoff** - Selecting a mission in the Mission Board must dispatch an event that causes the Hub to dispatch `request-team-builder`, effectively handing control back to the App Router ## **Event-Driven Architecture** - HubScreen must **never** directly call GameLoop or GameStateManager write operations - All state changes must be communicated via CustomEvents - Use `this.dispatchEvent(new CustomEvent('request-team-builder', { detail: { missionId } }))` for navigation