Context & invocation
The context is what every pixel knows about its surroundings: its coordinate (uv, 0–1
across the canvas with y down), the clock (time, in seconds), the canvas shape (aspect,
viewportSize) and the mouse (pointer). ctx names these as tokens you can pass to a word
or bind in a wgsl body's inputs.
The rest of this page is for a hand-written builder: a paint: or effect: given as a
function of the params instead of a composition or a wgsl body. Inside one, paintFrame
gives the coordinate and frame size to draw in, uniformOf reads a prop as a GPU value,
resolveScalar and resolveArg turn anything a word accepts (a prop ref, a Scalar, a
context token, a number) into a GPU value, and pointwiseOp wraps a compiled GPU function
as a new color word. Combine the results with the math words and return a vec4 color.
import {ctx, uv, time, …} from 'shaders/std'
Reach for it when
| When you need | Use |
|---|---|
| the mouse, the clock or the canvas size as an input to a word | ctx |
| the coordinate to draw at in a hand-written paint | paintFrame |
| a prop's value inside a hand-written builder | uniformOf |
a Scalar (a mask times a prop) inside a builder | resolveScalar |
| any value a word accepts, inside a filter builder | resolveArg |
| the same inside a warp's map factory | resolveArgIn |
| a new color word from a compiled GPU function | pointwiseOp |
Example
import {defineShader, p, paintFrame, uniformOf, animatedTime, math, transformColor, transformPosition} from 'shaders/std'
const {sub, mul, add, vec2, vec4, length, smoothstep, mix, sin} = math
// A spotlight: a soft disc around a draggable point that breathes on the layer's own clock.
export const Spotlight = defineShader({
name: 'Spotlight',
animatedTime: {speed: 'speed'},
props: {
colorA: {default: '#0b1026', transform: transformColor},
colorB: {default: '#ffd27a', transform: transformColor},
center: {default: {x: 0.5, y: 0.5}, transform: transformPosition},
radius: {default: 0.4},
speed: {default: 1},
},
paint: (params) => {
const {uv} = paintFrame(params)
const center = uniformOf(p('center'), params)
const colorA = uniformOf(p('colorA'), params)
const colorB = uniformOf(p('colorB'), params)
// A position prop's y is stored flipped; undo it to compare with uv.
const toCenter = sub(uv, vec2(center.member('x'), sub(1, center.member('y'))))
const d = length(mul(toCenter, vec2(params.ctx.aspect, 1)))
const breath = add(1, mul(0.1, sin(animatedTime(params))))
const t = sub(1, smoothstep(0, mul(uniformOf(p('radius'), params), breath), d))
return vec4(mix(colorA.member('rgb'), colorB.member('rgb'), t), 1)
},
})
Types
| Type | What it is |
|---|---|
ArgSpec | Anything a word accepts as an input value: a prop ref p('x'), a Scalar, a context token, or a plain number. |
CtxToken | One of the context values as a token you can pass where a word takes a value: ctx.uv, ctx.time, … |
SlotParams | The least a value needs to resolve against: the props, plus ctx where the host has one (a warp's map: does not). |
Words
- ctxThe context values as tokens:
ctx.uv,ctx.time,ctx.aspect,ctx.pointer,ctx.viewportSize,ctx.logicalViewportSize. - ctx.uvThe pixel's coordinate: 0–1 across the canvas, y down.
- ctx.timeThe global clock in seconds.
- ctx.aspectThe canvas's width divided by its height.
- ctx.pointerThe mouse position in uv (0–1, y down).
- ctx.viewportSizeThe frame size in device pixels, as a
vec2f. - ctx.logicalViewportSizeThe frame size in CSS pixels, as a
vec2f, for feature counts that should not change with screen density. - paintFrameThe coordinate and frame size a hand-written
paint:builder should draw in. - uniformOfThe live GPU value of a prop, for a hand-written builder:
uniformOf(p('radius'), params). - resolveScalarA
Scalaror prop ref as a GPU value, for a hand-written builder. - resolveArgAny input value a word accepts (a prop ref, a
Scalar, a context token, a number) as a GPU value inside a filter's builder. - resolveArgIn
resolveArgfor any host, including a warp'smap:factory. - pointwiseOpWrap a compiled GPU function as a pointwise filter effect: the child's color goes in first, then
args.