refactor(glow): move small-player glow strength into graphics overrides (#4634)

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 <noreply@anthropic.com>
This commit is contained in:
Evan
2026-07-17 19:29:53 -07:00
committed by evanpelle
co-authored by Claude Fable 5
parent e3676439d2
commit 11c5db8b6f
13 changed files with 116 additions and 143 deletions
+38
View File
@@ -74,6 +74,17 @@ describe("GraphicsOverridesSchema", () => {
}
});
test("accepts partial smallPlayerGlow overrides", () => {
const cases = [
{ smallPlayerGlow: {} },
{ smallPlayerGlow: { strength: 0 } },
{ smallPlayerGlow: { strength: 0.5 } },
];
for (const c of cases) {
expect(GraphicsOverridesSchema.safeParse(c).success).toBe(true);
}
});
test("accepts partial lighting overrides", () => {
const cases = [
{ lighting: {} },
@@ -128,6 +139,11 @@ describe("GraphicsOverridesSchema", () => {
railroad: { railThickness: "wide" },
}).success,
).toBe(false);
expect(
GraphicsOverridesSchema.safeParse({
smallPlayerGlow: { strength: "strong" },
}).success,
).toBe(false);
expect(
GraphicsOverridesSchema.safeParse({
lighting: { ambient: "dark" },
@@ -374,6 +390,28 @@ describe("applyGraphicsOverrides", () => {
expect(z.railThickness).toBe(defaults.railThickness);
});
test("applies smallPlayerGlow strength override (including 0 = off)", () => {
expect(
gen({ smallPlayerGlow: { strength: 0.5 } }).smallPlayerGlow.strength,
).toBe(0.5);
expect(
gen({ smallPlayerGlow: { strength: 0 } }).smallPlayerGlow.strength,
).toBe(0);
});
test("smallPlayerGlow strength absent → keeps default of 0.25", () => {
expect(gen({}).smallPlayerGlow.strength).toBe(0.25);
expect(gen({ smallPlayerGlow: {} }).smallPlayerGlow.strength).toBe(0.25);
});
test("smallPlayerGlow override leaves other glow fields at defaults", () => {
const defaults = createRenderSettings().smallPlayerGlow;
const g = gen({ smallPlayerGlow: { strength: 0.25 } }).smallPlayerGlow;
expect(g.alpha).toBe(defaults.alpha);
expect(g.pulseSpeed).toBe(defaults.pulseSpeed);
expect(g.color).toEqual(defaults.color);
});
test("ambient < 1 sets ambient and enables the lighting pass", () => {
const l = gen({ lighting: { ambient: 0.5 } }).lighting;
expect(l.ambient).toBe(0.5);
-31
View File
@@ -1,31 +0,0 @@
import { UserSettings } from "../src/core/game/UserSettings";
describe("UserSettings highlight glow strength", () => {
beforeEach(() => {
localStorage.clear();
// UserSettings keeps a static in-memory cache; reset it too so each test
// reads fresh from the (cleared) localStorage.
(
UserSettings as unknown as { cache: Map<string, string | null> }
).cache.clear();
});
it("defaults to 1 (100%, on)", () => {
expect(new UserSettings().highlightGlowStrength()).toBe(1);
});
it("persists a set value, including 0 (off)", () => {
const s = new UserSettings();
s.setHighlightGlowStrength(2.5);
expect(s.highlightGlowStrength()).toBe(2.5);
s.setHighlightGlowStrength(0);
expect(s.highlightGlowStrength()).toBe(0);
});
it("shares state across instances via the static cache", () => {
// The settings modal and the renderer's frame builder each hold their own
// UserSettings; a change in one must be visible to the other.
new UserSettings().setHighlightGlowStrength(3);
expect(new UserSettings().highlightGlowStrength()).toBe(3);
});
});