Highway Shields
Country-aware route markers driven by the network attribute on transportation and transportation_name.
Why this matters
A road tagged M1 looks completely different in:
- US (M1 = motorway in NY) → black-on-yellow oval
- UK (M1 = London-Leeds motorway) → blue-on-white pill
- Germany (no M1) → not applicable
Our Lua tile pipeline classifies every road's network from its OSM tags, so styles can render the right shield without parsing ref strings on the client.
Sprite
Required sprite — hosted at /sprites/shields?key=…. Each icon is named after its network:
| Sprite name | Network value | Visual |
|---|---|---|
shield-us-interstate | us-interstate | Red/blue/white pentagon |
shield-us-highway | us-highway | Black-on-white shield |
shield-us-state | us-state | Black-on-white circle/square |
shield-de-bundesautobahn | de-bundesautobahn | Blue rectangle "A" |
shield-de-bundesstrasse | de-bundesstrasse | Yellow rectangle "B" |
shield-gb-motorway | gb-motorway | Blue pill "M" |
shield-gb-trunk | gb-trunk | Green pill "A" |
shield-fr-autoroute | fr-autoroute | Red pill "A" |
shield-fr-route-nationale | fr-route-nationale | Red rectangle "N" |
shield-e-road | e-road | Green rectangle "E" |
shield-asian-highway | asian-highway | Blue rectangle "AH" |
shield-road | road (fallback) | Generic white pill |
Style layer
{
"id": "highway-shields",
"type": "symbol",
"source": "mfd",
"source-layer": "transportation_name",
"filter": ["all",
["has", "ref"],
["match", ["get", "class"], ["motorway", "trunk", "primary"], true, false]
],
"layout": {
"icon-image": [
"concat", "shield-",
["coalesce", ["get", "network"], "road"]
],
"icon-size": ["interpolate", ["linear"], ["zoom"], 8, 0.5, 16, 1.0],
"icon-text-fit": "both",
"icon-text-fit-padding": [1, 4, 1, 4],
"text-field": ["get", "ref"],
"text-font": ["Noto Sans Bold"],
"text-size": ["interpolate", ["linear"], ["zoom"], 8, 9, 16, 13],
"symbol-placement": "line",
"symbol-spacing": 200
},
"paint": {
"text-color": "#000",
"text-halo-color": "#fff",
"text-halo-width": 0
}
}Fallback chain
Some refs span countries (e.g. E-roads E40, AH-roads AH1). The Lua classifier picks the most specific country network when present, falls back to international networks (e-road, asian-highway), then to road.
If network is null, sprite name shield-road is used — always exists.
Custom sprite (your own brand)
Replace the hosted sprite with yours:
"sprite": "https://your-cdn.example.com/my-shields/v1"Names must match the network values exactly: shield-us-interstate.png, etc.
Generate from SVG with spreet:
spreet ./shields-svg/ ./output/my-shields
# produces my-shields.png + my-shields.jsonStatus
Shield rendering ships in style v1.1 (estimated 2026-05). Until then the network attribute is in tiles but the hosted style renders simple text refs.