Noon Break Mountains is a GLSL WebGL2 shader study that builds a calm midday landscape from layered silhouettes, a soft sun glow, and subtle atmospheric haze. This page is for anyone who wants to view the loop, download the renders, and learn from a readable, self-contained fragment shader.
Preview
Downloads
- Raw GIF (original loop)
- Video (MP4) (smaller, smoother playback)
- Video (OGV) (alternate format)
- Preview (PNG) (still frame)
Source code (GLSL ES 3.00)
This is a clean reconstruction of the original idea: a midday sky gradient, a bright sun with a gentle halo, and multiple mountain layers blended front-to-back. It is intended to be easy to tweak (palette, layer spacing, and motion) while keeping the same overall “noon break” mood.
#version 300 es
precision highp float;
in vec2 UV;
uniform float time;
uniform float ratio;
out vec4 out_color;
float hash21(vec2 p){
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 34.345);
return fract(p.x * p.y);
}
float noise(vec2 p){
vec2 i = floor(p);
vec2 f = fract(p);
float a = hash21(i);
float b = hash21(i + vec2(1.0, 0.0));
float c = hash21(i + vec2(0.0, 1.0));
float d = hash21(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
float fbm(vec2 p){
float v = 0.0;
float a = 0.5;
for(int i = 0; i < 5; i++){
v += a * noise(p);
p *= 2.0;
a *= 0.5;
}
return v;
}
vec4 alpha_over(vec4 top, vec4 bottom){
float a = top.a + bottom.a * (1.0 - top.a);
vec3 c = (top.rgb * top.a + bottom.rgb * bottom.a * (1.0 - top.a)) / max(a, 1e-5);
return vec4(c, a);
}
float mountain_mask(vec2 uv, float seed, float base_h, float scale){
float n = fbm(vec2(uv.x * scale + seed, uv.y * scale * 0.35));
float wav = 0.015 * sin(uv.x * 2.2 + seed + time * 0.15);
float h = base_h + (n - 0.5) * 0.18 + wav;
return smoothstep(h, h - 0.03, uv.y);
}
vec3 sky_colour(vec2 uv){
vec3 nearHorizon = vec3(0.06, 0.12, 0.18);
vec3 zenith = vec3(0.12, 0.20, 0.28);
float t = smoothstep(0.0, 1.0, uv.y);
return mix(nearHorizon, zenith, t);
}
vec3 sun_colour(vec2 uv){
vec2 p = uv - vec2(0.18, 0.78);
p.x *= ratio;
float d = length(p);
float core = smoothstep(0.11, 0.0, d);
float halo = smoothstep(0.55, 0.0, d);
vec3 warm = vec3(1.00, 0.86, 0.58);
return warm * core + warm * halo * 0.20;
}
void main(){
// Normalised UV for aspect-correct shapes
vec2 uv = UV;
vec2 p = uv - 0.5;
p.x *= ratio;
vec3 col = sky_colour(uv);
// Sun glow
col += sun_colour(uv);
// Light atmospheric haze near horizon
float haze = smoothstep(0.05, 0.55, uv.y) * 0.12;
col = mix(col, vec3(0.16, 0.22, 0.28), haze);
// Layered mountains (back to front)
vec4 acc = vec4(col, 1.0);
vec4 back = vec4(vec3(0.10, 0.18, 0.24), mountain_mask(uv, 10.0, 0.52, 2.2));
vec4 mid = vec4(vec3(0.07, 0.14, 0.19), mountain_mask(uv, 20.0, 0.44, 2.8));
vec4 front= vec4(vec3(0.04, 0.09, 0.12), mountain_mask(uv, 30.0, 0.36, 3.6));
acc = alpha_over(back, acc);
acc = alpha_over(mid, acc);
acc = alpha_over(front, acc);
// A tiny bit of grain to keep gradients looking “gif-friendly”
float g = (hash21(UV * vec2(900.0, 600.0) + time) - 0.5) * 0.015;
acc.rgb += g;
out_color = vec4(clamp(acc.rgb, 0.0, 1.0), 1.0);
}
What to tweak
- Palette: change the three mountain RGB values and the sky gradient in
sky_colour(). - Layer spacing: adjust
base_hin the threemountain_mask()calls. - Motion: increase or remove the
wavterm for a calmer or more animated horizon. - Compression friendliness: reduce haze and gradients if you want smaller GIF sizes.
Explore next
- GLSL examples library – ready-to-run shaders you can remix.
- Pick a language in the editor – GLSL, JavaScript, or p5.js.
- How ShaderGif works – why previews are used and how to keep GIFs small.
- Browse the latest GIFs – discover more shader loops from the gallery.
Last updated: 28 December 2025
