# Shaders std vocabulary (engine 4.0.4) Compose shaders from these words with `defineShader` from `shaders/std`. Every word is a plain TypeScript function; the engine lowers the composition to WGSL at runtime. A `wgsl` body is the escape hatch. ## Defining a shader ### defineShader & wgsl (`shaders/std` top level) — https://shaders.com/docs/primitives/define A shader is a plain object: a name, the props a user can set, and one field that says what it draws. Hand it to `defineShader` and it becomes a component you can mount, nest, blend, mask and animate like any shader in the library. - `defineShader(definition: StdDefinition): GpuShaderDefinition` — Define a shader component from a plain object: its props, and one field that says what it draws. - `wgsl(spec: WgslSpec): WgslBody wgsl(body: string): WgslBody wgsl(strings: TemplateStringsArray, ...values: unknown[]): WgslBody` — Write the per-pixel math by hand, as one WGSL function body that returns a `vec4f` color. - `registerShader>(definition: T): T` — Make a user-defined shader findable by its `name`, so preset JSON can reference it as `type: 'Halo'`. - `unregisterShader(name: string): void` — Forget a user-defined shader by name. - `getRegisteredShader(name: string): GpuShaderDefinition | undefined` — Look up a user-defined shader by name. - `getRegisteredShaders(): GpuShaderDefinition[]` — Every user-defined shader currently registered, oldest first. - `onShaderRegistered(listener: (name: string, definition: GpuShaderDefinition | null) => void): () => void` — Be told when a user-defined shader is registered, replaced or removed. - `class WgslBody` — What `wgsl` returns: a body ready to sit in `paint:` or `effect:`. ### Props & values (`shaders/std` top level) — https://shaders.com/docs/primitives/values How a definition points at its own props. `p('radius')` is a **prop ref**: hand it to any word that takes a color, a position or a number and the word reads that prop live on the GPU, with drivers and animation applied, and no rebuild when the value changes. A **Scalar** is a number built from props and masks. `radialMask(…)` returns one, so does `oscillating(…)` from `motion`, and `.times(p('intensity'))` scales one by a prop. Words that take a `ScalarInput` accept either a prop ref or a Scalar. - `p(name: string): PropRef` — Reference one of the definition's props by name, wherever a word asks for a value. - `class Scalar` — A number built from props: what `radialMask(…)`, `motion.oscillating(…)` and `.times()` return. ### Identity & recompile rules (`shaders/std` top level) — https://shaders.com/docs/primitives/slots Two small kinds of rule that make a filter cheap. An **identity rule** sits on a filter definition's `identityWhen:` and says when the filter does nothing: while it holds, the layer inside passes through untouched and the effect costs no GPU time. A **recompile rule** sits on a prop's `recompile:` and says which changes rebuild the shader rather than just update a value. - `crosses(value: number): RecompileRule` — Rebuild the shader only when the prop crosses `value`, not on every change. - `isZero(prop: string): IdentityRule` — Skip the filter entirely while `prop` is exactly 0. - `isValue(prop: string, value: unknown): IdentityRule` — Skip the filter entirely while `prop` equals `value`, for a filter whose no-op is not 0. - `allOf(...rules: IdentityRule[]): IdentityRule` — Skip the filter only while every rule holds, for a no-op that needs several props at rest. - `identityWhenever(props: string[], when: (values: Record) => boolean): IdentityRule` — Skip the filter when your own test of the props' values says so. - `recompileWhen(predicate: (prev: any, next: any) => boolean): RecompileRule` — Rebuild when your own test of the old and new value says so, for a threshold `crosses` cannot express. ### Context & invocation (`shaders/std` top level) — https://shaders.com/docs/primitives/invoke 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`. - `ctx.uv: CtxToken` — The pixel's coordinate: 0–1 across the canvas, y down. - `ctx.time: CtxToken` — The global clock in seconds. - `ctx.aspect: CtxToken` — The canvas's width divided by its height. - `ctx.pointer: CtxToken` — The mouse position in uv (0–1, y down). - `ctx.viewportSize: CtxToken` — The frame size in device pixels, as a `vec2f`. - `ctx.logicalViewportSize: CtxToken` — The frame size in CSS pixels, as a `vec2f`, for feature counts that should not change with screen density. - `paintFrame(params: GpuFragmentParams): {uv: Expr; viewport: Expr}` — The coordinate and frame size a hand-written `paint:` builder should draw in. - `uniformOf(ref: PropRef, params: {uniforms: Record}): Expr` — The live GPU value of a prop, for a hand-written builder: `uniformOf(p('radius'), params)`. - `resolveScalar(input: Scalar | ScalarSource, params: SlotParams): Expr` — A `Scalar` or prop ref as a GPU value, for a hand-written builder. - `resolveArg(spec: ArgSpec, params: FilterParams): Expr` — Any 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(spec: ArgSpec, params: SlotParams): Expr` — `resolveArg` for any host, including a warp's `map:` factory. - `pointwiseOp(fn: unknown, hint: string, args: ArgSpec[], extra?: {compose?: PointwiseEffect['compose']; setup?: PointwiseEffect['setup']}): PointwiseEffect` — Wrap a compiled GPU function as a pointwise filter effect: the child's color goes in first, then `args`. ### List props (`shaders/std` top level) — https://shaders.com/docs/primitives/lists A **list prop** holds any number of items of the same shape: lights, points, anchors. Declare it with `listPropConfig`: each item is a small record of typed fields (`position`, `color`, `number`, `boolean`) and the list has a `maxItems` cap. The editor renders it as an add and remove list, every position field becomes a draggable handle, and any position can follow the mouse. Adding or removing an item at runtime never rebuilds the shader. - `listOf(params: {uniforms: Record}, prop: string): ListRef` — Read a list prop inside a hand-written builder: its live item count and each item's fields. - `accumulate(list: ListRef, body: (i: Expr) => Expr, opts: {zero?: 'f32' | 'vec3f'; deps?: Expr[]; hint?: string} = {}): Expr` — Add up a per-item value over every item of a list, in a real GPU loop over the live count. ## Painting ### Fields, palettes & ramps (`import {paint} from 'shaders/std'`) — https://shaders.com/docs/primitives/paint The words every gradient and most textures are drawn with. A **field** is a number per pixel (`Field`): the distance from a point, a noise value, a flow pattern. A **palette** turns a number into a color (`Palette`): two colors, or a multi-stop ramp, mixed in the color space your definition declares. `rampOver` joins the two and is the single most common line in a generator. - `rampOver(field: Field, palette: Palette, opts?: {edges?: PropRef}): Paint` — A paint that colors each pixel by looking its field value up in a palette. - `pair(a: PropRef, b: PropRef, space: PropRef): Palette` — A palette of two color props, mixed in the color space named by the `space` prop. - `stops(space: PropRef): Palette` — The standard multi-stop palette, read from the `stops`, `colorA` and `colorB` props. - `standardPalette(t: Expr, params: GpuFragmentParams): Expr` — The color for a 0–1 value from the standard palette props: `colorA`, `colorB`, `stops`, `colorSpace`. - `noiseField(basis: NoiseBasis): Field` — A field of smooth noise in the chosen flavor. - `warped(field: Field, opts: {amount: FieldScalar; amountScale?: number; timeScale?: number}): Field` — Makes a field flow like liquid by bending its coordinate with moving noise. - `scaledVolume(field: Field, opts: {scale: FieldScalar}): Field` — Gives a noise field a zoomable, aspect-correct coordinate. - `tone(field: Field, opts: {glow: FieldScalar; contrast: FieldScalar; balance: FieldScalar; invert: true}): Field` — Reshapes a 0–1 field with glow, contrast and balance controls, then flips it. - `threshold(field: Field, opts: {low: number; high: number; bias?: FieldScalar}): Field` — Turns a signed field (−1 to 1) into a soft 0–1 mask. - `rings(field: Field, count: FieldScalar): Field` — Repeats a field as concentric bands. - `tiles(field: Field, count: FieldScalar): Field` — Repeats a field `count` times, always wrapping. - `share(field: Field): Field` — Evaluates a field once and lets several words read the same result. - `flowField(slots: {detail: FieldScalar}): Field` — A swirling, animated wave pattern from −1 to 1. - `pulse(field: Field, opts: {speed: number; span: number; depth: number}): Field` — A gentle brightness pulse that follows a pattern field, hovering around 1. - `shimmered(paint: Paint, gain: Field): Paint` — Multiplies a paint's color and alpha by a gain field, for a slow shimmer over a pattern. - `wrapRamp(opts: {t: Expr; cycles: Expr | number}): Expr` — Runs a palette value back and forth `cycles` times so a ramp repeats without a seam. - `foldRamp(t: Expr): Expr` — Folds any number into 0–1 as a seamless zigzag: up from 0 to 1, back down, every 2 units. - `warpedPoint(opts: {at: Expr; time: Expr | number; amount: Expr | number; levels?: 1 | 2}): Expr` — A 3D position pushed around by moving noise, for reading several fields at one warped spot. - `warpStep(opts: { at: Expr scale: number z: Expr | number offsets: [[number, number], [number, number]] reach: number strength: Expr | number }): Expr` — One step of a chained warp: pushes a 2D position by two noise reads and hands them back. - `scatterField(opts: { at: Expr count: Expr | number seed: Expr | number drift: Expr | number aspect: Expr | number time: Expr | number softness: Expr | number /** The points precomputed each frame by `scatteredAnchors`. When given, `drift`, `aspect` and `time` are ignored here. */ anchors?: Expr }): Expr` — A mesh-gradient field: up to 8 drifting points scattered across the canvas, blended by nearness. - `scatteredAnchors(params: GpuFragmentParams, slots: {count: PropRef; seed: PropRef; drift: PropRef; field: string}): Expr` — Computes the `scatterField` points once per frame instead of once per pixel. - `quadBlend(slots: {a: PropRef; b: PropRef; c: PropRef; d: PropRef; space: PropRef}): (t1: Expr, t2: Expr, params: GpuFragmentParams) => Expr` — A four-color blend on a square: `a` to `b` across the top, `c` to `d` across the bottom, then top to bottom. - `colorLadder3(slots: {a: PropRef; b: PropRef; c: PropRef; space: PropRef}): (t1: Expr, t2: Expr, params: GpuFragmentParams) => Expr` — A three-color blend: `a` to `b` by the first value, then on to `c` by the second. - `hueWheel(h: Expr): Expr` — A rainbow color for a hue value: 0 is red, cycling through the spectrum and back every 1. - `dist.conic(slots: {center: PropRef; rotation: FieldScalar}): Field` — A sweep around a center, like a clock hand: 0 to 1 once around. - `dist.diamond(slots: {center: PropRef; size: FieldScalar; rotation: FieldScalar; roundness: FieldScalar}): Field` — A diamond-shaped gradient spreading out from a center. - `dist.linear(slots: {from: PropRef; to: PropRef; angle: FieldScalar}): Field` — A straight gradient from one point to another. - `dist.radial(slots: {center: PropRef; radius: FieldScalar; aspect: FieldScalar; skew: FieldScalar}): Field` — A round or elliptical gradient spreading out from a center. - `dist.spiral(slots: {center: PropRef; scale: FieldScalar; width: FieldScalar; falloff: FieldScalar; softness: FieldScalar}): Field` — A turning spiral stripe: 0 on the background, 1 on the stroke. ### Gradients (`import {gradients} from 'shaders/std'`) — https://shaders.com/docs/primitives/gradients Finished gradient paints: a flat fill, a color wheel that cycles over time, a cloud of five colored points, and a beam of light between two points. Each word binds your props and returns a paint, so a definition is the props plus one line. They are complete looks rather than building blocks. For a gradient of your own shape, compose a `dist` field with `rampOver` from the fields words instead. - `solidColor(color: PropRef): Paint` — A flat fill in one color prop. - `beam(slots: { from: PropRef to: PropRef thickness: {start: ArgSpec; end: ArgSpec} softness: {start: ArgSpec; end: ArgSpec} colors: {inside: PropRef; outside: PropRef} space: PropRef }): Paint` — A glowing beam of light between two points. - `colorWheel(slots: { mode: PropRef direction: ArgSpec scale: ArgSpec palette: {a: PropRef; b: PropRef; c: PropRef} space: PropRef }): Paint` — A striped gradient that slides across the canvas, cycling through its colors over time. - `pointCloudGradient(slots: { points: {color: PropRef; position: PropRef}[] smoothness: ArgSpec space: PropRef }): Paint` — Five colored points placed anywhere on the canvas, each pixel taking the colors of the points nearest it. ### Patterns & tiling (`import {patterns} from 'shaders/std'`) — https://shaders.com/docs/primitives/patterns Repeating patterns you can color and animate: checkers, stripes, zigzags, rings, falling streaks, and tiled lattices of squares, hexagons, triangles, bricks, truchet arcs, woven threads and isometric cubes, plus the print-screen filters (halftone dots, CMYK plates and dithering). Most pattern words return a **mask**: a number per pixel that is 1 on the pattern and 0 off it. The lattice words also return a per-cell **shade**, a brightness factor around 1 that `vary` multiplies into a fill so every tile reads slightly different. - `strokeOver(layers: {fill: PaintSlot; stroke: PaintSlot; mask: PaintSlot; space?: PropRef}): PatternPaint` — Two colors mixed through a mask: `fill` where the mask is 0, `stroke` where it is 1. - `withAlpha(color: PaintSlot, alpha: PaintSlot): PatternPaint` — A color with its alpha replaced by a separately built mask. - `checkerCells(slots: {cells: PropRef; softness: PropRef}): PatternPaint` — A checkerboard mask: 1 on one set of squares, 0 on the other, with clean edges at any size. - `stripeBands(slots: { angle: PropRef density: PropRef balance: PropRef softness: PropRef offset: PropRef }): PatternPaint` — A mask of straight parallel stripes that scroll with the layer's clock. - `zigzagBands(slots: { count: PropRef angle: PropRef balance: PropRef softness: PropRef offset: PropRef }): PatternPaint` — A mask of chevron (zigzag) stripes that scroll with the layer's clock. - `ringWaves(slots: { center: PropRef frequency: PropRef thickness: PropRef softness: PropRef phase: PropRef }): PatternPaint` — A mask of concentric rings spreading out from a point, animated by the layer's clock. - `fallingStreaks(slots: { angle: PropRef density: PropRef speedVariance: PropRef trailLength: PropRef strokeWidth: PropRef rounding: PropRef balance: PropRef }): {mask: PatternPaint; fade: PatternPaint}` — Streaks that fall across the canvas in columns, each column at its own random speed. - `dotLattice(slots: { density: PropRef dotSize: PropRef offset: PropRef speedVariance: PropRef twinkle: PropRef }): PatternPaint` — A mask of round dots on a square grid, with optional row stagger, drift and twinkle. - `cellFrame(slots: {cells: PropRef; rotation: PropRef; convention: CellFrameConvention}): PatternPaint` — The shared coordinate system of a tiled pattern: how many cells fit down the canvas height and how far the whole lattice is rotated. - `gridLines(slots: { frame: PatternPaint thickness: PropRef softness: PropRef variation: PropRef }): {lines: PatternPaint; shade: PatternPaint}` — Square grid lines drawn in a `cellFrame`, plus a per-cell shade for the fill. - `hexLines(slots: { frame: PatternPaint thickness: PropRef softness: PropRef variation: PropRef }): {lines: PatternPaint; shade: PatternPaint}` — Honeycomb lines (pointy-top hexagons) drawn in a `cellFrame`, plus a per-cell shade. - `triangleLines(slots: { frame: PatternPaint thickness: PropRef softness: PropRef variation: PropRef speedVariance: PropRef }): {lines: PatternPaint; shade: PatternPaint}` — A lattice of equilateral triangles drawn in a `cellFrame`, with rows that can drift. - `brickCourses(slots: { cellsX: PropRef cellsY: PropRef mortar: PropRef softness: PropRef variation: PropRef rotation: PropRef offset: PropRef speedVariance: PropRef seed: PropRef }): {bricks: PatternPaint; shade: PatternPaint}` — A brick wall: staggered rows with mortar gaps, optional rotation and per-row drift. - `truchetArcs(slots: { frame: PatternPaint thickness: PropRef softness: PropRef seed: PropRef }): PatternPaint` — A maze of quarter-circle arcs, two per tile, flipped at random so they join into flowing curves. - `weaveThreads(slots: { frame: PatternPaint gap: PropRef /** `[horizontal, vertical]` thread colors. */ colors: [PropRef, PropRef] }): PatternPaint` — Two sets of threads woven over and under each other, returned as a finished color. - `isoCubeFaces(slots: { frame: PatternPaint thickness: PropRef softness: PropRef }): {random: PatternPaint; tone: PatternPaint; wire: PatternPaint}` — Tumbling blocks: three shaded rhombus faces per hexagon that read as a field of 3D cubes. - `vary(color: PaintSlot, factor: PaintSlot): PatternPaint` — A color lightened or darkened per cell by a shade factor, alpha untouched. - `sampleMapsAtCellCentres(slots: { cells: PropRef rotation?: PropRef props: string[] }): GpuMapSampleUVs` — Makes map-driven props change per whole cell instead of per pixel, so a mapped dot size or line thickness grows cell by cell rather than being cut off mid-cell. - `times(a: PaintSlot, b: PaintSlot): PatternPaint` — The product of two values: a mask scaled by a prop, an RGB dimmed by a shade, two masks combined. - `mixOf(from: PaintSlot, to: PaintSlot, amount: PaintSlot): PatternPaint` — A straight blend from one value to another by an amount from 0 to 1. - `alphaOf(color: PaintSlot): PatternPaint` — The alpha channel of a color, as a number per pixel. - `rgbOf(color: PaintSlot): PatternPaint` — The RGB channels of a color, without its alpha. - `opaque(rgb: PaintSlot): PatternPaint` — An RGB value finished as a fully opaque color. - `dotScreen(slots: {angle: PropRef; frequency: PropRef}): GatherEffect` — A classic halftone filter: the layer inside it redrawn as a grid of dots that grow where it is bright. - `cmykPress(slots: { paper: PropRef frequency: PropRef misprint: PropRef misprintAngle: PropRef plates: InkPlateSpec[] }): GatherEffect` — A four-color print filter: the layer inside it separated into ink plates, each screened into dots at its own angle and laid down on paper in order. - `inkPlate(spec: InkPlateSpec): InkPlateSpec` — Declares one ink plate for `cmykPress`. - `dotScreenMask(uv: Expr, aspect: Expr, angle: Expr, intensity: Expr, frequency: Expr): Expr` — The dot coverage of one halftone screen: 1 inside a dot, 0 between, with the dot size set by an ink amount. - `inkTransmission(inkColor: Expr, inkMask: Expr): Expr` — How much light passes one ink plate: white where the dot mask is 0, the ink color where it is 1. - `chosenBy(prop: PropRef, read: (raw: unknown) => K, recipes: Record): GatherEffect` — Picks one whole effect recipe from a select prop, decided when the shader compiles. - `pixelGrid(slots: {size: PropRef}): PixelGrid` — The pixel grid of a dither: the layer inside it chopped into square cells of a given size. - `quantise(slots: {grid: PixelGrid; pattern: PropRef; threshold: PropRef; spread: PropRef}): GatherStage` — Reduces each grid cell of the layer inside to 0 or 1 using a dither pattern. - `ditherInks(slots: { grid: PixelGrid levels: GatherStage mode: PropRef colors: [PropRef, PropRef] }): GatherEffect` — A dither filter: colors the 0/1 levels from `quantise`, either with two colors of your own or with darkened and brightened versions of the layer's own pixels. - `scatterPoint(coord: Expr, opts: ScatterOptions): ScatteredPoint` — One random point in each cell of a square grid: the classic scatter for glitter, stars, dust and sparkles. - `scatterPoints(coord: Expr, opts: ScatterOptions): ScatteredPoint[]` — The scattered points of the four grid cells nearest the pixel, so anything drawn up to half a cell from its point shows whole, never clipped at a cell edge. ### Figures & strokes (`import {figures} from 'shaders/std'`) — https://shaders.com/docs/primitives/figures Drawn lines: a straight segment and a traveling sine wave. Each word binds your props and returns a paint that draws the stroke in one color prop with an antialiased edge and leaves everything else transparent, so it layers cleanly over what sits behind it. - `strokedSegment(slots: StrokedSegmentSlots): Paint` — A straight line between two points, solid, dashed or dotted, with square or round ends. - `sineStroke(slots: SineStrokeSlots): Paint` — A wavy line that travels along itself, drawn as a soft band. ### Layering & output (`import {compose} from 'shaders/std'`) — https://shaders.com/docs/primitives/compose The words that finish a `paint:` function. `layers` stacks several colors into one, back to front, each with an optional opacity and an optional factor it is seen through. `layered` builds N variations of one recipe from a data list and sums them, which is how curtains, cloud banks and echo trails get their depth cheaply. - `layers(entries: Layer[]): Expr` — Stacks colors into one, first entry at the back. - `emissiveAlpha(rgb: Expr, hint: string = 'emissive'): Expr` — Turns an rgb light value into a color with alpha, so glows composite over transparency. - `dithered(color: Expr, params: GpuFragmentParams): Expr` — Adds a tiny amount of noise to a final color so long soft gradients show no banding. - `layered(layerData: readonly T[], build: (layer: T, index: number) => {value: Expr; weight: Expr}): {weightedSum: Expr; totalWeight: Expr}` — Builds N variations of one thing from a data list and sums them with weights. ### Media (`import {media} from 'shaders/std'`) — https://shaders.com/docs/primitives/media Pixels that come from an image, a video or the user's camera instead of from math. Each word loads its source, fits it into the layer the way CSS `object-fit` fits an image into a box, and returns the GPU half of a definition. Spread it into `defineShader({...})` next to your props, with `role: 'media'` and `species: 'custom'`. - `imageMedia(opts: MediaFitSlots & { /** The URL prop. */ src: PropRef /** A debug label for the texture, shown in GPU tooling. */ label: string /** Called when the image fails to load. */ onError?: (error: unknown, url: string) => void }): MediaSurfaceHalf` — An image from a URL prop, fitted into the layer. - `videoMedia(opts: MediaFitSlots & { /** The URL prop. */ src: PropRef /** The loop prop, synced to the video each frame. */ loop: PropRef /** Milliseconds to wait for the video's metadata before giving up. */ metadataTimeoutMs: number onError?: (error: unknown, info: {url: string | null; stage: 'acquire' | 'autoplay'}) => void }): MediaSurfaceHalf` — A video from a URL prop, playing in the layer. - `webcamMedia(opts: MediaFitSlots & { /** The selfie-mirror boolean prop. */ mirror: PropRef /** The `getUserMedia` constraints to request the camera with. */ constraints: MediaStreamConstraints /** The key the definition's `naturalSizeKey: {fixed}` uses (a webcam has no URL). */ naturalSizeKey: string onError?: (error: unknown, info: {url: string | null; stage: 'acquire' | 'autoplay'}) => void }): MediaSurfaceHalf` — The user's camera, live in the layer. ## Noise, light & materials ### Noise (`import {noise} from 'shaders/std'`) — https://shaders.com/docs/primitives/noise Words for grainy, cloudy, cellular and streaked surfaces: the textures behind clouds, film grain, stone, water and brushed metal. Read a noise recipe from the inside out, in four steps. A **basis** is the raw pattern, one number per point (`gaborGrains`, `curlSpeed`, `blueSpeckle`, or a `noiseField` from paint). A **framing** decides where on the canvas the basis is sampled and how big it is: `seededPlane` for almost everything, `pixelGrid` for patterns that live on pixels. A **tone** word turns the raw number into a 0–1 ramp position with contrast and balance controls: `noiseTone` for a 0–1 basis, `signedTone` for a −1 to 1 one, or `unitized` to convert first. A **ramp** closes it: `rampOver` with `stops` or `linearPair` gives the field color. - `seededPlane(field: Field, slots: {scale: PropRef; seed: PropRef}): Field` — Frames a field on a zoomable plane: how big the pattern is and where it starts. - `evolving(field: Field, opts: {rate: number}): Field` — Makes a 3D noise basis morph in place over time instead of sliding across the canvas. - `noiseTone(field: Field, slots?: {contrast?: PropRef; balance?: PropRef}): Field` — The standard contrast and balance controls of a noise texture, turning a 0–1 field into the ramp position. - `unitized(field: Field): Field` — Turns a signed field (−1 to 1) into a unit field (0 to 1). - `signedTone(field: Field, slots: {contrast: PropRef; balance: PropRef}): Field` — Contrast and balance for a signed field (−1 to 1), applied before it is squashed to 0–1. - `gainTone(field: Field, slots: {contrast: PropRef; balance: PropRef}): Field` — Contrast as a multiplier and balance as a shift over a 0–1 field, not flipped. - `gaborGrains(slots: {frequency: PropRef}): Field` — Oriented sine grains: short striped patches, each facing a random way, like brushed metal or wood grain. - `waveletBands(slots: {detail: PropRef}): Field` — Rotating bands of wavelets: layered ripples that turn against each other, a watery interference look. - `curlSpeed(opts: {rate: number}): Field` — How fast a swirling flow moves at each point: soft eddies and streams that morph in place. - `erosionRidges(): Field` — Terrain eroded by water: sharp branching ridges with gullies running off them. - `scratchStreaks(slots: {thickness: PropRef}): Field` — Fine hairline scratches, like a scuffed surface, flickering on the layer's clock. - `pixelGrid(field: Field, slots: {grain: PropRef; seed: PropRef}): Field` — Frames a field on the pixel grid: one value per block of `grain` device pixels. - `blueSpeckle(): Field` — Fine, even speckle with no clumps: blue noise, one random value per pixel block. - `scaledPlane(field: Field, slots: {scale: PropRef}): Field` — Frames a field on the aspect-corrected canvas plane, zoomed by a plain multiplier. - `linearPair(a: PropRef, b: PropRef): Palette` — A two-color palette mixed in linear RGB, for a definition with no color-space prop. - `fractalNoise(slots: { angle: PropRef detail: PropRef contrast: PropRef octaves: PropRef seed: PropRef space: PropRef }): Paint` — A complete fractal-noise paint: layered simplex noise that morphs over time, read through the color ramp. - `worleyNoise(slots: { scale: PropRef jitter: PropRef lacunarity: PropRef persistence: PropRef contrast: PropRef balance: PropRef seed: PropRef /** Compile-time prop: `'f1' | 'f2' | 'f2MinusF1' | 'f1PlusF2' | 'f1TimesF2'`. */ mode: PropRef /** Compile-time prop: `'euclidean' | 'manhattan' | 'chebyshev'`. */ distance: PropRef /** Compile-time prop: 1 to 4. */ octaves: PropRef space: PropRef }): Paint` — A complete cellular-noise paint: distances to drifting cell points, read through the color ramp. - `transformWorleyMode(value: string): number` — The `transform` for a `worleyNoise` `mode` prop: maps `'f1'`, `'f2'`, `'f2MinusF1'`, `'f1PlusF2'` or `'f1TimesF2'` to the number the paint reads. - `transformWorleyDistance(value: string): number` — The `transform` for a `worleyNoise` `distance` prop: maps `'euclidean'`, `'manhattan'` or `'chebyshev'` to the number the paint reads. - `cellDistances(slots: {scale: PropRef; seed: PropRef}): Field` — Distances from each pixel to its nearest two cell points, as `(d1, d2)`: the raw material for Voronoi fills and borders. - `cellFill(cells: Field, slots: {edgeIntensity: PropRef}): Field` — A 0–1 fill for each cell: 0 at the cell's point, 1 at its boundary, whatever the cell size. - `cellBorders(cells: Field, slots: {softness: PropRef; scale: PropRef}): Field` — A mask of the lines between cells: 0 on a boundary, 1 inside a cell. - `borderOverlay(paint: Paint, mask: Field, slots: {color: PropRef}): Paint` — Draws a color over a paint wherever a mask falls to 0, keeping the paint's alpha. - `waves(axes: {x: Expr | number; y?: Expr | number; t?: Expr | number}, schedule: WaveTerm[]): Expr` — Overlapping traveling sine waves from a schedule written as data: the organic wobble behind blob edges, water lines and drifting fills. - `wavyLine(opts: { along: Expr | number time: Expr | number waves: {freq: number; speed: number; amount: number; phase?: Expr | number}[] }): Expr` — The height of an animated wavy line at a point along it: a stack of traveling sines. - `organicWaves(opts: {frequency: number; detail?: number; drift?: number; seed?: number}): WaveTerm[]` — A ready-made `waves` schedule from three knobs, for when you have no hand-tuned constants. - `ribbons(slots: { from: PropRef to: PropRef count: PropRef width: PropRef amplitude: PropRef frequency: PropRef softness: PropRef spread: PropRef pinEdges: PropRef colorScale: PropRef colorVariance: PropRef }): Paint` — Flowing gradient-colored ribbons between two points: the Strands look. - `overRgb(paint: Paint, ...stages: RgbStage[]): Paint` — Runs color-only steps over a paint, in order, leaving its alpha alone. - `backToP3(slots: {space?: PropRef}): RgbStage` — Brings `ribbons` color from its working color space back to display color. - `tonePow(): RgbStage` — A gentle lift of the mid-tones (rgb to the power 0.85), as an `overRgb` step. - `noiseRelief(basis: ReliefBasis): (params: GpuFragmentParams) => Expr` — Embosses the layer inside with a textured surface: the child is slightly distorted, then lit by a height field so it reads as carved stone or woven cloth. - `clothCoords(coords: {along: Expr | number; across: Expr | number}, folds: Fold[], opts: DrapeOptions & {foreshorten?: number}): {along: Expr; across: Expr}` — Where on the unfolded cloth a point lands: the material coordinates to draw a pattern in, so it follows the folds instead of floating over them. - `drapedFolds(coords: {along: Expr | number; across: Expr | number}, folds: Fold[], opts: DrapeOptions): Expr` — The height of a draped cloth at a point: rounded ridges running along one direction, each rippling and swaying along its length, gathered where the cloth is pinned. - `foldSet(opts: { count: number seed: Expr | number spread: Expr | number width: Expr | number height: Expr | number jitter?: number }): Fold[]` — Lays out the ridges of a draped cloth: `count` folds spread evenly across `spread`, each nudged sideways, widened and raised by a seeded amount so no two are alike. - `reliefBases.stone: { readonly fn: TgpuFn<(p: Vec2f) => F32>; readonly hint: "stone12"; }` — Marbled stone height field. - `reliefBases.wool: { readonly fn: TgpuFn<(p: Vec2f) => F32>; readonly hint: "wool12"; }` — Interwoven fibrous fabric height field. ### Light (`import {light} from 'shaders/std'`) — https://shaders.com/docs/primitives/light Words for drawing light: glows, rays, beams, flares and halos, plus the frames they are drawn in. A **frame** is the coordinate system a light evaluates in. `radialFrame` gives each pixel its distance and angle from a center; `beamFrame` gives its distance along and across a beam. **Parts** such as `glowPoint`, `rayLobes` and `featherMask` shape a light over a frame and return a *field*, a 0–1 number per pixel. `withFrame` evaluates a part in a frame, `modulate` multiplies parts (a mask over a pattern), and `additive` sums finished lights. - `glowAt(opts: {uv: Expr; aspect: Expr | number; x: Expr | number; y: Expr | number; sizeSq: Expr | number}): Expr` — A soft round glow at a position on the canvas. - `glowSpot(du: Expr, dv: Expr, sharpness: Expr): Expr` — A soft oval glow over an offset you have already scaled, the core of a bloom or a glare. - `emitterFalloff(d: Expr, opts: {radius: Expr | number; power: Expr | number}): Expr` — How light spilling from an emitter dims with distance, with a long realistic tail. - `radialFrame(center: PropRef): LightValue` — The frame for a burst, halo or sweep around a center prop. - `seamlessRadialFrame(center: PropRef): LightValue` — The frame `noiseRays` needs: a radial frame around a center prop with no visible seam. - `beamFrame(anchor: PropRef): LightValue` — The frame of a beam that starts at an anchor prop and points at the canvas center. - `withFrame(frame: LightValue, part: LightPart, hint?: string): LightValue` — Evaluate a light part in a frame. - `modulate(first: LightPart, ...rest: LightPart[]): LightPart` — Multiply light parts drawn in the same frame, such as a mask over a pattern. - `glowPoint(slots: {sharpness: ArgSpec}): LightPart` — A soft glow at the center of a radial frame with no hard edge. - `featherMask(slots: {radius: ArgSpec; feather: ArgSpec}): LightPart` — A round mask that is solid inside a radius and fades out at its edge. - `rayLobes(slots: {count: ArgSpec; spin: number; sharpness: ArgSpec}): LightPart` — Soft rays fanning out from the center of a radial frame, turning with the layer's clock. - `softRayLobes(slots: {count: ArgSpec; softness: ArgSpec; spin: number}): LightPart` — `rayLobes` with a softness slider instead of a sharpness. - `raySpikes(slots: {halfCount: ArgSpec; power: ArgSpec}): LightPart` — Thin star spikes with dark gaps between them, like light through a camera aperture. - `ringBand(slots: {center: ArgSpec; spread: ArgSpec; width: ArgSpec}): LightPart` — Three thin colored rings around the center, the rainbow edge of a lens or a halo. - `noiseRays(slots: {density: ArgSpec; intensity: ArgSpec; spotty: ArgSpec}): LightPart` — Volumetric god rays: shafts of light drifting outward from the center, moving on the layer's clock. - `rayBands(opts: { along: Expr frequency: Expr | number time: Expr | number speed: Expr | number phase?: Expr | number sharpness: Expr | number }): Expr` — Bright bands that travel along a coordinate, for aurora curtains or shimmering rays. - `shine(opts: {normal: Expr; light: Expr; gloss: Expr | number}): Expr` — A specular highlight on any surface that gives you a normal. - `domeNormal(opts: { delta: Expr dist: Expr radius: Expr | number bulge?: {tilt?: number; drop?: number} }): Expr` — The surface normals of a flat disc treated as a puffy dome, ready to light with `shine`. - `additive(first: Expr, ...rest: Expr[]): Expr` — Adds lights together, since light from several sources simply sums. - `heatRamp(colors: {hot: PropRef; mid: PropRef; fringe: PropRef}): { kind: "heatRamp"; taps: (heat: Expr, params: { uniforms: Record; }) => Expr; }` — The colors of overexposed light, from a dim fringe through a mid tone to a hot core. - `vignetteMask(slots: {strength: ArgSpec; scale?: number}): LightValue` — Darkens the corners of the canvas. - `screenGlow(glow: (params: FilterParams) => Expr): PointwiseEffect` — An `effect` that shines emitted light onto the layer inside it, the way light hits film. - `coverageMix(slots: {color: PropRef; background: PropRef; coverage: LightValue; hint?: string}): LightValue` — Blends from a background color to a light color by a coverage field, as a finished paint. - `coverageOver(slots: {color: PropRef; background: PropRef; coverage: LightValue}): LightValue` — Lays a light color over a background color by a coverage field, like a layer with an opacity mask, as a finished paint. - `slowDrift(slots: {seed: ArgSpec; flicker: ArgSpec}): (clock: Expr, params: GpuFragmentParams) => Expr` — The slow breathing and drifting signals that keep a light leak alive. - `beamBloom(slots: {spread: ArgSpec}): (frame: Expr, drift: Expr, params: GpuFragmentParams) => Expr` — The soft pool of light at the start of a beam, with a wider faint shoulder around it. - `beamStreaks(slots: {spread: ArgSpec; strength: ArgSpec}): (frame: Expr, drift: Expr, params: GpuFragmentParams) => Expr` — Two bright bands crossing a beam further along it, slowly drifting, like light bouncing inside a film camera. - `streakBand(u: Expr, center: Expr, width: Expr): Expr` — One soft band across a single coordinate, peaking at `center`. - `lightBeam(dist: Expr, t: Expr, thickness: {start: Expr; end: Expr}, softness: {start: Expr; end: Expr}): Expr` — The glow of a beam that can be thicker or softer at one end than the other. - `segmentProject(p: Expr, a: Expr, b: Expr): Expr` — Where a pixel falls along a line from `a` to `b`, and how far it is from that line. - `flareFrame(slots: {position: PropRef; intensity: ArgSpec; edgeFade: ArgSpec}): LightValue` — The shared frame of a camera lens flare, which every `flare*` part reads. - `lensGhost(slots: {intensity: ArgSpec; spread: ArgSpec; chroma: ArgSpec}): (flare: Expr, disc: [number, number, number, number], tint: [number, number, number, number], params: GpuFragmentParams) => Expr` — One ghost disc of a lens flare, the faint circles that line up across from the light. - `flareHalo(slots: {intensity: ArgSpec; radius: ArgSpec; chroma: ArgSpec; softness: ArgSpec}): (flare: Expr, params: GpuFragmentParams) => Expr` — The rainbow halo ring of a lens flare, drawn across the canvas from the light. - `flareStarburst(slots: {intensity: ArgSpec; points: ArgSpec}): (flare: Expr, params: GpuFragmentParams) => Expr` — The star of thin spikes around the light in a lens flare. - `flareStreak(slots: {intensity: ArgSpec; length: ArgSpec}): (flare: Expr, params: GpuFragmentParams) => Expr` — The horizontal widescreen streak through the light in a lens flare. - `flareGlare(slots: {intensity: ArgSpec; size: ArgSpec}): (flare: Expr, params: GpuFragmentParams) => Expr` — The broad warm-white wash around the light that lifts contrast near it. - `flareCore(slots: {intensity: ArgSpec}): (flare: Expr, params: GpuFragmentParams) => Expr` — The bright point at the light itself: a hard pinpoint inside a small soft glow. - `flareComposite(total: Expr, flare: Expr): Expr` — Closes a lens flare: turns the summed flare parts into the color to return from `paint`. - `dithered(heat: Expr, uv: Expr, clock: Expr): Expr` — Adds a trace of noise to a heat field so long soft ramps do not show bands. - `starGlint(offset: Expr, opts: { core: Expr | number rayLength: Expr | number rayWidth: Expr | number rays: Expr | number /** Optional: the glint fades to nothing by this distance from its centre (measured along the larger axis). */ reach?: Expr | number }): Expr` — A four-point star of light: a round core with a thin ray along each axis, like a glint off glitter or a star in a photograph. ### Materials & surfaces (`import {materials} from 'shaders/std'`) — https://shaders.com/docs/primitives/materials Words that shade a surface so a shape reads as glass, metal, plastic or stone. A material is three things: a **normal** (which way the surface faces at this pixel), a **light** (where it comes from) and a **response** (how the surface answers: diffuse, glint, mirror, tint). `shapedSurface` turns a shape prop into a surface you can shade. It hands your `surface` function a frame with the shape's distance field, and `surfaceField` binds what you read from it: the signed distance, the pixel size, the neighbour taps. - `shapedSurface(spec: ShapedSurfaceSpec): ShapedSurfaceEffect` — Turns a shape prop into a surface your material shades. - `surfaceField(frame: SurfaceFrame, params: GpuFragmentParams, opts: {scale?: Expr} = {}): SurfaceField` — The first line of a material: the field taps, the signed distance and the pixel size, bound once. - `geometricNormal(frame: SurfaceFrame, field: SurfaceField, opts: {bevelWidth: Expr; bevelShape: Expr; sharpness?: number; eps?: number; hint?: string}): Expr` — The surface normal of the shape, whichever kind of shape is active. - `marchedNormal(field: SurfaceField, sharpness: number = 5, hint: string = 'nGeo'): Expr` — The surface normal of a 3D shape, from the marched depth. - `nudgeNormal(n: Expr, dx: Expr, dy: Expr, hint: string = 'n'): Expr` — Tilts a normal by a slope in x and y, turning a height field into relief. - `tiltNormal(n: Expr, frame: DirectionFrame, slopes: {along?: Expr; across?: Expr}, hint: string = 'n'): Expr` — Tilts a normal along and across a direction, for brushed or woven relief. - `tiltAlong(n: Expr, axis: Expr, amount: Expr, hint: string = 'n'): Expr` — Tilts a normal along one 2D direction by a slope amount. - `fdSlope(sampleAt: (p: Expr) => Expr, p: Expr, eps: number, hint: string = 'fd'): {value: Expr; dx: Expr; dy: Expr}` — The value and slope of any field at a point: `value`, `dx` and `dy`. - `perlinSlope(q: Expr, gain: Expr | number): Expr` — The slope of smooth noise at a point, for wavy or molten relief. - `fieldSlope(field: SurfaceField, eps: number = 0.01): Expr` — The direction the shape's distance grows in: a 2D vector pointing outward at this pixel. - `surfacePattern(frame: SurfaceFrame, field: SurfaceField, opts: {uv?: Expr} = {}): Expr` — Coordinates for a pattern that sticks to the shape's surface. - `keyLightAt(dir: Expr, elevation: number, hint: string = 'kl'): Expr` — A key light from an angle: the light direction `.L` and the half vector `.H` for highlights. - `keyLightXY(x: Expr, y: Expr, elevation: number, hint: string = 'kl'): Expr` — A key light from explicit x and y components, for a second or a crossed light. - `lightVec3(dir: Expr, z: number, hint: string = 'L'): Expr` — A 3D light direction from a `direction()` vector and an elevation. - `placementPoint(params: GpuFragmentParams, position: Expr, hint: string = 'placed'): Expr` — A position prop in the shape's own coordinates, so you can compare it with the field. - `pointLightFrom(light: {position: Expr; height: Expr | number}, at: Expr, hint: string = 'pl'): {L: Expr; toLight: Expr; distance: Expr}` — A point light as seen from a point on the shape: the 3D light vector `L`, the 2D direction `toLight` and the `distance`. - `inverseSquare(distance: Expr, range: Expr | number): Expr` — How a point light fades with distance: 1 at the source, half at `range`. - `lambert(normal: Expr, light: Expr, opts: {wrap?: Expr | number} = {}): Expr` — How much a light falls on a surface: 0 facing away, 1 facing it. - `sharpGlint(ndh: Expr, sharpness: Expr, cfg: Expr): Expr` — A highlight whose tightness follows a sharpness slider. - `dualLobeGlint(ndh: Expr, opts: { /** `[exponent, gain]` of the hot core lobe. */ core: [number, number] /** `[exponent, gain]` of the wide halo lobe. */ halo: [number, number] softness?: Expr gain: Expr }): Expr` — A highlight with a tight hot core and a wide dim halo. - `anisoSpecular(opts: { normal: Expr /** The 2D grain direction. */ tangent: Expr /** A unit 3D light direction (see `lightVec3`). */ light: Expr view: Expr alphas: {along: Expr; across: Expr} gain?: Expr | number }): Expr` — A highlight stretched along a grain, as on brushed metal or carbon fibre. - `wardAlphas(roughness: Expr | number, anisotropy: Expr | number): {along: Expr; across: Expr}` — Turns roughness and anisotropy sliders (0–1 each) into the two lobe widths `anisoSpecular` takes. - `viewRay(params: GpuFragmentParams, field: Pick, fov: number = 0.6): Expr` — The direction the viewer looks along at this pixel, for reflections that sweep across a face. - `grazingOf(n: Expr, view: Expr): Expr` — How edge-on the surface is to the viewer: 0 face-on, 1 grazing. - `grazingFlat(n: Expr): Expr` — How edge-on the surface is to a straight-on viewer: 0 face-on, 1 grazing. - `fresnelBoost(grazing: Expr, opts: {power?: number; amount: Expr | number}): Expr` — A multiplier that brightens grazing edges: 1 face-on, up to `1 + amount` at the rim. - `schlickFresnel(grazing: Expr, opts: {r0?: number; gain: Expr | number; power?: number}): Expr` — How mirror-like a surface is at this pixel: `r0` face-on, rising to `r0 + gain` at the rim. - `studioSoftboxes(x: Expr, y: Expr, opts: { /** A `direction()` vector that rotates the studio. */ rotation: Expr keyRadius: Expr | number drift: Expr | number strength: Expr | number skyGain: number }): Expr` — The brightness of a five-light studio seen in a reflected direction. - `smearAlong(opts: {center: Expr; axis: Expr; spread: Expr; taps?: number; sigma?: number; hint?: string}, sample: (x: Expr, y: Expr) => Expr): Expr` — Blurs any 2D lookup along a direction, for streaked reflections and motion smear. - `opticalThickness(field: SurfaceField, frame: SurfaceFrame): Expr` — How much material the view passes through at this pixel: 0 at the edge, up to about 1.2 deep inside. - `beerLambert(thickness: Expr, absorb: Expr): Expr` — How much light survives a thickness of tinted material, per channel. - `cosineRainbow(t: Expr, phases: [number, number, number]): Expr` — A smooth rainbow color from a value that wraps every 1. - `tintRamp(t: Expr, dark: Expr, light: Expr): Expr` — Maps a lighting value (0 dark, 1 light) onto two colors. - `neutralTone(rgb: Expr): Expr` — Compresses bright color back into range without shifting its hue. - `exposureTone(rgb: Expr): Expr` — Turns light that piles past 1 into a soft burn toward white, like film. - `silhouette(field: SurfaceField, edgeSoftness: Expr): Expr` — The shape's coverage at this pixel: 1 inside, 0 outside, soft across the edge. - `insideShape(sdf: Expr, pxH: Expr): Expr` — True inside the shape and up to two pixels outside it. - `guarded(cond: Expr, inner: Expr, fallback: Expr, hint: string = 'guarded', deps: Expr[] = []): Expr` — Evaluates an expression only where a condition holds, and a cheap fallback everywhere else. - `surfaceNoise(x: Expr | number, y: Expr | number): Expr` — Smooth signed noise at a 2D point, roughly −1 to 1, with features about one unit wide. - `surfaceNoiseAt(p: Expr): Expr` — `surfaceNoise` at a 2D point you already hold. - `volumeNoiseAt(p: Expr): Expr` — Smooth signed noise at a 3D point, roughly −1 to 1. - `cellNoiseAt(p: Expr): Expr` — Cellular noise at a 2D point: 0 at each cell's seed point, rising toward the cell walls. - `valueNoise(x: Expr | number, y: Expr | number): Expr` — Smooth noise 0–1 at a 2D point, softer and blockier than `surfaceNoise`. - `hashNoise(x: Expr | number, y: Expr | number): Expr` — Random 0–1 per point, with no smoothness between neighbours. - `interleavedNoise(pixel: Expr, clock: Expr | number = 0): Expr` — A 0–1 dither pattern over device pixels where neighbours differ as much as possible. - `grainNoise(coords: {along: Expr; across: Expr}, opts: {freq: [Expr | number, Expr | number]; offset?: [number, number]; drift?: Expr}): Expr` — One octave of smooth signed noise along and across a direction, for grain. - `flowWarp(warpInput: Expr, flowT: Expr): Expr` — A slowly folding 2D offset to add to pattern coordinates, for molten or wind-blown motion. - `sensorGrain(rgb: Expr, opts: {amount: Expr | number; pixel: Expr; clock: Expr | number}): Expr` — Adds a fine per-pixel brightness jitter, so rendered light reads as photographed. - `pointStars(p: Expr, opts: { /** Frequency of the per-point variation field relative to `p` (slow, about 0.1). */ variationFreq: number /** Point radius as `[base, jitter]`: base plus variation times jitter. */ radius: [number, number] /** The band of the variation field that keeps a point at all. Narrower is sparser. */ keep: [number, number] /** Brightness as `[base, gain]`: base plus variation squared times gain. */ brightness: [number, number] /** A per-point shimmer factor built from the variation field (see `twinkle`). */ shimmer?: (variation: Expr) => Expr /** Overall gain. */ gain: Expr /** Color the glints: variation mixes `from` to `to`, scaled by the glint times `gain`. */ tint?: {from: [number, number, number]; to: [number, number, number]; gain: number} hint?: string }): {glint: Expr; variation: Expr; rgb?: Expr}` — A plane of sparse glinting points: stars, glitter, dust. - `twinkle(t: Expr, phase: Expr, opts: {amount: Expr; rate: number; spread: number}): Expr` — A brightness factor that shimmers over time, different for each element. - `shellRefract(frame: SurfaceFrame, n: Expr, amount: Expr): { x: Expr y: Expr centered: {x: Expr; y: Expr} }` — Coordinates for what sits inside a glass shell, bent where the shell curves. - `rotationSensor(frame: SurfaceFrame): {x: Expr; y: Expr}` — How far a 3D shape has rotated, as a 2D pan you can move content by. - `nearestEdge(sdfUV: Expr, sdf: Expr, slope: Expr, hint: string = 'edge'): {point: Expr; normal: Expr}` — The closest point on the shape's edge to this pixel, and the outward normal there. - `continuedField(frame: SurfaceFrame, field: SurfaceField, params: GpuFragmentParams): {sdf: Expr; outward: Expr; at: (uv: Expr) => Expr}` — The distance field extended past the edge of an SVG shape's texture. - `fdCurvature(sampleAt: (p: Expr) => Expr, p: Expr, eps: number, hint: string = 'fd'): {value: Expr; dx: Expr; dy: Expr; curvature: Expr}` — The value, slope and curvature of any field at a point: `value`, `dx`, `dy` and `curvature`. - `sheenLobe(opts: { normal: Expr light: Expr view: Expr roughness: Expr | number gain?: Expr | number }): Expr` — The soft glow of light scattered off fibres where a surface turns edge-on to the viewer: the velvet sheen on the flanks of satin, velour and wool. ### Volumes (`import {volume} from 'shaders/std'`) — https://shaders.com/docs/primitives/volume Words for filling a shape with something you look through: smoke, gas, tinted glass, a starfield behind a window. They work inside a shape-effect material, the `surface:` of `shapedSurface` from `materials`. An **interior ray** is the line of sight through the shape: where it enters, how far it travels inside, and where it is at any depth. A **medium** is a density at each point inside. A **march** walks the ray front to back, adding up what each sample glows and how much it dims what lies behind it. - `interiorRay(field: SurfaceField, frame: SurfaceFrame, opts: {origin: {x: Expr; y: Expr}; view?: Expr; shear?: number; lengthScale?: number}): InteriorRay` — The line of sight through a shape: where it enters, how far it travels inside, and where it is at any depth. - `volumeMarch(opts: { steps: number entry: Expr length: Expr /** A per-pixel offset added to each step's position along the ray, as a fraction of the ray. */ jitter?: Expr /** A multiplier on every sample's `emit`. */ emissionGain?: Expr hint?: string }, sample: (step: VolumeMarchStep) => {emit: Expr; absorb: Expr}): {color: Expr; transmittance: Expr}` — Walk a ray through the medium front to back, adding up what glows and what dims. - `turbulentMedium(p: {x: Expr; y: Expr; z: Expr}, opts: {frequency: Expr; drift?: Expr; seed?: Expr; billow?: Expr; hint?: string}): {density: Expr; mid: Expr; fine: Expr}` — A billowing cloud density at a point inside the shape. - `parallaxPlane(ray: InteriorRay, opts: {depth: number; pan?: {x: Expr; y: Expr}; panRate?: number; hint?: string}): {x: Expr; y: Expr; z: Expr}` — A flat layer at a fixed depth inside the shape, like scenery seen through a window. ### Radiance (`import {radiance} from 'shaders/std'`) — https://shaders.com/docs/primitives/radiance Words for light a shape gives off or blocks. Colored point lights strike the shape's silhouette, the lit edges spill light into their surroundings, and the shape's body casts shadows, so light stays out of a ring's hole and off the far side of a wall. They work inside a shape-effect material, the `surface:` of `shapedSurface` from `materials`. The shape is a **signed distance**, a function from a point to its distance from the edge, and every word here marches rays against it. - `irradianceField(spec: IrradianceFieldSpec): { compute: GpuComputeNode sample: (params: GpuFragmentParams) => Expr | undefined }` — The light spilling from a shape's edges, gathered once into a texture and read per pixel. - `shadowVisibility(spec: ShadowSpec): Expr` — How much of a light reaches a point, 1 when nothing is in the way and 0 when the shape blocks it. - `gatherIrradiance(spec: GatherSpec): Expr` — The light arriving at a pixel from a glowing shape edge, with the shape's body blocking it. ### Voxels (`import {voxels} from 'shaders/std'`) — https://shaders.com/docs/primitives/voxels One word, `voxelSurface`, rebuilds any shape out of blocks. A flat shape becomes chunky pixel art, an SVG a slab of bricks, a 3D shape a lit voxel model. It asks you for one thing: the color of a single block. For that it hands your `surface` a **voxel frame**, everything a material needs already worked out: the block's normal, how open its surroundings are, how much shadow other blocks cast on it, its cell position, a random number that stays fixed to that block, how high and how deep it sits, and how close the pixel is to the face's edge. - `voxelSurface(spec: VoxelSurfaceSpec): ShapedSurfaceEffect` — Rebuild the shape from blocks and shade each block with your `surface`. ## Shapes, frames & warps ### Shapes (`import {shape} from 'shaders/std'`) — https://shaders.com/docs/primitives/shape The 2D shapes: a circle, a star, a heart and a dozen more, each as a function of a point that tells you how far that point is from the shape's edge. The number is a **signed distance**: negative inside, zero on the edge, positive outside. Sizes are in uv, where 1 is the canvas height. - `circle(x: Val, y: Val, radius: Val): Expr` — A circle of a given radius. - `ellipse(x: Val, y: Val, radiusX: Val, radiusY: Val): Expr` — An ellipse with separate horizontal and vertical radii. - `roundedRect(x: Val, y: Val, width: Val, height: Val, rounding: Val): Expr` — A rectangle with rounded corners. - `polygon(x: Val, y: Val, radius: Val, sides: Val): Expr` — A regular polygon with any number of sides. - `star(x: Val, y: Val, outerRadius: Val, sides: Val, innerRatio: Val): Expr` — A star with straight sides and sharp points. - `flower(x: Val, y: Val, outerRadius: Val, sides: Val, innerRatio: Val): Expr` — A flower with pointed petals and V-shaped valleys between them. - `heart(x: Val, y: Val, radius: Val): Expr` — A heart, point down at rotation 0. - `ring(x: Val, y: Val, radius: Val, thickness: Val): Expr` — A ring: a circular band around a centre. - `arc(x: Val, y: Val, radius: Val, halfAngle: Val): Expr` — A pie wedge: a filled sector of a circle. - `APERTURE_TO_HALF_ANGLE: 0.008726646259971648` — The factor that turns an opening angle in degrees into the half-angle `arc` takes. - `vesica(x: Val, y: Val, radius: Val, spread: Val): Expr` — A vesica: the lens where two equal circles overlap. - `crescent(x: Val, y: Val, outerRadius: Val, innerRatio: Val, offset: Val): Expr` — A crescent: a disc with a smaller disc bitten out of it. - `teardrop(x: Val, y: Val, radius: Val, height: Val): Expr` — A teardrop: a round bulb tapering to a sharp point, point up at rotation 0. - `cross(x: Val, y: Val, size: Val, thickness: Val, rounding: Val): Expr` — A plus-shaped cross with four equal arms. - `trapezoid(x: Val, y: Val, topWidth: Val, bottomWidth: Val, height: Val): Expr` — A trapezoid: a four-sided shape with a flat top and bottom of different widths. - `parallelogram(x: Val, y: Val, width: Val, height: Val, skew: Val): Expr` — A parallelogram: a rectangle with its top edge slid sideways. ### Frames & coordinates (`import {frames} from 'shaders/std'`) — https://shaders.com/docs/primitives/frames Frames are how a generator measures its pixels. Instead of raw uv you get named numbers ready to use: the distance from a centre, how far along and across a line between two points, or the axes of a chosen direction. `surfaceOf` is the starting point: the canvas's `uv` (0–1, y down), its size in pixels and its aspect ratio. Every frame is aspect-corrected, so 1 is the canvas height and a circle stays round on a wide canvas. - `surfaceOf(params: GpuFragmentParams): {uv: Expr; viewport: Expr; aspect: Expr}` — The canvas a generator paints on: its `uv`, its `viewport` size in pixels and its `aspect`. - `centredFrame(slots: {center: PropRef}): (params: GpuFragmentParams, surface: { uv: Expr; aspect: Expr; }) => CentredFrame` — A frame centred on a position prop: each pixel's offset from the centre and its distance. - `segmentFrame(slots: {from: PropRef; to: PropRef}): (params: GpuFragmentParams, surface: { uv: Expr; aspect: Expr; }) => SegmentFrame` — A frame along the line between two position props: how far each pixel is along it and across it. - `direction(angleDeg: Expr | number, hint: string = 'dir'): Expr` — A direction in degrees as a unit vector. - `directionFrame(angleDeg: Expr | number, hint: string = 'grain'): DirectionFrame` — The two axes of a direction given in degrees, for patterns that run along it. - `sectorFold(x: Expr, y: Expr, sectorAngle: Expr, center: number = 0.5): Expr` — Fold a point into one mirrored wedge around a centre: the kaleidoscope fold. - `rawSurfaceOf(params: GpuFragmentParams): {uv: Expr; viewport: Expr; aspect: Expr}` — The canvas like `surfaceOf`, but always measured against the whole canvas, never a fitted box. ### Warps (`import {warps} from 'shaders/std'`) — https://shaders.com/docs/primitives/warps Words for the `map:` field. A **warp** is a component that moves the pixels of the layer inside it (the child): for every pixel on screen, the map says where in the child to look. Twisting, bulging, mirroring, tilting and wiping are all warps. Positions are in uv (0–1 across the canvas, y down) and angles are in degrees. - `twirl(slots: {center: ArgSpec; intensity: ArgSpec}): UvMapSource` — Twist the child around `center`, turning more the farther a pixel is from it. - `bulge(slots: {center: ArgSpec; strength: ArgSpec; radius: ArgSpec; falloff: ArgSpec}): UvMapSource` — Magnify or pinch the child inside a disc around `center`. - `mirrorLine(slots: {center: ArgSpec; angle: ArgSpec}): UvMapSource` — Mirror the child across a line through `center` at `angle`. - `flip(slots: {flipX: ArgSpec; flipY: ArgSpec}): UvMapSource` — Flip the child horizontally, vertically, or both. - `kaleidoscope(slots: {center: ArgSpec; segments: ArgSpec; angle: ArgSpec}): UvMapSource` — Fold the child into mirrored pie slices around `center`. - `perspective(slots: { center: ArgSpec pan: ArgSpec tilt: ArgSpec fov: ArgSpec zoom: ArgSpec offset: ArgSpec }): UvMapSource` — Tilt the child in 3D, as if it were a card turned away from the camera. - `cornerPin(slots: { topLeft: ArgSpec topRight: ArgSpec bottomRight: ArgSpec bottomLeft: ArgSpec amount: ArgSpec }): UvMapSource` — Pin the four corners of the child to new positions, with true perspective between them. - `bend(slots: {strength: ArgSpec; falloff: ArgSpec; angle: ArgSpec}): UvMapSource` — Curve the child like a bent sheet seen in perspective, so its ends swell or shrink. - `stretch(slots: {center: ArgSpec; strength: ArgSpec; angle: ArgSpec; falloff: ArgSpec}): UvMapSource` — Stretch the child along one direction, starting at `center`. - `wave(slots: {strength: ArgSpec; frequency: ArgSpec; angle: ArgSpec; waveType: PropRef}): UvMapSource` — Ripple the child with a travelling wave. - `flowNoise(slots: {strength: ArgSpec; detail: ArgSpec; seed: PropRef}): UvMapSource` — Push the child around with a slowly flowing liquid motion. - `toPolar(slots: {center: ArgSpec; wrap: ArgSpec; radius: ArgSpec; intensity: ArgSpec}): UvMapSource` — Unroll the child around `center`, so angle becomes x and distance becomes y. - `fromPolar(slots: {center: ArgSpec; scale: ArgSpec; intensity: ArgSpec}): UvMapSource` — Wrap the child into a circle around `center`, reading its x as angle and its y as distance. - `concentricRings(slots: { center: ArgSpec intensity: ArgSpec rings: ArgSpec smoothness: ArgSpec seed: ArgSpec speedRandomness: ArgSpec }): UvMapSource` — Cut the child into rings around `center` and spin each ring by its own amount. - `barOffset(slots: {count: ArgSpec; angle: ArgSpec; intensity: ArgSpec; seed: ArgSpec}): UvMapSource` — Cut the child into parallel bars and shift each one sideways by a random amount. - `slicedSlide(slots: {angle: ArgSpec; count: ArgSpec; progress: ArgSpec}): UvMapSource` — Slice the child into strips that slide out of frame in alternating directions. - `liquidDisplace(slots: {intensity: ArgSpec; output: string}): UvMapSource` — Move the child smoothly by a displacement field your own simulation produces. - `gridCellDisplace(slots: {gridSize: ArgSpec; output: string}): UvMapSource` — Move the child by a displacement field your own simulation produces, one grid cell at a time. - `displaceByLayer(slots: { source: PropRef amount: ArgSpec channels: PropRef angle: ArgSpec edges: PropRef }): GatherEffect` — Distort the child using another layer's pixels as a displacement map. ### Masks (`import {mask} from 'shaders/std'`) — https://shaders.com/docs/primitives/mask A mask is coverage: a number from 0 to 1 at every pixel that says how much of something shows there. Multiply it into a color's alpha to cut a shape out of a paint, or hand it to an effect as its amount so the effect fades in across the canvas. Most masks start from a distance, how far this pixel is from a center, a line or a shape's edge, and the mask word turns that distance into an edge. `softDisc` and `softBand` give soft, styled edges for orbs and curtains. `crispFill` and `crispStroke` give clean anti-aliased fills and outlines from a signed distance, such as one of the `shape` words. `radialMask` is the ready-made one for effects: 0 at a center, 1 past a radius, plugged straight into an effect's amount. - `radialMask(slots: {center: PropRef; radius: PropRef; falloff: PropRef}): Scalar` — An amount that is 0 near a center and grows to 1 with distance, for an effect's strength. - `softDisc(opts: { dist: Expr radius: Expr | number softness: {width: Expr | number; curve: Expr | number} }): Expr` — A filled disc with a soft, shaped edge. - `crispFill(opts: {distance: Expr; footprint: Expr | number}): Expr` — A clean fill of a shape: 1 inside, 0 outside. - `crispStroke(opts: {distance: Expr; width: Expr | number; footprint: Expr | number}): Expr` — A clean outline of a shape, or a drawn curve, of a given width. - `softBand(opts: { distance: Expr below: {from: Expr | number; to: Expr | number} above: {from?: Expr | number; to: Expr | number} }): Expr` — A soft band around a line, sharp on one side and long on the other. ### Math (`import {math} from 'shaders/std'`) — https://shaders.com/docs/primitives/math The arithmetic you write your own paint with. Every word takes expressions or plain numbers and returns an expression the GPU works out once per pixel: `mul(color, coverage)` fades a color, `smoothstep(a, b, dist)` turns a distance into a soft mask, `mix(a, b, t)` blends two colors. Props reach you as `params.uniforms.` (or `uniformOf(p('name'), params)`), a frame gives you the coordinate, and the words compose by nesting until you return a `vec4` color from `paint:`. Wrap anything you read twice in `local` so it is computed once. - `add(a: Val, b: Val): Expr` — The sum of two values. - `sub(a: Val, b: Val): Expr` — The first value minus the second. - `mul(a: Val, b: Val): Expr` — The product of two values. - `div(a: Val, b: Val): Expr` — The first value divided by the second. - `mix(a: Val, b: Val, t: Val): Expr` — A blend from `a` to `b` by `t`, where 0 gives `a` and 1 gives `b`. - `smoothstep(e0: Val, e1: Val, x: Val): Expr` — A soft edge: 0 below `e0`, 1 above `e1`, an S-curve between. - `clamp(x: Val, lo: Val, hi: Val): Expr` — The value limited to the range `lo`..`hi`. - `local(e: Expr, hint: string): Expr` — A value computed once per pixel and shared by everything that reads it. - `vec4(...parts: Val[]): Expr` — A 4D vector, usually the final color with alpha. - `vec3(x: Val, y: Val, z: Val): Expr` — A 3D vector from three values, often a color without alpha. - `vec2(x: Val, y: Val): Expr` — A 2D vector from two values. - `splat3(x: Val): Expr` — One number copied into all three channels of a vec3. - `length(v: Val): Expr` — The length of a vector. - `distance(a: Val, b: Val): Expr` — The distance between two points. - `abs(x: Val): Expr` — The value without its sign. - `fract(x: Val): Expr` — The fractional part of a value, 0..1. - `floor(x: Val): Expr` — The value rounded down to a whole number. - `min(a: Val, b: Val): Expr` — The smaller of two values. - `max(a: Val, b: Val): Expr` — The larger of two values. - `sin(x: Val): Expr` — The sine of an angle in radians, −1..1. - `cos(x: Val): Expr` — The cosine of an angle in radians, −1..1. - `step(edge: Val, x: Val): Expr` — A hard edge: 0 when `x` is below `edge`, 1 from `edge` on. - `pow(x: Val, y: Val): Expr` — The first value raised to the power of the second. - `exp(x: Val): Expr` — e raised to the value. - `sqrt(x: Val): Expr` — The square root of a value. - `neg(a: Val): Expr` — The value with its sign flipped. - `select(cond: Expr, ifTrue: Val, ifFalse: Val): Expr` — `ifTrue` when the condition holds, otherwise `ifFalse`. - `lt(a: Val, b: Val): Expr` — True when `a` is less than `b`. - `gt(a: Val, b: Val): Expr` — True when `a` is greater than `b`. - `le(a: Val, b: Val): Expr` — True when `a` is less than or equal to `b`. - `ge(a: Val, b: Val): Expr` — True when `a` is greater than or equal to `b`. - `atan2(y: Val, x: Val): Expr` — The angle of the point (x, y) in radians, −π..π. - `dot(a: Val, b: Val): Expr` — The dot product of two vectors. - `normalize(v: Val): Expr` — The vector scaled to length 1. - `rotate2(p: Val, cosA: Val, sinA: Val): Expr` — A 2D point rotated around the origin. - `gaussBell(x: Expr, k: Val): Expr` — A bell curve: 1 at zero, falling toward 0 on both sides. - `softPlus(x: Expr, k: Val): Expr` — A soft hinge: about 0 for values well below zero, about `x` above, rounded near zero. - `hashPhase(seed: Val, salt: {k: number; big: number}): Expr` — A random but stable angle in radians, 0..2π, from a seed. - `sign(x: Val): Expr` — −1, 0 or 1 by the sign of the value. - `ceil(x: Val): Expr` — The value rounded up to a whole number. - `log(x: Val): Expr` — The natural logarithm of a value. - `exp2(x: Val): Expr` — 2 raised to the value. - `tan(x: Val): Expr` — The tangent of an angle in radians. - `cross(a: Val, b: Val): Expr` — The cross product of two 3D vectors. - `reflect(i: Val, n: Val): Expr` — The direction `i` bounced off a surface with unit normal `n`. - `refract(i: Val, n: Val, eta: Val): Expr` — The direction `i` bent through a surface with unit normal `n`. - `float(n: number): Expr` — A plain number as an expression. ### Motion & timing (`import {motion} from 'shaders/std'`) — https://shaders.com/docs/primitives/motion Words that turn a clock into rhythm. The clock is a number of seconds: declare `animatedTime: {speed: 'speed'}` on the definition and read the layer's clock with `animatedTime(params)`, and a speed prop and a pause button come for free. `cycle` splits that clock into "which pass is this" and "how far through it are we", `cycleSeed` gives each pass a stable random number, `oscillate` and `pulseTrain` shape it into a sweep or a blink, and the easings bend a 0..1 progress. The result is a number you multiply into a color, a radius or a coordinate. - `oscillating(opts: {rate?: number; min?: Expr | number; max?: Expr | number; offset?: number; clock?: SignalClock}): Scalar` — A knob that sweeps between `min` and `max` on its own, for any slot that takes a prop. - `pulsing(opts: {period: number; duty: number; soften?: number; clock?: SignalClock}): Scalar` — A knob that switches on and off in a rhythm, for any slot that takes a prop. - `cycle(t: Expr, period: Expr | number): {progress: Expr; index: Expr}` — A repeating cycle as two numbers: `progress` (0..1 through the current cycle) and `index` (which cycle this is). - `cycleSeed(index: Expr, salt: number = 0): Expr` — A random but stable number, 0..1, for each cycle index. - `oscillate(t: Expr, opts: {rate?: number; min?: Expr | number; max?: Expr | number; offset?: number}): Expr` — A smooth back-and-forth between `min` and `max`. - `pulseTrain(t: Expr, opts: {period: Expr | number; duty: Expr | number; soften?: number}): Expr` — An on/off rhythm: 1 for the first part of each cycle, 0 for the rest. - `phase(t: Expr, period: Expr | number): Expr` — How far through a repeating cycle the clock is, 0..1. - `easeInOut(x: Expr): Expr` — A 0..1 value that starts slow, speeds up, and slows again at the end. - `easeOut(x: Expr): Expr` — A 0..1 value that starts fast and slows to a stop. - `easeIn(x: Expr): Expr` — A 0..1 value that starts slow and speeds up. - `flashes(t: Expr, opts: {rate: Expr | number; offset?: Expr | number; sharpness: 2 | 4 | 8 | 16}): Expr` — Short, bright flashes at a steady rate: dark most of the time, peaking briefly to 1. ### Signals (`import {signal} from 'shaders/std'`) — https://shaders.com/docs/primitives/signal Live inputs a simulation reads every frame: where the pointer is and how fast it is moving. You never read the numbers yourself. You hand a signal to a simulation step, such as the splat step of a grid simulation, and the engine tracks the pointer, measures its speed in uv per second, and feeds both in. `pointer` carries one choice, the teleport guard, which stops a cursor that jumps into the canvas from slamming the field. `pointerSpeed` caps the speed so a fast flick cannot overdrive it. Both are also exported at the top level of `shaders/std`. - `pointer(opts?: {teleportGuard?: 'on' | 'off'}): PointerSignal` — The pointer's position, for a simulation step that reacts to the cursor. - `pointerSpeed(opts?: {max?: number}): PointerSpeedSignal` — The pointer's speed, capped at `max`, as the strength of a simulation step. - `cpuHash01(x: number): number` — A random but stable number, 0..1, from a seed, computed in JavaScript. ## Filters & effects ### Filter effects (`shaders/std` top level) — https://shaders.com/docs/primitives/filter Words for the `effect:` field. A **filter** is a component that changes the layer inside it (the child). A definition with an `effect:` is a filter, nothing else to declare. - `tintToward(color: PropRef, opts: {amount: ScalarInput}): TintTowardEffect` — Mix the child's color toward one color by an amount, leaving its alpha alone. - `paintThrough(paint: Paint, opts: {by?: 'alpha' | 'luminance'} = {}): PointwiseEffect` — Show a paint through the child, so the child becomes the mask. - `displaceBy(field: import('./sim').SimOutputRef, opts: {strength: PropRef; chromatic: PropRef; edges: PropRef}): DisplaceByEffect` — Push the child's pixels around by a vector field from one of your simulations. - `pointwise(config: Omit): PointwiseEffect` — Write your own pointwise effect: a function of the child's color at this pixel. - `gather(config: Omit): GatherEffect` — Write your own gather effect: a function that can read the child anywhere. ### Color effects (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.color Words that recolor the layer inside them, one pixel at a time. Each returns a **pointwise effect** for a filter definition's `effect:` field: it reads the child's color at this pixel and returns the adjusted color, with alpha kept. Nothing is sampled from neighbouring pixels, so these filters are cheap and stack freely. Pass props with `p('name')`; the units are the ones the word names (degrees, 0–1 amounts, a multiplier around 1). - `saturate(intensity: ArgSpec): PointwiseEffect` — Scale the child's saturation. - `vibrance(intensity: ArgSpec): PointwiseEffect` — Boost muted colors while leaving already-vivid ones mostly alone. - `hueRotate(shift: ArgSpec): PointwiseEffect` — Rotate the child's hue around the color wheel. - `brightnessContrast(slots: {brightness: ArgSpec; contrast: ArgSpec}): PointwiseEffect` — Adjust the child's brightness and contrast together. - `exposure(gain: ArgSpec): PointwiseEffect` — Multiply the child's brightness, like opening a camera's aperture. - `grayscale(): PointwiseEffect` — Turn the child black and white, weighted the way the eye sees brightness. - `invert(): PointwiseEffect` — Flip every color of the child to its negative. - `solarize(slots: {threshold: ArgSpec; strength: ArgSpec}): PointwiseEffect` — Invert only the bright parts of the child, the darkroom solarization look. - `posterize(steps: ArgSpec): PointwiseEffect` — Reduce the child to a few flat color levels, like a screen-printed poster. - `tint(slots: {color: PropRef; amount: ArgSpec; preserveLuminosity: PropRef}): PointwiseEffect` — Wash the child toward one color. - `duotone(slots: {colorA: PropRef; colorB: PropRef; blend: ArgSpec; colorSpace: PropRef}): PointwiseEffect` — Repaint the child in two colors: `colorA` for the shadows, `colorB` for the highlights. - `tritone(slots: {colorA: PropRef; colorB: PropRef; colorC: PropRef; blendMid: ArgSpec; colorSpace: PropRef}): PointwiseEffect` — Repaint the child in three colors: `colorA` for the shadows, `colorB` for the midtones, `colorC` for the highlights. - `gradientMap(slots: { palette: PropRef colorLow: PropRef colorMid: PropRef colorHigh: PropRef speed: PropRef contrast: ArgSpec blackPoint: ArgSpec whitePoint: ArgSpec strength: PropRef colorSpace: PropRef }): PointwiseEffect` — Recolor the child by its brightness through a gradient, the Photoshop gradient map. - `filmGrain(slots: {strength: ArgSpec; bias: ArgSpec; animated: PropRef}): PointwiseEffect` — Sprinkle film grain over the child, heaviest in the shadows. - `isolines(slots: { source: PropRef levels: ArgSpec lineWidth: ArgSpec softness: ArgSpec gamma: ArgSpec invert: ArgSpec colorMode: PropRef lineColor: PropRef backgroundColor: PropRef }): PointwiseEffect` — Draw topographic contour lines over the child, traced from its brightness or its alpha. - `lutAtlasGrade(slots: { select: PropRef strength: PropRef size: number decode: (key: string) => Uint8Array fallback: string label: string }): (color: Expr, params: FilterParams | GpuFragmentParams) => Expr` — Grade a color through a measured 3D color lookup table (LUT), the film-stock look. ### Blurs, glows & screens (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.blurs Effects that read the layer inside them (the child) as a texture and rebuild it: blurs, glows, sharpening, pixelation, shadows, retro screens, glitches, fluted glass, page peels and mirror floors. A **pointwise** effect edits the child's color at one pixel; the words here are **gather** effects, which sample the child at other pixels too, so they can smear, spread and displace it. Every word here goes in a filter definition's `effect:` field, or spreads into a definition when it needs its own pass over the child first. - `gaussianBlur(opts: {intensity: PropRef}): ComputeBackedEffect` — A soft, even blur of the child. - `motionBlur(opts: {path: BlurPathSpec; amount: ArgSpec; detail?: MotionBlurDetailSlots}): GatherEffect` — Smears the child along a path: a straight streak, an arc around a point, or a zoom out of a point. - `progressiveBlur(opts: { intensity: PropRef angle: PropRef center: PropRef falloff: PropRef detail?: VariableBlurDetailSlots }): ComputeBackedEffect` — A blur that ramps from sharp to full strength in one direction across the child. - `tiltShift(opts: { intensity: PropRef width: PropRef falloff: PropRef angle: PropRef center: PropRef detail?: VariableBlurDetailSlots }): ComputeBackedEffect` — Keeps a band of the child in focus and blurs everything beyond it, like a tilt-shift lens. - `bloom(opts: {intensity: PropRef; threshold: PropRef; size: PropRef}): ComputeBackedEffect` — A glow: the child's bright parts spread into a soft halo that adds back on top. - `bokehDefocus(opts: { radius: PropRef gain: PropRef threshold: PropRef shape: PropRef blades: PropRef rotation: PropRef fringe: PropRef catEye?: PropRef }): {compute: GpuComputeNode; gpu: {fragment: (params: GpuFragmentParams) => Expr}}` — A photographic lens blur where bright highlights bloom into aperture-shaped discs. - `channelBlur(opts: {red: PropRef; green: PropRef; blue: PropRef}): ComputeBackedEffect` — Blurs red, green and blue by separate amounts, for a soft chromatic fringe. - `scatter(opts: {amount: ArgSpec; edges: PropRef; chromatic?: PropRef}): GatherEffect` — Scatters every pixel of the child by a random offset: a grainy diffusion, not a smooth blur. - `sharpen(amount: ArgSpec): GatherEffect` — Sharpens the child by boosting the contrast between each pixel and its neighbours. - `pixelate(opts: {scale: ArgSpec; gap: ArgSpec; roundness: ArgSpec}): GatherEffect` — Turns the child into a grid of flat cells, each showing one color. - `gatherStack(sample: SampleStage, overlays: OverlayStage[], opts?: {resultAlpha?: 'premultiplied' | 'straight'}): GatherEffect` — Assemble an effect from one sampling stage and an ordered list of overlay stages. - `childTap(): SampleStage` — The child's own color at this pixel, unchanged. - `shadowOffset(opts: {angle: ArgSpec; distance: ArgSpec}): (params: RttFilterParams) => Expr` — The coordinate a shadow reads the child's silhouette from: `distance` away in the compass direction `angle`. - `silhouetteCoverage(opts: {at: (params: RttFilterParams) => Expr; blur: ArgSpec}): (params: RttFilterParams) => Expr` — A soft copy of the child's alpha silhouette: a number per pixel from 0 to 1. - `shadowComposite(opts: { coverage: (params: RttFilterParams) => Expr color: PropRef intensity: ArgSpec cutout: PropRef }): OverlayStage` — A tinted shadow behind the child. - `rgbSplit(opts: {amount: ArgSpec}): SampleStage` — The child with its red and blue pulled a little to either side, like a misaligned CRT. - `adjust(opts: {brightness: ArgSpec; contrast: ArgSpec}): OverlayStage` — Brightness and contrast, pivoting around mid-grey. - `scanlines(opts: {frequency: ArgSpec; intensity: ArgSpec}): OverlayStage` — Horizontal scanlines darkening the child in a smooth wave. - `phosphorMask(opts: {pitch: ArgSpec}): OverlayStage` — A faint red, green and blue phosphor stripe pattern across the child. - `vignetteOverlay(opts: {radius: ArgSpec; intensity: ArgSpec}): OverlayStage` — Darkens the child toward its corners. - `opaque(): OverlayStage` — Closes a three-channel stack as a solid color with alpha 1. - `tapeWarp(opts: {wobble: ArgSpec; jitter: ArgSpec; speed: ArgSpec}): (params: RttFilterParams) => Expr` — The wobbling, jittering coordinates of a worn VHS tape, to feed into `chromaSmearTaps`. - `chromaSmearTaps(opts: {warp: (params: RttFilterParams) => Expr; smear: ArgSpec}): SampleStage` — The child sampled like a VHS deck: brightness stays sharp while color bleeds sideways. - `beatPulse(opts: {wobble: ArgSpec; speed: ArgSpec}): OverlayStage` — A faint brightness throb, like the mains hum of an old television. - `glitchFrame(opts: { intensity: ArgSpec speed: ArgSpec blockDensity: ArgSpec mirrorAmount: ArgSpec }): GatherFrame` — The shared geometry of a digital glitch: when bursts fire, which horizontal bands jitter, and which blocks shift or flip. - `glitchRgbSplit(frame: GatherFrame, opts: {shift: ArgSpec}): SampleStage` — The child sampled through a glitch frame, with red and blue pulled apart inside the active bands. - `colorBarFills(frame: GatherFrame, opts: {intensity: ArgSpec}): OverlayStage` — Neon color bars filling the blocks a glitch frame currently has active. - `distortedScanlines(frame: GatherFrame, opts: {intensity: ArgSpec}): OverlayStage` — CRT-style scanlines that appear only where a glitch frame is currently distorting. - `sphereFrame(opts: {center: ArgSpec; radius: ArgSpec; depth: ArgSpec}): GatherFrame` — The geometry of a sphere bulging out of the canvas: where each pixel reads the child from, where the sphere ends, and which way its surface faces. - `crispTap(frame: GatherFrame): SampleStage` — One clean sample of the child at a frame's warped coordinate. - `rimLit(frame: GatherFrame, opts: { position: ArgSpec intensity: ArgSpec softness: ArgSpec color: PropRef }): OverlayStage` — A tinted rim of light around the edge of a bulged surface, added on top of the child's color. - `fluteFrame(opts: { shape: PropRef angle: ArgSpec frequency: ArgSpec softness: ArgSpec waveAmplitude: ArgSpec waveFrequency: ArgSpec refraction: ArgSpec aberration: ArgSpec }): GatherFrame` — The geometry of fluted (reeded) glass over the child: where each pixel reads through the glass, how far its colors split, and the slope of the flute at that point. - `refractedTaps(frame: GatherFrame, opts: {aberration: PropRef; edges: PropRef}): SampleStage` — The child seen through a flute frame, with edge handling and a color split when `aberration` is above 0. - `fluteHighlight(frame: GatherFrame, opts: { lightAngle: ArgSpec highlight: ArgSpec softness: ArgSpec color: PropRef }): OverlayStage` — A specular highlight running along each flute, added on top of the child's color. - `peelFrame(opts: {corner: PropRef; amount: ArgSpec; radius: ArgSpec}): GatherFrame` — The geometry of a page curling up from one corner: where the curl reads the child from, how far it has turned, and how far each pixel is from the crease. - `peelCompose(frame: GatherFrame, parts: { shade: PeelShade sheen: PeelShade overhang: PeelShade reveal: PeelShade }): SampleStage` — A finished page peel: the cast shadows, the flat page and the lit curl, layered back to front. - `curlShading(frame: GatherFrame, opts: {shading: ArgSpec}): PeelShade` — The darkening in the crook of a curl, easing to full brightness at the lip. - `curlSheen(frame: GatherFrame, opts: {highlight: ArgSpec; softness: ArgSpec}): PeelShade` — The band of light running up a curl. - `overhangShadow(frame: GatherFrame, opts: {amount: ArgSpec; shadow: ArgSpec}): PeelShade` — The shadow a lifted curl casts on the flat page just past the crease. - `revealShadow(frame: GatherFrame, opts: {amount: ArgSpec; shadow: ArgSpec}): PeelShade` — The shadow on the surface a peel reveals, just inside the crease. - `mirrorAcrossRow(line: PropRef): (params: GpuFragmentParams) => Expr` — The coordinate mirrored across a horizontal line, for reading a reflection below it. - `depthRampBlur(opts: {line: PropRef; blur: PropRef; blurDistance: PropRef; halfKernel: number}): {compute: GpuComputeNode}` — The blur half of a mirror floor: blurs the child more the further a row sits below the line. - `planarReflection(opts: {line: PropRef; distance: PropRef; falloff: PropRef; edges: PropRef}, original: Expr, reflection: (uv: Expr) => Expr, reflectedUV: (params: GpuFragmentParams) => Expr): (params: GpuFragmentParams) => Expr` — A mirror floor: the child as it is above a line, and its reflection fading out below it. - `screenedBloom(slots: { strength: PropRef radius: PropRef tint: [number, number, number] threshold: number output: string extractName: string }): { compute: GpuComputeNode screen: (base: Expr, at: Expr, params: GpuFragmentParams) => Expr }` — A tinted glow of the child's bright parts, screened over a color you have already graded: film halation, phosphor bloom. - `frameSway(slots: {amount: PropRef; field: string}): (params: GpuFragmentParams) => Expr` — A slight drifting shift and rotation of where the child is read from, like film in an unsteady projector gate. - `blurPath.linear(angle: PropRef): BlurPathSpec` — A straight streak along an angle prop, in degrees (0 points right, 90 points down). - `blurPath.orbit(center: PropRef): BlurPathSpec` — An arc streak rotating around a center prop (a position in uv). - `blurPath.zoom(center: PropRef): BlurPathSpec` — A radial streak rushing outward from a center prop (a position in uv). - `brightestNear(read: (uv: Expr) => Expr, center: Expr, opts: {radius: Expr; taps: number; angle?: number}): { color: Expr luma: Expr }` — The brightest color in a small ring around a point: the layer grown outward, so a spot just outside a bright area still reads as bright. ### Stylize (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.stylize Hand-made looks for the layer inside: a watercolor wash, a chalk drawing on a board, ASCII characters, and copper-plate line engraving. Each look is a recipe of two or three words. A **stage** is one piece of the look that reads the layer once it is rendered to a texture (a wobbled sample position, a brush, a ring of edge samples, a character grid). Build a stage once and hand the same one to every word that needs it, so they agree. The closing word (`wash`, `chalkSketch`, `linework`) returns the effect for `effect:`. The ASCII look closes with `glyphTint`, which returns a fragment for `gpu.fragment` because it also needs a character atlas drawn on the CPU. - `wash(slots: { at: GatherStage brush: KuwaharaBrush grain: GatherStage paper: PropRef paperColor: PropRef strength: PropRef }): GatherEffect` — The watercolor look: the layer inside flattened into soft patches of color over paper grain. - `kuwahara(slots: {at: GatherStage; radius: PropRef}): KuwaharaBrush` — A painter's brush: the flattening that turns fine detail into soft patches of one color. - `bleedWarp(slots: {amount: PropRef}): GatherStage` — A sample position that drifts slowly past hard edges, so paint bleeds instead of stopping. - `paperGrain(slots: {amount: PropRef}): GatherStage` — Fine paper grain for the pigment to settle into, one brightness value per screen pixel. - `chalkSketch(slots: { edges: SobelRing sensitivity: PropRef hatchScale: PropRef shading: PropRef grain: PropRef board: PropRef chalk: PropRef }): GatherEffect` — The chalk-drawing look: edges become chalk strokes and dark areas fill with cross-hatching. - `sobelTaps(slots: {spacing: PropRef}): SobelRing` — Eight brightness samples in a ring around each pixel, for finding edges. - `linework(slots: { style: PropRef frequency: PropRef angle: PropRef center: PropRef relief: PropRef waviness: PropRef contrast: PropRef ink: PropRef paper: PropRef }): GatherEffect` — The engraving look: the layer inside redrawn as ink lines that swell where it is dark. - `glyphTint(slots: { grid: FragmentStage cell: FragmentStage glyph: FragmentStage alphaThreshold: PropRef preserveAlpha: PropRef }): FragmentStage` — The finished ASCII look: each character tinted with its cell's color, everything else transparent. - `glyphFor(slots: { grid: FragmentStage cell: FragmentStage gamma: PropRef atlas: (params: GpuFragmentParams) => KitTexture }): FragmentStage` — The character drawn in each cell, picked by how bright the cell is. - `charGrid(slots: {cellSize: PropRef; spacing: PropRef}): FragmentStage` — The character grid: which cell each pixel falls in, and where it sits inside that cell. - `cellSample(slots: {grid: FragmentStage}): FragmentStage` — The color of the layer inside at the centre of each character cell. ### Lens (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.lens Words for the color fringing a real lens leaves behind: the red, green and blue copies of the layer inside pushed apart, or fanned out into a whole spectrum. Because they read the child at several places per pixel, these are **gather effects**: the child is rendered to a texture first and the effect samples it. `chromaticFan` is a sampling stage; hand it to `gatherStack` (from `effects.blurs`) to turn it into the `effect:` of a filter definition, optionally followed by more stages. `spectralLens` is a complete fragment for a `gpu:` definition, with the lens warp, focus zones and grain built in. - `chromaticFan(opts: { strength: ArgSpec angle: ArgSpec red: ArgSpec green: ArgSpec blue: ArgSpec }): SampleStage` — Split the child into red, green and blue copies pushed apart along one direction. - `spectralLens(slots: SpectralLensSlots): (params: GpuFragmentParams) => Expr` — Fan the child out into many color-shifted copies through a warped lens, the spectral-lens look. ### Reveals & wipes (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.reveal Words that make the layer inside disappear in a chosen order: a straight edge, a growing circle, a clock sweep, a grid of blocks, a noise dissolve. Every wipe is the same effect, `reveal`, fed a different **coverage**: a number per pixel from 0 to 1 that says when that pixel goes (0 first, 1 last). As the `progress` prop climbs from 0 to 1, pixels whose coverage falls below it fade out across a soft front `feather` wide. - `reveal(slots: RevealSlots): PointwiseEffect` — Fade the child away in coverage order as `progress` goes from 0 to 1. - `coverage.directional(angleDeg: ArgSpec): Coverage` — A straight edge sweeping across the canvas. - `coverage.radial(center: ArgSpec): Coverage` — A circle growing out from `center`, an iris wipe. - `coverage.angular(center: ArgSpec, startDeg: ArgSpec, direction: PropRef | AngularDirection): Coverage` — A clock hand sweeping around `center`. - `coverage.cells(size: ArgSpec): CellCoverage` — A grid of square cells `size` wide. - `coverage.noise(scale: ArgSpec, seed: ArgSpec): Coverage` — Soft blobs eating the image away, the classic film dissolve. - `class Coverage` — The order pixels disappear in: a number per pixel from 0 (goes first) to 1 (goes last). - `class BandedCoverage` — A coverage cut into bands. - `class CellCoverage` — The canvas cut into a grid of square cells, waiting for you to pick the order the cells go in. ### Instances (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.instances Repeat the layer inside. `repeatInstances` draws many copies of it, laid out in a grid, around a circle or along a line, each copy scaled, turned, faded and jittered a little more than the last. It returns the fragment for `gpu.fragment`. The layout words (`grid`, `radial`, `line`) say where the copies go, `byMode` lets one select prop switch between all three, and the recipe's `variation` object says how the copies differ. - `repeatInstances(recipe: RepeatInstancesRecipe): (params: GpuFragmentParams) => Expr` — Many copies of the layer inside, laid out and varied as the recipe says. - `grid(slots: GridSlots): PlacementSpec` — Copies in rows and columns, filling this layer's bounding box. - `radial(slots: RadialSlots): PlacementSpec` — Copies around a circle centred on the layer inside. - `line(slots: LineSlots): PlacementSpec` — Copies in a row, marching away from the layer inside in one direction. - `byMode(mode: PropRef, members: PlacementPick['members']): PlacementPick` — Lets one select prop switch between a grid, a radial and a linear layout. ### Fracture (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.fracture Broken glass. The canvas splits into **shards** around a set of random sites; a pixel belongs to the nearest site. Where a shard has moved, a **crack** opens along its border with the next-nearest shard, and the layer inside bends and colour-splits across it like light through a prism. `voronoiRegionField` is the compute hook (for `compute:`) that finds each pixel's shard and the next-nearest one; it only recomputes when the seed changes. The crack words run in the fragment: `crackGeom` measures the crack at a pixel, `crackRefractUV` bends one colour channel across it, and `crackShardCompose` joins the three channels with a little light on tilted shards. - `voronoiRegionField(opts: { count: number size: number sites: (seed: number) => Float32Array seedProp: string seedDefault: number output: string }): GpuComputeNode` — Splits the canvas into shards around random sites and records, per pixel, its shard and the next-nearest one. - `crackGeom(uv: v2f, nPosX: number, nPosY: number, sPosX: number, sPosY: number, dispX: number, dispY: number, crackWidth: number): { crackIntensity: number; edgeNormal: v2f; displacedUV: v2f; disp: v2f; }` — How much crack there is at a pixel, and which way the shard under it has moved. - `crackRefractUV(displacedUV: v2f, edgeNormal: v2f, crackIntensity: number, refractionStrength: number, chromaticSplit: number, channel: number): v2f` — Where to sample one color channel so the crack bends the light and splits it like a prism. - `crackShardCompose(normalColor: v4f, rFinal: v4f, gFinal: v4f, bFinal: v4f, crackIntensity: number, disp: v2f, shardLighting: number): v4f` — The finished glass: the three refracted channels blended into the crack, with a hint of light on tilted shards. - `cellLaneUVFor(laneWidth: number): TgpuFn<(idx: F32, field: F32) => Vec2f>` — Where one shard's value sits in a one-row data texture. ### Edge glow (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.edgeGlow A band of light hugging the edge of any shape, with coloured spots racing around it. The words live inside a `shapedSurface` surface function (from `materials`), which hands them the shape's **distance field**: for every pixel, how far it is from the shape's edge, negative inside. `edgeGlowBand` turns that distance into the glowing band (with drifting smoke) and also gives the angle around the shape. `orbitSpotsAccum` places one colour's spots along that angle. The spots of every colour are folded together, starting from `edgeGlowAccumZero` and adding one colour at a time with the step from `edgeGlowAccumColorFor`, and `edgeGlowCompose` turns the fold into the final colour with bloom. `heartbeatPulse` is the beat the band and the spots share. - `edgeGlowBand(fieldRaw: number, sdfUV: v2f, viewport: v2f, scale: number, thickness: number, softness: number, smokeSize: number, smokeAmt: number, animTime: number, pulse: number, beat: number): v2f` — The glowing band around the shape's edge, with drifting smoke, plus the angle around the shape. - `orbitSpotsAccum(angle01: number, border: number, animTime: number, beat: number, spotsF: number, spotSize: number, pulse: number, intensity: number, softness: number, seed: number, colorIdxF: number): v2f` — The spots of one color orbiting the band, as coverage at this pixel. - `heartbeatPulse(animTime: number): number` — A double heartbeat, 0 to 1, driven by the layer's clock. - `edgeGlowAccumZero(): { rgb: v3f; w: number; ba: number; ac: v3f; aa: number; }` — The empty state to start folding colors into. - `edgeGlowAccumColorFor(mode: number): TgpuFn<(st: WgslStruct<{ rgb: Vec3f; w: F32; ba: F32; ac: Vec3f; aa: F32; }>, color: Vec4f, sectors: Vec2f) => WgslStruct<{ rgb: Vec3f; w: F32; ba: F32; ac: Vec3f; aa: F32; }>>` — The fold step for one color space: adds one color's spots to the running state. - `edgeGlowCompose(st: { rgb: v3f; w: number; ba: number; ac: v3f; aa: number; }, bloom: number): v4f` — The final color from the folded state, over a transparent background. - `colorAtIndex(colors: v4f[], idx: number): v4f` — One color from a `stops` prop, by index. ### Overlays (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.overlay Heads-up-display overlays: whole fragments that look at the layer inside, find things in it and draw chrome on top. `detectionOverlay` cuts the canvas into cells, finds the bright, dark, colored or opaque content in each and draws a bounding box with an optional label around it, the computer-vision look. `motionTrackerHud` draws tracker gizmos that chase content over time, dropping keyframe diamonds behind them along their paths. - `detectionOverlay(slots: DetectionOverlaySlots): (params: GpuFragmentParams) => ExprT` — Draw computer-vision style detection boxes over whatever the child contains. - `motionTrackerHud(slots: MotionTrackerHudSlots): (params: GpuFragmentParams) => ExprT` — Draw motion-tracker gizmos that chase content across the child, leaving keyframe trails. ### Pointer fields (`import {effects} from 'shaders/std'`) — https://shaders.com/docs/primitives/effects.pointerFields Push fields the pointer stirs. Each word is a whole simulation: a grid of cells, each holding how far the layer inside should shift there, that the cursor pushes and that settles back on its own. Spread the word into a warp definition with `...sim.grids.gridSim(word)` and it publishes the field under its `output` name; the warp's `map:` then reads it with `warps.gridCellDisplace` (per cell, blocky) or `warps.liquidDisplace` (smoothly, scaled by an intensity prop). The definition needs `usesPointer: true`. - `pointerSplatField(slots: { gridSize: PropRef decay: PropRef intensity: PropRef radius: PropRef output: string }): (params: GpuFragmentParams, root: GridRoot) => GridSimConfig` — A field the cursor smears: cells near the pointer move with it, then fade back to rest. - `springLatticeField(slots: { stiffness: PropRef damping: PropRef radius: PropRef output: string }): (params: GpuFragmentParams, root: GridRoot) => GridSimConfig` — A cloth of springs the cursor pushes: it stretches, rings and settles like fabric. - `clampSplatGridSize(v: number): number` — The grid size `pointerSplatField` really uses for a prop value: floored, then held to 8–128. - `SPLAT_MIN_GRID: 8` — The smallest grid `pointerSplatField` runs on: 8 cells per side. - `SPLAT_MAX_GRID: 128` — The largest grid `pointerSplatField` runs on: 128 cells per side. ## Simulation ### Simulate (`shaders/std` top level) — https://shaders.com/docs/primitives/simulate Say "simulate this" and let the engine run it. `simulate.grid` declares a square grid of numbers that changes a little every frame: you list the steps that advance it (`op.wave` makes it ripple, `op.splat` presses the pointer into it) and name the outputs you want derived from it (`op.gradient`, the slope at every cell). The engine allocates the state, keeps the history a wave needs, tracks the pointer, clamps the frame clock, and stops dispatching once the field has faded to nothing. There is no GPU code in the definition at all. - `simulate.grid(config: GridSimConfig): GridSim` — A square grid of numbers advanced once per frame by `step`, with named outputs in `derive`. - `op.wave(config: {damping: PropRef}): WaveOp` — A wave step: the grid ripples outward from any disturbance and fades by `damping` (a prop, 0–20). - `op.splat(config: {at: PointerSignal; amount: PointerSpeedSignal; radius: PropRef}): SplatOp` — A brush step: a soft round push into the grid at the pointer, scaled by how fast it moves. - `op.gradient(): GradientOp` — A derived output: the grid's slope at every cell as a 2D vector, ready for `displaceBy`. - `class GridSim` — A declared grid simulation. ### Grid programs (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.grids A grid simulation is a fixed-size field of cells (a displacement per cell, two chemical concentrations, a sort offset) that changes a little every frame. `gridSim` runs it: you describe the frame as an ordered list of **stages** built with `op.*`, and the engine runs that list every frame, owning the clock, the frame-delta clamp, the ready gate, the settle gate and the outputs the layer samples. A stage is bookkeeping (`op.host`, `op.values`, `op.readyWhen`, `op.settle`) or work (`op.pass`, `op.cache`, `op.seedOnce`, `op.iterate`, `op.sortPass`), and every frame ends with `op.publish`, which writes the state into the texture the fragment reads. - `gridSim(build: (params: GpuFragmentParams, root: GridRoot) => GridSimConfig | null): {compute: GpuComputeNode}` — A field of cells advanced every frame by an ordered list of stages. - `op.values(name: string, run: (f: GridFrame) => void): GridStage` — A named step that writes this frame's values for the passes after it. - `op.pass(step: ComputeStep): GridStage` — One GPU pass, the same every frame. - `op.publish(step: (f: GridFrame) => ComputeStep): GridStage` — The last stage: write the state into the texture the layer samples. - `op.iterate(opts: {count: (f: GridFrame) => number; step: (i: number, nodes: ComputeStep[], f: GridFrame) => void}): GridStage` — Run a step `count` times this frame. - `op.seedOnce(opts: {pass: ComputeStep; staleWhen: (f: GridFrame) => boolean; onSeed?: () => void}): GridStage` — A one-shot reset run before the rest of the frame whenever `staleWhen` says the state is stale: on the first frame, or when a seed prop changes. - `op.sortPass(opts: {passes: (f: GridFrame) => number; pass: (parity: 0 | 1, side: 'A' | 'B') => ComputeStep}): SortPassStage` — A compare-and-swap sort that converges a little more every frame: `passes` swaps per frame, alternating odd and even pairs and the two buffers. - `op.cache(step: (f: GridFrame) => ComputeStep): GridStage` — A GPU pass chosen per frame, for a pass whose input is rebound after the frame starts. - `op.readyWhen(fn: () => boolean): GridStage` — Run nothing until `fn` returns true, typically once the child's picture has arrived through `bindInputs`. - `op.settle(opts: {activeWhen: (f: GridFrame) => boolean; settleMs: (f: GridFrame) => number}): GridStage` — Sleep the simulation once nothing has driven it for `settleMs` of simulated time. - `op.host(name: string, run: (f: GridFrame) => void): GridStage` — A named step that runs before any gate: pointer smoothing, activity flags, anything a later `settle` needs to know. - `trackedViewport(params: GpuFragmentParams): { tracked(): {width: number; height: number} safe(fp: GridFrameParams): {width: number; height: number} }` — The canvas size in pixels, kept current across resizes, in the two forms a stage wants. - `hostGridProgram(opts: {clampDt: number; steps: HostStep[]}): (fp: unknown) => void` — A frame program for a small grid stepped in plain JavaScript: the steps run in order every frame until one returns `'skip'`. - `hostStep(name: string, run: (f: HostFrame) => void | 'skip'): HostStep` — One named step of a JavaScript-stepped grid. - `hostFieldTexture(params: GpuFragmentParams, opts: {size: number; label: string}): {texData: Uint16Array; texture: ReturnType; upload(): void}` — The texture a JavaScript-stepped grid is read through. ### Fluids (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.fluids Smoke, ink and fog that flow. A fluid is a square grid of velocity plus a **dye** (a density and an age, or a color) that the engine advances with a full fluid solve every frame: swirl, pressure, advection. `fluidSim` owns the state buffers, the output texture, the solve chain, the pointer tracker, the clock and the idle gate that sleeps a settled field. You bring the parts that make the look and declare them by role. - `fluidSim(build: (params: GpuFragmentParams, root: FluidRoot) => FluidSimConfig): {compute: GpuComputeNode}` — A fluid the engine solves every frame. - `splat(opts: {kernel: FluidKernel} | {setup: (ctx: FluidSetupCtx) => KitComputePipeline}): FluidEmitter` — An emitter at a fixed source: one pass per frame that adds dye and momentum where your pass function says (a cone from a point, a line along an edge). - `cursorRibbon(opts: { /** Pointer tracking: smoothing, the teleport distance, the minimum drag. */ tracker?: PointerVelocityTrackerOptions /** Whether the stroke emits this frame. A live frame keeps the simulation awake. */ activeWhen: (ptr: PointerFrame, f: FluidFrame) => boolean /** Seconds after the last activity before the simulation may sleep. */ fadeSeconds: (f: FluidFrame) => number /** Extra bookkeeping per frame before the idle gate. */ // InkFlow's color-cycle time drift. onFrame?: (f: FluidFrame, ptr: PointerFrame) => void /** The stamp pass: a pass function, or a `setup` that builds one on resources of its own. */ pass: {kernel: FluidKernel} | {setup: (ctx: FluidSetupCtx) => KitComputePipeline} /** This frame's stamps. */ ribbon: (f: FluidFrame, ptr: PointerFrame, values: TParams) => CursorRibbonSpec }): FluidEmitter & {ptr(): PointerFrame | null; active(): boolean}` — An emitter that paints along the pointer's stroke: a ribbon of stamps between last frame's position and this one, so a fast flick leaves a continuous line, not dots. - `seededFieldInit(opts: { kernel: FluidKernel /** The value whose change forces a re-seed. */ seed: (f: FluidFrame) => number warm: { /** How many silent solves to run. */ steps: number jacobiIters: number /** Simulated seconds per warm step. */ dt: number /** Where the warm clock starts. Randomize it so two instances differ. */ startTime: () => number /** The full values for a warm step at simulated time `t`. `t = 0` is the seed write. */ values: (t: number, f: FluidFrame) => TParams } }): FluidInitPart` — A field that starts full: seed it from a pass function, then run the solve silently `warm.steps` times so the first visible frame already flows. - `ambientForce(kernel: FluidKernel): FluidSolveStage` — A force applied to the whole field before every solve: a turbulence field, a steady wind. - `restoreToward(kernel: FluidKernel): FluidSolveStage` — A correction applied after every solve: re-seed a color that the solve slowly blurs away. ### Feedback (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.feedback Effects that remember the last frame. A feedback simulation keeps a picture of its own previous output and advances it by one step of your rule every frame: read last frame's state, apply the rule, write the new state. Temporal echoes, codec smears and decaying trails all live here. `feedbackSim` keeps the two state textures and swaps them, keeps a display copy the layer samples, binds the child's picture once it exists, and runs a clock you can scale with a speed prop. - `feedbackSim(build: (params: GpuFragmentParams, root: FeedbackRoot) => FeedbackSimConfig): {compute: GpuComputeNode}` — A simulation that advances a picture of its own last frame by one step of your rule, every frame. ### Agents (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.agents Thousands of small things that move: flocks, motes, filings, swarms, particles standing on an image. An agent simulation keeps a state per agent, moves every agent one step per frame, draws each one into a shared canvas, and hands the result to the layer. `agentSim` owns the plumbing: the state buffers, the output texture, the spawn on the first frame and again on a seed change, the lower count on phones, the child's picture when one is needed, and the fragment that samples the picture over the full canvas. - `agentSim(cfg: AgentSimConfig): AgentSimSpread` — A simulation of many agents, spread into a definition: `bake` assembles the steps from your declared parts, `frame` writes the per-frame values, and the fragment samples the picture. - `renderAgents.orientedWorld(layout: WorldSplatLayout & RampResolveLayout, cfg: Omit & { ramp: Omit & {invGain?: number} names: {splat: string; resolve: string} /** Give the splat the second resource group as well (a shape family's own resources). */ extraOnSplat?: boolean }): RenderAgentsPipelines` — Agents with a heading, drawn as a shape pointing the way they move (or the way they are turned), colored from a rest color to an excited color. - `renderAgents.pointWorld(layout: PointWorldSplatLayout & Parameters[0], cfg: Omit & {names: {splat: string; resolve: string}}): RenderAgentsPipelines` — Round motes with no heading, drawn in one tint with a live softness. - `renderAgents.volume(layout: Parameters[0] & RampResolveLayout, cfg: Omit & { ramp: Omit names: VolumeSplatConfig['names'] & {resolve: string} extraOnSplat?: boolean }): RenderAgentsPipelines` — A 3D swarm seen in perspective: nearer particles draw larger and brighter, and the color runs from rest to excited with speed. - `renderAgents.relief(layout: Parameters[0], cfg: Omit & { out: [number, number] weightedColor: {alphaK: number} names: {splat: string; resolve: string} }): RenderAgentsPipelines` — Particles standing on an image, seen through a camera: each carries the child's color at its home, and nearer particles win the color where they overlap. ### Agent forces (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.agentForces What pushes, turns and carries each agent. The physics of an agent simulation is a list of parts folded into one update step by an **integrator**. A `force` returns a push for one agent; a `torque` returns a turn; a `field` samples something at the agent's position (the magnet at the cursor, a home on a grid); a `drift` is a built-in velocity. Every part is built over your layout, which names the per-agent buffers and the per-frame values it reads, so the same part works in any layer that provides those names. - `integrator.steering2d(layout: SteeringLayout, cfg: { forces: AgentSteer2[] /** Excitement: effort above `rest` (in max-force units) charges by `gain`, and cools at `cool` per second. */ agitation: {rest: number; gain: number; cool: number} /** Slowest cruise, as a fraction of each agent's top speed. */ cruiseFloor: number /** Speed kept when an agent bounces off an edge (0–1). */ wallRestitution: number name: string }): (i: number) => void` — A flock under summed steering, kept cruising, arcing off the canvas edges. - `integrator.forces3d(layout: VolumeSwarmLayout, cfg: { forces: AgentForce3[] maxSpeed: number posClamp: number name: string }): (i: number) => void` — A 3D swarm under summed forces, with drag, a speed limit and a position clamp. - `integrator.orientation2d(layout: OrientationLayout, cfg: { home: AgentHome2 fieldAt: AgentFieldAt torques: AgentTorque[] maxOffset: number name: string }): (i: number) => void` — Agents that turn in place under summed torques and drift a little toward the field. - `integrator.drift2d(layout: DriftLayout, cfg: { drift: AgentDrift gust: (pos: d.v2f) => d.v2f name: string }): (i: number) => void` — Motes that glide on a built-in drift plus a fading gust, wrapping around the canvas. - `integrator.relief(layout: ReliefLayout, cfg: { channel: AgentChannel cursor: (homeW: d.v2f, off: d.v2f, z: number) => d.v3f stiffness: number maxSpeed: number /** Child alpha below which a particle is never latched. Match the render's `minAlpha`. */ // Matches the splat's early-out. minAlpha: number name: string }): (x: number, y: number) => void` — Particles standing on the child's image, rising by a color channel, springing home. - `integrator.advect2d(layout: AdvectLayout, cfg: { gridN: number inertiaRate: number homeRate: number name: string }): (i: number) => void` — Particles carried by a fluid's velocity texture, easing back to an even spread. - `force.flocking(layout: SteeringLayout, cfg: {maxAgents: number}): AgentSteer2` — Separation, alignment and cohesion for a flock, with live weights and radii. - `force.cursorSteer(layout: SteeringLayout): AgentSteer2` — The cursor on a flock: attract, scatter like a predator, or nothing. - `force.wallTurn(layout: SteeringLayout): AgentSteer2` — A soft turn back toward the canvas near an edge, so a flock arcs instead of bouncing. - `force.pressure(layout: VolumeSwarmLayout, cfg: { gridDim: number /** The grid covers shape-local [−domain, domain]³. */ domain: number names: {clear: string; splat: string} }): PressureForce` — Spread a 3D swarm evenly by pushing agents away from crowded cells of a density grid. - `force.containment(layout: VolumeSwarmLayout, cfg: { field: ShapeField3 /** How far apart the two samples of the field's slope are taken. 0.02 is typical. */ // Central-difference epsilon for the field gradient. gradEps: number /** The spring at the surface: fades in from `featherFrom` to `featherTo` (signed distance), `base` push plus `springK` per unit outside. */ // Strong outside, diffuse inside (a sharp feather packs a coherent shell). wall: {featherFrom: number; featherTo: number; base: number; springK: number} /** The pull home once an agent is `from`..`to` from the origin, with strength `k`. */ // A hard clamp piles strays into lines. recall: {from: number; to: number; k: number} /** The pull toward the middle where the signed distance is `from`..`to`, with strength `k`. */ // SDF-VALUE-driven pull toward the origin — direction-safe where the gradient degenerates. homing: {from: number; to: number; k: number} /** How wide a band around the surface the rotation drag fades over. */ // Drag toward the rotating container's feature velocity ω×r, feathered to inside. entrainment: {featherHalf: number} }): AgentForce3` — Keep a 3D swarm inside a shape: a spring at the surface, a pull back from far away, and a drag when the shape rotates. - `force.cursorXY(layout: VolumeSwarmLayout): AgentForce3` — The cursor as a magnet on a 3D swarm, pushing away (or pulling in when the force is negative). - `force.gravity(layout: VolumeSwarmLayout): AgentForce3` — A constant pull on a 3D swarm in the direction of `params.gravX, gravY`. - `force.turbulence(layout: VolumeSwarmLayout, cfg: {posScale: number; timeX: number; timeY: number; seedScale: number; gain: number}): AgentForce3` — A per-agent jitter that keeps a 3D swarm alive, scaled by `params.agitation`. - `force.cursorGust(layout: DriftLayout): (pos: d.v2f) => d.v2f` — A puff from the cursor on drifting motes, zero while the force slider sits at 0. - `force.cursorInView(layout: ReliefLayout, cfg: {perspK: number}): (homeW: d.v2f, off: d.v2f, z: number) => d.v3f` — The cursor on an image relief, applied where each particle appears on screen. - `torque.alignToField(layout: OrientationLayout): AgentTorque` — Swing onto the field's line like a compass needle. - `torque.rest: (layout: OrientationLayout) => AgentTorque` — A weak swing back to each agent's rest angle, felt only where the field is faint. - `field.dipoleOrRadial(layout: OrientationLayout): AgentFieldAt` — The field of a magnet at the cursor: a bar magnet along its travel, or a single pole. - `field.jitteredGridHome(layout: OrientationLayout, cfg: {overscan: number}): AgentHome2` — Each agent's resting position on a jittered grid that runs past the canvas edges. - `drift.variedHeading(layout: {readonly $: {readonly params: HeadingDriftParamsView}}): AgentDrift` — One shared heading and speed, each varied a little per mote. - `FieldSample(props: { rhat: v2f; strength: number; phi: number; }): { rhat: v2f; strength: number; phi: number; }` — What a field sample carries: the direction away from the source (`rhat`), the `strength`, and the line angle `phi` in radians. - `channel.alpha: AgentChannel` — The pixel's alpha. - `channel.blue: AgentChannel` — The blue channel. - `channel.byMode: Record` — The same seven by a select prop's number: 0 luminance, 1 inverted, 2 red, 3 green, 4 blue, 5 saturation, 6 alpha. - `channel.green: AgentChannel` — The green channel. - `channel.luminance: AgentChannel` — The color's brightness, 0 black to 1 white. - `channel.luminanceInverted: AgentChannel` — One minus the brightness, so dark areas rise. - `channel.red: AgentChannel` — The red channel. - `channel.saturation: AgentChannel` — How colorful the pixel is, 0 grey to 1 pure. ### Agent frame (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.agentFrame The once-per-frame arithmetic an agent simulation writes into its values. Inside `agentSim`'s `frame` callback you turn props and the pointer into the numbers the GPU steps read. These are the recipes that come up in every agent layer, as plain functions with no GPU in them: a drag factor that does not depend on frame rate (`expDecay`), the pointer in the shape's own coordinates (`pointerToShapeLocal`), a grid that fits the agent count (`fitJitteredGrid`, `fitIsoGrid`), a direction that follows the cursor's travel (`createMotionAxis`), camera rows for a 3D view (`cameraRowsYDown`), and the rotation bookkeeping a spinning shape needs to carry its swarm along (`omegaFromRotationDeltas`, `entrainmentFromOmega`, `r3SubCellOffset`). - `expDecay(rate: number, dt: number): number` — The per-frame multiplier that decays a value at `rate` per second, whatever the frame rate. - `pointerToShapeLocal(opts: { pointerX: number pointerY: number centerX: number centerYv: number scale: number rotC: number rotS: number aspect: number }): {x: number; y: number}` — The pointer in the shape's own coordinates: undo the layer's center, scale and rotation so a cursor force can act in the same space the swarm lives in (y up, isotropic). - `createMotionAxis(opts?: {smoothing?: number; teleport?: number}): { update(x: number, y: number): { x: number; y: number; }; }` — A unit direction that follows where the pointer has been travelling, smoothed frame to frame. - `fitJitteredGrid(count: number, domainX: number, overscan: number): { cols: number; cellW: number; cellH: number; }` — A grid of about `count` roughly square cells over the canvas plus an `overscan` border on every side, for agents that rest on a jittered grid. - `fitIsoGrid(count: number, aspect: number, min: number, max: number): { w: number; h: number; }` — A W×H grid of square cells holding about `count` agents at the canvas `aspect`, each side clamped to `[min, max]`. - `cameraRowsYDown(rx: number, ry: number, rz: number): { rowX: [number, number, number] rowY: [number, number, number] rowZ: [number, number, number] }` — The three rows of a camera rotation for a 3D view drawn on a y-down canvas. - `omegaFromRotationDeltas(prev: {x: number; y: number; z: number} | null, next: {x: number; y: number; z: number}, dt: number): {x: number; y: number; z: number} | null` — How fast a rotating shape's surface moves, from its rotation this frame and last frame, so a swarm inside it can be dragged along. - `entrainmentFromOmega(om: {x: number; y: number; z: number}, opts: {cap: number; gainRate: number; gainMax: number}): { omegaX: number; omegaY: number; omegaZ: number; entrain: number; }` — The values `force.containment` reads for a rotating shape: the rotation rate capped at `cap`, and an `entrain` gain that grows with the rate up to `gainMax`. - `r3SubCellOffset(frameIdx: number, cell: number): {x: number; y: number; z: number}` — A tiny offset for frame `frameIdx`, within one grid `cell`, that `force.pressure` reads to keep its density grid from lining up with the shape. ### Agent rendering (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.agentRender How agents become a picture. Every agent frame ends the same way: each agent stamps its shape into a shared canvas (the **splat**), then one pass turns the canvas into the output picture and clears it for the next frame (the **resolve**). `renderAgents` in `sim.agents` pairs a splat with its resolve for you; reach into this module when you need another pairing, or for the `pointSlot` parts that give round motes their placement, brightness and size. - `pointSlot.orbitalPlace(layout: {readonly $: {readonly params: {readonly time: number; readonly randomness: number}}}, cfg: {radius: number; rate: number}): PointWorldSplatConfig['place']` — The mote's drawn position: its stored position plus a slow circle of `radius` (canvas heights) at `rate` turns per second, both scaled by `params.randomness` and varied per mote. - `pointSlot.twinkleBrightness(layout: {readonly $: {readonly params: {readonly time: number; readonly twinkle: number}}}, cfg: {freq: number}): PointWorldSplatConfig['brightness']` — The mote's brightness: a twinkle at `freq` cycles per second, blended in by `params.twinkle` (0 steady, 1 full shimmer), times a per-mote presence so some motes read nearer than others. - `pointSlot.presenceRadius(layout: {readonly $: {readonly params: {readonly bodyR: number}}}): PointWorldSplatConfig['bodyRadius']` — The mote's size: `params.bodyR` scaled by the same per-mote presence as the brightness, so the motes that read nearer are bigger and brighter together. - `splat.orientedWorld: (layout: WorldSplatLayout, cfg: OrientedWorldSplatConfig) => (i: number) => void` — Agents with a heading: arrows, streaks, squares, dots or comets drawn along the way they point. - `splat.pointWorld: (layout: PointWorldSplatLayout, cfg: PointWorldSplatConfig) => (i: number) => void` — Round motes with a live softness, placed, brightened and sized by `pointSlot` parts. - `splat.volume: (layout: VolumeRenderLayout, cfg: VolumeSplatConfig) => (i: number) => void` — A 3D swarm in perspective, recording speed for the ramp resolve. - `splat.relief: (layout: ReliefRenderLayout, cfg: ReliefSplatConfig) => (x: number, y: number) => void` — Particles standing on an image, drawn in the child's color through a camera. - `resolve.ramp: (layout: RampResolveLayout, cfg: RampResolveConfig) => (x: number, y: number) => void` — Rest-to-excited color from two colors, with optional motion trails. - `resolve.tint: (layout: { readonly $: { readonly accumE: atomicU32[]; readonly outTex: StorageTex; readonly params: { readonly color: v4f; }; }; }, cfg: { res: number; name: string; }) => (x: number, y: number) => void` — One color, with an alpha from coverage. - `resolve.weightedColor: (layout: ReliefRenderLayout, cfg: { fp: number; alphaK: number; name: string; }) => (x: number, y: number) => void` — The average of the colors that landed, nearer particles first. ### Shape fields (`import {sim} from 'shaders/std'`) — https://shaders.com/docs/primitives/sim.shapeFields The shape a swarm is held inside. `force.containment` needs one thing from a shape: the signed distance to its surface at any 3D point, negative inside and positive outside. `shapeField` builds that distance function from whatever shape the layer was given, so one integrator serves every shape kind: `analyticExtruded` gives a flat shape (circle, polygon, star) a depth; `svgExtruded` does the same for an SVG outline uploaded as a distance texture; `analytic3d` wraps a true 3D solid; `svgLifted3d` wraps an SVG lifted into 3D. The last two rotate with the shape's live rotation, so the swarm follows the surface as it turns. - `shapeField.analyticExtruded(layout: {readonly $: {readonly params: ExtrudedAnalyticParamsView}}, sdf2d: AnalyticSdf2d): ShapeField3` — A flat shape given depth: the 2D distance of a circle, polygon or star, extruded in z by `params.halfDepth`. - `shapeField.svgExtruded(layout: {readonly $: {readonly params: {readonly halfDepth: number}}}, svgLayout: {readonly $: {readonly sdfSource: d.Infer>}}, cfg: {size: number}): ShapeField3` — An SVG outline given depth: the outline's distance texture, extruded in z by `params.halfDepth`. - `shapeField.analytic3d(layout: RotatedFieldLayout, baked: ShapeField3): ShapeField3` — A true 3D solid (sphere, torus, knot…) from its baked distance function, rotated by the shape's live rotation so the swarm follows the surface as it turns. - `shapeField.svgLifted3d(layout: RotatedFieldLayout, baked: ShapeField3): ShapeField3` — An SVG outline lifted into a 3D solid, rotated by the shape's live rotation.