Sprites.Shader
The WebGL2 render driver for the shader media. One render pass turns a piece of GLSL plus a set of inputs into a texture, and that texture is carried as a small handle { changeCount, glBuffer } so the same GPU buffer is reused across renders rather than re-created. One shared WebGL2 context owns every program and buffer, and programs are cached by source, so editing a parameter reuses the compiled program and only resets uniforms. Sprites.Shader.Render returns a reactive handle, so a chain of passes composes like any other reactive code: a layer's texture becomes the next layer's uInput. Display copies a handle's buffer to a 2D canvas.
- Sprites.Shader.Supported
- Sprites.Shader.Render
- Sprites.Shader.Draw
- Sprites.Shader.NewBuffer
- Sprites.Shader.FreeBuffer
- Sprites.Shader.Pass
- Sprites.Shader.Compiled
- Sprites.Shader.Context
- Sprites.Shader.Vertex
- Sprites.Shader.Blit
- Sprites.Shader.Stage
- Sprites.Shader.Program
- Sprites.Shader.Size
- Sprites.Shader.Uniform
- Sprites.Shader.Zoom
- Sprites.Shader.Pan
- Sprites.Shader.Surface
- Sprites.Shader.Preview
- Sprites.Shader.Thumbnail
Sprites.Shader.Supported Boolean
Sprites.Shader.Supported()
Whether the browser has WebGL2. The Context creates a probe once and remembers the answer, so repeated calls are cheap; the shader editor uses it to decide whether to render or to show a message rather than failing silently.
| Input | Type | Description |
|---|---|---|
| None. | ||
Returns a boolean: true when a WebGL2 context could be created, false otherwise.
Sprites.Shader.Render Value
Sprites.Shader.Render(width, height, inputs, glsl)
A reactive render: a texture handle that recomputes, into its own reused buffer, whenever the code or any input changes. inputs is a map of uniform name to value, where the reserved name uInput carries the input texture handle of the layer below, or is left out for the blank input. The returned reactive value carries { changeCount, glBuffer, width, height, optionalError }; changeCount rises on each render so a downstream consumer knows the buffer's contents changed. The buffer is freed when the surrounding reactive scope is torn down.
| Input | Type | Description |
|---|---|---|
width | Sprites.Reactive.Value | The pixel width of the render target. |
height | Sprites.Reactive.Value | The pixel height of the render target. |
inputs | Object | A map of uniform name to reactive value; the reserved name uInput carries the input texture handle of the layer below. |
glsl | Sprites.Reactive.Value | The full layer source (see Sprites.Media.Shader.Source). |
Returns a reactive value of { changeCount, glBuffer, width, height, optionalError }.
const width = Sprites.Reactive.Value(160);
const height = Sprites.Reactive.Value(160);
const amount = Sprites.Reactive.Value(0.6);
const descriptor = Sprites.Reactive.ReadOnly({ name: 'uAmount', value: amount });
const uniforms = Sprites.Array.Gather(() => {
Sprites.Array.Emit(descriptor);
});
const glsl = Sprites.Reactive.Binding'#version 300 es\nprecision highp float;\nuniform vec2 uResolution;\nuniform float uAmount;\nout vec4 fragColor;\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n fragColor = vec4(uv, uAmount, 1.0);\n}');
const handle = Sprites.Shader.Render(width, height, uniforms, undefined, glsl);
Sprites.Ui.Dom.Tag('canvas', () => {
const canvas = Sprites.Reactive.currentElement;
Sprites.Ui.Dom.Style('width', '160px');
Sprites.Ui.Dom.Style('height', '160px');
Sprites.Shader.paint(canvas, handle, undefined);
});
Sprites.Ui.Input.Slider(amount, 0, 1, 0.01);
uAmount uniform and the render recomputes into its reused buffer as you drag.Sprites.Shader.Draw Void
Sprites.Shader.Draw(handle, canvas, optionalMax)
Copy a handle's texture to a 2D canvas, flipping V so it shows the right way up. The blit runs at the handle's native resolution; the 2D canvas is sized to the handle, or scaled down to fit optionalMax on its longer side when one is given, so a small layer preview holds a small bitmap rather than the full image. Used by the editor's stage canvas and the layer previews.
| Input | Type | Description |
|---|---|---|
handle | Object | A render handle { changeCount, glBuffer, width, height } from Render or a fold. |
canvas | Element | The 2D canvas element to copy the texture onto. |
optionalMax | Number | An optional maximum for the longer side in pixels; when absent the canvas is sized to the handle. |
Returns nothing.
Sprites.Shader.NewBuffer Value
Sprites.Shader.NewBuffer()
A new render buffer: a GL texture and a framebuffer that renders into it, unsized until the first pass. A handle carries this as its glBuffer. Render and the shader chain own these directly so the same GPU buffer is reused across renders.
| Input | Type | Description |
|---|---|---|
| None. | ||
Returns a buffer object { texture, framebuffer, width, height }.
Sprites.Shader.FreeBuffer Void
Sprites.Shader.FreeBuffer(buffer)
Free a buffer's GL resources. Called when the reactive render that owns it is torn down, so a chain that shrinks or an editor that closes releases the textures and framebuffers it no longer needs.
| Input | Type | Description |
|---|---|---|
buffer | Object | A buffer from NewBuffer to delete. |
Returns nothing.
Sprites.Shader.Pass Value
Sprites.Shader.Pass(buffer, source, width, height, inputTexture, params)
Run one render pass: compile or reuse the program for source, size the target buffer, bind the input texture to unit 0 and the parameter uniforms, and draw the quad. inputTexture is the GL texture of the layer below, or undefined for the blank input. params is a plain map of name to value. On a compile error the target is cleared to transparent and the error string is returned; on success it returns undefined.
| Input | Type | Description |
|---|---|---|
buffer | Object | The owned target buffer to render into. |
source | String | The full fragment GLSL for the pass. |
width | Number | The pixel width of the pass. |
height | Number | The pixel height of the pass. |
inputTexture | Object | The GL texture of the layer below, or undefined for the blank input. |
params | Object | A plain map of uniform name to value. |
Returns the compile error string, or undefined on success.
Sprites.Shader.Compiled Value
Sprites.Shader.Compiled(source)
The cached compiled program for a fragment source, with a per-name uniform-location cache. On a compile error it caches a record with an error string and no program, so a broken layer neither recompiles every frame nor throws; the caller renders it as transparent.
| Input | Type | Description |
|---|---|---|
source | String | The fragment GLSL to compile or look up in the program cache. |
Returns a record { program, resolution, input, locations, error }.
Sprites.Shader.Context Value
Sprites.Shader.Context()
The shared context and its resources, created once. Returns undefined when WebGL2 is missing, so the caller can show a message rather than crash. It holds the GL context, the quad buffer, the blit program, a blank 1x1 transparent texture for a chain's first input, and the program cache keyed by fragment source.
| Input | Type | Description |
|---|---|---|
| None. | ||
Returns the shared state object, or undefined when WebGL2 is missing.
Sprites.Shader.Vertex String
The fixed vertex shader source: a full-screen quad in clip space that carries a 0..1 uv. Every render pass and the blit link this same vertex shader; a layer's fragment shader ignores the uv and reads gl_FragCoord, while the blit reads the uv. A plain string, so it drops straight into Program and Stage.
const source = Sprites.Reactive.Value(Sprites.Shader.Vertex);
Sprites.Ui.Dom.Tag('pre', () => {
Sprites.Ui.Dom.Text(source);
});
Sprites.Shader.Blit String
The blit fragment shader source: it samples the texture with V flipped, turning the top-first stored texture back to screen orientation. The shared context links this once as its display program, so a handle's buffer paints the right way up. A plain string.
const source = Sprites.Reactive.Value(Sprites.Shader.Blit);
Sprites.Ui.Dom.Tag('pre', () => {
Sprites.Ui.Dom.Text(source);
});
Sprites.Shader.Stage Void
Sprites.Shader.Stage(gl, type, source)
Compile one shader stage, returning the GL shader object. It creates the shader, sets the source, compiles it, and checks the compile status; on a failure it reads the info log, deletes the shader, and throws an error carrying the log. Program uses it for both the vertex and the fragment stage.
| Input | Type | Description |
|---|---|---|
gl | Object | The WebGL2 context, from the shared Context. |
type | Number | The GL stage type, gl.VERTEX_SHADER or gl.FRAGMENT_SHADER. |
source | String | The GLSL source for the stage. |
Returns the compiled GL shader object, or throws with the compile log.
const context = Sprites.Shader.Context();
const gl = context.gl;
const shader = Sprites.Shader.Stage(gl, gl.VERTEX_SHADER, Sprites.Shader.Vertex);
const ok = Sprites.Reactive.Value(shader !== undefined);
Sprites.Ui.Dom.Text('vertex stage compiled = ', ok);
Sprites.Shader.Program Void
Sprites.Shader.Program(gl, fragmentSource)
Link a program from the fixed vertex shader and a fragment source, binding the quad attributes aPos and aUv to fixed locations. It compiles both stages through Stage, attaches and links them, deletes the stage objects, and checks the link status; on a compile or link failure it reads the info log, deletes the program, and throws an error carrying the log.
| Input | Type | Description |
|---|---|---|
gl | Object | The WebGL2 context, from the shared Context. |
fragmentSource | String | The fragment GLSL to link with the fixed vertex shader. |
Returns the linked GL program object, or throws with the compile or link log.
const context = Sprites.Shader.Context();
const gl = context.gl;
const program = Sprites.Shader.Program(gl, Sprites.Shader.Blit);
const ok = Sprites.Reactive.Value(program !== undefined);
Sprites.Ui.Dom.Text('blit program linked = ', ok);
Sprites.Shader.Size Void
Sprites.Shader.Size(buffer, width, height)
Size a buffer's texture to width by height if it is not already, reusing the same texture object. When the buffer already holds that size it returns at once; otherwise it re-allocates the texture storage and records the new width and height on the buffer. A pass calls it so a render target grows or shrinks to the pass without a fresh texture.
| Input | Type | Description |
|---|---|---|
buffer | Object | A buffer from NewBuffer to resize. |
width | Number | The target pixel width. |
height | Number | The target pixel height. |
Returns nothing.
const buffer = Sprites.Shader.NewBuffer();
Sprites.Shader.Size(buffer, 128, 96);
const width = Sprites.Reactive.Value(buffer.width);
const height = Sprites.Reactive.Value(buffer.height);
Sprites.Ui.Dom.Text('buffer = ', width, ' x ', height);
Sprites.Shader.Uniform Void
Sprites.Shader.Uniform(gl, record, name, value)
Set one parameter uniform on the bound program, choosing the GL call by the value's shape: a number is a float, and a { x, y }, { x, y, z } or { x, y, z, w } is a vec2, vec3 or vec4. It reads the uniform location from the record's per-name cache, filling it on a miss, and skips the write when the program has no such uniform. A pass calls it once per parameter.
| Input | Type | Description |
|---|---|---|
gl | Object | The WebGL2 context, from the shared Context. |
record | Object | A compiled record from Compiled, with its program and location cache. |
name | String | The uniform name in the fragment source. |
value | Number or Object | A number, or a { x, y }, { x, y, z } or { x, y, z, w } vector. |
Returns nothing.
const context = Sprites.Shader.Context();
const gl = context.gl;
const source = '#version 300 es\nprecision highp float;\nuniform vec2 uResolution;\nuniform float uAmount;\nout vec4 fragColor;\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n fragColor = vec4(uv, uAmount, 1.0);\n}';
const record = Sprites.Shader.Compiled(source);
gl.useProgram(record.program);
Sprites.Shader.Uniform(gl, record, 'uAmount', 0.5);
const set = Sprites.Reactive.Value(record.error === undefined);
Sprites.Ui.Dom.Text('uAmount uniform set = ', set);
Sprites.Shader.Zoom Void
Sprites.Shader.Zoom(scale, offset)
Zoom the stage toward the cursor on a wheel, over a scale and an offset, attached to the current element. On each wheel step it scales by a factor from the wheel delta, capped between 0.05 and 64, and moves the offset so the point under the cursor stays fixed as the scale changes. It composes the next values over the current ones and Sets both, so the view follows every wheel step.
| Input | Type | Description |
|---|---|---|
scale | Sprites.Reactive.Value | The reactive zoom scale the wheel drives. |
offset | Sprites.Reactive.Value | The reactive pan offset { x, y } kept fixed under the cursor. |
Returns nothing.
const scale = Sprites.Reactive.Value(1);
const offset = Sprites.Reactive.Value({ x: 0, y: 0 });
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Style('width', '160px');
Sprites.Ui.Dom.Style('height', '80px');
Sprites.Ui.Dom.Style('background', '#dcefe4');
Sprites.Shader.Zoom(scale, offset);
Sprites.Ui.Dom.Text('scale = ', scale);
});
Sprites.Shader.Pan Void
Sprites.Shader.Pan(active, offset)
Pan the stage on a drag while active is true: an overlay that captures the pointer and adds the drag to the offset. It is shown only while active, so it sits above the stage during the Move tool and steps aside otherwise. Each pointer move adds the movement to the offset and Sets it, so the view follows the drag.
| Input | Type | Description |
|---|---|---|
active | Sprites.Reactive.Value | Whether the drag overlay is shown and capturing. |
offset | Sprites.Reactive.Value | The reactive pan offset { x, y } the drag adds to. |
Returns nothing.
const active = Sprites.Reactive.Value(true);
const offset = Sprites.Reactive.Value({ x: 0, y: 0 });
const offsetX = Sprites.Object.Field(offset, 'x');
const offsetY = Sprites.Object.Field(offset, 'y');
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Style('position', 'relative');
Sprites.Ui.Dom.Style('width', '160px');
Sprites.Ui.Dom.Style('height', '80px');
Sprites.Ui.Dom.Style('background', '#dcefe4');
Sprites.Shader.Pan(active, offset);
});
Sprites.Ui.Dom.Text('offset = ', offsetX, ', ', offsetY);
Sprites.Shader.Surface Void
Sprites.Shader.Surface(handle, scale, offset, panActive)
The stage surface: a canvas that fills the current element, panned and zoomed, that paints the handle as it changes, with the drag-pan overlay. It attaches the wheel zoom, builds the transform from the offset and scale, paints the handle to the canvas as it renders, and places the pan overlay gated by panActive. This is the editor's main view.
| Input | Type | Description |
|---|---|---|
handle | Sprites.Reactive.Value | The reactive render handle to paint. |
scale | Sprites.Reactive.Value | The reactive zoom scale the wheel drives. |
offset | Sprites.Reactive.Value | The reactive pan offset { x, y } the wheel and drag drive. |
panActive | Sprites.Reactive.Value | Whether the drag-pan overlay is shown. |
Returns nothing.
const width = Sprites.Reactive.Value(160);
const height = Sprites.Reactive.Value(160);
const glsl = Sprites.Reactive.Binding'#version 300 es\nprecision highp float;\nuniform vec2 uResolution;\nout vec4 fragColor;\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n fragColor = vec4(uv, 0.6, 1.0);\n}');
const uniforms = Sprites.Reactive.Value([]);
const handle = Sprites.Shader.Render(width, height, uniforms, undefined, glsl);
const scale = Sprites.Reactive.Value(1);
const offset = Sprites.Reactive.Value({ x: 0, y: 0 });
const panActive = Sprites.Reactive.Value(false);
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Style('position', 'relative');
Sprites.Ui.Dom.Style('width', '160px');
Sprites.Ui.Dom.Style('height', '160px');
Sprites.Shader.Surface(handle, scale, offset, panActive);
});
Sprites.Shader.Preview Void
Sprites.Shader.Preview(handle, max)
A small square preview canvas that paints a handle, for the Layers list. It builds a 40 by 40 canvas with a white ground and rounded corners, and paints the handle scaled to max on its longer side as it changes. Each layer row uses one so the list shows the image up to that layer.
| Input | Type | Description |
|---|---|---|
handle | Sprites.Reactive.Value | The reactive render handle up to a layer. |
max | Number | The largest side in pixels the preview draws. |
Returns nothing.
const width = Sprites.Reactive.Value(64);
const height = Sprites.Reactive.Value(64);
const glsl = Sprites.Reactive.Binding'#version 300 es\nprecision highp float;\nuniform vec2 uResolution;\nout vec4 fragColor;\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n fragColor = vec4(uv.x, 0.4, uv.y, 1.0);\n}');
const uniforms = Sprites.Reactive.Value([]);
const handle = Sprites.Shader.Render(width, height, uniforms, undefined, glsl);
Sprites.Shader.Preview(handle, 40);
Sprites.Shader.Thumbnail Void
Sprites.Shader.Thumbnail(handle, thumb, info, summary)
Keep the saved thumbnail and info summary following the render, through the thumbnail driver. thumb gets a small PNG data URL a little after the image settles, and info gets the summary text. Both writes are async outside work, an encode and a deferred write, so they run in a driver rather than a reactive read.
| Input | Type | Description |
|---|---|---|
handle | Sprites.Reactive.Value | The reactive render handle to encode. |
thumb | Sprites.Reactive.Value | The store field the small PNG data URL is written to. |
info | Sprites.Reactive.Value | The store field the info summary is written to. |
summary | Sprites.Reactive.Value | The reactive info text copied into info. |
Returns nothing.
const width = Sprites.Reactive.Value(64);
const height = Sprites.Reactive.Value(64);
const glsl = Sprites.Reactive.Binding'#version 300 es\nprecision highp float;\nuniform vec2 uResolution;\nout vec4 fragColor;\nvoid main() {\n fragColor = vec4(0.2, 0.7, 0.9, 1.0);\n}');
const uniforms = Sprites.Reactive.Value([]);
const handle = Sprites.Shader.Render(width, height, uniforms, undefined, glsl);
const thumb = Sprites.Reactive.Value(undefined);
const info = Sprites.Reactive.Value(undefined);
const summary = Sprites.Reactive.Value('64 x 64 - 1 layer');
Sprites.Shader.Thumbnail(handle, thumb, info, summary);
Sprites.Ui.Dom.Text('info = ', info);