Skip to content

Cartographic Choices

How the Woosmap tile schema decides what appears, when, and how.

The tile generator does the heavy lifting — classification, ranking, height arithmetic, name translation — so the style layer gets clean attributes it can filter on directly.

Places — Why This City Before That One?

Place labels come from two sources depending on zoom:

Zoom Source What appears
z0–z6 Natural Earth Countries and states, ranked by the dataset's built-in rank field
z7+ OpenStreetMap Cities, towns, villages, hamlets, suburbs, islands

Country visibility (Natural Earth)

Rank Min zoom Examples
1 z0 China, USA, Russia, India
2 z1 France, Germany, Japan
3+ z2 Belgium, Singapore

Rank comes from Natural Earth's own ranking. We don't recompute it.

City and town visibility (OSM)

Each OSM place gets a rank derived from its population tag:

Population Rank
>= 1,000,000 1
>= 500,000 2
>= 100,000 3
>= 50,000 4
>= 10,000 5
>= 5,000 6
>= 1,000 7
< 1,000 8
unknown 10

But the min zoom is driven by place class, not rank:

Class Min zoom
city z6
town z7
village z10
hamlet, neighbourhood, suburb, island, islet z12
state (rank <= 2) z3
state (rank > 2) z5

So Paris (city, pop 2.1M, rank 1) and Limoges (city, pop 130k, rank 3) both appear at z6. The style layer can further filter on rank to show Paris first and Limoges a couple of zooms later. The tile provides the data; the style makes the final call.

Roads — Classification Hierarchy

OSM highway tags are grouped into 8 classes:

Class OSM tags Min zoom
motorway motorway, motorway_link z4
trunk trunk, trunk_link z5
primary primary, primary_link z7
secondary secondary, secondary_link z9
tertiary tertiary, tertiary_link z11
minor residential, living_street, unclassified z12
service service z12
path pedestrian, footway, cycleway, steps, bridleway, track z13

Pre-split by structure

Roads are emitted to three separate MVT layers based on structure:

MVT layer Contains
roads_tunnel Roads inside tunnels
roads Normal roads (plus fords)
roads_bridge Roads on bridges

This eliminates the need for brunnel filters in the style — the layer name encodes the structure. The style renders tunnel layers first, then normal roads, then bridges on top, achieving correct z-ordering without runtime filtering.

Additional road attributes

  • ramp: 1 for *_link highways (on/off ramps) — style can draw them thinner
  • oneway: 1 for forward, -1 for reverse — enables directional arrows
  • service: parking_aisle, driveway, or alley — finer control over service road rendering

Road Labels — Shields and Route Refs

Road labels are separate from road geometry so the style can place them independently (symbol layer vs line layer).

Route reference shields

When a road has a ref tag (e.g. "A1", "I-95", "US-101"), the tile emits:

  • ref: the raw reference string
  • ref_length: character count — the style uses this to size the shield background

US network classification

US highway shields need different icons. The tile classifies the network:

Condition Network value
network tag contains US:I us-interstate
network tag contains US:US us-highway
network tag contains US: us-state
ref starts with I or I- us-interstate
ref starts with US or US- us-highway

The network tag takes precedence over ref prefix guessing when both exist.

Buildings — Height and 3D Extrusion

Height computation

The tile computes render-ready heights so the style doesn't have to:

Priority Source Computation
1 height tag Direct numeric value (meters)
2 building:levels tag Levels × 3 meters
3 (fallback) 5 meters

Same fallback chain for render_min_height (from min_height or building:min_level × 3, default 0).

The hide_3d flag

Generic buildings tagged just building=yes with no height or levels info get hide_3d=1. The style uses this to suppress 3D extrusion for these features — extruding thousands of unknown-height buildings to a default 5m looks bad. Named building types (residential, commercial, hospital, etc.) always get extruded.

Building classes

Class When
residential, commercial, industrial, retail, warehouse, church, school, hospital, garage Matching building=<value>
building Everything else

Water Labels

Water feature labels use different geometries depending on the type:

Class Geometry Min zoom Why
ocean point z0 Label placed at a single point
sea point z3 Same as ocean
lake point z8 Centroid label
river line z10 Label follows the river path for curved text

Rivers are the only water labels emitted as lines — this lets the style render text that curves along the waterway using symbol-placement: line.

POI — What Makes the Cut

Not every OSM node becomes a POI. The tile classifies raw OSM tags into a single type attribute using a direct mapping. Only features that match a known tag/value combination get through — everything else is dropped at tile generation time. This keeps tiles small and focused on what the style actually renders.

There's no two-level class/subclass taxonomy. That's OpenMapTiles baggage. One field — type — is all the style needs to filter on.

OSM tag → type mapping

The tile checks these OSM tag keys in order and maps the first match:

