aether-shards/.agent/rules/ui/HubScreen/RULE.md

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