Add a Color Relief Layer
Color relief (also called hypsometric tinting) paints the map with colors based on elevation — lowlands are green, mid-elevations are brown, mountain peaks are white. This makes elevation immediately visible at a glance.
No three.js or external libraries needed. This uses a standard raster layer with a color expression.
How Color Relief Works
Color relief paints the terrain surface with colors that represent altitude:
🌊 Water / low → Deep blue / dark green
🌿 Plains → Light green
🌄 Hills → Yellow / brown
⛰️ Mountains → Dark brown / grey
🏔️ Peaks → White / light greyThe simplest approach is to use a hillshade layer with carefully chosen shadow/highlight colors, combined with a semi-transparent base map.
Adding Color Relief with Hillshade
javascript
map.addSource('dem', {
type: 'raster-dem',
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
tileSize: 256,
encoding: 'terrarium',
maxzoom: 15,
});
map.addLayer({
id: 'color-relief',
type: 'hillshade',
source: 'dem',
paint: {
'hillshade-shadow-color': '#2d6a4f', // low elevation → green
'hillshade-highlight-color': '#f8f9fa', // high elevation → white
'hillshade-accent-color': '#8B4513', // steep slopes → brown
'hillshade-exaggeration': 0.8,
'hillshade-illumination-anchor': 'viewport',
},
});Make the Base Map Semi-Transparent
To blend color relief with the base map:
javascript
// Reduce base map opacity so relief colors show through
map.setPaintProperty('osm', 'raster-opacity', 0.4);
// Full opacity to hide relief
map.setPaintProperty('osm', 'raster-opacity', 1);Complete Example
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
<script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
<style>body { margin: 0; } #map { height: 100vh; width: 100%; }</style>
</head>
<body>
<div id="map"></div>
<script>
const map = new mapmetricsgl.Map({
container: 'map',
zoom: 5,
center: [13, 47],
style: {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
maxzoom: 19,
},
dem: {
type: 'raster-dem',
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
tileSize: 256,
encoding: 'terrarium',
maxzoom: 15,
},
},
layers: [
{ id: 'osm', type: 'raster', source: 'osm', paint: { 'raster-opacity': 0.4 } },
{
id: 'color-relief',
type: 'hillshade',
source: 'dem',
paint: {
'hillshade-shadow-color': '#2d6a4f',
'hillshade-highlight-color': '#f8f9fa',
'hillshade-accent-color': '#8B4513',
'hillshade-exaggeration': 0.8,
'hillshade-illumination-anchor': 'viewport',
},
},
],
},
});
map.addControl(new mapmetricsgl.NavigationControl(), 'top-right');
</script>
</body>
</html>jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';
const ColorReliefLayer = () => {
const mapContainer = useRef(null);
const map = useRef(null);
useEffect(() => {
if (map.current) return;
map.current = new mapmetricsgl.Map({
container: mapContainer.current,
zoom: 5,
center: [13, 47],
style: {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
attribution: '© OpenStreetMap Contributors',
maxzoom: 19,
},
dem: {
type: 'raster-dem',
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
tileSize: 256,
encoding: 'terrarium',
maxzoom: 15,
},
},
layers: [
{ id: 'osm', type: 'raster', source: 'osm', paint: { 'raster-opacity': 0.4 } },
{
id: 'color-relief',
type: 'hillshade',
source: 'dem',
paint: {
'hillshade-shadow-color': '#2d6a4f',
'hillshade-highlight-color': '#f8f9fa',
'hillshade-accent-color': '#8B4513',
'hillshade-exaggeration': 0.8,
'hillshade-illumination-anchor': 'viewport',
},
},
],
},
});
map.current.addControl(new mapmetricsgl.NavigationControl(), 'top-right');
return () => { map.current?.remove(); map.current = null; };
}, []);
return <div ref={mapContainer} style={{ height: '100vh', width: '100%' }} />;
};
export default ColorReliefLayer;For more information, visit the MapMetrics GitHub repository.