docs: user-facing documentation and signing key

This commit is contained in:
2026-08-27 12:32:26 +01:00
commit 017c04fc3c
16 changed files with 3422 additions and 0 deletions
+475
View File
@@ -0,0 +1,475 @@
<!-- Generated from the Runi source repository at v0.4.0. -->
<!-- Edit the original there, not this copy. -->
# User flows
See [config-schema.md](config-schema.md) for the exact fields referenced
below, and architecture.md (source repository) for how `run` resolves all of
this internally.
## 1. First run on a fresh machine
`runi versions` auto-discovers whatever's already installed (Steam's
official Proton if Steam is present; nothing else yet). To get GE-Proton:
`runi versions list-remote --source ge-proton` shows installable
releases, `runi versions install ge-proton latest` downloads, verifies
checksum, extracts into `compatibilitytools.d` with a progress bar, and now
shows up in `runi versions`.
## 2. Add and run a standalone `.exe` (no storefront)
```
runi add ~/Games/MyIndieGame/game.exe --name "My Indie Game"
runi run my-indie-game
```
Exe path validated, `game.id = my-indie-game` (unique slug),
`identity.umu_gameid = umu-default` (shared fallback, no game-specific fixes — expected for an
unknown title). `run` resolves backend=umu (the global default), builds
`PROTONPATH`/`WINEPREFIX`/`GAMEID=umu-default`, execs `umu-run`. First launch
creates the Wine prefix.
## 3. Add a second build of a game you already have
Keeping two builds installed at once — a working one and a newer one you want
to test — is a normal thing to do. Both derive the same id, so Runi
resolves it instead of overwriting:
```
runi add ~/Games/Mortal.Shell.II.v92120-P2P/.../MortalShell2-Win64-Shipping.exe \
--name "Mortal Shell II"
added mortal-shell-ii-cl92120 (Mortal Shell II)
note: a different copy of 'Mortal Shell II' is already registered as
mortal-shell-ii; this one is registered alongside it (build version cl92120,
from pe-file-version)
shared with the other copy: game identity, notes, artwork
kept separate: Wine prefix, settings, environment, logs, save backups, mod receipts
```
The suffix is the build version read from the executable, so the id says which
copy it is. When the two copies report the same version — common for engines
that stamp their own version rather than the game's — there is nothing to tell
them apart and Runi asks instead of guessing:
```
Error: 'Ascend to ZERO' is already registered as ascend-to-zero and no build
version tells the two copies apart; re-run with --id <unique-id> to add it as a
separate installation
```
In the GUI this is one dialog with the proposed id pre-filled and editable,
showing the raw version string it came from.
**If you moved or renamed the folder instead**, that is not a second copy —
Runi recognises the installation by the marker inside it and offers to
repoint the existing registration, keeping its prefix, saves, settings and
mods:
```
Error: this installation is already registered as 'Mortal Shell II'
(mortal-shell-ii); it appears to have moved
```
## 4. Add a Steam game with a different Proton version than Steam's own choice
```
runi steam-scan
runi add --steam-appid 292030 --backend native --proton GE-Proton9-27
```
`steam-scan` lists installed titles with their AppIDs. `add --steam-appid`
resolves title/exe path automatically from the scan (no manual path-typing),
sets `game.id = steam-292030`, `identity.steam_appid = 292030`, and
`identity.umu_gameid = umu-292030` (so
protonfixes still key correctly even though this game runs outside Steam's
own launch path). `runi versions` would have already flagged
`GE-Proton9-27` as safe for `native` (no `⚠ needs steamrt`), so `add` doesn't
need to warn here.
In the GUI, Runtime separates **Launch Engine** from **Runner family** and
**Version**. UMU Automatic selects the newest installed GE-Proton; Direct
Proton selects an explicit installed build.
Manual game creation asks for the executable and suggests Display Name from a
local Steam manifest, PE ProductName/FileDescription, a cleaned installation
folder or finally the executable filename. The player may edit the suggestion.
Runi then resolves Steam/UMU identity in the background from a
game-provided `steam_appid.txt`, corroborated AppID metadata in bounded local
INI files, an exact local Steam manifest match, or an exact Steam Store title
match. Local AppIDs are validated directly through Steam app details, so an
imperfect folder title does not prevent identification. Ambiguous matches
require confirmation; unavailable or failed validation leaves `umu-default`. Runtime shows the
canonical title, source, confidence and validation timestamp, retains editable
technical fields and offers explicit revalidation.
Settings → Runners manages GE-Proton, UMU-Proton, Proton-CachyOS and experimental
Proton-EM releases. Proton Experimental is detected but remains Steam-managed.
Installed versions show manager and usage badges. Selecting a games badge
expands the titles configured to use that exact version; removal remains
disabled until those games are moved to another Runtime version.
Selecting an already installed release changes the action to **Installed**.
New builds are installed transactionally, so Runi never extracts over an
existing runner or exposes a partially extracted build to Steam/UMU.
### Add from Dolphin
On KDE Plasma, enable **Settings → Desktop Integration → Show “Add to
Runi” in Dolphin**. Right-click one local Windows `.exe` and choose
**Add to Runi**. Dolphin sends the path to the already-running GUI, or
starts it when necessary, and the normal Add Game review opens.
The local candidate check is shared by Dolphin, the GUI and `runi add`.
Malformed files and DLLs are blocked. A valid PE whose role is unclear, or a
file that resembles a settings/installer utility, is shown with evidence and
ranked alternatives but may still be added deliberately. Selecting a game
already in the library focuses its existing card instead of creating a
duplicate. Requests received while a game or modal task is active remain in a
small in-memory queue.
The same entry point is available for desktop integration testing:
```bash
runi gui --add-file /path/to/game.exe
runi desktop-integration dolphin status
runi desktop-integration dolphin install
runi desktop-integration dolphin remove
```
## 5. Add a GOG/Epic title
```
runi add ~/Games/SomeGogGame/game.exe --store gog --name "Some Game"
```
Manual registration in v1 (no Heroic/Legendary auto-scan yet — see
roadmap.md (source repository)); `STORE=gog` is still forwarded so protonfixes keyed
by store apply if the umu-database has an entry for it.
## 6. Add games from Ubisoft Connect
In the GUI choose **+ → Ubisoft Connect**. Install the client automatically or
import an existing Ubisoft prefix, open it to log in/install games, then close
it. Review the locally detected titles and import the selected ones. Later,
**Play** sends the Ubisoft deeplink directly; **Tools → Stores** reopens client
management. See [ubisoft-connect.md](ubisoft-connect.md) for the shared-prefix,
runner, process-monitoring and cloud-sync rules.
## 7. Tweak display settings on a stuttery game
```
runi config steam-292030 \
--set gamescope.enabled=true \
--set gamescope.output_width=2560 --set gamescope.output_height=1440 \
--set gamescope.render_width=1920 --set gamescope.render_height=1080 \
--set gamescope.filter=fsr \
--set mangohud.enabled=true
runi run steam-292030 --dry-run
```
`--dry-run` prints the fully composed command so you can verify before
committing:
```
gamescope -W 2560 -H 1440 -w 1920 -h 1080 -F fsr --mangoapp -- umu-run witcher3.exe
```
Note MangoHud folded into gamescope's own `--mangoapp` flag rather than
becoming a separate wrapper stage (gamescope's nested compositor doesn't
support the plain MangoHud overlay). Drop `--dry-run` to launch for real.
## 8. Install OptiScaler for a game with a weak native upscaler
```
runi optiscaler install steam-292030 --dll dxgi.dll
runi run steam-292030
```
Downloads the release, backs up any `dxgi.dll` the game already shipped,
copies OptiScaler's files alongside the game exe, sets
`env.WINEDLLOVERRIDES = "dxgi=n,b"` and `[optiscaler]` state in the config.
`run` launches normally; in-game `Insert` opens the OptiScaler overlay to pick
an upscaler backend.
```
runi optiscaler remove steam-292030
```
Restores the original file from the recorded manifest and clears the env
override.
## 9. Manage Proton versions over time
```
runi versions install ge-proton latest
runi versions remove GE-Proton9-20
```
The second command fails with `VersionInUseError` listing which games still
reference that version; re-point those games first
(`runi config <id> --set runtime.proton=GE-Proton9-27`), then removal
succeeds.
## 10. Clean up
```
runi remove my-indie-game
```
The CLI deletes the registration and its Wine prefix by default; pass
`--keep-prefix` to preserve the prefix. In the GUI, removing only the
registration is the safe default. A separate checkbox can permanently delete
the marked game installation and its prefix, and warns that local saves and
settings stored in either location are also deleted. Runi refuses this
disk deletion when the installation ownership marker does not match. The
originally selected folder remains the deletion unit even when the executable
is nested deeply; recognized Unreal packages include the sibling `Engine`
directory rather than only `Binaries/Win64`. Existing Runi save backups
are kept.
For Ubisoft games, the shared prefix is always preserved. The GUI can open
Ubisoft Connect's own uninstall confirmation before removing the Runi
registration; it never deletes the Ubisoft game directory itself.
## 11. Recipes, and what replaced them
**There is no Recipe tab, and adding a game no longer offers one.** Recipes
asked the player to assemble a setup from required items, recommended items,
supplied asset files and a review step - which is a great deal of deciding for
someone who wanted to press Play. The OptiScaler tab now narrows the same
ground to two explicit choices with automatic selection between them, so the
flow that used to live here is [flow 8](#8-install-optiscaler-for-a-game-with-a-weak-native-upscaler).
What remains is rollback. A game that had a recipe applied *before* the
retirement still carries its receipt, and shows a **Recipe (Legacy)** entry
for as long as that receipt exists, so the transaction can still be reverted.
Nothing creates a new one.
For an upscaler build with no official source to automate - a leaked FSR
package, a DLSS/XeSS swap - the supported path is a customize profile, which
is [flow 13](#13-apply-a-community-upscaler-workaround-manually-advanced).
## 12. Known launch compatibility
When Runi recognises an exact canonical game with a verified launch
workaround, it applies the safe default during registration or before launch
and shows a short notification. Explicit user launch options take precedence.
The first verified case is Pathogenic's Windows build on Linux: its Godot 4.7
D3D12 path crashed in RADV while creating a VKD3D compute pipeline, while the
same executable ran correctly with `--rendering-driver vulkan`. This argument
is scoped to Pathogenic's PGID; it is not inferred for other Godot games.
## 13. Apply a community upscaler workaround manually (advanced)
Real example, validated end-to-end: enabling a leaked FSR 4.1.1 INT8 build
on non-RDNA4 hardware, for a game with OptiScaler already installed.
```
runi optiscaler install my-game --dll dxgi.dll
```
Write `~/.config/runi/profiles/fsr411-workaround.toml` once (see
[customize-profiles.md](customize-profiles.md) for the full format):
```toml
[profile]
name = "fsr411-workaround"
description = "Community FSR 4.1.1 INT8 workaround for non-RDNA4 GPUs"
[[files]]
src = "/home/user/Downloads/FidelityFX-Samples-v2.3.0-prebuilt/.../amd_fidelityfx_upscaler_dx12.dll"
dest = "amd_fidelityfx_upscaler_dx12.dll"
[[ini_edits]]
file = "OptiScaler.ini"
[ini_edits.set]
Fsr4Update = "true"
```
```
runi customize apply my-game fsr411-workaround
runi run my-game
```
In-game, press `Insert` for the OptiScaler overlay and select FSR4 → the
INT8 model. If a newer leaked build shows up later, just edit the profile's
`[[files]]` source paths and re-`apply` — the previous version is reverted
automatically before the new one is applied.
```
runi customize remove my-game
```
Restores the pre-customize state exactly (the stock OptiScaler files,
`Fsr4Update` back to its original value) — OptiScaler itself stays installed.
## 14. Enable LinUwUx for a Reflex/DenuvOwO-protected game
```
runi config my-game --set linuwux.enabled=true
runi run my-game --dry-run
```
`--dry-run` confirms the wrapper is in place:
```
linuwux umu-run MyGame.exe
```
Drop `--dry-run` to launch for real. If the Technology Scan (GUI Overview
tab, or `runi doctor`) already flagged a "Compat Shim: LinUwUx (Reflex)"
or "LinUwUx (DenuvOwO)" finding for this game, that's an informational hint
only — Runi never enables the wrapper automatically.
`[linuwux].debug=true` adds `LINUWUX_DEBUG=1` for troubleshooting; leave it
off for normal play, since it produces heavy `sigsys redirect` logging.
`[linuwux].enabled` cannot be combined with `[gamescope].enabled` —
confirmed crashing on real hardware (the gamescope session dies before the
game process ever starts), not just untested. `runi run`/`--dry-run`
refuse with `IncompatibleWrapperError` up front rather than launching into a
crash; disable gamescope first if you need linuwux.
`[mangohud].enabled` works fine alongside linuwux — Runi activates it
with `MANGOHUD=1` alone instead of mangohud's usual `LD_PRELOAD` wrapper
(which does collide), confirmed working on real hardware. No extra
configuration needed; just enable both.
If you want a custom MangoHud layout via `[mangohud].config_file`, MangoHud's
own `core_load` option (per-core CPU load/frequency) is worth knowing about:
bisected on real hardware (Monster Hunter Wilds) that enabling `core_load`
forces MangoHud back to a vertical layout even with `horizontal` set - a
per-core breakdown doesn't fit a horizontal row. Every other stat option
(`cpu_stats`, `gpu_stats`, `ram`, `vram`, `frame_timing`, etc.) composes fine
with `horizontal`; only `core_load` is the exception. This is MangoHud's own
behavior, unrelated to Runi or linuwux specifically.
That exact layout ships as a bundled preset - see flow 15 below - so you
don't have to rebuild it by hand:
`runi mangohud-preset apply horizontal-complete <id>`.
LinUwUx upstream documents only GE-Proton and Proton-CachyOS as supported
(official Valve Proton is not). If `[runtime].proton` resolves to anything
else, `runi doctor` surfaces a non-blocking advisory finding rather
than refusing to launch:
```
runi doctor
```
Requires `linuwux` to already be on `PATH` (installed via upstream's own
`install.sh`/`build.sh --install` — see
[github.com/brcly/linuwux-runtime](https://github.com/brcly/linuwux-runtime));
Runi never installs or manages it.
## 15. Save and apply a named MangoHud preset
```
runi mangohud-preset list
```
Shows every available preset — bundled (shipped with Runi) plus any
you've saved locally. Runi ships one bundled preset out of the box,
`horizontal-complete`, the exact layout validated in flow 14 above:
```
runi mangohud-preset apply horizontal-complete my-game
runi config my-game --set mangohud.enabled=true
```
This writes the preset's content to a per-game file
(`~/.local/share/runi/mangohud/<id>.conf`) and sets
`[mangohud].config_file` to it — the same effect as building the file by
hand and pointing `config_file` at it, just one command. `runi run
my-game --dry-run` shows the resolved `MANGOHUD_CONFIGFILE` to confirm.
To save your own config (built by hand, or already applied to a game you're
happy with) as a reusable preset:
```
runi mangohud-preset save my-layout --from-game my-game --description "my favorite layout"
# or, from an arbitrary file:
runi mangohud-preset save my-layout --from-file ~/some/MangoHud.conf
```
Saved presets are plain TOML at
`~/.config/runi/mangohud-presets/<name>.toml`; a local preset with the
same name as a bundled one takes priority, so you can override
`horizontal-complete` itself by saving your own version under that name.
```
runi mangohud-preset remove my-game
```
Clears `[mangohud].config_file` (falling back to MangoHud's own default
resolution order) and deletes the applied per-game file.
**Deliberately per-game only** — there is no "apply globally" (writing
`~/.config/MangoHud/MangoHud.conf`). That file is commonly managed by
third-party tools like GOverlay/MangoJuice; a second tool silently writing
over it (even with a backup taken first) creates an ongoing "who owns this
file" conflict with no clean resolution, confirmed real on a machine already
running MangoJuice. If you want a preset's layout system-wide, apply it to
each game you care about, or use GOverlay/MangoJuice's own global-config
tooling directly.
## 16. Import a Ludusavi save backup into a game's prefix
CLI-only, low-key utility — reads a [Ludusavi](https://github.com/mtkennerly/ludusavi)
backup folder (`mapping.yaml` + `drive-C/`, the "simple" non-zip format)
directly and copies the files into the game's own Wine prefix. No
dependency on the `ludusavi` binary itself.
```
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game --preview
```
`--preview` shows exactly what would be copied — source → destination →
size — without writing anything. The prefix must already exist (launch the
game for real at least once first); otherwise this refuses rather than
half-creating one.
```
runi saves import-ludusavi my-game /path/to/ludusavi/backups/My\ Game
```
Copies every recorded file, verifying each one's SHA1 against what
`mapping.yaml` recorded (catches SMB/network corruption, not just logic
bugs), and — unless `--no-set-save-path` is passed — updates
`[saves].path` to the backup's own save location, so Runi's own
`saves backup`/`restore` also point at the right place afterward. If the
computed destination already has files in it, the *current* state is
backed up first via the normal `saves backup` mechanism, so an import is
always reversible.
Two real things this surfaced, worth knowing if a result looks surprising:
- **Path casing and shared folders.** Ludusavi records the source Windows
machine's own path casing (`Users`, capitalized) and username segment
(e.g. `Users/cvarandas/...`). Wine's real prefix directory is lowercase
(`users`) with its own account name (`steamuser` in every
runi-managed prefix) — a blind copy would create a bogus sibling
directory the game never sees. The importer resolves both against what's
actually on disk. It also knows `Users/Public/...` is a real, shared
folder, not a personal account to remap — confirmed by a real game (The
Sinking City 2) whose save data legitimately lives partly under `Public`.
- **A RUNE/crack config's declared save path and a Ludusavi backup's
actual files can legitimately disagree.** The Sinking City 2's RUNE
crack (`steam_emu.ini`) declares saves at
`users/Public/Documents/Steam/RUNE/2825860` — that's likely where RUNE
stores its *own* Steam-emulation state (fake achievements/cloud markers),
not necessarily the engine's native save files, which for this game
turned out to be `AppData/Local/TSC2/Saved` (confirmed by both the real
backup content and an actual game launch). The importer prints a note
when this happens (reusing Runi's existing RUNE detection as a
cross-check) but always imports to where the backup's files really are.
**Runi cannot verify a backup matches the installed game's specific
version/release** — Ludusavi's `mapping.yaml` records hashes for the save
data itself, not the source machine's game build. The safety backup above
is the actual mitigation; confirm compatibility the same way it was
confirmed here — launch the game and check.
Only the simple (non-zip) backup format is supported; a zip-format backup
folder is refused with a clear error rather than silently mishandled.