Last active
August 26, 2026 23:30
-
-
Save patte/7480ff313bf95267b81cb6ad7da0af85 to your computer and use it in GitHub Desktop.
maplibre-gl 6.6.0: stale terrain drape textures after a zoom animation — press ① then ②
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>maplibre-gl: stale terrain drape textures after a zoom animation</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <link href="https://unpkg.com/maplibre-gl@6.6.0/dist/maplibre-gl.css" rel="stylesheet"> | |
| <style> | |
| html, body { margin: 0; height: 100%; } | |
| #map { position: absolute; inset: 0; } | |
| #panel { | |
| position: absolute; top: 10px; left: 10px; z-index: 1; | |
| background: rgba(20, 20, 24, 0.94); color: #eee; padding: 16px; | |
| font: 16px/1.5 system-ui, sans-serif; border-radius: 10px; max-width: 400px; | |
| } | |
| #panel b { font-size: 18px; } | |
| #panel button { | |
| display: block; width: 100%; margin: 8px 0; padding: 12px; | |
| font: inherit; cursor: pointer; border-radius: 8px; | |
| background: #3a6df0; color: #fff; border: none; | |
| } | |
| #panel button:hover:enabled { background: #4c7cff; } | |
| #panel button:disabled { | |
| background: #2a2a30; color: #9a9aa4; border: 1px solid #44444c; cursor: default; | |
| } | |
| #status { color: #fc6; min-height: 4.5em; } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="map"></div> | |
| <div id="panel"> | |
| <b>Stale drape textures after a zoom animation</b> | |
| <p>The rings are draped over the terrain and styled by zoom: <b style="color:#e8a33d">amber</b> below z16.5, <b style="color:#e8452e">red</b> above. The map rests at z16.05, so rings must be amber.</p> | |
| <button id="ease" disabled>① animate: ease to z17.5 and back</button> | |
| <button id="rebake" disabled>② force re-bake — must change nothing</button> | |
| <div id="status">loading…</div> | |
| </div> | |
| <script type="module"> | |
| import * as maplibregl from 'https://unpkg.com/maplibre-gl@6.6.0/dist/maplibre-gl.mjs'; | |
| const status = (t) => { document.getElementById('status').textContent = t; }; | |
| const map = new maplibregl.Map({ | |
| container: 'map', | |
| center: [10.190674, 45.93998], | |
| zoom: 16.05, | |
| style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', | |
| fadeDuration: 0, | |
| }); | |
| window.map = map; | |
| // concentric rings: the staleness shows in the bends, so give the texture bends in | |
| // every direction; the zoom-interpolated width adds a second visible mismatch | |
| const CLAT = 45.93998, CLNG = 10.190674; | |
| const lines = []; | |
| for (let r = 60; r <= 1500; r += 90) { | |
| const ring = []; | |
| for (let a = 0; a <= 96; a++) { | |
| const t = (a / 96) * 2 * Math.PI; | |
| ring.push([ | |
| CLNG + (r * Math.sin(t)) / (111320 * Math.cos((CLAT * Math.PI) / 180)), | |
| CLAT + (r * Math.cos(t)) / 111320, | |
| ]); | |
| } | |
| lines.push(ring); | |
| } | |
| map.on('load', () => { | |
| map.addSource('dem', { | |
| type: 'raster-dem', encoding: 'terrarium', | |
| tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'], | |
| maxzoom: 12, tileSize: 256, | |
| }); | |
| map.setTerrain({source: 'dem'}); | |
| map.addSource('grid', {type: 'geojson', data: { | |
| type: 'Feature', | |
| geometry: {type: 'MultiLineString', coordinates: lines}, | |
| properties: {}, | |
| }}); | |
| map.addLayer({ | |
| id: 'grid', type: 'line', source: 'grid', | |
| paint: { | |
| // zoom-stepped color: any ring drawn red while the map rests below z16.5 is a | |
| // texture that was baked at a zoom the map is no longer at | |
| 'line-color': ['step', ['zoom'], '#e8a33d', 16.5, '#e8452e'], | |
| 'line-width': ['interpolate', ['exponential', 2], ['zoom'], 15, 1.5, 18, 10], | |
| }, | |
| }); | |
| map.once('idle', () => { | |
| document.getElementById('ease').disabled = false; | |
| status('ready — this is the correct rendering for z16.5'); | |
| }); | |
| }); | |
| document.getElementById('ease').addEventListener('click', () => { | |
| status('animating…'); | |
| map.easeTo({zoom: 17.5, duration: 1200}); | |
| map.once('moveend', () => setTimeout(() => { | |
| map.easeTo({zoom: 16.05, duration: 1200}); | |
| map.once('moveend', () => map.once('idle', () => { | |
| document.getElementById('rebake').disabled = false; | |
| status('settled back at z16.05 — every ring must be amber and thin again. Any red, fat ring ' + | |
| 'is a stale texture, baked mid-animation above z16.5. Now press ②.'); | |
| })); | |
| }, 400)); | |
| }); | |
| document.getElementById('rebake').addEventListener('click', () => { | |
| // a layout-property change reloads the grid source, which invalidates the cached | |
| // drape textures — the camera is untouched, so a correct renderer changes nothing | |
| map.setLayoutProperty('grid', 'visibility', 'none'); | |
| map.setLayoutProperty('grid', 'visibility', 'visible'); | |
| status(''); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment