From 4544e18ce6e7740c254c67893842095a9cb95a75 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 ## Summary 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. ## Bug fix 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 ## Notes - 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 ## Test plan - [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 | 28 ---------- 13 files changed, 116 insertions(+), 140 deletions(-) diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index b22c045b9..9f99bd91c 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -572,17 +572,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 b46f85337..ffea83f46 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). @@ -597,6 +603,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 ( @@ -679,6 +708,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` @@ -1426,6 +1456,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)}% -
-
-