7.7 KiB
Overlay Controller Support Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Add Chrome Gamepad API controller support to the visible overlay as a supplement to keyboard-only mode, including controller selection/debug modals, config-backed logical bindings, and selected-token highlight cleanup.
Architecture: Keep controller support in the visible overlay renderer. Poll and normalize gamepad state in a dedicated runtime, route logical actions into the existing keyboard-only/Yomitan helpers, and persist preferred-controller config through the existing config pipeline and preload bridge.
Tech Stack: TypeScript, Bun tests, Electron preload IPC, renderer DOM modals, Chrome Gamepad API
Task 1: Track work and lock the design
Files:
- Create:
backlog/tasks/task-159 - Add-overlay-controller-support-for-keyboard-only-mode.md - Create:
docs/plans/2026-03-11-overlay-controller-support-design.md - Create:
docs/plans/2026-03-11-overlay-controller-support.md
Step 1: Record the approved scope
Capture controller-only-in-keyboard-mode behavior, the modal shortcuts, config scope, and the stale selection-highlight cleanup requirement.
Step 2: Verify the written scope matches the approved design
Run: sed -n '1,220p' backlog/tasks/task-159\\ -\\ Add-overlay-controller-support-for-keyboard-only-mode.md && sed -n '1,240p' docs/plans/2026-03-11-overlay-controller-support-design.md
Expected: task and design doc both mention controller selection/debug modals and highlight cleanup.
Task 2: Add failing config tests and defaults
Files:
- Modify:
src/config/config.test.ts - Modify:
src/config/definitions/defaults-core.ts - Modify:
src/config/definitions/options-core.ts - Modify:
src/config/definitions/template-sections.ts - Modify:
src/types.ts - Modify:
config.example.jsonc
Step 1: Write the failing test
Add coverage asserting a new controller config block resolves with the expected defaults and accepts logical-field overrides.
Step 2: Run test to verify it fails
Run: bun test src/config/config.test.ts
Expected: FAIL because controller config is not defined yet.
Step 3: Write minimal implementation
Add the controller config types/defaults/registry/template wiring and regenerate the example config if needed.
Step 4: Run test to verify it passes
Run: bun test src/config/config.test.ts
Expected: PASS
Task 3: Add failing keyboard-selection cleanup tests
Files:
- Modify:
src/renderer/handlers/keyboard.test.ts - Modify:
src/renderer/handlers/keyboard.ts - Modify:
src/renderer/state.ts
Step 1: Write the failing tests
Add tests for:
- turning keyboard-only mode off clears
.keyboard-selected - closing the popup clears stale selection highlight when keyboard-only mode is off
Step 2: Run test to verify it fails
Run: bun test src/renderer/handlers/keyboard.test.ts
Expected: FAIL because selection cleanup is incomplete today.
Step 3: Write minimal implementation
Centralize selection clearing in the keyboard-only sync helpers and popup-close flow.
Step 4: Run test to verify it passes
Run: bun test src/renderer/handlers/keyboard.test.ts
Expected: PASS
Task 4: Add failing controller runtime tests
Files:
- Create:
src/renderer/handlers/gamepad-controller.test.ts - Create:
src/renderer/handlers/gamepad-controller.ts - Modify:
src/renderer/context.ts - Modify:
src/renderer/state.ts - Modify:
src/renderer/renderer.ts
Step 1: Write the failing tests
Cover:
- first connected controller is selected by default
- preferred controller wins when connected
- controller actions are ignored unless keyboard-only mode is enabled, except keyboard-only toggle
- stick/button mappings invoke the expected logical helpers
- smooth scroll and repeat throttling behavior
Step 2: Run test to verify it fails
Run: bun test src/renderer/handlers/gamepad-controller.test.ts
Expected: FAIL because controller runtime does not exist.
Step 3: Write minimal implementation
Add a renderer-local polling runtime with deadzone handling, action edge detection, repeat timing, and helper callbacks into the keyboard/Yomitan flow.
Step 4: Run test to verify it passes
Run: bun test src/renderer/handlers/gamepad-controller.test.ts
Expected: PASS
Task 5: Add failing controller modal tests
Files:
- Modify:
src/renderer/index.html - Modify:
src/renderer/style.css - Create:
src/renderer/modals/controller-select.ts - Create:
src/renderer/modals/controller-select.test.ts - Create:
src/renderer/modals/controller-debug.ts - Create:
src/renderer/modals/controller-debug.test.ts - Modify:
src/renderer/renderer.ts - Modify:
src/renderer/context.ts - Modify:
src/renderer/state.ts
Step 1: Write the failing tests
Add tests for:
Alt+Copens controller selection modalAlt+Shift+Copens controller debug modal- selection modal renders connected controllers and persists the chosen device
- debug modal shows live axes/buttons state
Step 2: Run test to verify it fails
Run: bun test src/renderer/modals/controller-select.test.ts src/renderer/modals/controller-debug.test.ts
Expected: FAIL because modals and shortcuts do not exist.
Step 3: Write minimal implementation
Add modal DOM, renderer modules, modal state wiring, and controller runtime integration.
Step 4: Run test to verify it passes
Run: bun test src/renderer/modals/controller-select.test.ts src/renderer/modals/controller-debug.test.ts
Expected: PASS
Task 6: Persist controller preference through preload/main wiring
Files:
- Modify:
src/preload.ts - Modify:
src/types.ts - Modify:
src/shared/ipc/contracts.ts - Modify:
src/core/services/ipc.ts - Modify:
src/main.ts - Modify: related main/runtime tests as needed
Step 1: Write the failing test
Add coverage for reading current controller config and saving preferred-controller changes from the renderer.
Step 2: Run test to verify it fails
Run: bun test src/core/services/ipc.test.ts
Expected: FAIL because no controller preference IPC exists yet.
Step 3: Write minimal implementation
Expose renderer-safe getters/setters for the controller config fields needed by the selection modal/runtime.
Step 4: Run test to verify it passes
Run: bun test src/core/services/ipc.test.ts
Expected: PASS
Task 7: Update docs and config example
Files:
- Modify:
config.example.jsonc - Modify:
README.md - Modify: relevant docs under
docs-site/for shortcuts/usage/troubleshooting if touched by current docs structure
Step 1: Write the failing doc/config check if needed
If config example generation is covered by tests, add/refresh the failing assertion first.
Step 2: Implement the docs
Document controller behavior, modal shortcuts, config block, and the keyboard-only-only activation rule.
Step 3: Run doc/config verification
Run: bun run test:config
Expected: PASS
Task 8: Run the handoff gate and update the backlog task
Files:
- Modify:
backlog/tasks/task-159 - Add-overlay-controller-support-for-keyboard-only-mode.md
Step 1: Run targeted verification
Run:
bun test src/config/config.test.tsbun test src/renderer/handlers/keyboard.test.tsbun test src/renderer/handlers/gamepad-controller.test.tsbun test src/renderer/modals/controller-select.test.tsbun test src/renderer/modals/controller-debug.test.tsbun test src/core/services/ipc.test.ts
Expected: PASS
Step 2: Run broader gate
Run:
bun run typecheckbun run test:fastbun run test:envbun run build
Expected: PASS, or document exact blockers/failures.
Step 3: Update backlog notes
Fill in implementation notes, verification commands, and final summary in TASK-159.