Add Graphics Settings modal with live name-label tuning (#4065)

## Description:

- Add a user-facing **Graphics Settings** modal accessible from the
in-game Settings menu, with live preview as sliders change.
- First two knobs: **Name Scale** and **Minimum Name Size** (the
name-cull threshold).
- Overrides stored as a single JSON blob in `localStorage` under
`settings.graphics`, validated by a Zod schema
(`GraphicsOverridesSchema`). Future graphics knobs just extend the
schema + slider list.

## How it fits together

- `generateRenderSettings(overrides)` (`RenderSettings.ts`) — pure
function: clones `render-settings.json` defaults, layers overrides on
top, returns a fresh `RenderSettings`.
- `UserSettings.graphicsOverrides()` / `setGraphicsOverrides()` —
read/write the blob; falls back to `{}` on a missing/corrupt entry.
- `ClientGameRunner` listens for
`USER_SETTINGS_CHANGED_EVENT:settings.graphics`, regenerates, and
`Object.assign`s each category into the live `view.getSettings()` slice
so passes pick up the new values on the next frame (no renderer
reconstruction).
- Modal reads defaults straight from `render-settings.json` so there's
no duplication.


<img width="599" height="515" alt="Screenshot 2026-05-28 at 11 18 43 AM"
src="https://github.com/user-attachments/assets/263d7d91-10d8-4a66-a069-10015c735d60"
/>

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan
This commit is contained in:
Evan
2026-05-28 13:06:43 -07:00
committed by GitHub
parent 8142bc1070
commit 20bc311caf
11 changed files with 401 additions and 7 deletions
+22
View File
@@ -1,3 +1,7 @@
import {
GraphicsOverrides,
GraphicsOverridesSchema,
} from "../../client/render/gl/GraphicsOverrides";
import { Cosmetics } from "../CosmeticSchemas";
import { PlayerPattern } from "../Schemas";
@@ -53,6 +57,7 @@ export const COLOR_KEY = "settings.territoryColor";
export const DARK_MODE_KEY = "settings.darkMode";
export const PERFORMANCE_OVERLAY_KEY = "settings.performanceOverlay";
export const KEYBINDS_KEY = "settings.keybinds";
export const GRAPHICS_KEY = "settings.graphics";
export class UserSettings {
private static cache = new Map<string, string | null>();
@@ -354,6 +359,23 @@ export class UserSettings {
this.setFloat("settings.attackRatio", value);
}
// Returns {} if missing, unparseable, or fails schema validation.
graphicsOverrides(): GraphicsOverrides {
const raw = this.getString(GRAPHICS_KEY, "");
if (!raw) return {};
try {
const parsed = GraphicsOverridesSchema.safeParse(JSON.parse(raw));
if (parsed.success) return parsed.data;
} catch {
// fall through
}
return {};
}
setGraphicsOverrides(value: GraphicsOverrides): void {
this.setString(GRAPHICS_KEY, JSON.stringify(value));
}
// In case localStorage was manually edited to be invalid, return an empty object
parsedUserKeybinds(): Record<string, any> {
const raw = this.getString(KEYBINDS_KEY, "{}");