Game: player-facing graphics settings screen (quality, vsync, frame cap) at runtime
Goal
A player-facing settings screen in the shipped game: resolution, vsync, frame cap, anti-aliasing level, post-processing, shadow quality, and the rest of the scalability knobs — changeable at runtime and persisted per user.
Why it isn't #160 (closed)
#160 (closed) wires ProjectSettings.graphics.quality into the renderer and exposes per-feature toggles in Studio, for the developer, applied at game startup. That is the plumbing this needs, but it stops at the editor: the shipped game reads a preset once and the player can never change it.
The missing pieces are all outside #160 (closed)'s scope:
- An in-game UI — a
.uidocsettings screen, so this depends on the Guinevere GUI epic (#47). - Runtime application. #160 (closed) applies the feature set at startup. Changing MSAA live means rebuilding the scene pipeline cache (pipelines bake in the sample count); changing render scale means reallocating targets. Both are safe between frames but neither is wired.
- Per-user persistence, separate from the project's authored defaults. #42 wants the same thing for input rebinding and calls it a "settings profile" — these should share one mechanism rather than grow two.
- Vsync and frame cap at runtime. Today vsync is fixed at window creation:
ProjectSettings.graphics.vsync→GameBuild→ the generatedmain.zig→gpu.Window.create→SDL_GPU_PRESENTMODE_VSYNC. The generated loop has no frame limiter at all, so a cap needs building, not just exposing. Studio already does the live half (GpuRenderer.requestVsync/applyPendingVsyncswap present modes between frames) — the game can reuse that shape.
Scope
- A default settings
.uidocshipped with the engine that a project can use as-is or replace. - A runtime
render.Featuresapply path (from #160 (closed)) that is safe to call between frames, including the pipeline-cache rebuild for MSAA. - A frame limiter in the generated main loop, for capping below the refresh rate.
- Per-user persistence, shared with #42's profile.
Depends on
- #160 (closed) — the feature set and its presets
- #47 — the in-game GUI this would be authored in
- #42 — the settings-profile persistence
Note
Worth confirming the shipped game's 60 fps is vsync before sizing this: docs/decisions/bistro-perf-baseline.md traces the code path, and the renderer measures ~12.8 ms (~78 fps) on the same scene with vsync off.