From 81d701adc4102d8ee4bcf12dac7399d5c9f01727 Mon Sep 17 00:00:00 2001
From: Zixer1 <99333209+Zixer1@users.noreply.github.com>
Date: Mon, 13 Jul 2026 14:07:22 -0400
Subject: [PATCH] feat(highlight): replace the small-player highlight toggle
with a strength slider (#4588)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replaces the "Highlight small players" on/off toggle with a **0-500%
Strength slider** controlling the glow's **width** (0 = off, 100% = the
previous default).
- `UserSettings`: `highlightSmallPlayers()`/toggle →
`highlightGlowStrength()`/set, float-backed, clamped to [0, 5].
- `SmallPlayerGlowPass` takes the strength via a setter (pushed by
`ClientGameRunner` on the settings-changed event), so it stays a pure
consumer and the slider still updates live while the settings modal has
the sim paused. Width = a non-linear blur-iteration count; intensity
compensated so wider stays about as bright.
- `MapRenderer` persists the strength across a WebGL context restore.
- `SettingsModal`: the toggle row becomes a range input.
Behavior note: with the toggle gone the glow **defaults ON at 100%**
(old toggle defaulted OFF); can default to 0 (opt-in) if preferred.
- [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
---
resources/lang/en.json | 2 +-
src/client/ClientGameRunner.ts | 11 +++
src/client/WebGLFrameBuilder.ts | 5 +-
src/client/hud/layers/SettingsModal.ts | 32 +++++----
src/client/render/gl/MapRenderer.ts | 12 ++++
src/client/render/gl/Renderer.ts | 4 ++
.../render/gl/passes/SmallPlayerGlowPass.ts | 68 +++++++++++++++----
src/core/game/UserSettings.ts | 14 ++--
tests/UserSettings.test.ts | 22 +++---
9 files changed, 120 insertions(+), 50 deletions(-)
diff --git a/resources/lang/en.json b/resources/lang/en.json
index 9f5529854..3d8704cfe 100644
--- a/resources/lang/en.json
+++ b/resources/lang/en.json
@@ -1410,8 +1410,8 @@
"ground_attack_desc": "Send a ground attack to the tile under your cursor.",
"help_messages_desc": "Show contextual tips and warnings during gameplay, such as army limit warnings and general gameplay advice.",
"help_messages_label": "Help Messages",
+ "highlight_glow_strength_label": "Highlight strength",
"highlight_small_players_desc": "Add a glow to small players so they're easy to find.",
- "highlight_small_players_label": "Highlight small players",
"keybind_conflict_error": "The key {key} is already bound to another action.",
"keybinds_hint": "Click a key to rebind it. You can assign a single key or Shift + key combination.",
"left_click_desc": "When ON, left-click opens menu and sword button attacks. When OFF, left-click attacks directly.",
diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts
index fcb79f42f..76e3215ef 100644
--- a/src/client/ClientGameRunner.ts
+++ b/src/client/ClientGameRunner.ts
@@ -527,6 +527,17 @@ 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/WebGLFrameBuilder.ts b/src/client/WebGLFrameBuilder.ts
index 79194795d..359f8fffe 100644
--- a/src/client/WebGLFrameBuilder.ts
+++ b/src/client/WebGLFrameBuilder.ts
@@ -3,7 +3,6 @@ import { base64url } from "jose";
import { assetUrl } from "../core/AssetUrls";
import { decodePatternData } from "../core/PatternDecoder";
import { PlayerType } from "../core/game/Game";
-import { UserSettings } from "../core/game/UserSettings";
import { uploadFrameData } from "./render/frame/Upload";
// Type-only: a value import would pull GPURenderer and its `.glsl?raw` shader
// imports into any non-Vite consumer (e.g. the Node perf harness).
@@ -93,7 +92,6 @@ export class WebGLFrameBuilder {
}
private readonly highlightSetBuf = new Uint8Array(PALETTE_SIZE);
- private readonly userSettings = new UserSettings();
private glowRescanTick = 0;
update(gameView: GameView): void {
@@ -209,8 +207,9 @@ export class WebGLFrameBuilder {
* Client-only view — toggle it live in the settings.
*/
private syncSmallPlayerGlow(gameView: GameView): void {
+ // Strength (incl. off at 0) is read live in the glow pass; here we only
+ // decide who qualifies. Skip spawn + the first minute.
if (
- !this.userSettings.highlightSmallPlayers() ||
gameView.inSpawnPhase() ||
gameView.elapsedGameSeconds() < SMALL_PLAYER_GLOW_GRACE_SECONDS
) {
diff --git a/src/client/hud/layers/SettingsModal.ts b/src/client/hud/layers/SettingsModal.ts
index 6b905f63a..8b9880a0c 100644
--- a/src/client/hud/layers/SettingsModal.ts
+++ b/src/client/hud/layers/SettingsModal.ts
@@ -135,11 +135,6 @@ export class SettingsModal extends LitElement implements Controller {
this.requestUpdate();
}
- private onToggleHighlightSmallPlayersButtonClick() {
- this.userSettings.toggleHighlightSmallPlayers();
- this.requestUpdate();
- }
-
private onToggleAlertFrameButtonClick() {
this.userSettings.toggleAlertFrame();
this.requestUpdate();
@@ -210,6 +205,12 @@ 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;
@@ -356,30 +357,35 @@ export class SettingsModal extends LitElement implements Controller {
-
+