# 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 `
` (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.1–3.6, mangohud, proton, dxvk, wine) | ## Conventions - New programs are preset factory functions in `src/lib/preset/.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/.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 `