Repository navigation
fix(city3d): fade the city in as one solid layer, dithered, never blended - #205
Merged
Merged
Conversation
…nded Between 15.5 and 16.5 (BUILDINGS_3D_FADE) every building and tree surface was blended at the fade's alpha. A pixel then mixed the front surface with whatever the city drew behind it, so walls and streets showed through the blocks at any resting zoom in the window (Madrid, owner report). The zoom fade is now the same screen door as a level's crossfade (`dithered`): each drawn entry keeps its share of the transition's pixels, scaled by the zoom's (`setEntryFade(from * opacity, to * opacity)`), so complementary level fades still partition exactly the zoom's share. The buildings and trees are opaque again and keep their depth. Each pixel is the city's front surface or the map, never a blend. The opacity uniform is gone from every material, web and native alike. Chosen over drawing the city opaque into its own target and compositing it at one alpha. The dither costs no target (a phone-sized colour+depth target is about 20 MB), no extra full-screen pass, and no depth hand-off to MapLibre. Its variants already exist and are warmed. Measured (bench:map, pixel6a profile, RTX 5090, machine shared): draws and triangles identical; GPU p50 eixample 4.6-4.8 -> 1.6 ms, manhattan 1.5-2.3 -> 1.2 ms (no blending, half the fragments). Gate: check-city3d-visible's nosky leg adds a mid-fade view at z16 that measures each pixel's coverage by the city: the city alone, shot over black and over white. Main: 37% of the city's pixels show a surface behind another (coverage 0.5, 0.8, 0.9). This fix: 0.3% (coverage 0 or 1). The limit is 2%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the gate's view() parameters: main's relief, then this branch's backdrops and zoomTo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NateIsern
force-pushed
the
fix/city3d-solid-zoom-fade
branch
from
October 13, 2026 01:17
b52be82 to
97dc7b3
Compare
Resolves the gate script with main's behaviour kept: main's camera- clearance import and its view() inspect hook (run first, on the untouched page), then this branch's backdrops and zoomTo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
At a resting zoom between 15.5 and 16.5 (
BUILDINGS_3D_FADE), every building and tree surface was blended at the fade's alpha. A pixel mixed the front surface with whatever the city drew behind it, so walls and streets showed through the blocks. The report came from Madrid at z16, night.Fix: the zoom fade is a dither
The zoom fade now uses the same screen door as a level's crossfade (
ditheredintsl/common.ts):setEntryFade(entry, from × opacity, to × opacity).cityTileViewincluded.BUILDINGS_3D_FADE.What it does and doesn't change: a fade still shows the map. At z16, half the screen's pixels draw the city and half draw the map. What can no longer happen is a pixel blending the city's front surface with a surface behind it (inner walls, or streets behind a block).
Why a dither and not an offscreen layer composited at one alpha
The offscreen option costs, on a phone:
The dither costs none of these: its variants already exist and are warmed.
Measured
bench:map(production builds, pixel6a profile, real GPU RTX 5090). The machine was shared and loaded, so treat CPU numbers as noise; the GPU process crashed on a third pass.main→ this PRThere is no blending, and half the fragments are discarded.
Regression check (fails on
main)check-city3d-visible's nosky leg adds a mid-fade view at z16 (or--skies=fadealone):main@52dde03Checks
bun run lintandtscpass.🤖 Generated with Claude Code