Skip to Content
ExamplesCustom Earthquake Shader

MapsGL - Custom earthquake symbols using a shader

This example customizes the symbols displayed by the earthquakes layer using a custom fragment shader.

Custom shaders can be used for symbol or circle layer types to create a unique animated visual effect for each symbol based on the feature’s data and properties.

custom-earthquake-shader.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MapsGL SDK - Custom earthquake symbols using a shader</title> <meta name="description" content="Use a custom WebGL fragment shader to apply unique and animated visual effects to earthquake data." /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://api.mapbox.com/mapbox-gl-js/v3.12.0/mapbox-gl.css" rel="stylesheet" /> <script defer src="https://api.mapbox.com/mapbox-gl-js/v3.12.0/mapbox-gl.js"></script> <link href="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.css" rel="stylesheet" /> <script defer src="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.js"></script> <style> body, html { margin: 0; padding: 0; } #map { height: 100vh; width: 100%; } </style> </head> <body> <div id="map"></div> <script> window.addEventListener('load', () => { mapboxgl.accessToken = 'MAPBOX_TOKEN'; const map = new mapboxgl.Map({ container: document.getElementById('map'), style: 'mapbox://styles/mapbox/light-v9', center: [124.091, 26.232], zoom: 2 }); const account = new aerisweather.mapsgl.Account('CLIENT_ID', 'CLIENT_SECRET'); const controller = new aerisweather.mapsgl.MapboxMapController(map, { account }); controller.on('load', () => { controller.addWeatherLayer('earthquakes', { type: 'symbol', source: 'earthquakes', paint: { symbol: { shader: ` // https://www.shadertoy.com/view/ldycR3 #extension GL_OES_standard_derivatives : enable precision mediump float; uniform vec2 resolution; uniform float dpr; uniform float time; varying vec2 vUv; varying vec2 vPosition; varying float vFactor; varying float vRandom; float saturate(float x) { return clamp(x, 0.0, 1.0); } vec3 hsb2rgb(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0); rgb = rgb*rgb*(3.0-2.0*rgb); return c.z * mix( vec3(1.0), rgb, c.y); } void main() { vec2 pos = vUv; float t = time; float dist = length(2.0 * pos - 1.0) * 2.0; vec2 p = vec2(dist); float r = length(p) * 0.9; vec3 color = hsb2rgb(vec3(0.03, 0.7, 0.6)); float a = pow(r, 3.0); float b = sin(r * 1.8 - 1.6); float c = sin(r - 0.010); float s = sin(a - t * 2.0 + b) * c; color *= abs(1.0 / (s * 1.8)) - 0.01; float d = length(2.0 * pos - 1.0); // float delta = fwidth(d); float alpha = 1.0 - d; // alpha *= min(1.0, 0.2 + vFactor); gl_FragColor = vec4(color, alpha); gl_FragColor.rgb *= gl_FragColor.a; } `, animated: true, pitchWithMap: true, // blending: 2, size: (data) => { const mag = Math.max(data.report?.mag || 1); const size = 20 + 100 * (mag / 10); return { width: size, height: size }; } } } }); }); }); </script> </body> </html>
© 2026 Xweather (opens in a new tab)Terms of Service (opens in a new tab)Privacy Policy (opens in a new tab)