# **Skill Tree UI Specification**

This document 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.

### **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:

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. Prompt for Coding Agent**

"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`."
