What it does
The effect packs (backdrops, post passes, sprite and mesh shaders, deformers) describe each effect as a WGSL snippet
spliced into a fixed template. WebGPU runs it as written. On a device without WebGPU, wgslSnippetToGLSL turns the
snippet body into GLSL ES 3.0, checked against every name the template declares and its type, so content that exists
only as WGSL still draws.
It parses the whole expression grammar into a tree and works out the type of every part, because two differences
between the languages break shaders without any error. In WGSL an integer literal becomes a float where it meets one,
so uv * 2 is legal there and an error in GLSL; the translator writes 2.0 in those places and an int elsewhere.
And WGSL's float % keeps the sign of the dividend, unlike GLSL's mod, so it becomes a - b * trunc(a / b).
The snippet contract is straight-line maths over scalars, vectors and small square matrices, let and var, if,
for and while, and the helper set. Anything outside it throws an Error that names the construct, and the caller
reports it once and skips that layer, because GLSL that names an undeclared identifier compiles to a silent black
pass.
Features
- WGSL snippets to GLSL ES 3.0 — one call,
wgslSnippetToGLSL(code, scope, helpers?). - Checked against the template —
scopelists every declared name with its GLSL type, struct members included, and anything else throws. - Typed literals — integer literals become floats where WGSL would make them so, default to
intotherwise, and hex literals are always integers. - Correct remainders — float
%keeps the dividend's sign, as in WGSL. - Shared helpers —
hash21,noise2,fbm2,bgAtandtex, plus a template's own functions throughhelpers. - Loud failures — an error naming the construct, never guessed GLSL.
- Pure string work — no DOM and no GL context, so it runs anywhere, headless included.
Good for
- Games on the WebGL2 fallback — custom backdrops, post effects and shaders still appear on devices without WebGPU, through the packs that use it.
- Effect authors — write a snippet once in WGSL and get the WebGL2 path from it.
- Template authors — declare a template's names and helpers once, and check every snippet against them.
Make it yours
There are no options; what you control is the call. You pass the snippet, the scope of names your template
declares with their GLSL types (scalars, vectors, small square matrices such as 'mat3', or { members: { … } } for
a struct), and any helpers your template adds beside the shared set, which the template must declare in both
dialects. Two different uses: a backdrop template that declares uv and color and turns a short noise snippet into
a full-screen GLSL pass; and a template with a helper of its own, such as noise3, declared with its argument and
return types so snippets can call it.
A quick look
A snippet translated and spliced into a GLSL template:
const body = wgslSnippetToGLSL('let p = uv * 2; color = vec4(vec3(noise2(p)), 1);', { uv: 'vec2', color: 'vec4' });
const glsl = `${head} void main() { vec4 color; ${body} out_color = color; }`; // head: your template's declarations
Works with
render-webgl2— the WebGL2 backend, which translates custom snippets through it.backdrops,post,sprite-shaders,mesh-shadersandtrippatron— the effect packs that use it.render-auto— picks WebGL2, and so this path, when WebGPU is missing.
Good to know
- It is not a general WGSL compiler:
fn,switch,loop, structs, arrays, pointers, texture calls and undeclared names throw. - A snippet that works on WebGPU but uses one of those does not draw on WebGL2.
- Game code does not need it; the effect packs and the WebGL2 renderer call it.





