Add 3D Terrain in Maptoolkit Maps JS
Maps JS includes a TerrainControl that adds the Maptoolkit terrain tile source and wires up the toggle button automatically. Add it to the map after the style loads. The TERRAIN constant provides the pre-configured raster-dem source pointing to the Maptoolkit terrain tile endpoint.
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: [12.805988, 47.310897],
zoom: 12,
pitch: 70,
maxPitch: 85,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
map.on('load', () => {
map.addSource('terrain-rgb', {
type: 'raster-dem',
tiles: [`https://tiles.maptoolkit.net/terrain/{z}/{x}/{y}.webp?api_key=${API_KEY}`],
tileSize: 256,
minzoom: 5,
maxzoom: 12,
encoding: 'terrarium'
});
map.setTerrain({ source: 'terrain-rgb', exaggeration: 1.0 });
});<!DOCTYPE html>
<html lang="en">
<head>
<title>Terrain Tiles - 3D Terrain - Maptoolkit Maps JS</title>
<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: [12.805988, 47.310897],
zoom: 12,
pitch: 70,
maxPitch: 85,
attributionControl: { compact: false }
});
map.addControl(new maptoolkit.NavigationControl(), 'top-right');
map.on('load', () => {
map.addSource('terrain-rgb', {
type: 'raster-dem',
tiles: [`https://tiles.maptoolkit.net/terrain/{z}/{x}/{y}.webp?api_key=${API_KEY}`],
tileSize: 256,
minzoom: 5,
maxzoom: 12,
encoding: 'terrarium'
});
map.setTerrain({ source: 'terrain-rgb', exaggeration: 1.0 });
});
</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
Maps JS wraps MapLibre GL JS, so the terrain setup is the same shape, with the key passed
once as apiKey and reused for the style and the DEM tiles.
The source is raster-dem rather than raster, so the renderer reads each pixel as a
height value instead of painting it. encoding: 'terrarium' is required: the tiles are
Terrarium-encoded despite the terrain path, and the wrong encoding produces plausible but
incorrect relief rather than an error.
setTerrain sits inside map.on('load') because it attaches to the loaded style.
Two camera options matter. pitch: 70 tilts far enough for relief to read, and
maxPitch: 85 raises the ceiling above the default so a user can tilt further toward the
horizon. exaggeration: 1.0 is true-to-life; raising it deepens valleys and sharpens peaks
without changing the underlying data.
Next steps
TerrainControl gives users the toggle, which is usually the right default rather than
starting tilted: terrain is the most expensive thing on the page and not every visitor wants
it. exaggeration is the other dial, and above 1 it flatters the landscape rather than
describing it.
From here terrain is a base for other things. A route over tilted terrain is much more legible than the same route flat, and the Routing API plus the Elevation API together give you the line and its climb profile.