Learn GLSL for Shadertoy and WebGL

GLSL is the language of OpenGL and WebGL, and the language of Shadertoy, where most shader art lives. Everything you learn here is plain GLSL, and you can write the Shadertoy-style mainImage entry point or the simpler frag(uv); the export gives you a Shadertoy-ready file.

Things to know about GLSL

  • Vectors are vec2, vec3 and vec4; blend with mix; use fract for the fractional part.
  • mod(a, b) is always positive for positive b, unlike HLSL's fmod.
  • Matrix multiplication is M * v with the matrix on the left.
  • Shadertoy provides iTime and iResolution; both work in the editor.

Cheat sheet

IdeaWrite
Vectorsvec2 vec3 vec4
Declare a valuefloat d = length(p);
A functionfloat circle(vec2 p, float r) { ... }
Matricesmat2 mat3, multiply with M * v (this site writes v * M for lesson rotations)
Blendmix(a, b, t)
Fractional partfract(x)
Clamp to 0..1clamp(x, 0.0, 1.0)
Remaindermod(a, b) (always positive for positive b)
Choosec ? a : b
Angle of a vectoratan(y, x)
Time in secondstime, or Shadertoy's iTime
Pixel positionuv, or fragCoord in mainImage
Width / heightaspect, or iResolution.x / iResolution.y
Entry pointvec4 frag(vec2 uv) or void mainImage(out vec4 fragColor, in vec2 fragCoord)

Handy built-ins: sin cos abs sign floor ceil fract step smoothstep clamp min max pow exp sqrt length distance dot cross normalize reflect

Gotchas

  • Every pixel runs on its own, with no memory of other pixels.
  • Declare a function above the place you use it.
  • Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
  • Loops need a small fixed count: for (int i = 0; i < 5; i++).

Example: a glowing ring

The same shader as it is written for Shadertoy / WebGL:

vec4 frag(vec2 uv)
{
    vec2 p = (uv - 0.5) * vec2(aspect, 1.0);
    float d = length(p);
    float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
    vec3 bg = vec3(0.08, 0.08, 0.12);
    vec3 fg = vec3(0.4, 0.9, 1.0);
    return vec4(mix(bg, fg, m), 1.0);
}

Exporting to WebGL / Shadertoy

Paste into the Image tab on shadertoy.com. For your own WebGL app, call frag(gl_FragCoord.xy / resolution) from main().

// ShaderBattle: Glowing ring
#define time iTime
#define aspect (iResolution.x / iResolution.y)

vec4 frag(vec2 uv)
{
    vec2 p = (uv - 0.5) * vec2(aspect, 1.0);
    float d = length(p);
    float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
    vec3 bg = vec3(0.08, 0.08, 0.12);
    vec3 fg = vec3(0.4, 0.9, 1.0);
    return vec4(mix(bg, fg, m), 1.0);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    fragColor = frag(fragCoord / iResolution.xy);
}

Questions

Does this teach Shadertoy shaders?

Yes. The export wraps your function in a mainImage entry point so you can paste it into the Image tab on shadertoy.com.

Which GLSL version is it?

The browser editor runs GLSL ES 3.0 (WebGL 2). Desktop OpenGL and three.js exports are provided in their own versions.

Other languages

Unity (Built-in) · Unity (URP) · Unreal · OpenGL (LWJGL, raylib) · three.js · GameMaker · LÖVE (Lua) · Godot · Apple (iOS, macOS) · WebGPU / Bevy