aether-shards/.cursor/rules/ui/SkillTree/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.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-3d containing 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
  • 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:

  1. UNLOCKED: unit.classMastery.unlockedNodes.includes(node.id)
  2. AVAILABLE: Not unlocked AND parent is Unlocked AND unit.level >= node.req
  3. 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 unit prop 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:

  1. CSS 3D: Implement a .voxel-node class using transform-style: preserve-3d to create a cube. Use keyframes for rotation
  2. Layout: Render the tree tiers using flex-direction: column-reverse (Tier 1 at bottom)
  3. SVG Lines: Implement a _updateConnections() method that uses getBoundingClientRect() to draw lines between nodes in an absolute-positioned <svg>. Call this on resize and first render
  4. Interactivity: Clicking a node selects it. Show details in a fixed footer
  5. Logic: Calculate LOCKED/AVAILABLE/UNLOCKED state based on this.unit.unlockedNodes