Custom GPU passes

addPass runs your own full-screen fragment shader inside the map effects plugin’s GPU chain. Every effect drawn over the chain (bloom, grade, fog, edge blur, tint, vignette) then works on your picture. Use it for a stylisation, such as a watercolour, a posterise or a colour lookup. The demo below paints the map in watercolour, then lets bloom, a contrast grade and a vignette work on the painting:

Your own GPU passes

effects.addPass({
id: 'posterise',
fragment: `uniform float uLevels;
void main() {
vec4 colour = texture(uSource, vUv);
fragColor = vec4(floor(colour.rgb * uLevels) / uLevels, colour.a);
}`,
uniforms: { uLevels: 5 },
});
effects.removePass('posterise');
  • The shader is GLSL ES 3.00 without its preamble. The plugin declares the version, the precisions, uSource (the picture so far), vUv and fragColor. Declaring any of them again is a compile error. You declare your uniforms and main.
  • addPass throws on a missing id. It also throws, with the compiler’s log, on a shader that does not compile. It throws RangeError on an unknown placement. A browser without WebGL2 runs no pass, and the plugin warns once.
  • uniforms takes float and vec2 values by name, or a function that returns them, which the plugin calls on every draw. You can’t set an int or bool uniform, so declare numbers as float. A function that throws skips its pass for that draw, with one warning.
  • placement is before-depth-of-field (the default) or after-depth-of-field. Put a stylisation that the lens should blur before it, and one that should stay crisp after it.
  • Passes run in the order you add them. Adding under an id in use replaces that pass in place. removePass ignores an id with no pass.
  • Redraws follow the map, so for a pass that animates on its own, request frames with map.mapLibreMap.triggerRepaint().
  • capture() runs your passes too, at the capture’s resolution. getConfig() does not list them, since passes are code rather than settings.
  • A pass that shifts hues runs before bloom’s colour key, so a bloom.only scope may need a wider bloom.onlyTolerance.
  • The map needs preserveDrawingBuffer: true, since the chain reads the map canvas back.

Effects on top of everything

An effect that belongs on top of everything, such as film grain, scanlines or a watermark, needs no pass. Lay your own element over the map, above the effects container.

  • Mixed map effects - A watercolour pass of your own, with bloom, grade and vignette over it