11 KiB
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_namefor hardware detection,SteamClient.System.GetOSVersion()for OS, Steam app info for Proton version.api-client.ts— wrapsfetchcalls to DeckyVault's/api/performance/importwithx-api-keyheader. Also calls/api/games/lookupto verify the API key.exporter.ts— builds aDeckyVaultImportV1object 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
- User presses "Start Recording" in the plugin panel.
- 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 viabenchmark_percentiles, default97,AVG,1,0.1). The plugin can parse either the raw frame data or the summary section for FPS stats. - Plugin records the current timestamp and (if a game is running) the active app ID via
SteamClient.Apps. - 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
- User presses "Stop Recording".
- Plugin reads the MangoHud log file at
/tmp/deckyvault-mangohud.logand computes:fpsAvg— mean of all FPS samplesfpsLow— minimum FPSfpsHigh— maximum FPSfpsOnePercentLow— 1st percentile of frame times, converted to FPStdpWatts— average power draw across samples (if logged)
- 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
- 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
DeckyVaultImportV1payload and saves it as[game-name]-[date].deckyvault.jsonto the configured export path. - Upload to DeckyVault — builds the same payload and POSTs to
/api/performance/importwith thex-api-keyheader. 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 callsGET /api/games/lookup?steamAppId=0to verify the key works. Shows ✓ valid or ✗ invalid. - Export Path — text input, defaults to
/home/deck/Downloads. Where.deckyvault.jsonfiles 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 mangohudand 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.
- Steam Deck (SteamOS): MangoHud is pre-installed. Enable per-game via Steam launch options (
-
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:
- MangoHud log parsing — unit-testable with sample log files. Create test fixtures of MangoHud CSV output and verify FPS computation.
- System info reading — testable on any Linux machine with mock
/sysfiles. - API client — testable with mock fetch responses (success, 401, 404, network error).
- Exporter — testable by writing to a temp directory and verifying JSON structure matches
DeckyVaultImportV1. - 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)