Display Buildings in 3D in Maptoolkit Maps JS
3D buildings in Maptoolkit Maps JS are rendered using fill-extrusion layers that read height and base-height properties from the vector tile source. The extrusion height is set with a data expression that reads the building’s height attribute, while the pitch and bearing are adjusted to show depth. Use this to create urban map views, real estate applications, or any visualization where building heights add meaningful context.
const API_KEY = 'YOUR_API_KEY';
const map = new maptoolkit.Map({
container: 'map',
apiKey: API_KEY,
style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
center: [-74.0089, 40.7074],
zoom: 16,
pitch: 45,
bearing: -17.6,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
map.on('load', () => {
const layers = map.getStyle().layers;
let labelLayerId;
for (const layer of layers) {
if (layer.type === 'symbol' && layer.layout['text-field']) {
labelLayerId = layer.id;
break;
}
}
map.addLayer({
id: '3d-buildings',
source: 'mtk',
'source-layer': 'building',
filter: ['==', 'extrude', true],
type: 'fill-extrusion',
minzoom: 15,
paint: {
'fill-extrusion-color': '#aaa',
'fill-extrusion-height': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.05, ['get', 'height']],
'fill-extrusion-base': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.05, ['get', 'min_height']],
'fill-extrusion-opacity': 0.6
}
}, labelLayerId);
});<!DOCTYPE html>
<html lang="en">
<head>
<title>Display Buildings in 3D - Maptoolkit Maps JS</title>
<meta property="og:description" content="Extrude building footprints into 3D using fill-extrusion layers." />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
<style>
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const API_KEY = 'YOUR_API_KEY';
const map = new maptoolkit.Map({
container: 'map',
apiKey: API_KEY,
style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
center: [-74.0089, 40.7074],
zoom: 16,
pitch: 45,
bearing: -17.6,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
map.on('load', () => {
const layers = map.getStyle().layers;
let labelLayerId;
for (const layer of layers) {
if (layer.type === 'symbol' && layer.layout['text-field']) {
labelLayerId = layer.id;
break;
}
}
map.addLayer({
id: '3d-buildings',
source: 'mtk',
'source-layer': 'building',
filter: ['==', 'extrude', true],
type: 'fill-extrusion',
minzoom: 15,
paint: {
'fill-extrusion-color': '#aaa',
'fill-extrusion-height': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.05, ['get', 'height']],
'fill-extrusion-base': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.05, ['get', 'min_height']],
'fill-extrusion-opacity': 0.6
}
}, labelLayerId);
});
</script>
</body>
</html>Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.
How it works
No three.js here. Buildings come from the vector tiles and are drawn by a fill-extrusion
layer, which raises a polygon to a height read from the data.
The layer reads height and min_height off each building feature, so the extrusion follows
real building heights rather than a constant. Buildings without height data in OpenStreetMap
fall back to whatever default the expression provides, which is why a city block can come out
uniformly flat in less-mapped areas.
The labelLayerId loop finds the first symbol layer with a text-field and inserts the
buildings below it, so street names stay readable on top of the extrusions rather than
being hidden behind them.
pitch: 45 is what makes extrusions visible at all; from directly above they look like flat
polygons. bearing: -17.6 just frames the Manhattan grid diagonally.
Note that only the street and street-3d styles ship a building extrusion layer of their
own. On the other styles you add this layer yourself, as here.
Next steps
Colouring the extrusions by data is the next step and the one that makes them useful: height, age or type driven from the feature properties turns a grey city into something you can read. The Schema Reference lists what the building layer carries.
Coverage is the other thing to plan for. Building heights in OpenStreetMap are uneven, so a map that looks right in Vienna can be flat in a smaller town. A sensible fallback height, and testing in the places your users actually are, matters more than the styling does. For floor plans rather than whole buildings, extruding your own polygons uses the same layer type.