WebGL GLSL Shader Studio& Playground
A WebGL shader background is a fragment program that paints each frame from color and motion controls. This page previews presets and exports HTML, React, CSS, or Three.js.
In-browser execution: The shader compiles in this tab. The source and canvas frames are not uploaded.
Designer Controls & Color Palette
Uniform Parameters
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebGL Shader Output</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { width: 100vw; height: 100vh; display: block; }
</style>
</head>
<body>
<canvas id="glcanvas"></canvas>
<script>
const canvas = document.getElementById('glcanvas');
const gl = canvas.getContext('webgl');
const vs = `attribute vec2 p; void main() { gl_Position = vec4(p, 0.0, 1.0); }`;
const fs = `
precision highp float;
uniform vec2 iResolution;
uniform float iTime;
uniform vec4 iMouse;
uniform float uSpeed;
uniform float uZoom;
uniform vec3 uColor1;
uniform vec3 uColor2;
uniform vec3 uColor3;
uniform float uIntensity;
// Fluid Liquid Chrome — Glass & Chrome
// Uses uColor1, uColor2, uColor3 color pickers
float fcHash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
float fcNoise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(fcHash(i + vec2(0.0, 0.0)), fcHash(i + vec2(1.0, 0.0)), u.x),
mix(fcHash(i + vec2(0.0, 1.0)), fcHash(i + vec2(1.0, 1.0)), u.x), u.y);
}
float fcFbm(vec2 p) {
float v = 0.0;
float a = 0.5;
mat2 rot = mat2(0.8, 0.6, -0.6, 0.8);
for (int i = 0; i < 4; i++) {
v += a * fcNoise(p);
p = rot * p * 2.0;
a *= 0.5;
}
return v;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
float t = iTime * 0.4 * uSpeed;
vec2 p = uv * 2.5 * uZoom;
if (iMouse.z > 0.0) {
vec2 m = (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y;
p += (uv - m) * 0.4 / (length(uv - m) + 0.1);
}
float n1 = fcFbm(p + vec2(t * 0.3, t * 0.2));
float n2 = fcFbm(p + vec2(n1 * 3.0, t * 0.4));
float n3 = fcFbm(p + vec2(n2 * 2.5, n1 * 2.0 - t * 0.3));
// Calculate normal vector for metallic lighting
vec2 eps = vec2(0.01, 0.0);
float h = n3;
float hx = fcFbm(p + eps.xy + vec2(n2 * 2.5, n1 * 2.0 - t * 0.3));
float hy = fcFbm(p + eps.yx + vec2(n2 * 2.5, n1 * 2.0 - t * 0.3));
vec3 norm = normalize(vec3((hx - h) / eps.x, (hy - h) / eps.x, 0.8));
vec3 lightDir = normalize(vec3(0.5, 0.8, 1.0));
float diff = max(dot(norm, lightDir), 0.0);
float spec = pow(max(dot(reflect(-lightDir, norm), vec3(0.0, 0.0, 1.0)), 0.0), 32.0);
// Iridescent chrome gradient
vec3 chromeGrad = mix(uColor1, uColor2, sin(n3 * 6.28 + t) * 0.5 + 0.5);
chromeGrad = mix(chromeGrad, uColor3, cos(norm.x * 3.0 + norm.y * 3.0) * 0.5 + 0.5);
vec3 col = chromeGrad * (diff * 0.6 + 0.4) + vec3(1.0) * spec * 0.8;
col *= uIntensity;
fragColor = vec4(col, 1.0);
}
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}`;
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}
const program = gl.createProgram();
gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vs));
gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fs));
gl.linkProgram(program);
gl.useProgram(program);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, -1,1, 1,-1, 1,1]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'p');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
// Set color uniforms
gl.uniform1f(gl.getUniformLocation(program, 'uSpeed'), 1.0);
gl.uniform1f(gl.getUniformLocation(program, 'uZoom'), 1.0);
gl.uniform3f(gl.getUniformLocation(program, 'uColor1'), 0.388, 0.400, 0.945);
gl.uniform3f(gl.getUniformLocation(program, 'uColor2'), 0.925, 0.282, 0.600);
gl.uniform3f(gl.getUniformLocation(program, 'uColor3'), 0.024, 0.714, 0.831);
gl.uniform1f(gl.getUniformLocation(program, 'uIntensity'), 1.0);
function render(now) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
gl.uniform2f(gl.getUniformLocation(program, 'iResolution'), canvas.width, canvas.height);
gl.uniform1f(gl.getUniformLocation(program, 'iTime'), now * 0.001);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
</script>
</body>
</html>About WebGL Shader Studio — Animated Backgrounds for Web Designers
A WebGL shader background is a fragment program that paints each frame from a few color and motion controls. This page previews presets and exports HTML, React, CSS, or Three.js.
How to Use
- 1The gallery lists 30 presets. Categories include Hero Backgrounds, Gradients & Blobs, Geometric Patterns, Ambient & Texture, Dark Mode FX, Glass & Chrome, and others.
- 2uColor1, uColor2, and uColor3 are uniforms. A preset uses them only when its source reads those names.
- 3Speed, zoom, and intensity set uSpeed, uZoom, and uIntensity.
- 4The editor compiles the fragment shader and shows the GLSL error log, with the line adjusted for the preamble.
- 5Export tabs are Vanilla HTML, React TSX, Three.js, CSS Fallback, Web Component, and raw GLSL. PNG snapshot saves the current canvas.
Key Benefits
- Three color uniforms are declared on every compile.
- The gallery has 30 presets. Seven GLSL snippets are separate from that list.
- Export tabs are Vanilla HTML, React TSX, Three.js ShaderMaterial, a CSS gradient, a web component, and raw GLSL.
- The page does not measure a frame rate.
- The shader runs in the page. The source is not uploaded.
Frequently Asked Questions (FAQ)
Frequently Asked Questions
Select a preset, customize the colors using the 3 color pickers, adjust speed and intensity, then click the Export tab. Choose 'Vanilla HTML' for a standalone page, 'React TSX' for React apps, 'Web Component' for a drop-in <shader-bg> element, or 'CSS Fallback' for a static gradient approximation.
Three color uniforms are declared. A preset uses them only when its source reads uColor1, uColor2, or uColor3. The exported snippet includes the chosen hex values.
The preview prepends iResolution, iTime, iTimeDelta, iFrame, iMouse, and iDate. iDate is a vec3 of year, month, and day, not Shadertoy's vec4. iChannel0 is a generated texture. iChannel1 is declared and not bound. A mainImage function gets a main() wrapper. Multipass buffers and iChannelResolution are not provided.
The export tab copies Vanilla HTML, React TSX, a Three.js ShaderMaterial, a CSS gradient, a web component, or raw GLSL. A separate button saves the current canvas as a PNG.
The CSS fallback is a gradient that uses the shader palette. It can stand in for browsers without WebGL, or for a page that should not run JavaScript.
A custom preset can be stored in the browser's local storage, or copied as a link that contains the encoded shader.
The shader runs in the browser's WebGL context. The graphics and code are not uploaded.