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

4.9 KiB

description globs alwaysApply
Architecture, visuals, and integration logic for the HubScreen component - the persistent main menu of the campaign src/ui/screens/HubScreen.js 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

// 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