- list_screenshots: bump limit 12 → 50 so users can scroll further back
- Add versionString + buildId to DeckyVaultImportV1, SessionData, and
buildImportPayload. Import endpoint now saves them on new game versions.
- Screenshot delete button in preset detail modal: owner/admin sees a
trash icon on hover that calls DELETE /api/performance/:id/screenshots/:sid
- Root workspace scripts for plugin workflow:
bun run plugin:build | plugin:zip | plugin:release | plugin:deploy
- Add deploy.sh (SSH scripts to push plugin to Deck)
The screenshot picker now shows a live thumbnail next to each recent
Steam screenshot so users can identify the right one before selecting.
- read_screenshot() Python RPC: returns a base64 data URL for inline
display. Tries Pillow downscale (320px), falls back to raw bytes
(Steam Deck screenshots are ~78KB so this is fine without Pillow).
- Thumbnail component: 56x56 rounded image with loading placeholder.
- Thumbnails load progressively in both the picker list and the
selected-shots rows via a useEffect.
The plugin can now attach up to 2 Steam Deck screenshots (Steam + R1)
to a performance entry, uploaded together in one Submit tap.
Backend:
- Screenshot upload/delete endpoints now accept API key auth via
requireRoleWithApiKeyFallback (was session-only), so the plugin's
x-api-key header works. The 2-screenshot limit was already enforced
server-side (MAX_SCREENSHOTS_PER_ENTRY = 2).
Plugin Python (main.py):
- list_screenshots(): scans ~/Pictures/Screenshots/ + Steam Client/
subfolder, skips the most_recent.jpg duplicate, returns recent shots
- upload_screenshots(): hard-caps at 2, builds multipart/form-data with
urllib, posts to /api/performance/:id/screenshots
Plugin UI (session-form.tsx):
- New Screenshots section (max 2) with a picker listing recent Steam
screenshots (time + size), selected shots as removable rows
- Submit flow: upload entry → get entry ID → upload selected screenshots
→ combined success message (partial-success if screenshots fail)
Promotes the DeckyVault Decky plugin to Steam Deck owners browsing game
pages. Soft primary-tinted card with Gamepad2 icon, value-prop copy, and
'Get the plugin' CTA linking to /plugin. Dismissible via localStorage
(dv-plugin-cta-dismissed) so it stays gone across all games once closed.
Controller-navigable (data-gamepad-focusable), responsive layout.
Redesign 'See it in action' as a 3-act story with clearer flow:
- Act 1: Get set up (3 cards: panel, pair, launch option)
- Act 2: Capture performance (2 cards: recording, session-form)
- Act 3: Share & compare (1 large featured card: entry-live)
Gradient line connectors between acts imply flow; numbered badges moved
from per-card to per-act so cards feel like supporting visuals.
Add root smooth scrolling (scroll-smooth on <html>) for hash-link anchors.
Add recording + session-form screenshots (in-game captures from Steam
pause overlay), each rendered with the device-photo treatment
(rounded + drop shadow) to match the other in-game-style shots.
Flip all HAS_SCREENSHOT flags to true — the full gallery is now live.
- Update file paths to match provided .jpg captures (panel-overview, pair-qr,
launch-option, entry-live)
- Flip HAS_SCREENSHOT for the 4 available ones; keep recording + session-form
as placeholders for now (user will add in-game/phone photos later)
- entry-live.png → entry-live.jpg (smaller, still good quality at 1400px)
- All images compressed: Deck shots 1000px / q78, web shot 1400px / q78
- Add scripts/compress-screenshots.sh for re-compressing anytime
The QAM overlay can't be captured by Steam's screenshot shortcut while a game
runs, so the 'recording' and 'session-form' shots will be phone photos of the
Deck. These now render with rounded corners + drop shadow + ring so a device
photo looks intentional rather than like a broken screenshot. Placeholders
label them 'device photo coming soon'.
release.sh: build, package ZIP, tag, and create GitHub release in one command.
Screenshot slots now use 16:10 (matches Steam Deck's 1280x800 screen) with
object-contain so full-screen Deck captures fit without cropping.
Plugin docs page (/plugin):
- Hero, feature grid, numbered install guide, screenshot gallery, install CTA
- Navbar 'Plugin' link added
- Screenshot slots with placeholders for 6 captures (flip HAS_SCREENSHOT
once PNGs are dropped into /public/plugin/)
- Structured data (SoftwareApplication) + breadcrumbs
TDP fix:
- Add 3W fixed overhead to CPU+GPU power for screen/fan/speakers/peripherals
so reported TDP is closer to total system power draw
The ZIP bundles plugin.json, main.py, package.json, dist/index.js (+ map) at
the archive root (no enclosing folder) — the format Decky's 'Install Plugin
from ZIP File' / 'Install Plugin from URL' expects.
Usage:
bun run build:zip # build + package → releases/plugin-v<version>.zip
bun run zip # package already-built dist only
The old test hit /api/games/lookup which is a public endpoint with no auth,
so it never checked the key — any key (or a deleted one) reported as valid.
- Add GET /api/plugin/verify-key endpoint that uses authenticateWithApiKey
to properly verify the x-api-key header via Better Auth
- Plugin test_api_key now calls /api/plugin/verify-key instead of games-lookup
- Returns the linked user's name + avatar on success for richer feedback
- Profile page now reads ?tab= query param to open Settings tab directly
- Settings container reads ?subtab= query param to open API Keys directly
- /pair success link updated to /profile?tab=settings&subtab=api-keys (was /profile/settings?tab=api-keys which 404'd)
- Add plugin_pairings table + migration (0028) for short-lived pairing sessions
- Add pairing API: POST /api/plugin/pair/initiate, GET /status/:token, POST /confirm
- Add /pair web page: user scans QR on phone, confirms, API key auto-created
- Plugin: 'Pair with Phone' button renders QR code (qrcode.react), polls for status, saves API key
- Plugin: new initiate_pair + check_pair_status Python RPCs
- Revise MangoHud Setup Guide into clean numbered steps
- Fix SteamOS version detection: read VERSION_ID + BUILD_ID (was just 'SteamOS')