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 + ProtonShift — Linux game configuration toolkit

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.

+ CI + Latest release + Total downloads + License: AGPL-3.0 + Platform: Linux +

+ +

+ 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"