Clearer file names and layout; docs/development.md

- steam-keyboard-patch.nix -> vr-keyboard-extra-keys.nix (option
  keyboard.vr.extraKeys), helper.mjs -> xdotool-helper.mjs;
  homeManagerModules.steam-keyboard-patch stays as an alias.
- vr-keyboard: panel.js/unpatch-panel.js/relay.mjs ->
  suggestions-panel/{patch,unpatch}.js + relay.mjs; decoder.js ->
  swipe-decoder.js; build.nix split into dictionary.nix and check.nix.
- modules/lib -> modules/steam-ui-patches/lib (the UI patch library).
- docs/development.md: repository layout (what runs where), runtime names.

Patch names, user services and state files are unchanged.
This commit is contained in:
Pierre Kisters committed 2026-09-29 01:42:34 +02:00
1 parent b3d93e8526
commit 5d15902ba1
40 files changed
+330 -161

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
# Development
Which file does what and where it runs, for working on steam-frame-nix
itself. Writing your own patches: [UI patches](ui-patches.md).
## Conventions
- `modules/<name>.nix` is `homeManagerModules.<name>`; files only it uses
are in `modules/<name>/`.
- `patch.js` / `unpatch.js`: a runtime patch of a web page and the
expression that reverts it. A module with several patches has one
directory per patch (`launcher-menu/grid/`,
`vr-keyboard/suggestions-panel/`).
- `*.js` in `modules/` is browser JavaScript evaluated in Steam's or
SteamVR's pages (single expressions, no imports); `*.mjs` is a Node
program (user service, test or script).
- `check.nix` is the module's flake check (`nix flake check`, attribute
`checks.<system>.<name>`); `tests/*.test.mjs` are run by it.
- Runtime names (patch names, user services, state files) are listed
[below](#runtime-names); they stay stable when files move.
Where things run:
| Tag | Where |
|---|---|
| **Steam** | Steam's UI, page `SharedJSContext`, DevTools `127.0.0.1:8080` |
| **SteamVR** | SteamVR's dashboard (`vrwebhelper`), page `systemui`, DevTools `127.0.0.1:8087` |
| **service** | systemd user service (outer Steam/VR session) |
| **switch** | Home Manager activation (`home-manager switch`) |
| **build** | Nix build time |
| **app** | started with an app (launcher, `LD_PRELOAD`, autostart) |
| **test** | `nix flake check` |
| **dev** | run by hand from a checkout |
## Repository layout
```text
flake.nix homeManagerModules, packages/apps (cleanup), checks, template
install.sh install / uninstall / cleanup (curl | bash; also the
steam-frame-nix-cleanup package and the debugger arm step)
template/ `nix flake init -t` / installer config: flake.nix, home.nix
docs/ one page per feature; ui-patches.md for patch authors
scripts/
check-signatures.mjs dev: check signatures.json against the installed Steam
webpack-modules.mjs dev: webpack module extraction (used by check-signatures)
vr-keyboard-replay.mjs dev: replay recorded swipes through the swipe decoder
modules/
session.nix switch: outer bus/runtime dir, user services on switch
cleanup.nix switch: `cleanup --orphans`; steam-frame-nix-cleanup on PATH
cleanup/package.nix build: install.sh as a command (cleanup, steamvr-debugger-arm)
cleanup/check.nix test: install.sh cleanup on fake home/runtime dirs
portal.nix Steam session portal config (session.portalFix)
keyboard-layout.nix gamescope-session drop-in with XKB_DEFAULT_* (keyboard.layout)
clipboard-sync.nix app: KDE autostart of clipboard-sync (clipboardSync)
hidden-apps.nix Hidden=true desktop entries (launcherMenu.hiddenApps)
keyring.nix app: launchers sharing the KDE wallet (keyring)
docker.nix service: rootless dockerd (docker)
firefox.nix Flatpak prefs extension and launcher entry (firefox)
firefox/launcher.nix app: launcher script (desktop profile, fullscreen fix)
firefox/check.nix test: launcher against a fake flatpak
jellyfin.nix desktop entry with flatpak run options (jellyfin.hardwareDecoding)
jellyfin/mpv-hwdec-shim.c app: LD_PRELOAD shim, hwdec auto* -> v4l2m2m-copy
jellyfin/shim.nix build: the shim as lib/mpv-hwdec-shim.so
jellyfin/check.nix test: shim ELF and rewriting
steam-ui-patches.nix service steam-ui-patches: runs the injector (uiPatches.*)
steam-ui-patches/
injector.mjs service: injects/re-injects/reverts patches over DevTools
lib/default.nix build: mkPatch (wraps a patch.js with the library)
lib/finders.js Steam+SteamVR: signature lookup of webpack modules/React fibers
lib/hooks.js Steam+SteamVR: shared method hooks (e.g. SendMessage)
lib/signatures.json build+dev: per-patch signatures (also check-signatures)
steamvr-debugger.nix service steamvr-webhelper-debugger: DevTools port 8087
launcher-menu.nix the VR "+" menu (launcherMenu.*), icon fallbacks
launcher-menu/
order/ Steam: sort the list
pinned-desktop/ Steam: pin Desktop above/below the list
launch/ Steam: close on launch, debounce
grid/ Steam: programs as a grid of tiles
show-all/ Steam: all programs without Developer Mode
icon-fallbacks.sh switch: hints for iconFallbacks (read-only)
vr-keyboard-extra-keys.nix Esc/Ctrl/Alt/arrows etc. (keyboard.vr.extraKeys)
vr-keyboard-extra-keys/
patch.js, unpatch.js Steam: the extra bottom row and key routing
xdotool-helper.mjs service steam-keyboard-patch: own injector + xdotool keys
vr-keyboard.nix swipe, suggestions, Backspace drag (keyboard.vr)
vr-keyboard/
patch.js, unpatch.js Steam: gestures, text model, suggestion strip
swipe-decoder.js Steam (argument of patch.js): swipe path -> words
textmodel.js Steam (argument of patch.js): what the keyboard typed
corrector.js Steam (argument of patch.js): corrections, completions
suggestions-panel/
patch.js, unpatch.js SteamVR: the strip as a panel above/below the keyboard
relay.mjs service vr-keyboard-relay: strip state Steam <-> SteamVR
dictionary.nix, gen-dict.py build: dictionary from wordfreq + Hunspell
check.nix, tests/ test (also built before the patch): text model,
corrector, swipe-decoder accuracy
dashboard-windows.nix, dashboard-windows/ SteamVR: window scale/distance limits
steam-close-button.nix, steam-close-button/ SteamVR: X on the Steam window
window-curvature.nix, window-curvature/ SteamVR: curvature wheel
frame-controls.nix, frame-controls/ SteamVR: window control bar
```
## Runtime names
Patch names appear in the journal, key `signatures.json` and name the
state files (`~/.local/state/steam-frame-nix/ui-patches/<name>.json`), so
they are kept even where a file name says more:
| Module | Option | Patches (page) | User services |
|---|---|---|---|
| `launcher-menu` | `launcherMenu` | `launcher-menu-{order,pinned-desktop,launch,grid,show-all}` (Steam) | `steam-ui-patches` |
| `vr-keyboard` | `keyboard.vr` | `vr-keyboard` (Steam), `vr-keyboard-panel` = `suggestions-panel/` (SteamVR) | `steam-ui-patches`, `vr-keyboard-relay` |
| `vr-keyboard-extra-keys` | `keyboard.vr.extraKeys` | `steam-keyboard-patch` (Steam) | `steam-keyboard-patch` |
| `dashboard-windows` | `dashboard.windows` | `dashboard-windows` (SteamVR) | `steam-ui-patches` |
| `steam-close-button` | `dashboard.steamCloseButton` | `steam-close-button` (SteamVR, state) | `steam-ui-patches` |
| `window-curvature` | `dashboard.windowCurvature` | `window-curvature` (SteamVR) | `steam-ui-patches` |
| `frame-controls` | `dashboard.frameControls` | `frame-controls` (SteamVR, state) | `steam-ui-patches` |
| `steamvr-debugger` | `steamvrDebugger` | | `steamvr-webhelper-debugger` |
Log of all patches:
`journalctl --user -u steam-ui-patches -u steam-keyboard-patch -u vr-keyboard-relay`.
## Checks
```sh
nix flake check # all checks, on aarch64-linux
nix shell nixpkgs#nodejs -c node scripts/check-signatures.mjs --strict # on the Frame
```
+10 -7
View File
@@ -8,7 +8,8 @@ The keyboard layout of the Steam session itself is a separate fix
## Extra keys
`keyboard.vr.extraKeys.enable`, module `steam-keyboard-patch`.
`keyboard.vr.extraKeys.enable`, module `vr-keyboard-extra-keys` (sources in
`modules/vr-keyboard-extra-keys/`).
**Problem:** Steam's VR keyboard has no Ctrl, Alt or Esc, can't press real
keys, and its text emulation only maps plain ASCII: non-ASCII and
@@ -55,9 +56,10 @@ Steam client 1790377368 (UI build 11041156).
### How it works
- The `steam-keyboard-patch` user service (`helper.mjs`) injects a patch
into Steam's `SharedJSContext` over DevTools (`127.0.0.1:8080`) and
re-injects it after Steam restarts; stopping it (or disabling the option)
- The `steam-keyboard-patch` user service
(`modules/vr-keyboard-extra-keys/xdotool-helper.mjs`) injects a patch into
Steam's `SharedJSContext` over DevTools (`127.0.0.1:8080`) and re-injects
it after Steam restarts; stopping it (or disabling the option)
runs the unpatch.
- Ctrl/Alt chords and Esc are sent with `xdotool key` on `:0` (focus follows
the VR-selected window); a toggled Ctrl/Alt is held down with `xdotool`.
@@ -133,15 +135,16 @@ has the letters.
### How it works
- A Steam UI patch (`vr-keyboard`, injected by `steam-ui-patches` like the
other [UI patches](ui-patches.md)).
other [UI patches](ui-patches.md)); sources in `modules/vr-keyboard/`.
- Swiped words are matched by shape (SHARK2-style template matching)
against a dictionary built at build time from wordfreq frequency lists
and Hunspell, both from nixpkgs (per language the `words` most frequent
wordfreq entries, shifted by `frequencyOffset`, filtered by Hunspell
except words at or above `keepFrequentAbove`).
- The strip below/above the keyboard is a SteamVR dashboard panel
(`panel.js`, a patch of SteamVR's `systemui` page on port 8087), fed by
the `vr-keyboard-relay` user service (`relay.mjs`) between the two pages.
(`suggestions-panel/patch.js`, a patch of SteamVR's `systemui` page on
port 8087), fed by the `vr-keyboard-relay` user service
(`suggestions-panel/relay.mjs`) between the two pages.
With `inside` neither the panel nor the relay runs.
- Found by signature (entries `vr-keyboard`, `vr-keyboard-panel`).
+1 -1
View File
@@ -79,7 +79,7 @@ its option is set and reverted by its unpatch when unset:
sounds and controller navigation keep working;
- `show-all/`: empties the list Steam hides without Developer Mode.
Their anchors (APIs, React props, CSS) are in `modules/lib/signatures.json`
Their anchors (APIs, React props, CSS) are in `modules/steam-ui-patches/lib/signatures.json`
and verified by the [offline checker](ui-patches.md#after-a-steam-update).
## Hidden apps
+7 -6
View File
@@ -2,7 +2,8 @@
`uiPatches.patches`, `uiPatches.lib` (modules `steam-ui-patches`,
`steamvr-debugger`). For patch authors, and for fixing patches after a Steam
update. Options: [README, Options](../README.md#options).
update. Options: [README, Options](../README.md#options). Which file runs
where: [Development](development.md).
## Problem
@@ -53,7 +54,7 @@ it runs. What they have in common:
- Each turns on the [SteamVR debugger](steamvr-debugger.md) (**the first
time, restart SteamVR once**).
- They depend on SteamVR UI internals: each is found by signature (its entry
in `modules/lib/signatures.json` has the patch's name); after an update
in `modules/steam-ui-patches/lib/signatures.json` has the patch's name); after an update
that changes them the dashboard stays stock (see
[after a Steam update](#after-a-steam-update)). Tested with SteamVR build
11008059.
@@ -110,7 +111,7 @@ see [changes outside Nix](../README.md#changes-outside-nix-exceptions).
## Finders and signatures
Webpack module ids and export names change with every Steam UI build, so
patches never use them. `modules/lib/finders.js` (like Decky Loader's
patches never use them. `modules/steam-ui-patches/lib/finders.js` (like Decky Loader's
`findModule`/`findInReactTree` or Vencord's `find`) locates by *signature*:
- a **module** by strings/regexes in its factory source;
@@ -126,7 +127,7 @@ candidates r_, xy` as the patch's result. Results are cached per page. The
library also has `ensureStyle(doc, id, css)` and `logger(buffer)` (a capped
debug log).
Signatures live in `modules/lib/signatures.json`, shared by patches and the
Signatures live in `modules/steam-ui-patches/lib/signatures.json`, shared by patches and the
offline checker. An entry can also list `expects` (strings the patch relies
on, checked offline only) or be `checkOnly` (anchors not used through the
finder, checked offline only; with `stylesheet` instead of `module` it is
@@ -137,7 +138,7 @@ matched against the bundle's CSS).
`steamFrame.uiPatches.lib.mkPatch` wraps a patch file — a function
expression `(find, sigs, opts, hooks) => …` returning a status string — with
the finder library, its signatures, options and the shared hooks (details in
`modules/lib/default.nix`):
`modules/steam-ui-patches/lib/default.nix`):
```nix
steamFrame.uiPatches.patches = [ {
@@ -167,7 +168,7 @@ steamFrame.uiPatches.patches = [ {
### Shared method hooks
`modules/lib/hooks.js`, argument `hooks`, also `window.__sfuiHooks`: patches
`modules/steam-ui-patches/lib/hooks.js`, argument `hooks`, also `window.__sfuiHooks`: patches
intercepting the same method (e.g. the dashboard mailbox's `SendMessage`,
used by [dashboard windows](dashboard-windows.md#how-it-works) and
[window curvature](window-curvature.md#how-it-works)) register named hooks;