Skip to content
3D Buildings

3D Buildings

Buildings stand up on a Maptoolkit map in one of two ways: as 3D bodies with their roof shapes, together with official 3D city models and 3D trees, or as footprints extruded into blocks with flat tops. For a 3D map surface, see 3D Terrain.

For buildings like the ones on www.maptoolkit.org, you need two plugins. A style alone gives you extruded blocks at most.

Both work with MapLibre GL JS 6 or later.

Quick start

Install the two plugins together with three.js and MapLibre GL JS:

npm install @maptoolkit/maplibre-scene3d-control @maptoolkit/maplibre-3d-layers three maplibre-gl

Add the control to a map with the Street or Summer style:

import * as maplibregl from "maplibre-gl";
import { Scene3dControl } from "@maptoolkit/maplibre-scene3d-control";
import "@maptoolkit/maplibre-scene3d-control/style.css";

const map = new maplibregl.Map({
  container: "map",
  style: "https://styles.maptoolkit.org/street.json",
  center: [16.3731, 48.2085], // Vienna, St. Stephen's Cathedral
  zoom: 16,
  pitch: 70,
  maxPitch: 85,
  canvasContextAttributes: { antialias: true }, // smooth edges on distant trees
});
map.addControl(new Scene3dControl());

The control loads @maptoolkit/maplibre-3d-layers itself, so the code imports only the control. The community buildings source needs no API key, so leave out the control’s apiKey option. Without a bundler, load both packages from a CDN with an import map, as the 3D Buildings with Roof Shapes example shows.

Two ways

Extruded blocksBuildings with roof shapes
What you seeFootprints raised to their height, with flat tops3D bodies with roof shapes from zoom 15. Where an official 3D city model exists, as in Vienna, its buildings replace the OpenStreetMap ones
Databuilding layer of the mtk tileshttps://tiles.maptoolkit.org/buildings.json
Drawn withA standard fill-extrusion layerFill3DLayer from @maptoolkit/maplibre-3d-layers (with three.js) for the roof shapes, a fill-extrusion for the other buildings
Set up byThe style (Street, Summer) or a layer you add@maptoolkit/maplibre-scene3d-control, which reads the scene from the style
LibrariesEvery library with fill-extrusion, see What each library supportsMapLibre GL JS 6 or later
StylesStreet and Summer ship the layer. For the other styles, switch it on in MapMaker or add it yourselfStreet and Summer carry the scene that the Scene3D Control reads. For the other styles, switch it on in MapMaker

The two work together. Street and Summer show extruded blocks on their own. Add the two plugins, and the buildings with roof shapes replace them once they have loaded.

Buildings with roof shapes

Street and Summer, and their -3d and language versions, carry a 3D scene in the style metadata under maptoolkit:scene3d. The scene holds the buildings from buildings.json and 3D tree models, placed on single trees, along tree rows and in woods from zoom 15. Winter, Hiking, Cycling, Light and Dark have no scene.

MapLibre ignores style metadata, so the scene stays invisible until you add @maptoolkit/maplibre-scene3d-control. The control reads the scene and adds its layers; @maptoolkit/maplibre-3d-layers draws the buildings with roof shapes and the trees.

What the control does:

  • It adds the buildings source and puts the buildings and trees below the style’s labels.
  • It loads @maptoolkit/maplibre-3d-layers, which uses three.js, only once the map reaches zoom 12. The buildings source has no tiles below zoom 12.
  • Once the buildings source has loaded, it hides the style’s own extruded buildings (building_3d_multicolored), so no building is drawn twice. If the source cannot load, the style keeps them.
  • It reads the scene again on every style change. Switch to Winter and the scene goes away; switch back to Street and it returns.

The buildings get more opaque as you tilt the map. Looking straight down at zoom 15 and below, they are hidden, so tilt the map to see them. On a -3d style the buildings stand on the terrain.

For a style without a scene, switch the scene on in MapMaker (see Extruded blocks), pass one with the control’s scene option, or add the Fill3DLayer of @maptoolkit/maplibre-3d-layers yourself. Both READMEs list the options.

The buildings tileset

https://tiles.maptoolkit.org/buildings.json needs no API key. It has tiles from zoom 12 to 15. Beyond 15 the tiles overzoom: the geometry stays, no new detail arrives.

