From e87e2cd58ca52659469944baa3a5abdba00f0848 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Sat, 16 May 2026 17:34:53 -0700 Subject: [PATCH] add iconGrowZoom for structures that scale with deep zoom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously structures capped at iconScale = 1.0 once zoomed past iconScaleFactorZoomedOut, staying at a fixed pixel size no matter how far you zoomed in. They felt overlaid on the map instead of part of it. Add a third zoom band controlled by structure.iconGrowZoom. Past this threshold iconScale = uZoom / iconGrowZoom — structures grow with the canvas (world-anchored, fixed map-area coverage). Plumbed via the uIconGrowZoom uniform on StructurePass. Default 7 keeps normal play unchanged; only kicks in at deep zoom. --- src/client/render/gl/passes/structure-pass.ts | 3 +++ src/client/render/gl/render-settings.json | 5 +++-- src/client/render/gl/render-settings.ts | 7 +++++++ src/client/render/gl/shaders/structure/structure.vert.glsl | 6 ++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/client/render/gl/passes/structure-pass.ts b/src/client/render/gl/passes/structure-pass.ts index ea186f0ea..d5874fad8 100644 --- a/src/client/render/gl/passes/structure-pass.ts +++ b/src/client/render/gl/passes/structure-pass.ts @@ -76,6 +76,7 @@ export class StructurePass { private uDotsThreshold: WebGLUniformLocation; private uDotScale: WebGLUniformLocation; private uScaleFactor: WebGLUniformLocation; + private uIconGrowZoom: WebGLUniformLocation; private uShapeScales: WebGLUniformLocation; private uIconFills: WebGLUniformLocation; private uGhostAlpha: WebGLUniformLocation; @@ -147,6 +148,7 @@ export class StructurePass { "uDotsThreshold", )!; this.uScaleFactor = gl.getUniformLocation(this.program, "uScaleFactor")!; + this.uIconGrowZoom = gl.getUniformLocation(this.program, "uIconGrowZoom")!; this.uShapeScales = gl.getUniformLocation(this.program, "uShapeScales")!; this.uIconFills = gl.getUniformLocation(this.program, "uIconFills")!; this.uGhostAlpha = gl.getUniformLocation(this.program, "uGhostAlpha")!; @@ -334,6 +336,7 @@ export class StructurePass { gl.uniform1f(this.uDotsThreshold, ss.dotsZoomThreshold); gl.uniform1f(this.uDotScale, ss.dotScale); gl.uniform1f(this.uScaleFactor, ss.iconScaleFactorZoomedOut); + gl.uniform1f(this.uIconGrowZoom, ss.iconGrowZoom); // Build per-structure uniform arrays from settings, ordered by atlas column const scales = new Float32Array(ATLAS_COLS); diff --git a/src/client/render/gl/render-settings.json b/src/client/render/gl/render-settings.json index b9da108d4..2a0105c4c 100644 --- a/src/client/render/gl/render-settings.json +++ b/src/client/render/gl/render-settings.json @@ -82,10 +82,11 @@ "railAlpha": 1 }, "structure": { - "iconSize": 65, + "iconSize": 50, "dotsZoomThreshold": 1.2, "dotScale": 0.3, - "iconScaleFactorZoomedOut": 3.5, + "iconScaleFactorZoomedOut": 3, + "iconGrowZoom": 7, "shapes": { "City": { "scale": 1, diff --git a/src/client/render/gl/render-settings.ts b/src/client/render/gl/render-settings.ts index adbd373cf..1b661dea9 100644 --- a/src/client/render/gl/render-settings.ts +++ b/src/client/render/gl/render-settings.ts @@ -89,6 +89,13 @@ export interface RenderSettings { /** Icon size multiplier when zoomed out past dotsZoomThreshold. */ dotScale: number; iconScaleFactorZoomedOut: number; + /** + * Zoom level at which structures begin growing with the canvas. + * Below this zoom, structures stay at a fixed screen size (capped). + * Above this zoom, they grow proportionally to zoom — i.e. world-anchored, + * so they cover a fixed area of the map. + */ + iconGrowZoom: number; shapes: Record; highlightOutlineWidth: number; highlightDimAlpha: number; diff --git a/src/client/render/gl/shaders/structure/structure.vert.glsl b/src/client/render/gl/shaders/structure/structure.vert.glsl index b71006637..41be22f30 100644 --- a/src/client/render/gl/shaders/structure/structure.vert.glsl +++ b/src/client/render/gl/shaders/structure/structure.vert.glsl @@ -14,6 +14,7 @@ uniform float uIconSize; uniform float uDotsThreshold; uniform float uDotScale; uniform float uScaleFactor; +uniform float uIconGrowZoom; uniform float uShapeScales[ATLAS_COLS]; uniform float uIconFills[ATLAS_COLS]; @@ -38,6 +39,11 @@ void main() { float iconScale; if (uZoom <= uDotsThreshold) { iconScale = uDotScale; + } else if (uZoom >= uIconGrowZoom) { + // World-anchored: grow proportionally to zoom so the structure covers a + // fixed area of the map. Past this zoom, structures should feel like + // they're "on" the canvas rather than overlaid at constant pixel size. + iconScale = uZoom / uIconGrowZoom; } else { iconScale = min(1.0, uZoom / uScaleFactor); }