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,vec3andvec4; blend withmix; usefractfor the fractional part. mod(a, b)is always positive for positiveb, unlike HLSL'sfmod.- Matrix multiplication is
M * vwith the matrix on the left. - Shadertoy provides
iTimeandiResolution; both work in the editor.
Cheat sheet
| Idea | Write |
|---|---|
| Vectors | vec2 vec3 vec4 |
| Declare a value | float d = length(p); |
| A function | float circle(vec2 p, float r) { ... } |
| Matrices | mat2 mat3, multiply with M * v (this site writes v * M for lesson rotations) |
| Blend | mix(a, b, t) |
| Fractional part | fract(x) |
| Clamp to 0..1 | clamp(x, 0.0, 1.0) |
| Remainder | mod(a, b) (always positive for positive b) |
| Choose | c ? a : b |
| Angle of a vector | atan(y, x) |
| Time in seconds | time, or Shadertoy's iTime |
| Pixel position | uv, or fragCoord in mainImage |
| Width / height | aspect, or iResolution.x / iResolution.y |
| Entry point | vec4 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