OSM tag type value
amenity=restaurant restaurant
amenity=cafe cafe
amenity=fast_food fast_food
amenity=bar bar
amenity=pub pub
amenity=bank bank
amenity=atm atm
amenity=hospital hospital
amenity=pharmacy pharmacy
amenity=school school
amenity=university university
amenity=college college
amenity=library library
amenity=place_of_worship place_of_worship
amenity=police police
amenity=post_office post_office
amenity=cinema cinema
amenity=fuel fuel
amenity=parking parking
amenity=townhall townhall
shop=mall mall
shop=supermarket grocery
shop=greengrocer grocery
shop=convenience grocery
shop=butcher butcher
shop=bakery bakery
shop=toys toys
shop=electronics electronics
shop=furniture furniture
shop=sports sports
shop=clothes clothes
tourism=hotel hotel
tourism=museum museum
tourism=attraction attraction
tourism=zoo zoo
leisure=park park
leisure=sports_centre sports_centre
leisure=stadium stadium
leisure=golf_course golf_course
historic=castle castle
historic=monument monument
railway=station station
railway=halt halt
railway=tram_stop tram_stop
highway=bus_stop bus_stop

Note that some shop values merge into a single type: supermarket, greengrocer, and convenience all become grocery.

Large-geometry pull-up

Most POIs enter the tile at z12. But some POI types have large physical footprints — a university campus, a city park, a golf course. These are visible on the map long before z12, so their labels should appear earlier too.

For polygon POIs with one of these types, the min zoom drops to z10 with a pixel-size gate: the feature must occupy at least 12×12 pixels (~2% of a 256px tile) to appear below z13. This means a large park shows its label at z10, but a pocket park waits until z13 like everything else.

Pull-up types
university, college, school, hospital, park, castle, mall, sports_centre, golf_course, attraction

Point POIs (even with the same type) are not pulled up — only polygons, because there's no geometry to measure.

POI ranking

Each POI gets a rank derived from its type, not from the source data. Lower rank = more important. This avoids rank gaps when the style hides certain classes.

Rank Types
1 hospital, university, station
2 museum, attraction, zoo, castle, stadium
3 school, college, library, police, townhall, post_office, cinema
4 hotel
5 restaurant, cafe, fast_food, bar, pub, bank, pharmacy
6 fuel, mall, grocery, supermarket
7 bakery, butcher, clothes, electronics, furniture, sports, toys
8 place_of_worship, monument, park, sports_centre, golf_course
9 halt, tram_stop
10 bus_stop, atm, parking (and any unlisted type)

The rank also drives sort order within a tile and grid-based deduplication: at z13+ POIs are deduplicated within a 64-pixel grid (max 4 per cell), so higher-ranked types win the slot.

Transit network normalization

Railway POIs carry a network attribute. OSM's tagging is inconsistent, so the tile normalizes known aliases:

Raw OSM value Normalized
ratp;ratp-metro ratp-metro
ratp;ratp-rer ratp-rer
московский-метрополитен moscow-metro
london-underground london-underground
national-rail national-rail
metro-de-madrid metro-de-madrid
metro-de-barcelona metro-de-barcelona

Unknown networks pass through as-is. This lets the style use a single icon per network without handling alias variants.

Airports — Dual Source

Airport labels come from two sources to balance global coverage with regional detail:

Source Tag Classification Coverage
Natural Earth (ne_10m_airports) iata_code type=major → international, else regional ~893 major airports worldwide
OpenStreetMap aeroway=aerodrome + iata passengers >= 1M → international, else regional Regional airports (MPL, BVA, etc.)

Both emit to the same airports layer at min zoom 8. OSM aerodromes are polygons — pointOnSurface() extracts a centroid for the label point.

Name Translations

Every label layer (places, road labels, water labels, POI, airports) carries name plus 85 language-specific attributes (name:en, name:ja, name:ar, etc.). The client picks the right one based on user locale. No second pass or lookup needed — everything is in the tile.

Computed label fields

The tile generator also computes three derived fields for multi-script label display:

Field Value Example (Paris) Example (東京)
name_int name:enname:latinname Paris Tokyo
name:latin name if Latin, else name:en or first Latin name:* Paris Tokyo
name:nonlatin name if non-Latin, else omitted (omitted) 東京

The style expression uses these to render dual-script labels: "Tokyo \n 東京" in non-Latin regions, just "Paris" in Latin ones. Script detection uses Unicode block analysis (Basic Latin through Latin Extended).

Design Principles

  1. Tile computes, style renders. Complex arithmetic (height fallback, population ranking, network normalization) happens at tile generation time. The style gets clean attributes it can filter on directly.

  2. Allowlist over blocklist. POI types are explicitly mapped from OSM tags rather than trying to exclude the long tail. Cleaner tiles, predictable output.

  3. Dual source for places. Natural Earth provides authoritative country/state data with curated rankings at low zoom. OSM takes over at z7+ for city-level detail. No overlap — each source owns its zoom range.

  4. Separate geometry from labels. Roads and road labels are distinct layers so the style can render geometry (line layer) and labels (symbol layer) independently, with different min zooms and collision rules.