Chris Collins

Tools · graphics

Shader playground

Write GLSL fragment shaders and watch them run as you type — WebGL2 with a WebGL1 fallback, compile errors on their lines, Shadertoy's iTime/iResolution/iMouse/iFrame, sliders and colour pickers for your own uniforms, pause, step and scrub, PNG and WebM export, .frag export for Shadertoy, glslViewer and other hosts, share links, and nine examples with lessons from UV gradients to raymarching and a Boing ball.

Added · updated 27 October 2026

How to use it

A fragment shader is a small program that runs once for every pixel, all at the same time, on the graphics card. This page compiles the one in the editor every time you stop typing and runs it every frame on the canvas. If it doesn’t compile, the errors are marked on their lines and the last version that worked keeps running.

It speaks Shadertoy’s dialect: write void mainImage(out vec4 fragColor, in vec2 fragCoord) and use iResolution, iTime, iTimeDelta, iFrame, iMouse and iDate, and most single-pass Shadertoy shaders that don’t read textures paste straight in.

How to use it

Examples load with one click, each with a lesson beside the canvas: UV coordinates and gradients, shapes with signed distance functions, smoothstep and antialiasing, polar coordinates, value noise and fbm with domain warping, domain repetition, raymarching a sphere with soft shadows, the demo-scene plasma, and a checkered Boing ball bouncing over a purple grid. The Lessons tab has all the explanations in one place. I wrote all of them for this page.

Your own uniforms become controls. Declare a uniform with a comment and it gets a control under the canvas:

uniform float uSpeed;   // 0..5 = 1.5       a slider from 0 to 5, starting at 1.5
uniform int   uCount;   // 1..12 = 6        whole numbers only
uniform vec3  uTint;    // color = #ff8800  a colour picker
uniform vec2  uCentre;  // -1..1 = 0.2, 0   one slider per component
uniform bool  uGrid;    // = true           a checkbox
uniform float uAngle;   // min 0 max 2pi step 0.01 default 1

Time. Pause and play (or Space on the canvas), step one frame, go back to 0, or drag the time slider to scrub; the speed menu runs time from a quarter to four times as fast. Drag on the canvas to set iMouse: xy while the button is down, zw where it went down, negative after you let go, as on Shadertoy.

Output. Save PNG saves the frame at the canvas’s full resolution. Record captures a few seconds of the canvas as a WebM video (MP4 in Safari). ⛶ Full screen gives the canvas the whole screen, with the editor hidden behind ◫ Panels. The resolution menu renders at half or a quarter of the canvas’s pixels when a shader is too slow.

Share link (at the top) puts the shader’s source and your slider settings into the link, so the person who opens it sees the same thing.

Taking a shader to Shadertoy and other tools

Copy for Shadertoy puts a version on the clipboard that you can paste over everything in the Image tab at shadertoy.com/new and run. Download ▾ saves the same thing as a file, or one of the other forms:

Shadertoy .frag

Just mainImage() and the functions it calls: no #version, no precision line, no declarations of iTime, iResolution and the rest, because Shadertoy adds those itself. The Shader Toy extension for VS Code opens the same file.

Standalone GLSL ES 3.00 .frag

#version 300 es, the six uniforms declared, and a main() that calls mainImage(). For three.js, your own WebGL code, or anything else that takes a fragment shader and can set iTime and iResolution.

glslViewer .frag

For glslViewer (glslViewer shader.frag): it declares glslViewer’s u_time, u_resolution, u_mouse, u_delta, u_date and u_frame and #define`s the Shadertoy names to them. glslViewer has no mouse-button state, so `iMouse.zw stays 0.

Playground source (.glsl)

Exactly what is in the editor.

Shadertoy has no sliders, so in the exported files each slider uniform becomes a constant set to where the slider is now, with its comment kept:

uniform float uSpeed;   // 0..5 = 1.5        in the playground, slider at 3.2
const float uSpeed = 3.2;   // 0..5 = 1.5    in the exported file

A shader written with its own void main() is converted to mainImage(): gl_FragColor (or its single out vec4) becomes fragColor and gl_FragCoord.xy becomes fragCoord. Uniforms named the glslViewer / Book of Shaders way (u_time, u_resolution, u_mouse) or the GLSL Sandbox way (time, resolution, mouse) are #define`d to the Shadertoy ones. When a conversion would change what the shader does — it writes `gl_FragData, reads a varying, has more than one output, or writes the output from another function — nothing is downloaded and the page says why. Every file is compiled in your browser before it is saved (the Shadertoy one inside a copy of Shadertoy’s own wrapper), so a file that would not compile is not saved either.

The header comment names the shader, links back to it (to the example, or a share link if the shader is short enough to fit in one), and says the licence: my examples are MIT, so use them as you like; for your own shader it’s your choice — Shadertoy assumes CC BY-NC-SA 3.0 unless the code says otherwise.

Open… reads all of these back. A Shadertoy file opens as it is (a #version or precision line is removed, since the playground adds its own); a file saved from here gets its sliders back, set to the values it was saved with; the VS Code extension’s #iUniform lines become sliders and its #iChannel lines are commented out (no textures here); and a Book of Shaders or GLSL Sandbox shader gets the time, resolution and mouse it expects.

A source with its own void main() is compiled as written: GLSL ES 1.00 (with gl_FragColor) works everywhere; #version 300 es needs WebGL2. The playground fills in the uniforms it knows about if you declare them.

Browser support

Every current browser has WebGL2: Chrome, Edge, Firefox and Safari 15 and later, on desktop and phones. Where only WebGL1 is available, the same shaders are compiled as GLSL ES 1.00 (the examples avoid anything newer). Recording needs MediaRecorder on a canvas stream, which all of them have.

Not supported: textures and iChannel0–3, multi-pass buffers, sound and cube-map shaders. The exported files are compiled with WebGL2 before they are saved; in a browser with only WebGL1 they are saved without that check.

Privacy

Nothing leaves your browser. The shader runs on your own graphics card; the source and slider values are kept in this browser’s storage, and in the link only if you share one. Downloads and Copy for Shadertoy are made in the page; nothing is sent to Shadertoy or anywhere else.

Runs entirely in your browser; nothing you type leaves this page.