July 13, 2026 · 5 min read
Shaders, live: GLSL in the browser (and HLSL alongside)
A mockup post for the live shader system — a running WebGL demo, its GLSL source, and an HLSL snippet shown side-by-side.
Note to self: mockup post to test the
{% shader %}embed andglsl/hlslhighlighting. Safe to delete before launch.
Half of technical-art writing is "here's the code, here's what it does." A static screenshot loses the motion; a wall of code loses the intuition. So on this site a shader can run right in the page, with its source shown directly beneath it.
A live one — edit it yourself
The code below the canvas is the shader driving it, and it's editable: change a number,
tweak the colours, and the canvas recompiles as you type. Try bumping the 0.4 in the ramp
or swapping the green/amber values. Broke it? The last working version keeps running and
the compile error shows over the canvas; hit revert to restore the original.
The embed follows the Shadertoy convention, so anything you prototype there drops
straight in: write mainImage(out vec4, in vec2) and you get iResolution, iTime, and
iMouse for free.
It reads the pointer, too
iMouse.xy is the cursor in pixels — hover the canvas below and the glow follows you.
void mainImage(out vec4 O, in vec2 I)
{
vec2 uv = I / iResolution.xy;
vec2 m = iMouse.xy / iResolution.xy;
// Fall off from the cursor; drift to centre before it's ever touched.
if (iMouse.xy == vec2(0.0)) m = vec2(0.5);
float d = distance(uv, m);
float glow = smoothstep(0.45, 0.0, d);
vec3 col = mix(vec3(0.11, 0.12, 0.10), vec3(0.47, 0.68, 0.51), glow);
O = vec4(col, 1.0);
}The HLSL side
WebGL only speaks GLSL, so HLSL can't run here — but it still gets first-class highlighting, which is what you want when the source of truth is an Unreal Custom node or a Unity surface function. Here's a rim-light term I reach for constantly:
// Unreal "Custom" node — Fresnel rim term.
// In: N (float3 world normal), V (float3 view dir), power, scale, tint
// Out: float3 additive rim colour
float3 RimLight(float3 N, float3 V, float power, float scale, float3 tint)
{
float fresnel = pow(saturate(1.0 - dot(normalize(N), normalize(V))), power);
return tint * (fresnel * scale);
}
When a preview actually helps, I port the effect to a GLSL mainImage and drop it in a
live canvas next to the HLSL — same maths, running proof. The HLSL stays the reference; the
GLSL is the demo.
That's the whole system: GLSL runs, HLSL is shown, and the source is never a screenshot.