everything

This commit is contained in:
2026-08-05 20:27:01 +01:00
commit 2b746b2ecb
43 changed files with 6250 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
# AGENTS.md
## What this is
SvelteKit 5 (runes mode) static site that assembles Steam launch commands from
composable "program classes" (gamescope, MangoHud, Proton, obs-gamecapture,
gamemode). User flips toggles in a tabbed UI; the app renders one flat launch
command string like:
```
gamescope -f -- %command% mangohud waitforexecandrun %command%
```
Rendered by adapter-static (`prerender = true` in `src/routes/+page.ts`).
## Core model (`src/lib/`)
- `meow.ts` — the engine. `ArgEvaluatable` interface (`enabled()`, `envs()`,
`binary()`, `prefix()`, `suffix()`, `priority()`, `arguments()`); `ArgEval`
evaluates components: filter `enabled()`, sort by `priority()` (lowest =
outermost wrapper), envs as `VAR=VAL` space-joined, each program rendered
`prefix binary args suffix` (empty parts dropped), args sorted by `prio` and
rendered `arg val` (bare `arg` when val empty), then `%command%` appended.
- `programs.ts` — data types + `Program` class implementing `ArgEvaluatable`
from a `ProgramConfig`. Key fields: `enabled`, `name`, `binary`, `prefix`,
`suffix`, `priority`, `envs`, `args`, `options` (toggleable sub-flags),
`envSeparators` (per-var merge separators), option `conflicts` (see below).
- `presets.ts` — re-export index only; real factories live per-program in
`src/lib/preset/` (see file map).
- `preset/helpers.ts` — builders shared by presets: `envToggle(label, env,
val, category?)`, `group(program, labels)` (pairwise conflict keys).
(Mutually-exclusive flag choices like `-F` filter use ONE option with an
`args[].values` dropdown — do NOT reintroduce one-option-per-value.)
### Semantics to keep in mind
- Env vars with the same name merge into ONE var: values dedupe, joined by the
var's separator from `envSeparators` (default `,`).
- `conflicts` keys are `'programname'` (program-level) or
`'program:Option label'` (option-level). Only enabled vs enabled conflict;
conflicts are displayed as a non-blocking warning banner.
- Env merge destructuring: `var` is a reserved word in TS — use
`[varName, vals]` in destructures.
- Args are space-separated (`-W 1920`), never `arg=val`.
## File map
| file | role |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/lib/meow.ts` | evaluation engine (see above) |
| `src/lib/programs.ts` | types + `Program` adapter + `findConflicts()` |
| `src/lib/presets.ts` | re-exports the eight preset factories |
| `src/lib/preset/helpers.ts` | shared option builders |
| `src/lib/preset/gamescope.ts` | gamescope args (fullscreen, filter/scale dropdowns, HDR, VR, …) |
| `src/lib/preset/proton-ge.ts` | GloriousEggroll Proton env toggles |
| `src/lib/preset/proton-cachyos.ts` | CachyOS Proton env toggles (largest set) |
| `src/lib/preset/obs.ts` | obs-gamecapture CLI |
| `src/lib/preset/gamemode.ts` | `gamemoderun` wrapper (priority 5 = outermost) |
| `src/lib/preset/mangohud.ts` | MANGOHUD env options + `MANGOHUD_CONFIG` separator merge |
| `src/lib/preset/mesa.ts` | Mesa Vulkan layers env toggles (anti-lag, overlay layer, fps-monitor) |
| `src/lib/preset/prime.ts` | `prime-run` wrapper for NVIDIA PRIME offload |
| `src/lib/ProgramForm.svelte` | per-program editor: enabled checkbox, options list, Advanced `<details>` (name/binary/prefix/suffix/priority, env vars, args, env separators) |
| `src/lib/decode.ts` | `applyCommand(cmd, programs)` — enable options/programs a pasted command references (only ever enables, never disables) |
| `src/routes/+page.svelte` | tabs + `pre.result` command preview + conflict banner; localStorage persistence; decode textarea |
| `launch_args_env_vars.md` | reference: gamescope args, Proton env-var tables, OBS, gamemode |
| `steam-tinker-launcher.md` | reference: STL v14 docs (gamescope CLI catalog §3.13.6, mangohud, proton, dxvk, wine) |
## Conventions
- New programs are preset factory functions in `src/lib/preset/<name>.ts`
returning a `ProgramConfig`, re-exported from `presets.ts`, imported into
`+page.svelte`'s `programs` array.
- Every option carries a `category: string`; ProgramForm groups options under
category headings (keep categories consistent within a preset).
- Every option should also carry a `desc: string`; it appears as a hover
tooltip (1 s delay, CSS-only) next to the option row.
- Default new presets to `enabled: false` so the default output stays stable.
- Preset files ≤ ~140 lines; split if they grow (that's why the directory
exists). Shared builders go in `helpers.ts`.
- `+page.svelte` uses PURE TAB indentation — never build edit oldText with
spaces.
- Mutual exclusivity is expressed via `conflicts` (options) or `group()`
(helpers), never via extra app state.
- `user-select: none` on tabs/labels to stop double-click selection; inputs and
`pre.result` stay selectable.
## Adding options & programs (agent playbook)
Every task in this repo ends with the verification loop below; a change is not
done until all three pass.
### Add an option to an existing program
1. Edit `src/lib/preset/<name>.ts` — the program's factory, inside
`options: [...]`. Mine the flag/env catalogs from `launch_args_env_vars.md`
and `steam-tinker-launcher.md`.
2. Pick the builder (from `./helpers`):
- Env toggle (checkbox sets `VAR=1`):
`envToggle('Label', 'ENV_VAR', '1', 'Category')` — pass a custom value as
the 3rd arg for non-`1` values.
- Flag with a value (gets an editable input in the UI while enabled):
```ts
{ label: 'Mouse sensitivity', enabled: false, args: [{ arg: '-s', val: '1.0', prio: 0 }], category: 'Window' }
```
- Flag with a fixed value set (gets a `<select>` dropdown instead of a
text input): add `values: ['auto', 'drm', 'wayland']` to the arg.
- Flag whose value must match a regex (input turns red + banner error
while invalid): add `pattern: NUM` or `pattern: NUM_DEC` (exported from
`./helpers`) or a custom regex source string.
- Bare flag: same shape with `val: ''` (checkbox only, no input).
- Mutually exclusive flag with a fixed value set (e.g. `-F fsr` vs
`-F nis`): ONE option with `values` on the arg:
`{ label: 'Filter', enabled: false, args: [{ arg: '-F', val: 'fsr', prio: 0, values: ['none', 'linear', 'fsr', 'nis'] }], category: 'Filter' }`.
Do NOT create one option per value.
3. `category` is required — reuse an existing one from that preset or add a new
one (it becomes a tab). Keep categories consistent within a preset.
4. Mutual exclusivity: `conflicts: ['other-program']` or
`conflicts: ['same-program:Other option label']`; `group()` generates
these automatically.
5. Presets only supply defaults — the form binds arg `val` to an input while
the option is enabled, so users can override values.
### Add a new program
1. Create `src/lib/preset/<name>.ts` exporting
`export function <name>(): ProgramConfig` (model on
`src/lib/preset/obs.ts` — the smallest real example).
2. Required config: `name`, `enabled` (default `false` so output stays stable),
`binary`, `prefix` (wrapper like `'gamemoderun'`), `suffix`
(`'waitforexecandrun'` for proton, `'--'` for gamescope-style), `priority`,
`envs: []`, `args: []`, `options: [...]`.
3. Re-export: add `export { <name> } from './preset/<name>';` to
`src/lib/presets.ts`.
4. Import it in `src/routes/+page.svelte` and append to the
`programs = $state([...])` array.
5. Keep the file ≤ ~140 lines; use `envToggle()`/`group()` for builders and
repetitive options.
Priority semantics: components sort ascending by `priority()` — the outermost
wrapper has the LOWEST number (gamemoderun=5, gamescope=10, proton=20,
mangohud=30).
## Verification (mandatory before yielding)
```bash
pnpm exec prettier --write <edited files> # lint runs prettier --check
pnpm check # svelte-check — authoritative type check
pnpm lint # prettier --check + eslint
pnpm build # adapter-static build
```
All four must pass. `pnpm check` is the authority — see the known quirk below.
Known traps for agents:
- **pi-lens/LSP diagnostics on `.svelte` files are stale all session** — they
falsely report `enabled` / `category` / `envSeparators` as missing from
`ProgramConfig` on every edit. They are noise: the fields verifiably exist in
`programs.ts`. Do NOT chase them; rely on `pnpm check` (returns 0 errors
every time). The `.ts` files' diagnostics are accurate.
- `+page.svelte` uses pure tabs — edit `oldText` must use tabs, not spaces. If
the edit tool reports content-drift, re-read the file verbatim before
retrying.
- This file (AGENTS.md) is auto-reformatted by prettier/markdownlint after
edits — always re-read it before further edits; it also uses real em-dashes
(``).
- `var` is a reserved word in TS destructuring — use `[varName, vals]`.
- A stale `vite dev` server can serve corrupted modules (missing exports).
Fix: kill all `vite` processes and restart — never `pkill -f` with a pattern
that also appears in your own command line (it kills your shell).
- Do not add options the docs mark as per-user paths or STL-internal settings
(Vortex/MO2/winetricks/Conty…); README.md is sv boilerplate, ignore it.
Reference docs to mine for new options: `launch_args_env_vars.md` and
`steam-tinker-launcher.md` (README.md is sv boilerplate, ignore it).