diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 4e54483..46217dc 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -14,7 +14,7 @@ body:
attributes:
label: ProtonShift version
description: "Check the app's About dialog or `electron/package.json`."
- placeholder: "0.9.6"
+ placeholder: "0.9.7"
validations:
required: true
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000..b6eb436
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,326 @@
+# Architecture & contributor guide
+
+
+ How ProtonShift is built, how the pieces talk, and how to add to it.
+
+
+
+ Overview ·
+ System diagram ·
+ Renderer ·
+ Backend ·
+ HTTP API ·
+ Project layout ·
+ Building ·
+ VM testing ·
+ Pre-commit ·
+ Contributing ·
+ Release
+
+
+---
+
+## Overview
+
+ProtonShift is a three-layer desktop app:
+
+1. **An Electron renderer** that ships as a Next.js 16 *static export* — React 19, Tailwind v4, HeroUI v3 (base + Pro). It is the only thing the user sees.
+2. **An Electron main process** that spawns the Python backend, owns the window chrome, and exposes a tiny IPC surface (filesystem helpers, the running app version, etc.) over a preload contextBridge.
+3. **A Python FastAPI backend** running on `127.0.0.1` that does all the real OS work: scanning Steam/Heroic/Lutris, reading and writing config files, talking to `nvidia-smi`/`xrandr`/`wlr-randr`, managing Wine prefixes, etc.
+
+The renderer never talks to the OS directly. Everything funnels through the backend so the same logic is reusable from CLI tools, tests, or other front-ends.
+
+## System diagram
+
+```
+┌──────────────────────────────────────────────────────┐
+│ Electron renderer · Next.js 16 (static export) │
+│ React 19 · Tailwind v4 · HeroUI v3 (+ Pro) │
+│ │
+│ / ───────────── game library + detail │
+│ /environment ── ~/.config/environment.d │
+│ /system ────── GPU / displays / power │
+│ /mangohud ──── global + per-game .conf editor │
+│ /scopebuddy ── scb.conf + scb.conf.d/.conf │
+│ /controllers ─ detection + live gamepad tester │
+└─────────────────────┬────────────────────────────────┘
+ │ preload IPC bridge
+ │ (window.electron.*)
+┌─────────────────────▼────────────────────────────────┐
+│ Electron main process · electron/main.ts │
+│ Spawns Python, proxies HTTP, exposes app version │
+└─────────────────────┬────────────────────────────────┘
+ │ HTTP on 127.0.0.1
+┌─────────────────────▼────────────────────────────────┐
+│ Python FastAPI backend · src/game_setup_hub/ │
+│ │
+│ Sources steam · heroic · lutris │
+│ Configs gamescope · scopebuddy · mangohud │
+│ Runtime gpu · display · controllers · prefix │
+│ Data env_vars · profiles_storage · saves │
+│ Tooling protontricks · fixes · tool_check │
+│ │
+│ api/routes/ games heroic mangohud profiles │
+│ saves scopebuddy system utility │
+└──────────────────────────────────────────────────────┘
+```
+
+The renderer ships as a **static Next.js export** packaged inside Electron, so there is no server runtime at the framework layer — no server actions, no dynamic route handlers, no edge runtime. All dynamic behaviour goes through the IPC bridge to the bundled Python API.
+
+## Renderer
+
+The Electron renderer is a standalone Next.js app under [`electron/renderer/`](electron/renderer/). It is built once with `next build` (static export) and the resulting `out/` directory is what Electron loads at runtime.
+
+**Stack:**
+
+- **Next.js 16** App Router, static export only
+- **React 19** with hooks-first conventions
+- **Tailwind CSS v4** (no v3 fallback)
+- **HeroUI v3** — base components from `@heroui/react`, plus Pro components (`Sheet`, `Command`, charts, `Sidebar`, `Kanban`, etc.) from `@heroui-pro/react`
+- **TanStack Query** for server state, **Jotai** for cross-component client state
+- **Lucide** icons throughout
+
+**Conventions enforced by [`.cursor/rules/heroui-v3.mdc`](.cursor/rules/heroui-v3.mdc):**
+
+- Compound components everywhere (`Card.Header` not ``)
+- `onPress`, not `onClick`, for interactive elements
+- Prefer HeroUI semantic tokens (`border-border`, `bg-surface`, `text-foreground`) over hand-rolled colour utilities
+- Reserve renderer-local tokens (`neon-*`, `glow-*`, `blob-*`) for accent glow & ambient effects only
+- Toasts go through `appShowToast` in [`electron/renderer/src/lib/app-toast.ts`](electron/renderer/src/lib/app-toast.ts)
+- No parallel UI libraries — if HeroUI doesn't have it, write a thin local primitive under `electron/renderer/src/components/`
+
+**Renderer routes** map 1:1 to the nav items:
+
+| Route | Component | What it does |
+|---|---|---|
+| `/` | `app/page.tsx` | Unified game library + per-game detail panes |
+| `/environment` | `app/environment/page.tsx` | `~/.config/environment.d/` editor + presets |
+| `/system` | `app/system/page.tsx` | GPU info, displays, power profiles, quick actions |
+| `/mangohud` | `app/mangohud/page.tsx` | Global `MangoHud.conf` + per-game `wine-*.conf` |
+| `/scopebuddy` | `app/scopebuddy/page.tsx` | `scb.conf` + `scb.conf.d/.conf` editor |
+| `/controllers` | `app/controllers/page.tsx` | Detection + SDL mapping + live gamepad tester |
+
+The command palette (Ctrl+K) lives in [`electron/renderer/src/components/app-command.tsx`](electron/renderer/src/components/app-command.tsx) and dispatches through events in [`electron/renderer/src/lib/command-palette-events.ts`](electron/renderer/src/lib/command-palette-events.ts).
+
+## Backend
+
+The Python backend is a normal FastAPI app under [`src/game_setup_hub/`](src/game_setup_hub/). It can run standalone for development or be spawned automatically by the Electron main process for the packaged app.
+
+**Module layout:**
+
+- **Library sources** — `steam.py`, `heroic.py`, `heroic_config.py`, `lutris.py` discover games and expose a uniform shape
+- **Config surfaces** — `gamescope.py`, `scopebuddy.py`, `mangohud.py`, `env_vars.py`, `vdf_config.py`, `presets.py`
+- **OS runtime** — `gpu.py`, `display.py`, `controllers.py`, `prefix.py`, `paths.py`, `fsutil.py`
+- **Data & state** — `profiles_storage.py`, `saves.py`, `shader_cache.py`, `fixes.py`
+- **Tooling** — `protontricks.py`, `tool_check.py`
+- **Compat shim** — `_vendor_compat.py` smooths over differences between bundled and host Python
+
+The FastAPI app itself lives in [`src/game_setup_hub/api/`](src/game_setup_hub/api/):
+
+- `_app.py` — app factory
+- `_state.py` — shared, lazily-initialised dependencies (split out from `_app.py` for testability)
+- `_models.py` — Pydantic models
+- `_helpers.py` — common request/response helpers
+- `routes/` — one router file per surface
+
+The version string in [`src/game_setup_hub/__init__.py`](src/game_setup_hub/__init__.py) is the single source of truth for the Python package and AppStream metadata. The Electron app version (in [`electron/package.json`](electron/package.json)) is surfaced to the renderer at runtime via the `getVersion` IPC handler so the nav-bar badge never drifts from the actual packaged version.
+
+## HTTP API
+
+Both the UI and the backend share the same FastAPI server. The Electron app spawns it automatically, but you can also run it standalone:
+
+```bash
+pip install -e .
+protonshift-api --port 8000
+# or, equivalent:
+python -m game_setup_hub.api --port 8000
+```
+
+Endpoint groups (see [`src/game_setup_hub/api/routes/`](src/game_setup_hub/api/routes/) for the full surface):
+
+| Group | Highlights |
+|---|---|
+| `games` | unified library, per-game detail, launch helpers |
+| `heroic` | Heroic-specific toggles & compat tool selection |
+| `mangohud` | global + per-game config CRUD |
+| `scopebuddy` | global `scb.conf`, per-app overrides, env detection |
+| `profiles` | save/apply/delete configuration profiles |
+| `saves` | discover, backup, restore |
+| `system` | GPU, displays, power profiles, shader cache totals |
+| `utility` | tool detection, controllers, fixes DB, misc |
+| `health` | liveness probe |
+
+Open `http://127.0.0.1:8000/docs` for the live OpenAPI explorer when the API is running standalone.
+
+## Project layout
+
+```
+protonshift/
+├── electron/ # Electron app
+│ ├── main.ts # main process + IPC handlers
+│ ├── preload.ts # contextBridge surface
+│ ├── package.json # electron-builder config + app version (source of truth)
+│ └── renderer/ # Next.js renderer (static export)
+│ └── src/
+│ ├── app/ # routes: /, /environment, /system,
+│ │ # /mangohud, /scopebuddy, /controllers
+│ ├── components/ # UI components (HeroUI v3 base + Pro)
+│ ├── lib/ # api client, app-toast, events
+│ └── types/ # window.electron typings
+├── src/game_setup_hub/ # Python FastAPI backend
+│ ├── api/
+│ │ ├── _app.py # FastAPI app factory
+│ │ ├── _state.py # shared lazy deps
+│ │ ├── _models.py # Pydantic models
+│ │ └── routes/ # one router per surface
+│ ├── steam.py heroic.py # library sources
+│ ├── lutris.py #
+│ ├── gamescope.py # gamescope command builder + detection
+│ ├── scopebuddy.py # scb.conf + scb.conf.d/* I/O
+│ ├── mangohud.py # global + per-game configs
+│ ├── prefix.py saves.py # Wine prefix inspection, save backup
+│ ├── fixes.py profiles_storage.py
+│ ├── gpu.py display.py controllers.py
+│ ├── env_vars.py presets.py
+│ └── ...
+├── assets/ # icons, AppStream metainfo, social card
+├── docs/ # public docs
+│ └── internal/ # reviews, release snapshots
+├── scripts/ # dev/automation
+│ └── ci/ # linux-matrix.sh (cross-distro python check)
+├── tests/ # pytest suite (mirrors src/game_setup_hub)
+├── vm-test/ # Quickemu-based VM test harness
+│ ├── run-vm.sh # one-shot launcher per distro
+│ ├── provision/ # per-distro guest provisioners
+│ ├── quickemu/ # .extras.conf per distro
+│ ├── docs/ # per-distro runbooks (also mounted in-guest)
+│ └── smoke-checklist.md # manual smoke test
+├── .github/workflows/
+│ ├── ci.yml # ruff + pytest + linux-matrix + renderer build
+│ ├── build-release.yml # AppImage / deb / rpm / flatpak on release
+│ └── codeql.yml # security analysis
+└── pyproject.toml # Python package metadata
+```
+
+## Building from source
+
+### Python backend
+
+```bash
+python3 -m venv .venv && source .venv/bin/activate
+pip install -e ".[dev]"
+pytest -q
+ruff check
+protonshift-api --port 8000 # run standalone
+```
+
+### Renderer (dev)
+
+```bash
+cd electron/renderer
+pnpm install
+pnpm dev # next dev with hot reload
+```
+
+`@heroui-pro/react` is a private package — set `HEROUI_AUTH_TOKEN` in your shell before `pnpm install`, otherwise the postinstall step stops at a skeleton and TypeScript can't resolve the imports. Local devs store it in [q-ring](https://github.com/I4cTime/q-ring); CI pulls from the `HEROUI_AUTH_TOKEN` GitHub Actions secret (wired up in [`ci.yml`](.github/workflows/ci.yml) and [`build-release.yml`](.github/workflows/build-release.yml)).
+
+```bash
+# Local equivalent:
+export HEROUI_AUTH_TOKEN=$(qring get HEROUI_AUTH_TOKEN)
+pnpm install
+```
+
+### Electron app
+
+```bash
+cd electron
+pnpm install
+pnpm dev # spawns Python + opens an Electron window
+pnpm build # produces AppImage / deb / rpm / flatpak via electron-builder
+```
+
+`pnpm build` calls `next build` for the renderer first (static export to `out/`), then `electron-builder` bundles `out/`, the main process, the preload bundle, and a portable CPython 3.12 with the API stack pre-installed. Outputs land in `electron/dist/` and (for CI) are copied to `build/` at repo root.
+
+## VM testing harness
+
+[`vm-test/`](vm-test/) is a Quickemu-based harness for end-to-end-testing ProtonShift packages on real desktop distros without rebooting the host. It launches throwaway VMs, exposes the host's `build/` directory over SMB to the guest (`/mnt/protonshift-build/`), and stages both per-distro provisioning scripts *and* the runbook docs themselves into that share so you can `less /mnt/protonshift-build/_docs/.md` from inside the guest and paste the commands.
+
+Currently supported guests:
+
+- `ubuntu-24.04`
+- `fedora-41`
+- `bazzite` (atomic, gnome edition)
+- `cachyos`
+- `opensuse-tumbleweed`
+- `debian-12`
+
+```bash
+vm-test/run-vm.sh ubuntu-24.04
+# inside the guest, after the SMB share auto-mounts:
+ls /mnt/protonshift-build # AppImage / .deb / .rpm + _provision/ + _docs/
+less /mnt/protonshift-build/_docs/ubuntu-24.04.md
+sudo /mnt/protonshift-build/_provision/ubuntu.sh
+```
+
+Per-distro runbooks live under [`vm-test/docs/`](vm-test/docs/) and the smoke checklist at [`vm-test/smoke-checklist.md`](vm-test/smoke-checklist.md). Host prerequisites (Quickemu, KVM, samba) are documented in [`vm-test/docs/host-prerequisites.md`](vm-test/docs/host-prerequisites.md).
+
+## Pre-commit checks
+
+Local CI mirror — all of these are also enforced by [`.github/workflows/ci.yml`](.github/workflows/ci.yml):
+
+```bash
+# Python
+ruff check src tests
+pytest -q
+scripts/ci/linux-matrix.sh # cross-distro Python compat check
+
+# Renderer
+cd electron/renderer
+pnpm lint
+pnpm build # next build (static export); fails on type errors
+
+# Electron typecheck (main + preload)
+cd ../
+pnpm typecheck
+```
+
+If you only touched one layer, you can scope down — but at minimum run `ruff` + `pytest` for backend changes and `pnpm build` (in `electron/renderer/`) for renderer changes. The renderer build is the strictest gate; it surfaces any type drift between the API client and the FastAPI Pydantic models.
+
+## Contributing
+
+PRs are welcome. The basic flow:
+
+1. **Backend first.** Add the module under `src/game_setup_hub/`, write tests in `tests/`, expose a FastAPI router under `src/game_setup_hub/api/routes/`, register it in [`src/game_setup_hub/api/routes/__init__.py`](src/game_setup_hub/api/routes/__init__.py). Keep route handlers thin — push the work into a regular module so it's testable without a TestClient.
+2. **Then the renderer.** Add the API client method in [`electron/renderer/src/lib/api.ts`](electron/renderer/src/lib/api.ts), wire TanStack Query hooks, build the UI with HeroUI v3 (see [Renderer](#renderer) conventions). No parallel UI libraries.
+3. **Smoke it in a VM** with [`vm-test/run-vm.sh`](vm-test/run-vm.sh) before opening a PR if you've touched anything that talks to the OS — paths, sockets, system tools, packaging.
+4. **Branching.** Feature branches → PR into `develop`. Releases ship from `develop` → `main` via a PR. Don't push directly to `main`.
+5. **Commits.** Imperative-mood subject lines. Body should explain *why*, not what — the diff already shows the what.
+6. **Secrets.** Never commit `.env`, tokens, or credentials. Use [q-ring](https://github.com/I4cTime/q-ring) locally and GitHub Actions secrets for CI. See [`.cursor/rules/`](.cursor/rules/) for the project's secret-hygiene rule.
+
+For a deeper look at backend-side conventions, see [`docs/internal/python-review.md`](docs/internal/python-review.md). For renderer-side conventions, see [`.cursor/rules/heroui-v3.mdc`](.cursor/rules/heroui-v3.mdc).
+
+## Release process
+
+1. Bump versions to `X.Y.Z` in:
+ - [`electron/package.json`](electron/package.json) — single source of truth for the app
+ - [`electron/renderer/package.json`](electron/renderer/package.json)
+ - [`src/game_setup_hub/__init__.py`](src/game_setup_hub/__init__.py)
+ - [`assets/io.github.protonshift.metainfo.xml`](assets/io.github.protonshift.metainfo.xml) — add a new `` entry
+ - [`.github/ISSUE_TEMPLATE/bug_report.yml`](.github/ISSUE_TEMPLATE/bug_report.yml) — bump the placeholder
+2. Run the [pre-commit checks](#pre-commit-checks) locally.
+3. Commit on `develop`, push, open a PR from `develop` to `main`.
+4. Tag: `git tag vX.Y.Z && git push origin vX.Y.Z`.
+5. Create a GitHub Release for the tag — this fires [`build-release.yml`](.github/workflows/build-release.yml), which builds the AppImage / deb / rpm / flatpak and attaches them to the release.
+6. Merge the PR into `main`.
+
+To peek at download counts and per-format breakdowns for prior releases:
+
+```bash
+gh api repos/I4cTime/protonshift/releases --paginate \
+ --jq '.[] | "\(.tag_name)\t\(.published_at[:10])\t\(.assets | map(.download_count) | add)"' \
+ | column -t -s $'\t'
+```
+
+---
+
+If something here is wrong or unclear, [open an issue](https://github.com/I4cTime/protonshift/issues/new/choose) — this doc is the contract between the codebase and the next person editing it.
diff --git a/README.md b/README.md
index 3aa80b0..1141532 100644
--- a/README.md
+++ b/README.md
@@ -1,62 +1,109 @@
-
+
ProtonShift
- Linux game configuration toolkit. Everything you need, in one place.
- No terminal gymnastics required.
+ The Linux game configuration toolkit.
+ Steam, Heroic and Lutris in one library. Gamescope, MangoHud and ScopeBuddy
+ in one editor. No terminal gymnastics. No JSON spelunking. No winetricks arcana.
+
+
+
+
+
+
+
+
+ Why ·
+ Install ·
Features ·
- Installation ·
- Architecture ·
- Python API ·
+ Roadmap ·
+ Contributing & architecture ·
License
---
+## Why ProtonShift?
+
+Linux gaming finally works. The configuration around it still doesn't.
+
+You end up with launch options in Steam, Heroic JSON files for the same game in another launcher, `MangoHud.conf` hand-edited in `nano`, `gamescope` flags pasted from a Reddit comment, `scb.conf` for ScopeBuddy, `environment.d/*.conf` for system-wide tuning, `protontricks` from a terminal, and a `~/.steam/steam/steamapps/compatdata/` folder you're afraid to touch.
+
+ProtonShift gathers all of that into one place — a real desktop app, with a real backend — and gives every tool a sensible UI. Toggle DXVK and FSR with a switch. Build a Gamescope command with sliders. Hand-pick a MangoHud preset. Inspect a Wine prefix without `cd`-ing into it. Roll forward and back between configuration *profiles* per game.
+
+---
+
+## Install
+
+Grab the latest package for your distro from the [Releases](https://github.com/I4cTime/protonshift/releases) page.
+
+```bash
+# AppImage — works everywhere
+chmod +x ProtonShift-*.AppImage
+./ProtonShift-*.AppImage
+
+# Debian / Ubuntu / Pop!_OS / Mint
+sudo dpkg -i ProtonShift-*.deb
+
+# Fedora / RHEL
+sudo dnf install ProtonShift-*.rpm
+
+# openSUSE
+sudo zypper install ProtonShift-*.rpm
+
+# Flatpak
+flatpak install ProtonShift-*.flatpak
+flatpak run io.github.protonshift
+```
+
+Official builds bundle a portable **CPython 3.12** runtime *and* the full Python API stack (FastAPI, Uvicorn, VDF, etc.) beside the app. The only outside dependencies are the **game tools you actually want to manage** — Steam, Heroic, Lutris, MangoHud, Gamescope, ScopeBuddy, Protontricks, GameMode. No `python3-pydantic` on the host. Nothing leaking into your user site-packages.
+
+Press Ctrl+K anywhere in the app to jump between pages or focus the game search.
+
+---
+
## Features
-### Your Entire Library, Unified
+### Your entire library, unified
-ProtonShift pulls games from **Steam**, **Heroic** (Epic + GOG), and **Lutris** into a single searchable list. Source badges tell you where each game lives, and per-source counts keep things at a glance.
+ProtonShift pulls games from **Steam**, **Heroic** (Epic + GOG), and **Lutris** into a single searchable list. Source badges tell you where each game lives, per-source counts keep things at a glance.
-- Steam library discovery via `libraryfolders.vdf` + appmanifest files (native & Flatpak)
+- Steam discovery via `libraryfolders.vdf` + appmanifests (native & Flatpak)
- Heroic discovery via Legendary JSON + GOG install info (native & Flatpak)
- Lutris discovery via `pga.db` + YAML prefix detection (native & Flatpak)
- Search across all sources at once
-- Launch games directly: `steam://rungameid/` or `heroic://launch/`
-- Copy App ID to clipboard in one click
-- Open install folder or Wine prefix in your file manager
+- Launch directly with `steam://rungameid/` or `heroic://launch/`
+- Copy App ID, open install folder, open Wine prefix — one click each
-### Launch Options
+### Launch options, properly
-Edit per-game launch options with a proper text editor, not a tiny Steam dialog box.
+Edit per-game launch options with a real text editor instead of Steam's matchbox dialog.
-**Quick presets** let you toggle common snippets without memorizing them:
+**Quick presets** let you toggle common snippets without memorising them:
| Preset | What it does |
-|--------|-------------|
+|---|---|
| GameMode | Prepend `gamemoderun` for Feral GameMode |
| NVIDIA dGPU | Add offload env vars for hybrid GPU laptops |
| MangoHud | Enable the MangoHud overlay |
| Proton Log | Turn on `PROTON_LOG=1` for debugging |
-Presets detect whether their tool is installed and grey out with a hint if it's missing.
-Works for both **Steam** and **Heroic** games.
+Presets detect whether their tool is installed and grey out with a hint if it's missing. Works for **Steam** and **Heroic** games.
-### Proton & Wine Tool Selection
+### Proton & Wine tool selection
Pick your compatibility layer from a dropdown instead of hunting through config files.
-- **Steam:** Lists all installed Proton versions from `compatibilitytools.d` and built-in tools
-- **Heroic:** Scans `tools/wine` and `tools/proton` directories, shows current selection
+- **Steam:** lists all installed Proton versions from `compatibilitytools.d` and the built-in tools
+- **Heroic:** scans `tools/wine` and `tools/proton`, shows the current selection
-### Heroic Power User Toggles
+### Heroic power-user toggles
For Heroic games, flip switches for the settings that usually mean editing JSON by hand:
@@ -68,7 +115,7 @@ For Heroic games, flip switches for the settings that usually mean editing JSON
Changes persist immediately to Heroic's per-game config.
-### Gamescope Command Builder
+### Gamescope command builder
Build a complete Gamescope command visually. No man page required.
@@ -80,32 +127,42 @@ Build a complete Gamescope command visually. No man page required.
- One click to insert it into your launch options or copy to clipboard
- Install hints for Ubuntu, Fedora, Arch if Gamescope isn't found
-Available for Steam and Heroic games.
+When a [ScopeBuddy](#scopebuddy-integration-new-in-v095) override exists for the game, the builder picks it up and offers to round-trip back into ScopeBuddy.
+
+### ScopeBuddy integration *(new in v0.9.5)*
+
+[ScopeBuddy](https://github.com/HikariKnight/ScopeBuddy) is a brilliant little wrapper that intercepts `gamescope` invocations and lets you layer arguments per-application. ProtonShift now ships a first-class editor for it under **ScopeBuddy** in the nav.
-### MangoHud Config Editor
+- Inspect the global `scb.conf` and its environment variables side-by-side
+- KV editor for `SCB_GAMESCOPE_ARGS`, `SCB_AUTO_RES`, `SCB_AUTO_HDR`, `SCB_AUTO_VRR`, `SCB_AUTO_REFRESH`, `SCB_AUTO_FRAME_LIMIT`, `SCB_NOSCOPE`, `SCB_NESTEDFIX`, `SCB_APPENDMODE`, `SCB_DEBUG`
+- Per-app overrides under `scb.conf.d/` — create, edit, duplicate, delete
+- Detection toasts: ProtonShift tells you when ScopeBuddy is installed, missing, or shadowed by an older fork
+- Install hints for Bazzite/SteamOS, Fedora (Terra), Arch (AUR), NixOS, and a `curl` fallback
+- Game detail page has a **ScopeBuddy override** card that deep-links straight to the right `scb.conf.d/.conf`
+
+### MangoHud config editor
A full visual editor for MangoHud — no more hand-editing `.conf` files.
**Global config** (`~/.config/MangoHud/MangoHud.conf`):
-- Toggle individual metrics on/off grouped by category: Performance, CPU, GPU, Memory, I/O, System, Behavior
+- Toggle individual metrics grouped by category: Performance, CPU, GPU, Memory, I/O, System, Behavior
- Set values: FPS limit, overlay position (8 anchor points), font size, background alpha
-- Configure toggle hotkey with quick presets
-- Set log folder with path presets and folder opener
+- Configure the toggle hotkey with quick presets
+- Set the log folder with path presets and a folder opener
-**Per-game configs** (`wine-{game}.conf`):
+**Per-game configs** (`wine-.conf`):
- Auto-discovers existing per-game configs
- Deep-link from any game's detail page to its MangoHud config
- Create new per-game overrides
-**Presets** to get started fast:
-Minimal, FPS Only, Standard, CPU+GPU, Benchmark, Battery Saver, Streaming, Full, Debug
+**Presets to get started fast:** Minimal · FPS Only · Standard · CPU+GPU · Benchmark · Battery Saver · Streaming · Full · Debug.
-### Environment Variables
+### Environment variables
Manage global gaming environment variables that persist across reboots via `~/.config/environment.d/`.
**Built-in presets:**
-- Proton NVIDIA / AMD optimizations
+- Proton NVIDIA / AMD optimisations
- DXVK / VKD3D tuning
- Shader cache settings
- Wayland compatibility
@@ -114,7 +171,7 @@ Manage global gaming environment variables that persist across reboots via `~/.c
Each preset shows exactly which variables it sets with descriptions, so you know what you're enabling.
-### Configuration Profiles
+### Configuration profiles
Save a complete game setup as a named profile and restore it later — or apply it to a different game.
@@ -124,9 +181,9 @@ A profile captures:
- Current environment variables
- Active power profile
-Profiles auto-highlight when they match the current game name or App ID. Loading a profile can optionally restore environment variables and power profile system-wide.
+Profiles auto-highlight when they match the current game name or App ID. Loading a profile can optionally restore environment variables and the power profile system-wide.
-### Wine/Proton Prefix Management
+### Wine / Proton prefix management
See what's inside your Wine prefixes without digging through directories:
@@ -134,11 +191,11 @@ See what's inside your Wine prefixes without digging through directories:
- Detected DXVK version (from `d3d11.dll`)
- Detected VKD3D-Proton version (from `d3d12.dll`)
- Delete prefix with confirmation dialog
-- Open prefix folder in file manager
+- Open prefix folder in your file manager
-Works for Steam, Heroic, and Lutris games (anywhere a prefix path is known).
+Works for Steam, Heroic, and Lutris games — anywhere a prefix path is known.
-### Shader Cache
+### Shader cache
Keep tabs on Steam's shader cache:
@@ -146,17 +203,17 @@ Keep tabs on Steam's shader cache:
- Clear a single game's cache with confirmation
- Total shader cache size on the System page
-### Game Save Backup & Restore
+### Save backup & restore
Never lose a save file again.
- Auto-detects save locations in Proton prefixes and Steam `userdata`
- Shows per-directory save sizes
-- **Backup All** creates a timestamped ZIP archive under `~/.config/protonshift/backups/`
+- **Backup All** creates a timestamped ZIP under `~/.config/protonshift/backups/`
- Browse previous backups and restore with one click
-- Works for Steam, Heroic, and Lutris games with known prefix paths
+- Works for Steam, Heroic, and Lutris where a prefix path is known
-### Game-Specific Fixes Database
+### Game-specific fixes database
A built-in database of known fixes for common game issues.
@@ -170,39 +227,31 @@ A built-in database of known fixes for common game issues.
Run Protontricks without leaving the app:
- Open the Protontricks GUI for any Steam game
-- Quick-run common verbs: vcrun2022, dotnet48, d3dx9, corefonts, and more
-- Supports both native and Flatpak installations of Protontricks
-
-### System Info & Controls
-
-The System page gives you a dashboard for your hardware:
-
-**GPU:**
-- Detection for NVIDIA (via `nvidia-smi`) and AMD/Intel (via DRM sysfs)
-- Live temperature reading
-- VRAM usage (NVIDIA)
+- Quick-run common verbs: `vcrun2022`, `dotnet48`, `d3dx9`, `corefonts`, and more
+- Supports native **and** Flatpak installations of Protontricks
-**Power Profiles:**
-- Switch between performance / balanced / battery saver
-- Supports `system76-power` (Pop!_OS) and `powerprofilesctl` (generic)
+### System info & controls
-**Displays:**
-- Monitor detection via `xrandr` (X11) or `wlr-randr` (Wayland)
-- Resolution and refresh rate per monitor
+The System page is a dashboard for your hardware:
-**Quick Actions:**
-- Open MangoHud config folder
-- Open ProtonShift config directory
-- View total shader cache size
+**GPU** — NVIDIA detection via `nvidia-smi`, AMD/Intel via DRM sysfs, live temps, VRAM usage (NVIDIA).
+**Power profiles** — switch between performance / balanced / battery saver. Supports `system76-power` (Pop!_OS) and `powerprofilesctl` (generic).
+**Displays** — monitor detection via `xrandr` (X11) or `wlr-randr` (Wayland), resolution and refresh rate per monitor.
+**Quick actions** — open MangoHud config folder, open ProtonShift config directory, view total shader cache size.
-### Controllers
+### Controllers — with a live gamepad tester *(tester new in v0.9.5)*
-Detect connected game controllers and get the info you need:
+Detect connected game controllers and get the info you need.
- Auto-detect Xbox, PlayStation, Nintendo, and generic controllers from `/proc/bus/input`
- Show controller name and type with vendor identification
- Generate `SDL_GAMECONTROLLERCONFIG` mapping strings
- Copy mappings for use in Steam Input or as environment variables
+- **Live gamepad tester** — every button, every axis, every trigger, real-time. Buttons light up, axes turn into meters, deadzones are obvious, and a rumble test confirms haptics work before you fire up the game
+
+### Command palette *(new in v0.9.5)*
+
+Press Ctrl+K anywhere to jump between pages, focus the game search, or trigger common actions. Built on HeroUI Pro's `Command`. Closes on Esc.
### Theming
@@ -210,90 +259,45 @@ Multiple visual themes with light and dark variants, switchable from the nav bar
---
-## Installation
-
-Grab the latest package for your distro from the [Releases](https://github.com/I4cTime/protonshift/releases) page.
-
-### AppImage (any distro)
-
-```bash
-chmod +x ProtonShift-*.AppImage
-./ProtonShift-*.AppImage
-```
-
-### .deb (Ubuntu, Pop!_OS, Mint, elementary OS)
-
-```bash
-sudo dpkg -i ProtonShift-*.deb
-```
-
-### .rpm (Fedora, openSUSE, RHEL)
-
-```bash
-sudo dnf install ProtonShift-*.rpm
-# or on openSUSE:
-sudo zypper install ProtonShift-*.rpm
-```
+## Roadmap
-### Flatpak
+A few things wired up on the backend but not yet surfaced in the UI, plus close-to-the-edge wishlist items:
-```bash
-flatpak install ProtonShift-*.flatpak
-flatpak run io.github.protonshift
-```
+- [ ] Shader env-var toggles (`RADV_PERFTEST`, `MESA_SHADER_CACHE_DISABLE`)
+- [ ] Auto-backup saves before prefix deletion
+- [ ] Per-game display / monitor targeting
+- [ ] Per-game controller overrides (mapping presets per App ID)
+- [ ] User-defined fix creation screen
+- [ ] Resolution switching from the System page
+- [ ] Lutris launch options editor parity with Steam/Heroic
+- [ ] ScopeBuddy: bulk import/export of per-app overrides
+- [ ] Flatpak permission inspector for sandboxed launchers
-Official builds bundle a portable CPython 3.12 runtime *and* the Python API stack (FastAPI, Uvicorn, VDF, etc.) beside the app — so the only outside dependencies are the **game tools you actually want to manage** (Steam, Heroic, Lutris, MangoHud, Gamescope, Protontricks, GameMode). No `python3` or `python3-pydantic` needed on the host.
+Have an idea? [Open an issue](https://github.com/I4cTime/protonshift/issues/new/choose).
---
-## Architecture
-
-```
-┌─────────────────────────────────────┐
-│ Electron / Next.js UI │
-│ (React 19 + Tailwind + HeroUI v3) │
-└──────────┬──────────────────────────┘
- │ IPC (preload bridge)
-┌──────────▼──────────────────────────┐
-│ Electron Main Process │
-│ (spawns Python, proxies requests) │
-└──────────┬──────────────────────────┘
- │ HTTP localhost
-┌──────────▼──────────────────────────┐
-│ Python FastAPI Backend │
-│ steam.py │ gpu.py │ vdf_config.py │
-│ heroic.py│lutris.py│profiles.py │
-└─────────────────────────────────────┘
-```
-
----
+## Contributing
-## Python API
+PRs are welcome. The full contributor guide — architecture overview, project layout, build instructions, VM testing harness, pre-commit checks, and release process — lives in [**ARCHITECTURE.md**](ARCHITECTURE.md).
-Both the UI and the backend share the same Python FastAPI server. The Electron app spawns it automatically, but you can also run it standalone:
+TL;DR:
```bash
-pip install -e .
-protonshift-api --port 8000
-```
+# Backend
+python3 -m venv .venv && source .venv/bin/activate
+pip install -e ".[dev]"
+pytest -q
-Endpoints: `/games`, `/env-vars`, `/system`, `/profiles`, `/presets`, and more.
+# Renderer (needs HEROUI_AUTH_TOKEN for the private @heroui-pro/react package)
+cd electron/renderer && pnpm install && pnpm dev
----
-
-## What's Next
-
-A few things that are wired up on the backend but not yet exposed in the UI:
-
-- Shader env var toggles (RADV_PERFTEST, MESA_SHADER_CACHE_DISABLE)
-- Auto-backup saves before prefix deletion
-- Per-game display/monitor targeting
-- Per-game controller overrides
-- User-defined fix creation screen
-- Resolution switching from the System page
+# Full Electron app
+cd electron && pnpm install && pnpm dev
+```
---
## License
-[AGPL-3.0](LICENSE)
+[AGPL-3.0](LICENSE) — copyleft for the network era. If you ship a modified version of ProtonShift (even as a hosted service), the source has to stay open.
diff --git a/assets/io.github.protonshift.metainfo.xml b/assets/io.github.protonshift.metainfo.xml
index b275678..8f7e53e 100644
--- a/assets/io.github.protonshift.metainfo.xml
+++ b/assets/io.github.protonshift.metainfo.xml
@@ -26,6 +26,7 @@
io.github.protonshift.desktop
https://github.com/I4cTime/protonshift
+
diff --git a/electron/main.ts b/electron/main.ts
index 62ee4c7..1f2d2ae 100644
--- a/electron/main.ts
+++ b/electron/main.ts
@@ -269,7 +269,12 @@ function startStaticRendererServer(rootDir: string): Promise {
res.writeHead(400).end();
return;
}
- if (pathname.includes("..")) {
+ // Reject true directory-traversal segments (".."/".") but allow dots
+ // inside filenames — Turbopack's content-hashed chunk names can contain
+ // consecutive dots, e.g. `16-.0wq_hn57..css`. A naive `includes("..")`
+ // check 403s the CSS bundle and renders the app completely unstyled.
+ const segments = pathname.split("/").filter((s) => s.length > 0);
+ if (segments.some((s) => s === ".." || s === ".")) {
res.writeHead(403).end();
return;
}
diff --git a/electron/package.json b/electron/package.json
index edc86b7..0e62346 100644
--- a/electron/package.json
+++ b/electron/package.json
@@ -1,6 +1,6 @@
{
"name": "protonshift",
- "version": "0.9.6",
+ "version": "0.9.7",
"description": "Linux game configuration toolkit",
"main": "dist/main.js",
"scripts": {
diff --git a/electron/renderer/package.json b/electron/renderer/package.json
index ad31b4a..11b4fce 100644
--- a/electron/renderer/package.json
+++ b/electron/renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "protonshift-renderer",
- "version": "0.9.6",
+ "version": "0.9.7",
"private": true,
"scripts": {
"dev": "next dev",
diff --git a/electron/renderer/src/components/nav-bar.tsx b/electron/renderer/src/components/nav-bar.tsx
index c5ee4ed..e7ad6ed 100644
--- a/electron/renderer/src/components/nav-bar.tsx
+++ b/electron/renderer/src/components/nav-bar.tsx
@@ -114,7 +114,7 @@ export function NavBar() {
- {appVersion ? `v${appVersion}` : "v0.9.6"} · Linux gaming HUD
+ {appVersion ? `v${appVersion}` : "v0.9.7"} · Linux gaming HUD
diff --git a/src/game_setup_hub/__init__.py b/src/game_setup_hub/__init__.py
index acabad4..b91e736 100644
--- a/src/game_setup_hub/__init__.py
+++ b/src/game_setup_hub/__init__.py
@@ -1,3 +1,3 @@
"""ProtonShift — Linux game configuration toolkit."""
-__version__ = "0.9.6"
+__version__ = "0.9.7"