From 0c93915339a041b53d86d1997df491da5301e057 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 7 Mar 2026 16:23:48 +0000 Subject: [PATCH] docs: add follow highlight implementation plan Co-Authored-By: Claude Opus 4.6 --- .../plans/2026-03-07-follow-highlight-plan.md | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 docs/plans/2026-03-07-follow-highlight-plan.md diff --git a/docs/plans/2026-03-07-follow-highlight-plan.md b/docs/plans/2026-03-07-follow-highlight-plan.md new file mode 100644 index 0000000..884eb83 --- /dev/null +++ b/docs/plans/2026-03-07-follow-highlight-plan.md @@ -0,0 +1,266 @@ +# Follow Mode Highlight & Command Legend — Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add a toggleable red glow highlight on the followed NPC and a follow-mode command legend panel. + +**Architecture:** Parameterize `CommandPanel` to accept title and commands. Add highlight state and glow management to `GameScene`. Bind `1` key to toggle highlight in follow mode. + +**Tech Stack:** Phaser 3 postFX (glow), HTML/CSS command panel (existing) + +--- + +### Task 1: Parameterize CommandPanel constructor + +**Files:** +- Modify: `client/src/ui/CommandPanel.ts` + +**Step 1: Update constructor to accept title and commands** + +Change the constructor signature and replace hardcoded values: + +```typescript +export class CommandPanel { + private outerFrame: HTMLDivElement; + private listContainer: HTMLDivElement; + private visible = false; + + constructor(title = 'COMMANDS', commands: Command[] = [{ key: '1', label: 'Spawn NPC' }]) { +``` + +Replace line 90: +```typescript + title.textContent = `\u25C6 ${title} \u25C6`; +``` + +Replace line 108 (the hardcoded `addCommand` call) with a loop: +```typescript + for (const cmd of commands) { + this.addCommand(cmd); + } +``` + +**Step 2: Update camera panel instantiation in GameScene** + +In `GameScene.ts` line 48, pass explicit args to preserve current behavior: + +```typescript + this.commandPanel = new CommandPanel('COMMANDS', [{ key: '1', label: 'Spawn NPC' }]); +``` + +**Step 3: Verify client builds** + +Run: `npm -w client run build` +Expected: Build succeeds with no errors. + +**Step 4: Commit** + +```bash +git add client/src/ui/CommandPanel.ts client/src/scenes/GameScene.ts +git commit -m "refactor: parameterize CommandPanel title and commands" +``` + +--- + +### Task 2: Add follow mode command panel + +**Files:** +- Modify: `client/src/scenes/GameScene.ts` + +**Step 1: Add followCommandPanel property** + +After line 32, add: +```typescript + private followCommandPanel!: CommandPanel; +``` + +**Step 2: Create follow panel in create()** + +After line 49 (`this.commandPanel.show()`), add: +```typescript + this.followCommandPanel = new CommandPanel('FOLLOW', [ + { key: '\u2190 \u2192', label: 'Cycle NPC' }, + { key: '1', label: 'Highlight' }, + { key: 'TAB', label: 'Camera Mode' }, + ]); +``` + +**Step 3: Wire follow panel visibility into TAB handler** + +In the TAB key handler (lines 68-92), update panel visibility logic. + +When entering follow mode (line 79-81), replace: +```typescript + if (this.mode === 'follow') { + this.showFollowPanel(); + this.commandPanel.hide(); + } +``` +with: +```typescript + if (this.mode === 'follow') { + this.showFollowPanel(); + this.commandPanel.hide(); + this.followCommandPanel.show(); + } +``` + +When entering camera mode (lines 82-84), add follow panel hide: +```typescript + } else if (prevMode === 'follow') { + this.npcInfoPanel.hide(); + this.followCommandPanel.hide(); + } +``` + +The existing camera command panel show/hide block (lines 86-91) remains unchanged. + +**Step 4: Verify client builds** + +Run: `npm -w client run build` +Expected: Build succeeds. + +**Step 5: Commit** + +```bash +git add client/src/scenes/GameScene.ts +git commit -m "feat: add follow mode command legend panel" +``` + +--- + +### Task 3: Add highlight toggle and glow effect + +**Files:** +- Modify: `client/src/scenes/GameScene.ts` + +**Step 1: Add highlight state property** + +After the `followCommandPanel` property, add: +```typescript + private highlightEnabled = false; + private highlightedSpriteId: number | null = null; +``` + +**Step 2: Add glow helper methods** + +After `updateModeText()` method, add: + +```typescript + private applyHighlight(entityId: number): void { + const es = this.entitySprites.get(entityId); + if (!es) return; + this.clearHighlight(); + es.sprite.postFX.addGlow(0xff0000, 2, 0, false, 0.1, 4); + this.highlightedSpriteId = entityId; + } + + private clearHighlight(): void { + if (this.highlightedSpriteId != null) { + const es = this.entitySprites.get(this.highlightedSpriteId); + if (es) { + es.sprite.postFX.clear(); + } + this.highlightedSpriteId = null; + } + } +``` + +Note: `addGlow(color, outerStrength, innerStrength, knockout, quality, distance)` — we use a moderate outer strength of 2 with distance 4 for a visible but not overwhelming red outline. Adjust if needed after visual testing. + +**Step 3: Add follow-mode branch to the ONE key handler** + +In the `ONE` key handler (lines 95-101), change: +```typescript + this.input.keyboard!.addKey('ONE').on('down', () => { + if (this.mode !== 'camera') return; +``` +to: +```typescript + this.input.keyboard!.addKey('ONE').on('down', () => { + if (this.mode === 'follow') { + this.highlightEnabled = !this.highlightEnabled; + if (this.highlightEnabled) { + const npcIds = this.getNpcIds(); + const targetId = npcIds[this.followTargetIndex]; + if (targetId != null) this.applyHighlight(targetId); + } else { + this.clearHighlight(); + } + return; + } + if (this.mode !== 'camera') return; +``` + +**Step 4: Move glow when cycling NPCs** + +In the follow mode NPC cycling section (lines 344-356), after each index change and before `this.updateModeText()`, add glow transfer: + +For the `left` branch, after `this.followTargetIndex = ...`: +```typescript + if (this.highlightEnabled) { + this.applyHighlight(npcIds[this.followTargetIndex]); + } +``` + +Same for the `right` branch. + +**Step 5: Clear highlight when exiting follow mode** + +In the TAB handler, in the `else if (prevMode === 'follow')` block, add: +```typescript + this.clearHighlight(); + this.highlightEnabled = false; +``` + +**Step 6: Handle entity removal edge case** + +In `handleStateUpdate`, in the entity removal loop (lines 257-262), after `es.sprite.destroy()`, clear highlight if the removed entity was highlighted: + +```typescript + if (id === this.highlightedSpriteId) { + this.highlightedSpriteId = null; + } +``` + +**Step 7: Verify client builds** + +Run: `npm -w client run build` +Expected: Build succeeds. + +**Step 8: Commit** + +```bash +git add client/src/scenes/GameScene.ts +git commit -m "feat: add toggleable red glow highlight on followed NPC" +``` + +--- + +### Task 4: Manual visual verification + +**Step 1: Start server and client** + +Run in two terminals: +- `npm -w server run dev` +- `npm -w client run dev` + +**Step 2: Verify camera mode** + +- Confirm command legend shows "COMMANDS" with "1 Spawn NPC" +- Press `1` to spawn NPCs +- Confirm no follow command panel visible + +**Step 3: Verify follow mode** + +- Press TAB to enter follow mode +- Confirm command legend switches to "FOLLOW" with three commands +- Press left/right to cycle NPCs +- Press `1` to toggle highlight — confirm red glow appears around followed NPC +- Cycle NPCs — confirm glow follows to new NPC +- Press `1` again — confirm glow disappears +- Press TAB to return to camera mode — confirm follow panel hides, camera panel shows + +**Step 4: Commit any adjustments** + +If glow parameters need tuning (color, strength, distance), adjust in `applyHighlight()` and commit.