From 11c5db8b6fa1364c46cd796736ef4bdce9bb61e4 Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 17 Jul 2026 19:09:07 -0700 Subject: [PATCH] refactor(glow): move small-player glow strength into graphics overrides (#4634) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves the small-player glow strength from a standalone UserSettings key (`settings.highlightGlowStrength`) into the graphics overrides blob (`smallPlayerGlow.strength`), and moves its slider from the basic settings modal into the **Effects** section of the graphics settings modal. The pass now reads strength from its live `RenderSettings` slice like every other graphics knob, flowing through `applyGraphicsOverrides`. This removes the dedicated push chain (ClientGameRunner listener → MapRenderer → Renderer → pass setter) and MapRenderer's context-restore reapply — strength survives WebGL context restores automatically now, participates in the graphics modal's "Reset to defaults", and shows up in the render debug GUI. The old slider had no visible effect below ~115%: strength only drove the blur-iteration count (`round(strength ** 2.74)`, floored at 1 pass), and the composite intensity (`alpha * pulse * sqrt(passes)`) never factored strength directly — so 10% rendered identical to 100%. Strength is now a linear opacity fade on a fixed-width aura: - 100% = the aura's full brightness, 10% = barely visible, 0% = off - Slider capped at 100% (the >100% aura-widening mechanism became unreachable and is removed: `passesFor`, `lastPasses`, and the blur-iteration loop) - Default is 25% - The pass clamps persisted values above 1 so stale settings from the old 500% range can't over-brighten - Reuses the existing `user_setting.highlight_glow_strength_label` / `highlight_small_players_desc` translation keys — no en.json change - The legacy `settings.highlightGlowStrength` localStorage key is not migrated (the slider only shipped in #4588 a few days ago); users reset to the 25% default - [x] `tests/GraphicsOverrides.test.ts` — schema validation + apply coverage for the new override group - [x] Full suite (171 tests), tsc, eslint all pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 --- src/client/ClientGameRunner.ts | 11 ---- .../hud/layers/GraphicsSettingsModal.ts | 55 +++++++++++++++++++ src/client/hud/layers/SettingsModal.ts | 37 ------------- src/client/render/gl/GraphicsOverrides.ts | 6 ++ src/client/render/gl/MapRenderer.ts | 12 ---- src/client/render/gl/RenderOverrides.ts | 3 + src/client/render/gl/RenderSettings.ts | 1 + src/client/render/gl/Renderer.ts | 4 -- .../render/gl/passes/SmallPlayerGlowPass.ts | 47 ++++------------ src/client/render/gl/render-settings.json | 3 +- src/core/game/UserSettings.ts | 11 ---- tests/GraphicsOverrides.test.ts | 38 +++++++++++++ tests/UserSettings.test.ts | 31 ----------- 13 files changed, 116 insertions(+), 143 deletions(-) delete mode 100644 tests/UserSettings.test.ts diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 76e3215ef..fcb79f42f 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -527,17 +527,6 @@ async function createClientGame( { signal: graphicsListenerAbort.signal }, ); - // Push the small-player glow Strength to the pass (which is a pure consumer) - // on the settings-changed event, so moving the slider updates the glow live - // even while the settings modal has the sim paused. - view.setSmallPlayerGlowStrength(userSettings.highlightGlowStrength()); - globalThis.addEventListener( - `${USER_SETTINGS_CHANGED_EVENT}:settings.highlightGlowStrength`, - () => - view.setSmallPlayerGlowStrength(userSettings.highlightGlowStrength()), - { signal: graphicsListenerAbort.signal }, - ); - // Re-resolve names drawn on the map when the anonymous-names setting toggles // so they switch live, like the leaderboard. globalThis.addEventListener( diff --git a/src/client/hud/layers/GraphicsSettingsModal.ts b/src/client/hud/layers/GraphicsSettingsModal.ts index 268f54449..e22d2cf9e 100644 --- a/src/client/hud/layers/GraphicsSettingsModal.ts +++ b/src/client/hud/layers/GraphicsSettingsModal.ts @@ -70,6 +70,12 @@ const RAIL_THICKNESS_MIN = 0.5; const RAIL_THICKNESS_MAX = 3; const RAIL_THICKNESS_STEP = 0.1; +// Small-player glow strength is shown as a percentage: 0% = off, 100% = the +// glow's full brightness. +const GLOW_STRENGTH_MIN = 0; +const GLOW_STRENGTH_MAX = 100; +const GLOW_STRENGTH_STEP = 5; + // "Ambient light" level shown to the player: 0 = no darkening (lighting off), // 10 = darkest with the strongest glow. Mapped linearly onto the renderer's // ambient value (1 = identity, AMBIENT_MIN = darkest). @@ -541,6 +547,29 @@ export class GraphicsSettingsModal extends LitElement implements Controller { this.patchPassEnabled({ fallout: !this.currentFallout() }); } + private patchSmallPlayerGlow( + patch: Partial, + ) { + const current = this.userSettings.graphicsOverrides(); + this.userSettings.setGraphicsOverrides({ + ...current, + smallPlayerGlow: { ...current.smallPlayerGlow, ...patch }, + }); + this.requestUpdate(); + } + + private currentGlowStrength(): number { + return ( + this.userSettings.graphicsOverrides().smallPlayerGlow?.strength ?? + renderDefaults.smallPlayerGlow.strength + ); + } + + private onGlowStrengthChange(event: Event) { + const value = parseFloat((event.target as HTMLInputElement).value) / 100; + this.patchSmallPlayerGlow({ strength: value }); + } + /** Whether colorblind mode is currently enabled. */ private currentColorblind(): boolean { return ( @@ -619,6 +648,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller { const nukeColor = this.currentNukeColor(); const ambientLevel = this.currentAmbientLevel(); const unitGlow = this.currentUnitGlow(); + const glowStrength = this.currentGlowStrength(); const colorblind = this.currentColorblind(); return html` @@ -1258,6 +1288,31 @@ export class GraphicsSettingsModal extends LitElement implements Controller { +
+
+
+ ${translateText("user_setting.highlight_glow_strength_label")} +
+
+ ${translateText("user_setting.highlight_small_players_desc")} +
+ +
+
+ ${Math.round(glowStrength * 100)}% +
+
+
diff --git a/src/client/hud/layers/SettingsModal.ts b/src/client/hud/layers/SettingsModal.ts index 8b9880a0c..14c40e79a 100644 --- a/src/client/hud/layers/SettingsModal.ts +++ b/src/client/hud/layers/SettingsModal.ts @@ -19,7 +19,6 @@ import { ShowGraphicsSettingsModalEvent } from "./GraphicsSettingsModal"; const cursorPriceIcon = assetUrl("images/CursorPriceIconWhite.svg"); const emojiIcon = assetUrl("images/EmojiIconWhite.svg"); const exitIcon = assetUrl("images/ExitIconWhite.svg"); -const highlightIcon = assetUrl("images/HighlightIconWhite.svg"); const mouseIcon = assetUrl("images/MouseIconWhite.svg"); const ninjaIcon = assetUrl("images/NinjaIconWhite.svg"); const settingsIcon = assetUrl("images/SettingIconWhite.svg"); @@ -205,12 +204,6 @@ export class SettingsModal extends LitElement implements Controller { this.requestUpdate(); } - private onHighlightGlowStrengthChange(event: Event) { - const strength = parseFloat((event.target as HTMLInputElement).value) / 100; - this.userSettings.setHighlightGlowStrength(strength); - this.requestUpdate(); - } - render() { if (!this.isVisible) { return null; @@ -357,36 +350,6 @@ export class SettingsModal extends LitElement implements Controller {
-
- highlightGlowStrength -
-
- ${translateText("user_setting.highlight_glow_strength_label")} -
-
- ${translateText("user_setting.highlight_small_players_desc")} -
- -
-
- ${Math.round(this.userSettings.highlightGlowStrength() * 100)}% -
-
-