From 7137347b7df4aa0cdccb38a337b9c577c61d052c Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 11 Jun 2026 09:25:13 -0700 Subject: [PATCH] Fade player names under the cursor, with a graphics setting to tune it (#4221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Player name plates can block the view of what's underneath them (structures, units, terrain). This PR fades the entire name plate — name, troop count, flag, and emoji/status row — to 25% opacity while the cursor is over it, so you can see and click what's behind it. **How it works:** - `HoverHighlightController` pushes the cursor's world position into the renderer on mouse move. - `NamePass` hit-tests the cursor against each player's name plate bounds on the CPU (mirroring the lerp/sizing math in `name.vert.glsl`) and passes the matched player's ID to the text, icon, and status-icon programs, which apply the alpha multiplier in their shaders. **Graphics setting:** - New "Name opacity under cursor" slider in the Graphics Settings modal (Name Labels section), range 0–1, default 0.25. Setting it to 1 disables the fade entirely. - Wired through the existing `GraphicsOverrides` pipeline: changes apply live and are cleared by "Reset to defaults". - Tuning knob exposed as `name.hoverFadeAlpha` in `render-settings.json` and the debug GUI. ## Please complete the following: - [ ] 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 - [ ] I have added relevant tests to the test directory ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --- resources/lang/en.json | 2 + .../controllers/HoverHighlightController.ts | 3 + .../hud/layers/GraphicsSettingsModal.ts | 42 ++++++++++ src/client/render/gl/GameView.ts | 3 + src/client/render/gl/GraphicsOverrides.ts | 1 + src/client/render/gl/RenderOverrides.ts | 3 + src/client/render/gl/RenderSettings.ts | 2 + src/client/render/gl/Renderer.ts | 3 + src/client/render/gl/debug/Layout.ts | 1 + .../render/gl/passes/name-pass/IconProgram.ts | 10 +++ .../gl/passes/name-pass/StatusIconProgram.ts | 10 +++ .../render/gl/passes/name-pass/TextProgram.ts | 10 +++ .../render/gl/passes/name-pass/index.ts | 81 ++++++++++++++++++- src/client/render/gl/render-settings.json | 3 +- .../render/gl/shaders/name/icon.frag.glsl | 3 +- .../render/gl/shaders/name/icon.vert.glsl | 14 +++- .../render/gl/shaders/name/name.vert.glsl | 11 ++- .../gl/shaders/name/status-icon.frag.glsl | 3 +- .../gl/shaders/name/status-icon.vert.glsl | 14 +++- 19 files changed, 210 insertions(+), 9 deletions(-) diff --git a/resources/lang/en.json b/resources/lang/en.json index 80cb188e4..c53716615 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -939,6 +939,8 @@ "name_scale_label": "Name Scale", "name_cull_label": "Minimum name size", "name_cull_desc": "Hide names smaller than this size", + "hover_fade_label": "Name opacity under cursor", + "hover_fade_desc": "How visible names are while your cursor is over them (1 to disable fading)", "colored_names_label": "Name color", "colored_names_desc": "Show player names in their player color or in black", "colored": "Colored", diff --git a/src/client/controllers/HoverHighlightController.ts b/src/client/controllers/HoverHighlightController.ts index bf1f69552..e647bd659 100644 --- a/src/client/controllers/HoverHighlightController.ts +++ b/src/client/controllers/HoverHighlightController.ts @@ -31,6 +31,9 @@ export class HoverHighlightController implements Controller { } private onMouseMove(e: MouseMoveEvent): void { + const world = this.transformHandler.screenToWorldCoordinatesFloat(e.x, e.y); + this.view.setMouseWorldPos(world.x, world.y); + const cell = this.transformHandler.screenToWorldCoordinates(e.x, e.y); let ownerID = 0; if (this.game.isValidCoord(cell.x, cell.y)) { diff --git a/src/client/hud/layers/GraphicsSettingsModal.ts b/src/client/hud/layers/GraphicsSettingsModal.ts index 5ffd316c1..974df6d6a 100644 --- a/src/client/hud/layers/GraphicsSettingsModal.ts +++ b/src/client/hud/layers/GraphicsSettingsModal.ts @@ -20,6 +20,10 @@ const NAME_CULL_MIN = 0; const NAME_CULL_MAX = 0.05; const NAME_CULL_STEP = 0.001; +const HOVER_FADE_MIN = 0; +const HOVER_FADE_MAX = 1; +const HOVER_FADE_STEP = 0.05; + const HIGHLIGHT_FILL_MIN = 0; const HIGHLIGHT_FILL_MAX = 1; const HIGHLIGHT_FILL_STEP = 0.01; @@ -148,6 +152,13 @@ export class GraphicsSettingsModal extends LitElement implements Controller { ); } + private currentHoverFade(): number { + return ( + this.userSettings.graphicsOverrides().name?.hoverFadeAlpha ?? + renderDefaults.name.hoverFadeAlpha + ); + } + private patchName(patch: Partial) { const current = this.userSettings.graphicsOverrides(); this.userSettings.setGraphicsOverrides({ @@ -309,6 +320,11 @@ export class GraphicsSettingsModal extends LitElement implements Controller { this.patchName({ cullThreshold: value }); } + private onHoverFadeChange(event: Event) { + const value = parseFloat((event.target as HTMLInputElement).value); + this.patchName({ hoverFadeAlpha: value }); + } + private currentDarkNames(): boolean { return ( this.userSettings.graphicsOverrides().name?.darkNames ?? @@ -330,6 +346,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller { const nameScale = this.currentNameScale(); const nameCull = this.currentNameCull(); + const hoverFade = this.currentHoverFade(); const namesColored = !this.currentDarkNames(); const classicIcons = this.currentClassicIcons(); const highlightFill = this.currentHighlightFill(); @@ -425,6 +442,31 @@ export class GraphicsSettingsModal extends LitElement implements Controller { +
+
+
+ ${translateText("graphics_setting.hover_fade_label")} +
+
+ ${translateText("graphics_setting.hover_fade_desc")} +
+ +
+
+ ${hoverFade.toFixed(2)} +
+
+