diff --git a/plugins/decky-vault/src/index.tsx b/plugins/decky-vault/src/index.tsx
index 178425e..0de5783 100644
--- a/plugins/decky-vault/src/index.tsx
+++ b/plugins/decky-vault/src/index.tsx
@@ -1,32 +1,215 @@
-import { DeckyVaultImportV1 } from "@deckyvault/shared"
+import { useState, useEffect, useRef } from "react"
+import {
+ PanelSection,
+ PanelSectionRow,
+ staticClasses,
+} from "@decky/ui"
+import {
+ definePlugin,
+} from "@decky/api"
+import { FaDatabase } from "react-icons/fa"
+import MainPanel from "./components/main-panel"
+import SettingsPanel from "./components/settings-panel"
+import { useSettings, useSession } from "./lib/store"
+import {
+ readAndParseMangohudLog,
+ clearMangohudLog,
+ getHardwareInfo,
+ getOsVersion,
+ getProtonVersion,
+ getLaunchOptions,
+} from "./lib/api"
-interface PluginSettings {
- apiKey: string
- autoRecord: boolean
- exportPath: string
+function Content() {
+ const { settings, updateSetting, loaded } = useSettings()
+ const {
+ recordingState,
+ session,
+ recentSessions,
+ error,
+ setError,
+ startRecording,
+ stopRecording,
+ updateSession,
+ addToRecent,
+ reset,
+ onGameStart,
+ onGameStop,
+ } = useSession()
+ const [activeTab, setActiveTab] = useState<"main" | "settings">("main")
+ const gameStartedUnregRef = useRef<{ unregister: () => void } | null>(null)
+ const gameStoppedUnregRef = useRef<{ unregister: () => void } | null>(null)
+
+ // ── Register SteamClient game events ──────────────────────────
+ useEffect(() => {
+ try {
+ const startedReg = SteamClient.Apps.RegisterForGameStarted(async (appId: number) => {
+ let gameName = `App ${appId}`
+ try {
+ const info = await SteamClient.Apps.GetCurrentGameInfo()
+ if (info.appId === appId) {
+ gameName = info.strAppName
+ }
+ } catch {
+ // GetCurrentGameInfo may not be available in all contexts
+ }
+ onGameStart(appId, gameName)
+ })
+ gameStartedUnregRef.current = startedReg
+
+ const stoppedReg = SteamClient.Apps.RegisterForGameStopped((_appId: number) => {
+ onGameStop()
+ })
+ gameStoppedUnregRef.current = stoppedReg
+ } catch (e) {
+ console.warn("[DeckyVault] SteamClient event registration failed:", e)
+ }
+
+ return () => {
+ try {
+ gameStartedUnregRef.current?.unregister()
+ gameStoppedUnregRef.current?.unregister()
+ } catch {
+ // ignore
+ }
+ }
+ }, [onGameStart, onGameStop])
+
+ // ── Handle start recording ────────────────────────────────────
+ async function handleStart() {
+ // Clear any previous log file
+ await clearMangohudLog()
+ startRecording()
+ }
+
+ // ── Handle stop recording: parse log + read system info ────────
+ async function handleStop() {
+ stopRecording()
+
+ // Parse the MangoHud log
+ const logResult = await readAndParseMangohudLog()
+ if (logResult.error) {
+ setError(logResult.error)
+ // Still transition to stopped state so user can see the error + manual fields
+ return
+ }
+
+ // Read system info in parallel
+ const [hwInfo, osVersion] = await Promise.all([
+ getHardwareInfo(),
+ getOsVersion(),
+ ])
+
+ // Read Proton version + launch options if we have an app ID
+ let protonVersion = ""
+ let launchOptions = ""
+ if (session.appId) {
+ const [pv, lo] = await Promise.all([
+ getProtonVersion(session.appId),
+ getLaunchOptions(session.appId),
+ ])
+ protonVersion = pv
+ launchOptions = lo
+ }
+
+ // Use settings hardware override if set, otherwise auto-detected
+ const hardwareSlug = settings.hardwareSlug || hwInfo.slug
+
+ updateSession({
+ fpsAvg: logResult.fpsAvg ?? null,
+ fpsLow: logResult.fpsLow ?? null,
+ fpsHigh: logResult.fpsHigh ?? null,
+ fpsOnePercentLow: logResult.fpsOnePercentLow ?? null,
+ tdpWatts: logResult.tdpWatts ?? null,
+ hardwareSlug,
+ hardwareName: hwInfo.name,
+ osVersion,
+ protonVersion,
+ launchOptions,
+ })
+ }
+
+ if (!loaded) {
+ return (
+