A material is a small function you write: the engine runs it for every pixel (and, on a model, for every corner) and hands it what it knows about that place. This page lists all of it. The names are a promise: a shader written against them keeps working in later versions, so none is ever renamed. The engine's tests check that every name on this page exists on both graphics backends.
To see each input at work, every one drawing something you can see, open the Shader inputs example.
The hooks are written in WGSL for WebGPU (fragment, vertex) and in GLSL for WebGL2
(fragmentGlsl, vertexGlsl). Every name is the same in both; only the types are written the GLSL
way (vec4 for vec4<f32>). If you build the material with the shader composer, it writes both
for you.
In every shader: mu
A material's parameters arrive in mu. The engine's come first and always in the same order, then
yours, by the name you gave them: uniforms: { charge: 0 } is read as mu.charge.
| Name | Type | What it is |
|---|---|---|
mu.time | f32 | Game seconds. timeScale speeds it up or slows it down, and a pause stops it. |
mu.resolution | vec2<f32> | The size of what is being drawn into, in pixels. |
mu.progress | f32 | Screen effects only: how far through its half a scene change is, from 0 to 1. |
mu.phase | f32 | Screen effects only: 0 while a scene change covers the screen, 1 while it uncovers it. |
Outside a scene change, progress and phase are both 0. Those four names are taken: a parameter
of your own cannot use them.
A parameter is one of four types: f32, vec2<f32>, vec3<f32> or vec4<f32>. The whole block
holds 64 numbers, the engine's included. A vec3 or a vec4 starts on a multiple of four, so a
single number just before one leaves a small gap. A material that declares more than fits is drawn
with the built-in look, and the console says why.
Sprites, text and map layers
A material with shader: 'sprite2d' (the default) has one hook:
fn effect(color: vec4<f32>, uv: vec2<f32>) -> vec4<f32> {
return color;
}coloris the picture already read and already tinted.return color;draws exactly what the engine would have drawn, so an effect is a change to that.- On the letters of a vector font,
coloris the text's tint, with the letter's edge in its alpha. uvis the place on the sheet. It is not kept inside the sprite's frame: reading elsewhere on the sheet is allowed.sampleTexture(uv)reads the sheet at any place, also inside anifor a loop.
The same material works on a map layer without changing a word.
Models
A material with shader: 'mesh3d' has two hooks. Both are optional: the one you leave out does
what the engine does.
fn vertex(pos: vec3<f32>, ctx: VertContext) -> vec3<f32> {
return pos;
}
fn effect(surface: vec4<f32>, ctx: FragContext) -> vec4<f32> {
return vec4<f32>(surface.rgb * ctx.light + ctx.shine + ctx.emissive, surface.a);
}That effect is the engine's own, word for word: a good place to start from.
vertexmoves a corner, in the model's own space. Writing it costs a little: the surface is measured again after the move, which calls it two more times per corner.vertexcan also hand four numbers toeffect:carry = vec4<f32>(...). They arrive asctx.carry, blended across the triangle. A wave's height for foam on its crests, a light worked out at the corners, orpositself, so stripes stay on the model as it moves.surfaceis the picture times the tint times the colour painted on the corners.- Fog goes over what
effectreturns, andalphaCutoffcuts by its alpha.
What the corner hook is told:
| VertContext | Type | What it is |
|---|---|---|
normal | vec3<f32> | Which way the corner faces, in the model's space. |
uv | vec2<f32> | The picture's place. |
color | vec4<f32> | The colour painted on the corner, white if none. |
tangent, bitangent | vec3<f32> | Which way across and down the picture runs, in the model's space. |
uv2 | vec2<f32> | A second picture coordinate: the file's own, or uv again. |
What the colour hook is told:
| FragContext | Type | What it is |
|---|---|---|
uv | vec2<f32> | The picture's place, already stretched if the material is affine. |
normal | vec3<f32> | Which way the surface faces, in the world. |
worldPos | vec3<f32> | Where the pixel is, in the world. |
light | vec3<f32> | The light that falls here, shadows and ambient included. |
shine | vec3<f32> | The highlight. |
emissive | vec3<f32> | The material's own glow, through its glow picture. |
viewDir | vec3<f32> | From the surface towards the camera. |
color | vec4<f32> | The painted colour on its own. It is already in surface. |
screen | vec2<f32> | Where on the screen, in game pixels, (0, 0) at the top left. |
tangent, bitangent | vec3<f32> | Which way across and down the picture runs, in the world. |
uv2 | vec2<f32> | The second picture coordinate. |
frontFacing | bool | False only on the back of a material with cull: 'front' or 'none'. |
carry | vec4<f32> | What vertex wrote in carry, blended across the triangle. Zero if nothing. |
light and shine are worked out at the corners and blended across the triangle, not worked out
again for every pixel. That is how the consoles of the era lit a model, and it is the look the engine
is after.
Helpers a model's shader can call:
sampleTexture(uv): the model's picture.sampleMap_<name>(uv): one of the material'smaps, by its name (maps: { noise }is read withsampleMap_noise(ctx.uv)). A map the material does not have reads white.envUv(ctx): where a chrome reflection lands on a round picture of the surroundings. Read it withsampleMap_env(envUv(ctx)).
Screen effects
An effect over the whole screen (usePostProcess({ fragment })) has the same hook as a sprite. color is the frame already read at uv.
| Helper | What it reads |
|---|---|
sampleTexture(uv) | The frame, pixel by pixel. |
sampleTextureSmooth(uv) | The frame, blended between pixels: for blurs, bends and smaller passes. |
sampleInput(uv) | The frame the effect was handed. It is only different from sampleTexture in an effect with passes. |
sampleHistory(uv) | What the effect showed last frame: black at first, white if the effect did not ask for it. |
paletteSize(), paletteColor(i) | The palette given to the effect: how many colours, and colour i. |
lutSize(), lutTexel(x, y, slice, size), lutColor(rgb) | The colour table given to it. lutColor grades a colour through it. |
An effect reads one data picture: a palette or a colour table, never both.