138 lines
4.9 KiB
Markdown
138 lines
4.9 KiB
Markdown
---
|
|
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 `<hub-screen>`
|
|
2. **Mission Selection:**
|
|
- User clicks "Mission Board"
|
|
- `<hub-screen>` mounts `<mission-board>` overlay
|
|
- `<mission-board>` emits `mission-selected`
|
|
3. **Squad Assembly:**
|
|
- `<hub-screen>` 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 `<mission-board>` 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
|