osm basemap: degrade sub-pixel shapes to dots, and stop compositing toward black - #128
Merged
Merged
Conversation
…oward black Two independent reasons the overview drew a black core, both reported from a live z12 view of Berlin where the outskirts rendered correctly. ── 1. Edges that cannot resolve ── At z12 a Berlin building is a fraction of a pixel. Its OUTLINE was still stroked, and the stroke colours are dark by design (`other` is #39424f), so in the dense core thousands of them landed on the same pixels and saturated them, while the FILL — the colour that actually carries the meaning — never survived at all. Density made the map darker, and the outskirts stayed legible only because they were sparse. `dot_if_subpixel` measures each simplified shape in the same 2^(z-24) world-pixel units `encode_tile_bin` projects with, and below 1.5px collapses it to ONE centroid point carrying its class. The wire is unchanged: a dot is `npoints == 1`, which both client parsers previously skipped via `n<2`. This is a RESOLUTION rule, not a zoom rule — a no-op once a shape exceeds a pixel, so it needs no zoom branch and disables itself as you zoom in. The under-budget city view is byte-identical. Client, both paths: GL gains `uDot[10]` + `uMode==4` and draws the points between the fill and line passes, so road structure stays legible over the dot texture; Canvas2D gains a `dots` Path2D map drawn in the same slot. The dot takes the class FILL colour, falling back to stroke for the fill-less line classes — without that fallback road/rail/other would be transparent dots, recreating the disappearance being fixed. ── 2. Alpha over a dark ground ── Every fill was dark AND alpha'd (…80, …4d, …66), and `#map`'s background — which IS the land, since GL clears transparent and Canvas2D only clears — was #11151c. So each fill composited toward black instead of replacing it: one polygon read as a faint tint and a stack of them converged on the ground. Opaque fills also make FILL_PASS's back-to-front ordering the thing that decides what wins, which is what that ordering was written for and which alpha was quietly defeating. Palette is now opaque and OSM-Carto-shaped over #f2efe9 land, because that vocabulary is the point of a basemap: blue is water, green is vegetation, beige-grey is built. ── Verified ── - `cargo check -p cockpit-server` passes (exit 0, no new warnings). - The embedded JS extracts and passes `node --check` (936 lines) — it lives in a Rust string literal, so nothing in the Rust build can see it. - Both shaders COMPILE AND LINK in real headless WebGL2 (swiftshader), with uFill/uStroke/uDot/uMode/uView/uTrans/uPointPx and aPos/aCls all present. The first run of that check reported a false PASS by grepping the dumped DOM, which also contains the unexecuted 'PASS:' literal from the script source; the result is read from the output div only. - NOT verified: the live visual result. The dot-density and palette choices want a real browser look, and the resolution threshold (1.5px) is a first estimate, not a measured one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_7047aeb8-60e0-4b31-a96a-c1d554e4066f) |
AdaWorldAPI
marked this pull request as ready for review
August 13, 2026 13:23
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.
Follow-up to #127. Two independent causes of the black core in the z12 overview, both reported from a live Berlin view where the outskirts rendered correctly — which is the clue that made it two problems rather than one.
1. Edges that cannot resolve
At z12 a Berlin building is a fraction of a pixel. Its outline was still stroked, and stroke colours are dark by design (
other=#39424f), so in the dense core thousands landed on the same pixels and saturated them — while the fill, the colour that carries the meaning, never survived. Density made the map darker, which is backwards; the outskirts stayed legible only by being sparse.dot_if_subpixelmeasures each simplified shape in the same2^(z−24)world-pixel unitsencode_tile_binprojects with, and below 1.5 px collapses it to one centroid point carrying its class.npoints == 1, which both client parsers previously skipped atn<2.uDot[10]+uMode==4, drawn between the fill and line passes so road structure stays legible over the dot texture; Canvas2D gains adotsPath2D map in the same slot.road/rail/otherwould be transparent dots — recreating the exact disappearance being fixed.2. Alpha over a dark ground
Every fill was dark and alpha'd (
…80,…4d,…66), and#map's background — which is the land, since GL clears transparent and Canvas2D only clears — was#11151c. Each fill therefore composited toward black rather than replacing it: one polygon read as a faint tint, a stack of them converged on the ground colour.Opaque fills also restore
FILL_PASS's back-to-front ordering as the thing that decides what wins — what that ordering was written for, and what alpha was quietly defeating.Palette is now opaque and OSM-Carto-shaped over
#f2efe9land: blue is water, green is vegetation, beige-grey is built.Verification
cargo check -p cockpit-server— exit 0, no new warnings.node --check(936 lines). It lives inside a Rust string literal, so nothing in the Rust build can see it — this gap is worth knowing about.uFill/uStroke/uDot/uMode/uView/uTrans/uPointPxandaPos/aClsall present.'PASS:'literal from the script source. The result is now read from the output div only. Recording it because a detector that can't distinguish success from failure is the failure mode worth naming.Draft pending that visual check.
Generated by Claude Code