- Introduce the MissionDebrief component to display after-action reports, including XP, rewards, and squad status. - Implement the MissionGenerator class to create procedural side missions, enhancing replayability and resource management. - Update mission schema to include mission objects for INTERACT objectives, improving mission complexity. - Enhance GameLoop and MissionManager to support new mission features and interactions. - Add tests for MissionDebrief and MissionGenerator to ensure functionality and integration within the 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