diff --git a/docs/superpowers/specs/2026-06-28-decky-vault-plugin-design.md b/docs/superpowers/specs/2026-06-28-decky-vault-plugin-design.md new file mode 100644 index 0000000..fc11a8c --- /dev/null +++ b/docs/superpowers/specs/2026-06-28-decky-vault-plugin-design.md @@ -0,0 +1,206 @@ +# DeckyVault Decky Loader Plugin — Design Spec + +## Overview + +A Decky Loader plugin that records Steam Deck (and other Linux handheld) performance metrics during gameplay, then exports or uploads them to DeckyVault as benchmark entries. + +The plugin uses **MangoHud** for FPS/power logging, reads **system files** for hardware/OS/Proton detection, and lets the user fill in the few fields that can't be auto-detected (upscaler, frame gen, in-game settings, load times). + +## Architecture + +``` +plugins/decky-vault/src/ +├── index.tsx # Entry point — registers plugin with Decky Loader +├── components/ +│ ├── main-panel.tsx # Record/Stop button, session status, recent recordings +│ ├── session-form.tsx # Post-session summary with manual inputs + export/upload +│ └── settings-panel.tsx # API key, export path, hardware, MangoHud setup +├── lib/ +│ ├── mangohud.ts # Start/stop MangoHud logging, parse log for FPS stats +│ ├── system-info.ts # Read hardware model, OS version, Proton version, TDP +│ ├── api-client.ts # Upload to DeckyVault via API key +│ ├── exporter.ts # Save .deckyvault.json to disk +│ └── store.ts # Plugin state (settings, current session, recent sessions) +└── types.d.ts # Decky Loader API declarations (exists) +``` + +Each module has one clear purpose: + +- **`mangohud.ts`** — writes MangoHud logging config, reads/parses the log file after a session. Computes FPS avg/min/max/1% low and average TDP. +- **`system-info.ts`** — reads `/sys/class/dmi/id/product_name` for hardware detection, `SteamClient.System.GetOSVersion()` for OS, Steam app info for Proton version. +- **`api-client.ts`** — wraps `fetch` calls to DeckyVault's `/api/performance/import` with `x-api-key` header. Also calls `/api/games/lookup` to verify the API key. +- **`exporter.ts`** — builds a `DeckyVaultImportV1` object and writes it as JSON to the configured export path. +- **`store.ts`** — holds plugin settings (API key, export path, hardware override) and session state (recording status, current app ID, start time, parsed results). Also persists the last 5 recent sessions to Decky Loader's plugin storage so they survive plugin reloads. The single source of truth that components read from. + +## Recording Flow + +### Start Recording + +1. User presses "Start Recording" in the plugin panel. +2. Plugin writes a MangoHud config that enables logging. The config sets `output_folder=/tmp`, `output_file=deckyvault-mangohud.log`, and enables: `fps`, `frame_timing`, `cpu_power`, `gpu_power`, `cpu_temp`, `gpu_temp`. MangoHud's log includes a summary section with benchmark percentiles (configurable via `benchmark_percentiles`, default `97,AVG,1,0.1`). The plugin can parse either the raw frame data or the summary section for FPS stats. +3. Plugin records the current timestamp and (if a game is running) the active app ID via `SteamClient.Apps`. +4. Plugin checks if MangoHud is running. If not, shows a warning guiding the user to enable MangoHud for their game (via Steam launch options `mangohud %command%` or the Decky MangoHud toggle). Recording continues regardless — the log file will be populated once MangoHud is active. + +### During Recording + +- The main panel shows a live status: "Recording — [game name]" with an elapsed timer. +- The MangoHud log file accumulates FPS and power samples in the background. +- User plays their game normally. + +### Stop Recording + +1. User presses "Stop Recording". +2. Plugin reads the MangoHud log file at `/tmp/deckyvault-mangohud.log` and computes: + - `fpsAvg` — mean of all FPS samples + - `fpsLow` — minimum FPS + - `fpsHigh` — maximum FPS + - `fpsOnePercentLow` — 1st percentile of frame times, converted to FPS + - `tdpWatts` — average power draw across samples (if logged) +3. Plugin reads system info: + - `hardwareSlug` — from `/sys/class/dmi/id/product_name` ("Jupiter" → `steamdeck-lcd`, "Galileo" → `steamdeck-oled`; falls back to user-configured default) + - `osVersion` — `SteamClient.System.GetOSVersion()` + - `protonVersion` — from the Steam app info or process environment +4. Plugin transitions to the session summary form. + +### Edge Cases + +- **No MangoHud log found** → error: "MangoHud logging not detected. Make sure MangoHud is enabled for this game." with a link to the Settings → MangoHud Setup section. +- **Log file is empty** → error: "Recording was too short or MangoHud didn't capture data. Try again." +- **No game running when Record pressed** → allowed, but shows a warning that game info won't be auto-filled. User can still manually enter the Steam App ID in the form. +- **MangoHud log parsing fails** (corrupt/unexpected format) → error with raw log preview, fall back to manual FPS entry in the form. + +## Session Summary Form + +After stopping, the plugin shows a form with two sections: + +### Auto-Captured (read-only summary card) + +- Game name + Steam App ID +- FPS: avg / min / 1% low / max +- TDP (watts, average) +- Hardware (e.g. "Steam Deck OLED") +- OS version +- Proton version + +### Manual Inputs (user fills in) + +| Field | Type | Required | Notes | +|---|---|---|---| +| Upscaler type | dropdown | yes (default: None) | None / FSR / DLSS / XeSS / LSFG / Other | +| Upscaler version | text | no | e.g. "2.4" | +| Frame gen method | dropdown | yes (default: None) | None / FSR FG / DLSS FG / LSFG / Other | +| In-game settings | free text (stored as JSON array) | no | preset, graphics quality, resolution, etc. Maps to `settingsJson` in the import format. | +| Load time (SSD) | number (seconds) | no | | +| Load time (SD card) | number (seconds) | no | | +| Launch options | text | no | auto-filled from Steam if available | +| User notes | textarea | no | max 5000 chars | + +### Export / Upload Actions + +Two buttons at the bottom of the form: + +- **Export to File** — builds a `DeckyVaultImportV1` payload and saves it as `[game-name]-[date].deckyvault.json` to the configured export path. +- **Upload to DeckyVault** — builds the same payload and POSTs to `/api/performance/import` with the `x-api-key` header. Shows success or error response. + +Both build the identical `DeckyVaultImportV1` payload. If upload fails (invalid API key, game not in DeckyVault DB, network error), the error message is shown inline and the user can retry or fall back to file export. + +## Plugin UI Layout + +Two tabs in the Decky Loader Quick Access panel: + +### Tab 1: DeckyVault (Main) + +**Idle state:** +- Big "Start Recording" button +- Brief instructions: "Enable MangoHud for your game, then press Record before launching." + +**Recording state:** +- "Stop Recording" button +- Live elapsed timer +- Current game name (or "No game detected" if none running) + +**Stopped state:** +- The session summary form (above) replaces the button area. + +**Below (always visible):** +- "Recent recordings" list — last 5 sessions showing game name, FPS avg, date. Clickable to re-view the form and re-export/re-upload. + +### Tab 2: Settings + +- **API Key** — text input (prefixed `dv_`), with a "Test Key" button that calls `GET /api/games/lookup?steamAppId=0` to verify the key works. Shows ✓ valid or ✗ invalid. +- **Export Path** — text input, defaults to `/home/deck/Downloads`. Where `.deckyvault.json` files are saved. +- **Default Hardware** — auto-detected but overrideable dropdown. Options from `KNOWN_HARDWARE_SLUGS`. Useful for non-standard setups. +- **MangoHud Setup** — see below. + +### MangoHud Setup Section + +- **"Check MangoHud status" button** — runs `which mangohud` and reports: installed/not installed + version if available. + +- **Installation guide** (collapsible): + - **Steam Deck (SteamOS)**: MangoHud is pre-installed. Enable per-game via Steam launch options (`mangohud %command%`) or the Decky MangoHud toggle plugin. + - **Other Linux handhelds** (ROG Ally, Legion Go, etc.): install via Flatpak (`flatpak install flathub org.freedesktop.Platform.VulkanLayer.MangoHud`) or system package manager. + - Link to MangoHud GitHub (`https://github.com/flightlessmango/MangoHud`) for manual builds. + +- **Configuration guide** — shows the exact MangoHud config the plugin writes (so users can verify). Includes a "Write config now" button that writes the logging config to `~/.config/MangoHud/MangoHud.conf`. + +- **Troubleshooting** (collapsible): + - Log file empty → check MangoHud is enabled for the game, check the log path. + - Wrong path → ensure the plugin has write access to `/tmp/`. + - MangoHud not attaching → try adding `mangohud %command%` to the game's Steam launch options explicitly. + +## Data Flow + +``` +[Start Recording] + │ + ▼ +[MangoHud logs to /tmp/deckyvault-mangohud.log] + │ + ▼ (user plays game) +[Stop Recording] + │ + ├──► mangohud.ts parses log → FPS stats, TDP + ├──► system-info.ts reads → hardware, OS, Proton + │ + ▼ +[Session Summary Form] + │ (user fills manual fields) + ├──► exporter.ts → .deckyvault.json on disk + └──► api-client.ts → POST /api/performance/import + │ + ▼ + [DeckyVault database] +``` + +## Error Handling + +- **MangoHud not installed** → Settings tab shows installation guide. Main tab warns when Record is pressed. +- **MangoHud not enabled for game** → post-session error with link to Settings → MangoHud Setup. +- **Invalid API key** → upload fails with 401, message shown in form. User directed to Settings to re-enter key. +- **Game not in DeckyVault DB** → upload returns 404, message: "This game isn't in DeckyVault yet. Submit it on the website first, or export to file for now." +- **Network error during upload** → message shown, user can retry or export to file. +- **Filesystem write error (export)** → message: "Couldn't write to [path]. Check the path in Settings." + +## Testing + +Since the plugin runs on Steam Deck hardware in the Decky Loader environment, testing is primarily manual: + +1. **MangoHud log parsing** — unit-testable with sample log files. Create test fixtures of MangoHud CSV output and verify FPS computation. +2. **System info reading** — testable on any Linux machine with mock `/sys` files. +3. **API client** — testable with mock fetch responses (success, 401, 404, network error). +4. **Exporter** — testable by writing to a temp directory and verifying JSON structure matches `DeckyVaultImportV1`. +5. **End-to-end** — manual testing on a Steam Deck with MangoHud enabled, recording a game session and verifying upload/export. + +## Dependencies + +- `@deckyvault/shared` — workspace package (types: `DeckyVaultImportV1`, `KNOWN_HARDWARE_SLUGS`) +- React — provided by Decky Loader runtime +- MangoHud — external dependency, must be installed by the user (pre-installed on Steam Deck) + +## Out of Scope (for this phase) + +- Auto-detection of upscaler / frame gen / in-game settings (manual input only) +- Automatic recording on game start (manual start/stop only) +- Real-time performance overlay in the plugin (MangoHud already provides this) +- Multi-session batch upload (one session at a time) +- Support for non-Steam games (requires manual Steam App ID entry, which is handled in the form) \ No newline at end of file