Skip to content

3D Buildings with Roof Shapes

Add a Scene3dControl from @maptoolkit/maplibre-scene3d-control to show the 3D scene of the Street style: buildings with roof shapes and 3D trees. The control reads the scene from the style, adds the buildings from buildings.json and loads the 3D library once the map reaches zoom 12. This view looks at St. Stephen’s Cathedral in Vienna, where an official 3D city model replaces the OpenStreetMap buildings.

The Street and Summer styles carry a scene; the other styles have none. To extrude footprints without a plugin, see the 3D Buildings example. See 3D Buildings for the buildings tileset and what each library supports.

  • Map maplibre-gl in an import map. The control and the 3D library import MapLibre by its package name. The import map points that name at MapLibre’s /dist/maplibre-gl.mjs, so the page and both packages share one copy of MapLibre. Load the control from its /dist/ file too: jsDelivr’s +esm version would load a second, separately bundled MapLibre.
  • Pass library. It tells the control where to load @maptoolkit/maplibre-3d-layers from. The standalone build includes three.js (about 1 MB), so do not load three.js separately. The control loads it only once the map reaches zoom 12.
  • No API key. The community buildings source is open, so the control needs no apiKey.
  • Tilt the map. The buildings get more opaque with the pitch and are hidden when you look straight down at zoom 15 and below. Roof shapes appear from zoom 15. maxPitch: 85 allows a view up to the horizon, and antialias smooths the edges of distant trees.

Once the buildings have loaded, the control hides the Street style’s own extruded buildings, so no building is drawn twice.

import * as maplibregl from 'maplibre-gl';
import { LogoControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-logo-control@1.0.0/+esm';
import { Scene3dControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-scene3d-control@0.2.0/dist/maplibre-scene3d-control.js';
const map = new maplibregl.Map({ container: 'map', attributionControl: { customAttribution: '', compact: false }, style: 'https://styles.maptoolkit.org/street.json', center: [16.3731, 48.2085], zoom: 16, pitch: 70, maxPitch: 85, canvasContextAttributes: { antialias: true } }); // Vienna, St. Stephen's Cathedral

map.addControl(new LogoControl());
// The control reads the 3D scene from the style. It loads the 3D library,
// which includes three.js, only once the map reaches zoom 12.
map.addControl(new Scene3dControl({
  library: () => import('https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-3d-layers@0.5.4/dist/maplibre-3d-layers.standalone.mjs')
}));
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maplibre-gl@6.9.0/dist/maplibre-gl.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-logo-control@1.0.0/dist/maplibre-logo-control.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-scene3d-control@0.2.0/dist/maplibre-scene3d-control.css" />
  <style>
    html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
    #map { width: 100%; height: 100%; }
  </style>
  <script type="importmap">
    { "imports": { "maplibre-gl": "https://cdn.jsdelivr.net/npm/maplibre-gl@6.9.0/dist/maplibre-gl.mjs" } }
  </script>
</head>
<body>
  <div id="map"></div>
  <script type="module">
import * as maplibregl from 'maplibre-gl';
import { LogoControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-logo-control@1.0.0/+esm';
import { Scene3dControl } from 'https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-scene3d-control@0.2.0/dist/maplibre-scene3d-control.js';
const map = new maplibregl.Map({ container: 'map', attributionControl: { customAttribution: '', compact: false }, style: 'https://styles.maptoolkit.org/street.json', center: [16.3731, 48.2085], zoom: 16, pitch: 70, maxPitch: 85, canvasContextAttributes: { antialias: true } }); // Vienna, St. Stephen's Cathedral

map.addControl(new LogoControl());
// The control reads the 3D scene from the style. It loads the 3D library,
// which includes three.js, only once the map reaches zoom 12.
map.addControl(new Scene3dControl({
  library: () => import('https://cdn.jsdelivr.net/npm/@maptoolkit/maplibre-3d-layers@0.5.4/dist/maplibre-3d-layers.standalone.mjs')
}));
  </script>
</body>
</html>