Source layerZoomContentDraw with
buildings2d12–15OpenStreetMap footprints with the height, extrude and roof fields of the building layerfill-extrusion
buildings3d153D bodies with roof and wall surfaces, built from the OpenStreetMap roof tags (roof:shape and others). Where an official 3D city model exists, as in Vienna, its buildings replace the OpenStreetMap onesFill3DLayer from @maptoolkit/maplibre-3d-layers

Every buildings3d feature carries type (roof or wall), source (osm or citygml) and colour_index. Buildings from OpenStreetMap also carry roof_shape, height and min_height, and roof_colour, roof_material and building_colour where OpenStreetMap records them.

  • buildings3d is not standard vector tile geometry. It uses a Maptoolkit extension of the Mapbox Vector Tile (MVT) format that stores a height for every vertex. Standard vector tile renderers read its fields but not its geometry, and a fill-extrusion on buildings3d draws broken shapes. Use fill-extrusion on buildings2d only.
  • buildings2d alone has gaps from zoom 15. From zoom 15 it leaves out every building that buildings3d draws, so no building appears in both layers. For extruded blocks without the plugins, use the building layer of the mtk tiles instead.

Extruded blocks: fill-extrusion on the building layer

Street and Summer contain a fill-extrusion layer. Their building_3d_multicolored layer draws from zoom 14, filters on extrude, and takes its geometry from the height and min_height attributes. The -3d and language versions of both have it too; the other five styles draw buildings flat.

This is what Street and Summer show without the two plugins, and what the libraries without the plugins can draw. With the plugins, the style’s layer is hidden once the buildings with roof shapes have loaded.

To add 3D buildings to one of the other styles, switch them on in MapMaker, no code needed: in Easy Mode, open Edit Layer Groups › Buildings › Contained Layers and make 3D Buildings visible. The style then has the extruded blocks and also the buildings of the 3D scene for the plugins. 3D Trees under Nature adds the trees to the scene. Export the style and use it as described in Customize a Map Style.

To add the layer in code instead, the 3D Buildings example is a complete, runnable page.

The building layer

The building source layer exists from zoom 13 to 15. Zoom 15 is the maximum zoom of the tileset, so beyond it tiles overzoom: the geometry stays, no new detail arrives.

FieldTypeUse
extrudeBooleanWhether the footprint is meant to stand up
heightNumberBuilding height in metres
min_heightNumberHeight at which the building starts, for parts above ground
colour_indexNumberIndex for varying the fill across neighbouring buildings
building_colourStringColour where OpenStreetMap records one
roof_shape, roof_colour, roof_angle, roof_direction, roof_height, roof_levels, roof_material, roof_orientationStringRoof attributes

Filter on extrude. Not every footprint is meant to be extruded, and the Street style filters on the same flag. At a Midtown Manhattan view it excludes roughly 120 of about 16,700 footprints, mostly building parts that would otherwise stack on top of the building they belong to.

What each library supports

Library3D buildingsExample
MapLibre GL JSYes: with roof shapes through the two plugins, as extruded blocks without themBuildings, Buildings with roof shapes
deck.glExtruded blocks, through a MapLibre basemapNone
MapLibre Native AndroidExtruded blocksBuildings
MapLibre Native iOSExtruded blocksBuildings
FlutterExtruded blocksBuildings
React NativeExtruded blocksBuildings
kepler.glWhatever the style you load carriesNone
LeafletNoNone, not possible
OpenLayersNoNone, not possible
CesiumJSNoNone, not possible

Buildings with roof shapes need MapLibre GL JS 6 or later and the two plugins. The buildings3d layer uses a Maptoolkit extension of the vector tile format that the other libraries cannot draw, so they show extruded blocks from the building layer. kepler.gl has no setting of its own: it loads a style URL and renders what that style contains, so the Street and Summer styles give extruded buildings.

Where 3D buildings are not possible, and why

Leaflet. The maplibre-gl-leaflet plugin renders a MapLibre style inside Leaflet, but its README states plainly that there is no rotation, bearing or pitch support. Without pitch the map is always viewed from directly above, where extrusions have no visible effect. Use MapLibre GL JS directly for 3D.

OpenLayers. There is no fill-extrusion equivalent. OpenLayers is a 2D renderer; 3D requires pairing it with a separate engine such as Cesium.

CesiumJS. Our CesiumJS setup uses the basemap as an imagery layer, and Cesium’s 3D buildings come from 3D Tiles rather than vector tile footprints. You get a 3D globe with our cartography painted on it, not 3D buildings from our data.

Examples