feat: gamepad navigation rewrite, focus styling, container grid system
- Rewrite useControllerNav.ts with clean console-style navigation: Sidebar (up/down wrap, right→containers, left→nothing), Container tile grid (spatial nav, no wrap at edges), Nav bar support (up from containers, down to grid), Inner controls (enter drills in, escape exits, trapped arrows) - Add data-controller-container to Mesh, Fleet, Settings pages - Fix Home.vue fragment (modals outside root div) causing Vue warnings - Remove skip-to-content link (handled by controller nav) - Orange ambient glow focus styling matching glass aesthetic - Disable PWA service worker in dev mode (fixes HMR caching) - Add gamepad-nav skill and GAMEPAD-NAV-MAP.md spec document - 39 tests covering all navigation patterns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
1444bcb0c4
commit
aada19754d
@@ -0,0 +1,114 @@
|
||||
---
|
||||
name: gamepad-nav
|
||||
description: Expert-level gamepad/controller navigation for Archipelago's console-style UI. Use when working on D-pad navigation, focus management, spatial navigation, controller support, or 10-foot UI design.
|
||||
---
|
||||
|
||||
# Gamepad Navigation Expert
|
||||
|
||||
When working on gamepad/controller navigation in Archipelago, apply these console-derived patterns.
|
||||
|
||||
## Architecture
|
||||
|
||||
**File**: `neode-ui/src/composables/useControllerNav.ts`
|
||||
**Styles**: `neode-ui/src/style.css` (focus-visible rules)
|
||||
|
||||
The system uses `data-` attributes for navigation zones:
|
||||
- `data-controller-zone="sidebar"` / `"main"` — navigation zones
|
||||
- `data-controller-container` — focusable card/group (Enter drills in, Escape exits)
|
||||
- `data-controller-focusable` — marks element as focusable
|
||||
- `data-controller-ignore` — excludes from navigation
|
||||
- `data-controller-install` / `data-controller-launch` — app-specific actions
|
||||
|
||||
## Core Navigation Rules (Xbox/PS5/Switch consensus)
|
||||
|
||||
### D-pad Movement
|
||||
- **4 directions only** — Up/Down/Left/Right, one element per press
|
||||
- **Spatial navigation** — find nearest focusable in direction using bounding rect geometry
|
||||
- **Distance formula**: `euclidean + displacement - alignment` with overlap scoring
|
||||
- **Tiebreaker for up/down**: prefer leftmost element (visual consistency in grids)
|
||||
|
||||
### Wrapping
|
||||
- **Linear lists (1D)**: WRAP (last to first, first to last) — sidebar menu, tab bars
|
||||
- **Grids (2D)**: NO WRAP — stops at edges, prevents disorientation
|
||||
|
||||
### Zone Transitions
|
||||
- **Right from sidebar** -> first focusable in main content (topmost)
|
||||
- **Left from main's leftmost** -> sidebar's active tab (`.nav-tab-active`)
|
||||
- **Focus memory**: remember last-focused element per zone, restore on re-entry
|
||||
|
||||
### Container Navigation
|
||||
- **Enter/A**: drill into container (focus first inner element)
|
||||
- **Escape/B**: exit container (focus the container itself)
|
||||
- **D-pad inside container**: navigate among inner elements spatially
|
||||
- **D-pad at container edge**: exit and navigate to adjacent container
|
||||
|
||||
### Text Input Handling
|
||||
- **Up/Down arrows**: EXIT input, navigate to nearest element above/below
|
||||
- **Left/Right arrows**: stay in input (cursor movement)
|
||||
- **Enter**: if next focusable is a button, click it directly (submit)
|
||||
- **Escape**: blur input, navigate out
|
||||
|
||||
### Button Mapping
|
||||
| Action | Xbox | PlayStation | Switch | Keyboard |
|
||||
|--------|------|------------|--------|----------|
|
||||
| Confirm | A | Cross | A | Enter |
|
||||
| Back | B | Circle | B | Escape |
|
||||
| Navigate | D-pad | D-pad | D-pad | Arrow keys |
|
||||
|
||||
## Focus Visual Design
|
||||
|
||||
### Console standard (10-foot viewing distance)
|
||||
- **Minimum 2px** border/outline (1px flickers on interlaced TVs)
|
||||
- **3:1 contrast ratio** against adjacent colors (WCAG 2.4.7)
|
||||
- **Smooth transitions**: 150-200ms ease-out
|
||||
- **GPU compositing**: use `translateZ(0)` on animated elements
|
||||
- **Never pure white** (#f1f1f1 prevents TV halo effects)
|
||||
|
||||
### Archipelago Focus Patterns
|
||||
```css
|
||||
/* Global — subtle outline that follows border-radius */
|
||||
*:focus-visible {
|
||||
outline: 2px solid rgba(251, 146, 60, 0.6);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Containers — soft glow + slight scale */
|
||||
[data-controller-container]:focus-visible {
|
||||
outline: none;
|
||||
transform: scale(1.01);
|
||||
box-shadow: 0 0 0 1.5px rgba(251, 146, 60, 0.5),
|
||||
0 0 20px rgba(251, 146, 60, 0.15);
|
||||
}
|
||||
|
||||
/* Sidebar items — background tint + thin ring */
|
||||
.sidebar-nav-item:focus-visible {
|
||||
outline: none;
|
||||
background: rgba(251, 146, 60, 0.12);
|
||||
box-shadow: 0 0 0 1.5px rgba(251, 146, 60, 0.45);
|
||||
}
|
||||
```
|
||||
|
||||
## Gamepad API Integration
|
||||
|
||||
### Polling
|
||||
- Poll `navigator.getGamepads()` in `requestAnimationFrame` loop (cheap, returns snapshot)
|
||||
- Apply deadzone: `Math.abs(axis) > 0.2` before registering input
|
||||
- D-pad repeat: 400ms initial delay, 150ms interval (gamepads don't auto-repeat)
|
||||
|
||||
### Button indices (W3C Standard Mapping)
|
||||
- 0=A, 1=B, 2=X, 3=Y, 4=LB, 5=RB, 12=DUp, 13=DDown, 14=DLeft, 15=DRight
|
||||
|
||||
## When Investigating Issues
|
||||
|
||||
1. Check `useControllerNav.ts` for the `handleKeyDown` function
|
||||
2. Check `data-controller-*` attributes in the view's template
|
||||
3. Verify focusable elements are in the right `data-controller-zone`
|
||||
4. Test with: arrow keys on keyboard (simulates D-pad)
|
||||
5. Check `style.css` for `focus-visible` rules
|
||||
|
||||
## Key Sources
|
||||
- [Xbox Accessibility Guideline 112](https://learn.microsoft.com/en-us/gaming/accessibility/xbox-accessibility-guidelines/112)
|
||||
- [Microsoft: Gamepad and remote interactions](https://learn.microsoft.com/en-us/windows/apps/design/input/gamepad-and-remote-interactions)
|
||||
- [W3C CSS Spatial Navigation](https://www.w3.org/TR/css-nav-1/)
|
||||
- [W3C Gamepad Spec](https://w3c.github.io/gamepad/)
|
||||
- [Norigin Spatial Navigation (React reference)](https://github.com/NoriginMedia/Norigin-Spatial-Navigation)
|
||||
Reference in New Issue
Block a user