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.
4.1 KiB
4.1 KiB
| description | globs | alwaysApply |
|---|---|---|
| Skill Tree UI component - interactive progression tree for Explorer units | src/ui/components/SkillTreeUI.js, src/ui/components/SkillTreeUI.ts, src/types/SkillTreeUI.ts | false |
Skill Tree UI Rule
This rule defines the technical implementation for the SkillTreeUI component. This component renders the interactive progression tree for a specific Explorer.
1. Visual Architecture
Style: "Voxel-Web". We will use CSS 3D Transforms to render the nodes as rotating cubes, keeping the UI lightweight but consistent with the game's aesthetic.
A. The Tree Container (Scroll View)
- Layout: A vertical flex container
- Tiers: Each "Rank" (Novice, Apprentice, etc.) is a horizontal row (Flexbox)
- Connections: An
<svg>overlay sits behind the nodes to draw connecting lines (cables)
B. The Node (CSS Voxel)
- Structure: A div with
preserve-3dcontaining 6 faces - Animation:
- Locked: Static grey cube
- Available: Slowly bobbing, pulsing color
- Unlocked: Rotating slowly, emitting a glow (box-shadow)
- Content: An icon (
<img>or FontAwesome) is mapped to the Front face
C. The Inspector (Footer)
- A slide-up panel showing details for the selected node
- Contains the "Unlock" button
2. TypeScript Interfaces (Data Model)
// src/types/SkillTreeUI.ts
export interface SkillTreeProps {
/** The Unit object (source of state) */
unit: Explorer;
/** The Tree Definition (source of layout) */
treeDef: SkillTreeDefinition;
}
export interface SkillNodeState {
id: string;
def: SkillNodeDefinition;
status: 'LOCKED' | 'AVAILABLE' | 'UNLOCKED';
/** Calculated position for drawing lines */
domRect?: DOMRect;
}
export interface SkillTreeEvents {
/** Dispatched when user attempts to spend SP */
'unlock-request': {
nodeId: string;
cost: number;
};
}
3. Interaction Logic
A. Node Status Calculation
The UI must determine the state of every node on render:
- UNLOCKED:
unit.classMastery.unlockedNodes.includes(node.id) - AVAILABLE: Not unlocked AND
parentis Unlocked ANDunit.level >= node.req - LOCKED: Everything else
B. Connection Drawing
Since nodes are DOM elements, we need a ResizeObserver to track their positions.
- Logic: Calculate center
(x, y)of Parent Node and Child Node relative to the Container - Drawing: Draw a
<path>or<line>in the SVG layer with a "Circuit Board" style (90-degree bends) - Styling:
- If Child is Unlocked: Line is Bright Blue/Gold (Neon)
- If Child is Available: Line is Dim
- If Child is Locked: Line is Dark Grey
4. Conditions of Acceptance (CoA)
CoA 1: Dynamic Rendering
- The Tree must handle variable depths (Tier 1 to Tier 5)
- Nodes must visibly update state immediately when
unitprop changes (e.g., after unlocking)
CoA 2: Validation Feedback
- Clicking a "LOCKED" node should show the inspector but disable the button with a reason (e.g., "Requires: Shield Bash")
- Clicking an "AVAILABLE" node with 0 SP should show "Insufficient Points"
CoA 3: Responsive Lines
- If the window resizes, the SVG connecting lines must redraw to connect the centers of the cubes accurately
CoA 4: Scroll Position
- On open, the view should automatically scroll to center on the highest tier that has an "Available" node, so the player sees their next step
5. Implementation Requirements
Create src/ui/components/SkillTreeUI.js as a LitElement:
- CSS 3D: Implement a
.voxel-nodeclass usingtransform-style: preserve-3dto create a cube. Use keyframes for rotation - Layout: Render the tree tiers using
flex-direction: column-reverse(Tier 1 at bottom) - SVG Lines: Implement a
_updateConnections()method that usesgetBoundingClientRect()to draw lines between nodes in an absolute-positioned<svg>. Call this on resize and first render - Interactivity: Clicking a node selects it. Show details in a fixed footer
- Logic: Calculate
LOCKED/AVAILABLE/UNLOCKEDstate based onthis.unit.unlockedNodes