Skip to content

post: MapLibre's SDF icon edge is at 0.75, not 0.5 - #53

Open
clarkbw wants to merge 1 commit into
mainfrom
post/maplibre-sdf
Open

post: MapLibre's SDF icon edge is at 0.75, not 0.5#53
clarkbw wants to merge 1 commit into
mainfrom
post/maplibre-sdf

Conversation

@clarkbw

@clarkbw clarkbw commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

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 with script/bump.py / script/publish.py.

What it covers

slackwater-web 4de76d8 / 9dc473e / 04d66f1. Hand-authored SDF pin glyphs rendered as nothing. MapLibre's shader thresholds the icon fill at inner_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 at d = R × (A − 0.75), so A must be 0.75 (or your shape erodes) and R only 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:

  • Shader claim verified twice — against the maplibre-gl 5.24.0 bundle installed in slackwater-web, and against the tagged source. Two corrections vs. the commit message: the constant is named inner_edge in 5.24.0 (buff is the older Mapbox name, still used in the sibling symbol_text_and_icon shader — the post notes both), and the file is at src/shaders/glsl/…, not src/shaders/…. Permalinks in the post are pinned to v5.24.0.
  • Alpha numbers recomputed by running the old and new encodings over the real glyph geometry. The commit says interiors topped out at "176–182"; the measured peak is 176 for both glyphs, and 0 of 1936 pixels cross the threshold. The post uses the measured figures.
  • @mapbox/tiny-sdf formula pinned to v2.2.0 and shown to be algebraically identical to the fix.
  • python3 script/lint-liquid.py clean (35 posts); bundle exec jekyll build clean; all three SVGs present in _site/assets/img/…, all three <img> tags root-relative, both post_url links resolved. No {% raw %} guard needed — the body has no {{/{%.
  • Figures rendered to PNG and eyeballed for label collisions.

Two things worth your eye before merge

  1. The halo aside (in Why it matters) is derived from the shader plus the real paint values, not observed in a render: since halo_edge = (6.0 − halo_width/fontScale) / SDF_PX is 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 — and icon-halo-color is 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.
  2. R vs pixelRatio. The post says A = 0.75 is scale-invariant and mandatory, while R scales with the image, and recommends checking halo widths by eye. I deliberately did not try to derive the exact halo scaling for a pixelRatio: 2 image — MapLibre authors its own atlas with radius: 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 the sdf flag 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-web is public and is linked in the close.

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
@clarkbw clarkbw added the publish Approved to publish via the drip-publisher routine label Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

publish Approved to publish via the drip-publisher routine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant