schema_name: Shortbread schema_description: A basic, lean, general-purpose vector tile schema for OpenStreetMap data. See https://shortbread.geofabrik.de/ attribution: © OpenStreetMap contributors examples: shortbread.spec.yml args: area: description: Geofabrik area to download default: massachusetts osm_url: description: OSM URL to download default: '${ args.area == "planet" ? "aws:latest" : ("geofabrik:" + args.area) }' sources: ocean: type: shapefile url: https://osmdata.openstreetmap.de/download/water-polygons-split-3857.zip osm: type: osm url: '${ args.osm_url }' definitions: # TODO let attribute definitions set multiple keys so you can just use `- *names` attributes: - &name key: name - &name_en key: name_en tag_value: name:en - &name_de key: name_de tag_value: name:de - &poi_filter amenity: &poi_filter_amenity - arts_centre - atm - bank - bar - bench - bicycle_rental - biergarten - cafe - car_rental - car_sharing - car_wash - cinema - clinic - college - community_centre - courthouse - dentist - doctors - dog_park - drinking_water - embassy - fast_food - fire_station - food_court - fountain - grave_yard - hospital - hunting_stand - library - marketplace - nightclub - nursing_home - pharmacy - place_of_worship - playground - police - post_box - post_office - prison - pub - public_building - recycling - restaurant - school - shelter - telephone - theatre - toilets - townhall - university - vending_machine - veterinary - waste_basket emergency: &poi_filter_emergency - defibrillator - fire_hydrant - phone highway: &poi_filter_highway - emergency_access_point historic: &poi_filter_historic - archaeological_site - battlefield - castle - fort - memorial - monument - ruins - wayside_cross - wayside_shrine leisure: &poi_filter_leisure - golf_course - ice_rink - pitch - sports_centre - stadium - swimming_pool - water_park man_made: &poi_filter_man_made - lighthouse - surveillance - tower - wastewater_plant - water_well - water_works - watermill - windmill office: &poi_filter_office - diplomatic shop: &poi_filter_shop - alcohol - bakery - beauty - beverages - bicycle - books - butcher - car - chemist - clothes - computer - convenience - department_store - doityourself - dry_cleaning - florist - furniture - garden_centre - general - gift - greengrocer - hairdresser - hardware - jewelry - kiosk - laundry - mall - mobile_phone - newsagent - optician - outdoor - shoes - sports - stationery - supermarket - toys - travel_agency - video tourism: &poi_filter_tourism - artwork - alpine_hut - bed_and_breakfast - camp_site - caravan_site - chalet - guest_house - hostel - hotel - information - motel - picnic_site - theme_park - viewpoint - zoo layers: ## Water - id: ocean features: - source: ocean geometry: polygon - id: water_polygons features: - source: osm geometry: polygon min_zoom: default_value: 4 overrides: &water_zoom_overrides 10: waterway: [ dock, canal ] include_when: &water_filter natural: - glacier - water waterway: - riverbank - dock - canal landuse: - reservoir - basin attributes: - key: kind type: match_value - key: way_area # area in square meter (Mercator Projection) value: "${ feature.area('m2') }" - id: water_polygons_labels features: - source: osm geometry: polygon_centroid min_zoom: default_value: 14 overrides: *water_zoom_overrides include_when: *water_filter exclude_when: name: '' attributes: - key: kind type: match_value - *name - *name_en - *name_de - key: way_area # area in square meter (Mercator Projection) value: "${ feature.area('m2') }" - id: water_lines features: - source: osm geometry: line min_zoom: default_value: 9 overrides: 14: waterway: [ stream, ditch ] # TODO rivers and canals min length=0.25px include_when: waterway: - canal - river - stream - ditch attributes: - key: kind type: match_value - &attr_tunnel key: tunnel min_zoom: 11 # to reuse for streets, not relevant for water as min_zoom is lower value: true include_when: tunnel: [ yes, building_passage ] covered: yes else: false - &attr_bridge key: bridge min_zoom: 11 # to reuse for streets, not relevant for water as min_zoom is lower value: true include_when: bridge: - yes - viaduct - boardwalk - cantilever - covered - low_water_crossing - movable - trestle else: false - id: water_lines_labels features: - source: osm geometry: line min_zoom: default_value: 12 overrides: 14: waterway: [ stream, ditch ] # TODO rivers and canals min length=0.25px include_when: waterway: - canal - river - stream - ditch exclude_when: name: '' attributes: - key: kind type: match_value - *name - *name_en - *name_de - *attr_tunnel - *attr_bridge - id: dam_lines features: - source: osm geometry: line min_zoom: 12 include_when: &dam_filter # note that dykes are not dams waterway: dam attributes: &dam_atrs - key: kind value: dam - id: dam_polygons features: - source: osm geometry: polygon min_zoom: 12 include_when: *dam_filter attributes: *dam_atrs - id: pier_lines features: - source: osm geometry: line min_zoom: 12 include_when: &pier_filter man_made: - pier - breakwater - groyne attributes: &pier_attrs - key: kind type: match_value - id: pier_polygons features: - source: osm geometry: polygon min_zoom: 12 include_when: *pier_filter attributes: *pier_attrs ## Countries, States, Cities - id: boundaries features: - source: osm geometry: line # TODO get min admin level from relations min_size: 0 min_zoom: default_value: 7 overrides: 0: admin_level: 2 include_when: __all__: - boundary: administrative - admin_level: [ 2, 4 ] attributes: - key: maritime type: boolean value: true include_when: maritime: __any__ natural: coastline else: false - key: admin_level type: integer - key: disputed value: true include_when: disputed: yes # TODO: member of a relation with boundary=disputed and (admin_level unset or between 2 and 4) # see https://github.com/shortbread-tiles/shortbread-docs/issues/43 else: false - id: boundary_labels features: - source: osm geometry: polygon_point_on_surface min_zoom: default_value: 5 overrides: 2: '${ feature.tags["admin_level"] == "2" && feature.area("km2") >= 2e6 }' 3: '${ feature.area("km2") >= 7e5 }' 4: '${ feature.area("km2") >= 1e5 }' include_when: __all__: - boundary: administrative - admin_level: [ 2, 4 ] # TODO sort by way_area descending attributes: - key: admin_level type: integer - *name - *name_en - *name_de - key: way_area # area in hectare (Mercator Projection) value: "${ feature.area('ha') }" - id: place_labels features: - source: osm geometry: point include_when: place: - city - town - village - hamlet - suburb - quarter - neighbourhood - isolated_dwelling - farm - island - locality exclude_when: name: '' min_zoom: default_value: 10 overrides: 4: __all__: place: [ city, town, village, hamlet ] capital: [ yes, '4' ] 6: __all__: place: city __not__: capital: [ yes, '4' ] 7: __all__: place: town __not__: capital: [ yes, '4' ] # TODO z-order attributes: - key: kind value: default_value: '${ match_value }' overrides: capital: __all__: place: [ city, town, village, hamlet ] capital: yes state_capital: __all__: place: [ city, town, village, hamlet ] capital: '4' - *name - *name_en - *name_de - key: population type: integer value: match: - value: '${ feature.tags.get("population") }' if: { population: __any__ } - value: 100000 if: { place: city } - value: 5000 if: { place: town } - value: 1000 if: { place: suburb } - value: 500 if: { place: quarter } - value: 100 if: { place: [ village, neighborhood ] } - value: 50 if: { place: hamlet } - value: 5 if: { place: [ isolated_dwelling, farm ] } - else: 0 ## Land Use, Land Cover, Buildings - id: land features: - source: osm geometry: polygon include_when: amenity: - grave_yard landuse: - allotments - brownfield - cemetery - commercial - farmland - farmyard - forest - garages - grass - greenfield - greenhouse_horticulture - industrial - landfill - meadow - orchard - plant_nursery - quarry - railway - recreation_ground - residential - retail - village_green - vineyard leisure: - garden - golf_course - miniature_golf - park - playground natural: - bare_rock - beach - grassland - heath - sand - scree - scrub - shingle - wood wetland: - bog - marsh - string_bog - swamp - wet_meadow min_zoom: default_value: 11 overrides: 7: natural: wood landuse: forest 10: landuse: - brownfield - commercial - farmland - farmyard - garages - greenfield - industrial - landfill - railway - residential - retail natural: - beach - sand 13: amenity: grave_yard landuse: cemetery attributes: - key: kind value: '${match_value == "wood" ? "forest": match_value}' - id: sites features: - source: osm geometry: polygon min_zoom: 14 include_when: military: danger_area leisure: sports_center landuse: construction amenity: - bicycle_parking - college - hospital - parking - prison - university attributes: - key: kind type: match_value - id: buildings features: - source: osm geometry: polygon min_zoom: 14 include_when: building: __any__ exclude_when: building: no - id: addresses features: - source: osm geometry: polygon_centroid_if_convex min_zoom: 14 include_when: &address_filter __all__: - addr:housenumber: __any__ addr:housename: __any__ - __not__: *poi_filter attributes: &address_attributes - key: housename tag_value: addr:housename - key: housenumber tag_value: addr:housenumber - source: osm geometry: point min_zoom: 14 include_when: *address_filter attributes: *address_attributes ## Streets and Transport - id: streets features: - source: osm geometry: line min_size: 0 min_zoom: default_value: 13 overrides: 5: highway: motorway% 6: highway: trunk% 8: highway: primary% __all__: railway: [ rail, narrow_gauge ] service: __any__ 9: highway: secondary% 10: __all__: railway: [ rail, narrow_gauge ] service: '' railway: - funicular - light_rail - monorail - subway - tram highway: tertiary 11: aeroway: runway 12: highway: - bus_guideway - busway - residential - unclassified # TODO min_tile_cover_size: 0 # TODO z-order include_when: highway: - motorway - motorway_link - trunk - trunk_link - primary - primary_link - secondary - secondary_link - tertiary - tertiary_link - unclassified - residential - busway - bus_guideway - living_street - service - pedestrian - track - footway - steps - path - cycleway aeroway: # TODO update shortbread spec - runway - taxiway railway: - rail - narrow_gauge - tram - light_rail - funicular - subway - monorail attributes: - key: kind value: '${ match_value.replace("_link", "") }' - key: link min_zoom: 11 value: true include_when: highway: - motorway_link - trunk_link - primary_link - secondary_link - tertiary_link else: false - key: rail min_zoom: 5 value: true include_when: railway: __any__ else: false - *attr_tunnel - *attr_bridge - key: oneway min_zoom: 14 value: true include_when: __all__: railway: '' oneway: - yes - 1 - true - -1 else: false - key: oneway_reverse min_zoom: 14 value: true include_when: __all__: railway: '' oneway: -1 else: false - key: tracktype min_zoom: 11 - key: surface # TODO canonicalize? min_zoom: 11 - key: service min_zoom: 11 - key: bicycle min_zoom: 14 - key: horse min_zoom: 14 - id: street_polygons features: - source: osm geometry: polygon min_zoom: default_value: 14 overrides: 11: area:aeroway: runway 13: area:aeroway: taxiway include_when: # TODO this is a really strange difference to street_polygons. # https://github.com/shortbread-tiles/shortbread-docs/issues/80 area:aeroway: [ runway, taxiway ] highway: [ pedestrian, service ] attributes: - key: kind type: match_value - *attr_bridge - key: rail value: false - key: service - key: surface - *attr_tunnel - id: street_labels features: - source: osm geometry: line min_zoom: default_value: 14 overrides: 10: highway: motorway railway: - rail - narrow_gauge - tram - light_rail - funicular - subway - monorail 11: aeroway: runway 12: highway: [ trunk, primary ] 13: highway: - motorway_link - trunk_link - primary_link - secondary - secondary_link - tertiary aeroway: taxiway include_when: highway: - motorway - motorway_link - trunk - trunk_link - primary - primary_link - secondary - secondary_link - tertiary - tertiary_link - unclassified - residential - living_street - busway - bus_guideway - service - pedestrian - track - footway - steps - path - cycleway aeroway: - runway - taxiway railway: - rail - narrow_gauge - tram - light_rail - funicular - subway - monorail exclude_when: __all__: name: '' ref: '' attributes: - key: kind type: match_value - *name - *name_en - *name_de # TODO use ref var to avoid duplicating logic - key: ref exclude_when: &missing_ref ref: '' value: '${ feature.tags["ref"].replace(";", "\n") }' - key: ref_cols value: '${ max(feature.tags["ref"].split(";").map(r, size(r))) }' exclude_when: *missing_ref - key: ref_rows value: '${ size(feature.tags["ref"].split(";")) }' exclude_when: *missing_ref - key: tunnel value: true include_when: tunnel: [ yes, building_passage ] covered: yes else: false - id: streets_polygons_labels features: - source: osm geometry: polygon_point_on_surface min_zoom: 14 include_when: __all__: # TODO this is a really strange difference to street_polygons. # https://github.com/shortbread-tiles/shortbread-docs/issues/80 - aeroway: [ runway, taxiway ] highway: [ pedestrian, service ] - name: __any__ attributes: - key: kind type: match_value - *name - *name_en - *name_de - id: street_labels_points features: - source: osm geometry: point min_zoom: 12 include_when: highway: motorway_junction attributes: - key: kind type: match_value - key: ref - *name - *name_en - *name_de - id: bridges features: - source: osm geometry: polygon min_zoom: 12 include_when: man_made: bridge attributes: - key: kind value: bridge - id: aerialways features: - source: osm geometry: line min_zoom: 12 include_when: aerialway: - cable_car - gondola - goods - chair_lift - drag_lift - t-bar - j-bar - platter - rope_tow attributes: - key: kind type: match_value - id: ferries features: - source: osm geometry: line min_zoom: default_value: 12 overrides: 10: __not__: motor_vehicle: no include_when: route: ferry attributes: - key: kind type: match_value - *name - *name_en - *name_de ## Points of Interest - id: public_transport features: - source: osm geometry: point min_zoom: &public_transport_zoom default_value: 14 overrides: 11: aeroway: aerodrome 12: amenity: ferry_terminal 13: railway: [ station, halt ] aerialway: station aeroway: helipad amenity: bus_station include_when: &public_transport_filter aerialway: station aeroway: [ aerodrome, helipad ] amenity: [ bus_station, ferry_terminal ] highway: bus_stop railway: [ station, halt, tram_stop ] attributes: &public_transport_attrs - key: kind value: # only aerialway=station needs special handling coalesce: - tag_value: aeroway - tag_value: amenity - tag_value: railway - tag_value: highway - "aerialway_station" - *name - *name_en - *name_de - key: iata - source: osm geometry: polygon_point_on_surface min_zoom: *public_transport_zoom include_when: *public_transport_filter attributes: *public_transport_attrs - id: pois features: - source: osm geometry: point min_zoom: 14 include_when: *poi_filter attributes: &poi_attrs # For the attributes below, we need to include_when, as otherwise # the any-filter above could add variants if contains one matching and one non-matching variant - key: amenity include_when: amenity: *poi_filter_amenity - key: leisure include_when: leisure: *poi_filter_leisure - key: tourism include_when: tourism: *poi_filter_tourism - key: shop include_when: shop: *poi_filter_shop - key: man_made include_when: man_made: *poi_filter_man_made - key: historic include_when: historic: *poi_filter_historic - key: emergency include_when: emergency: *poi_filter_emergency - key: highway include_when: highway: *poi_filter_highway - key: office include_when: office: *poi_filter_office - *name - *name_en - *name_de - key: housename tag_value: addr:housename - key: housenumber tag_value: addr:housenumber - key: cuisine include_when: amenity: - restaurant - fast_food - pub - bar - cafe - key: sport include_when: leisure: - pitch - sports_centre - key: vending include_when: amenity: vending_machine - key: information include_when: tourism: information - key: tower:type include_when: man_made: tower - key: religion include_when: amenity: place_of_worship - key: denomination include_when: amenity: place_of_worship - key: recycling:glass_bottles type: boolean value: - if: { "recycling:glass_bottles": yes } value: true - else: false include_when: amenity: recycling - key: recycling:paper type: boolean value: - if: { "recycling:paper": yes } value: true - else: false include_when: amenity: recycling - key: recycling:clothes type: boolean value: - if: { "recycling:clothes": yes } value: true - else: false include_when: amenity: recycling - key: recycling:scrap_metal type: boolean value: - if: { "recycling:scrap_metal": yes } value: true - else: false include_when: amenity: recycling - key: atm type: boolean value: - if: { atm: yes } value: true - else: false include_when: amenity: bank - source: osm geometry: polygon_point_on_surface min_zoom: 14 include_when: *poi_filter attributes: *poi_attrs