aether-shards/.cursor/rules/ui/HubScreen/RULE.md
Matthew Mone 5c335b4b3c Add HubScreen and MissionBoard components for campaign management
Introduce the HubScreen as the main interface for managing resources, units, and mission selection, integrating with the GameStateManager for dynamic data binding. Implement the MissionBoard component to display and select available missions, enhancing user interaction with mission details and selection logic. Update the GameStateManager to handle transitions between game states, ensuring a seamless experience for players. Add tests for HubScreen and MissionBoard to validate functionality and integration with the overall game architecture.
2025-12-31 10:49:26 -08:00

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