post: MapLibre's SDF icon edge is at 0.75, not 0.5 - #53
Open
clarkbw wants to merge 1 commit into
Open
Conversation
Draft post on the hand-authored SDF encoding gotcha: maplibre's symbol_sdf shader thresholds the icon fill at inner_edge = (256-64)/256 = 0.75 over an SDF_PX = 8 field (matching @mapbox/tiny-sdf's cutoff = 0.25), not the 0.5 a symmetric signed-distance encoding suggests. Verified against maplibre-gl 5.24.0 source; three hand-written SVG figures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HaMaRk9UijJQMDX48EVvTk
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.
Post: 2026-08-11-maplibre-custom-sdf-icon-invisible-…-sdf-px-8.md
Draft (candidate #5 from
planning/docs/blog-candidates-2026-08-11.md). The date is the draft date — bump at merge withscript/bump.py/script/publish.py.What it covers
slackwater-web4de76d8/9dc473e/04d66f1. Hand-authored SDF pin glyphs rendered as nothing. MapLibre's shader thresholds the icon fill atinner_edge = (256.0 - 64.0) / 256.0= 0.75, not the intuitive 0.5, so encoding the edge at alpha 128 made the shader draw a contour 4 px inside the shape — and a 6.16 px stroke has nothing left after a 4 px erosion.The framing goes a bit past the commit message: rather than "0.75 not 0.5", the post derives the general rule that any linear encoding
255 × (A − d/R)draws its contour atd = R × (A − 0.75), soAmust be 0.75 (or your shape erodes) andRonly sets the ramp rate. That also explains why 0.75 — the field is deliberately asymmetric (2 px inside, 6 px outside) because 6 px of outside room is exactly the widest halo the shader can express.Verification
Every number was re-derived rather than taken from the commit message:
maplibre-gl5.24.0 bundle installed inslackwater-web, and against the tagged source. Two corrections vs. the commit message: the constant is namedinner_edgein 5.24.0 (buffis the older Mapbox name, still used in the siblingsymbol_text_and_iconshader — the post notes both), and the file is atsrc/shaders/glsl/…, notsrc/shaders/…. Permalinks in the post are pinned tov5.24.0.@mapbox/tiny-sdfformula pinned tov2.2.0and shown to be algebraically identical to the fix.python3 script/lint-liquid.pyclean (35 posts);bundle exec jekyll buildclean; all three SVGs present in_site/assets/img/…, all three<img>tags root-relative, bothpost_urllinks resolved. No{% raw %}guard needed — the body has no{{/{%.Two things worth your eye before merge
halo_edge = (6.0 − halo_width/fontScale) / SDF_PXis below 0.75 for any non-zero halo width, the broken field was bright enough to draw a halo even though it drew no fill — andicon-halo-coloris the water tone, so it would have painted the glyph in the background colour. Sound arithmetic, but if you'd rather not assert it without a screenshot, that paragraph can be cut without touching anything else.RvspixelRatio. The post saysA = 0.75is scale-invariant and mandatory, whileRscales with the image, and recommends checking halo widths by eye. I deliberately did not try to derive the exact halo scaling for apixelRatio: 2image — MapLibre authors its own atlas withradius: 8 * textureScale, and getting that derivation wrong in public would be worse than leaving it as "tune by eye".SEO
Slug carries the full headline; title stays short. Near-zero prior art confirmed — the only human-readable statement of the number anywhere is a Mapbox troubleshooting page about recolorable images, framed around font glyphs and never connected to
addImage. The post quotes it and links it, plus the two never-resolved "document SDF icons" issues (mapbox-gl-style-spec#97 from 2014, maplibre-native#2551). MapLibre's own docs define thesdfflag as, in full, "Whether the image should be interpreted as an SDF image."Target terms:
maplibre custom sdf icon not showing,maplibre addImage sdf icon invisible,mapbox gl js sdf icon transparent no error,how to encode sdf icon alpha channel maplibre,maplibre icon-color not working custom icon,tiny-sdf cutoff 0.25,sdf icon threshold 0.75 192 alpha.No private infrastructure referenced —
slackwater-webis public and is linked in the close.