"use client" import { useState } from "react" import Link from "next/link" import { motion } from "motion/react" import { QrCodeIcon, GaugeIcon, UploadIcon, Gamepad2Icon, ShieldCheckIcon, ZapIcon, DownloadIcon, TerminalIcon, ArrowRightIcon, CopyIcon, CheckIcon, CodeIcon, SettingsIcon, FolderArchiveIcon, } from "lucide-react" // ── Screenshot slots ──────────────────────────────────────────── // Each screenshot is a self-contained card. Until you drop real // screenshots into /public/plugin/ and set showScreenshot=true, a // styled placeholder describing the exact shot to capture is shown. interface Shot { id: string title: string caption: string // filename the user should save the capture as (in /public/plugin/) file: string // true = present as a device photo (rounded, shadow) instead of a flat // screenshot. Use for in-game shots where the QAM overlay can't be // captured by Steam's screenshot shortcut, so a phone photo is used. photo?: boolean } const SCREENSHOTS: Shot[] = [ { id: "developer-mode", title: "Enable Developer mode", caption: "In the Decky menu → General, toggle on Developer mode. This unlocks the 'Install Plugin from ZIP File' option in the Developer tab.", file: "developer-mode.jpg", }, { id: "zip-file", title: "Install from the ZIP", caption: "Switch to the Developer tab, tap Browse under 'Install Plugin from ZIP File', and pick the DeckyVault ZIP you just downloaded.", file: "zip-file.jpg", }, { id: "panel-overview", title: "The plugin panel", caption: "The full DeckyVault panel in the Quick Access Menu — recording, account, and setup sections all in one scrollable view.", file: "panel-overview.jpg", }, { id: "pair-qr", title: "Pair with your phone", caption: "Tap 'Pair with Phone' and a QR code appears. Scan it with your phone, confirm on deckyvault.xyz, and your account links automatically — no copy-pasting API keys.", file: "pair-qr.jpg", }, { id: "launch-option", title: "Add the launch option", caption: "In Steam, right-click your game → Properties → Launch Options, and paste the MangoHud wrapper command. Copy it straight from the plugin.", file: "launch-option.jpg", }, { id: "recording", title: "Record while you play", caption: "Once in-game, open the panel and hit Start Recording. A live timer tracks your session. Stop when you're done benchmarking.", file: "recording.jpg", photo: true, }, { id: "session-form", title: "Review & submit", caption: "After stopping, review the captured FPS, 1% lows, and power draw. Add notes, then upload straight to DeckyVault — or export to a file.", file: "session-form.jpg", photo: true, }, { id: "entry-live", title: "See it on DeckyVault", caption: "Your submission appears on the game's page instantly — FPS averages, frame-time consistency, and TDP, all tied to your account.", file: "entry-live.jpg", }, ] // Screenshot files that actually exist in /public/plugin/ — flip these // to true once you've captured and saved the corresponding file. const HAS_SCREENSHOT: Record = { "developer-mode": true, "zip-file": true, "panel-overview": true, "pair-qr": true, "launch-option": true, recording: true, "session-form": true, "entry-live": true, } const LAUNCH_COMMAND = "~/deckyvault-mangohud.sh %command%" const FEATURES = [ { icon: GaugeIcon, title: "Capture real gameplay", body: "Records FPS, frame times, and 1% lows with MangoHud — not synthetic benchmarks, but how the game actually runs on your Deck.", }, { icon: ZapIcon, title: "Power draw & TDP", body: "Measures CPU + GPU power and adds peripheral overhead (screen, fan, speakers) for a realistic estimate of total system draw.", }, { icon: QrCodeIcon, title: "QR-code pairing", body: "Link the plugin to your DeckyVault account by scanning a QR code with your phone. No manual key entry, no fiddly typing.", }, { icon: UploadIcon, title: "One-tap upload", body: "Submit entries straight to DeckyVault from the Quick Access Menu. They appear on the game's page instantly, tied to your profile.", }, { icon: Gamepad2Icon, title: "Auto game detection", body: "Detects the running game and its Steam App ID, reads the Proton version, and resolves the game name automatically.", }, { icon: ShieldCheckIcon, title: "Your key, your control", body: "Pairing creates a real API key you can view and revoke anytime from Settings → API Keys. Nothing is stored without your say-so.", }, ] const STEPS = [ { icon: DownloadIcon, title: "Install Decky Loader", body: ( <> If you haven't, install{" "} Decky Loader {" "} on your Steam Deck — it's a one-time prerequisite that adds the Quick Access Menu plugin browser. ), }, { icon: SettingsIcon, title: "Enable Developer mode", body: ( <> In the QAM, open the Decky settings → General, and flip on{" "} Developer mode. This unlocks the "Install Plugin from ZIP File" option in the Developer tab. ), }, { icon: FolderArchiveIcon, title: "Install from the ZIP", body: ( <> Download{" "} the latest plugin ZIP {" "} from GitHub Releases. Then in QAM → Decky DeveloperInstall Plugin from ZIP FileBrowse, pick the ZIP and let Decky Loader do the rest. ), }, { icon: QrCodeIcon, title: "Pair your account", body: ( <> Open the plugin in the Quick Access Menu → Account →{" "} Pair with Phone. Scan the QR code with your phone and confirm on deckyvault.xyz. Your API key is created and saved automatically. ), }, { icon: TerminalIcon, title: "Set the launch option", body: ( <> In MangoHud Setup, tap Write Config. Then add the launch option to your game (Steam → right-click → Properties → Launch Options): ), code: LAUNCH_COMMAND, }, { icon: GaugeIcon, title: "Record & upload", body: ( <> Launch the game, open the panel, and hit Start Recording{" "} once you're in-game. When you're done, stop it, review the stats, and upload to DeckyVault. ), }, ] // ── Screenshot acts ──────────────────────────────────── // The "See it in action" gallery is structured as a 4-act narrative so the // story flows: Install → Set up → Capture → Share. Each act has a heading + // a list of shots. The last act's shot is rendered larger as a visual payoff. const ACTS: { number: string title: string subtitle: string shotIds: string[] layout: "grid-3" | "grid-2" | "feature" }[] = [ { number: "1", title: "Install the plugin", subtitle: "Enable Developer mode and load the ZIP from the Decky menu.", shotIds: ["developer-mode", "zip-file"], layout: "grid-2", }, { number: "2", title: "Get set up", subtitle: "Pair your account and add the MangoHud launch option.", shotIds: ["panel-overview", "pair-qr", "launch-option"], layout: "grid-3", }, { number: "3", title: "Capture performance", subtitle: "Hit record, play, then review your stats.", shotIds: ["recording", "session-form"], layout: "grid-2", }, { number: "4", title: "Share & compare", subtitle: "Your entry appears on the game's page for the community.", shotIds: ["entry-live"], layout: "feature", }, ] export function PluginPageClient() { const [copied, setCopied] = useState(false) async function copyCommand() { try { await navigator.clipboard.writeText(LAUNCH_COMMAND) setCopied(true) setTimeout(() => setCopied(false), 2000) } catch { // ignore } } return (
{/* ── Hero ────────────────────────────────────────────── */}
Decky Loader Plugin · v1.0.0 Benchmark your Steam Deck,{" "} straight from the Quick Access Menu The DeckyVault plugin captures real-world FPS, frame times, and power draw with MangoHud — then uploads them to DeckyVault with a single tap. No spreadsheets, no manual screenshots, no fuss. Download Plugin ZIP Installation Guide
{/* ── Features grid ────────────────────────────────────── */}

Built for the Steam Deck

Everything you need to capture and share performance data, designed around the Deck's controller-friendly UI.

{FEATURES.map((f, i) => (

{f.title}

{f.body}

))}
{/* ── How it works (steps) ─────────────────────────────── */}

How it works

Six steps from install to your first uploaded benchmark.

{STEPS.map((step, i) => (
{i + 1}
{i < STEPS.length - 1 && (
)}

{step.title}

{step.body}

{step.code && (
{step.code}
)}
))}
{/* ── See it in action: 3-act narrative ──────────────────────── */}

See it in action

A walkthrough of the plugin, from pairing to publishing.

{ACTS.map((act, actIdx) => { const shots = act.shotIds .map((id) => SCREENSHOTS.find((s) => s.id === id)) .filter((s): s is (typeof SCREENSHOTS)[number] => Boolean(s)) return (
{/* Act heading */}
{act.number}

{act.title}

{act.subtitle}

{/* Shot grid for this act */}
{shots.map((shot) => { const isFeature = act.layout === "feature" return (
{HAS_SCREENSHOT[shot.id] ? ( // eslint-disable-next-line @next/next/no-img-element {shot.title} ) : (
{shot.photo ? "device photo" : "screenshot"} not yet captured
)}
{shot.title}

{shot.caption}

) })}
{/* Flow arrow between acts */} {actIdx < ACTS.length - 1 && (
)}
) })}
{/* ── Install CTA ──────────────────────────────────────── */}

Ready to start benchmarking?

Download the plugin ZIP and install it via Decky Loader's{" "} Install Plugin from ZIP File option, or grab it from URL.

Download ZIP View Source
) }