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

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.

InputTypeDescription
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.

InputTypeDescription
widthSprites.Reactive.ValueThe pixel width of the render target.
heightSprites.Reactive.ValueThe pixel height of the render target.
inputsObjectA map of uniform name to reactive value; the reserved name uInput carries the input texture handle of the layer below.
glslSprites.Reactive.ValueThe 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);
A one-pass render whose output texture is drawn to a canvas; the slider feeds the 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.

InputTypeDescription
handleObjectA render handle { changeCount, glBuffer, width, height } from Render or a fold.
canvasElementThe 2D canvas element to copy the texture onto.
optionalMaxNumberAn 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.

InputTypeDescription
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.

InputTypeDescription
bufferObjectA 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.

InputTypeDescription
bufferObjectThe owned target buffer to render into.
sourceStringThe full fragment GLSL for the pass.
widthNumberThe pixel width of the pass.
heightNumberThe pixel height of the pass.
inputTextureObjectThe GL texture of the layer below, or undefined for the blank input.
paramsObjectA 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.

InputTypeDescription
sourceStringThe 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.

InputTypeDescription
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);
});
The shared vertex source shown as text; every pass links this quad.

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);
});
The blit source shown as text; it flips V so the image shows upright.

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.

InputTypeDescription
glObjectThe WebGL2 context, from the shared Context.
typeNumberThe GL stage type, gl.VERTEX_SHADER or gl.FRAGMENT_SHADER.
sourceStringThe 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);
The shared vertex source compiled to a GL stage in the real context.

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.

InputTypeDescription
glObjectThe WebGL2 context, from the shared Context.
fragmentSourceStringThe 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);
The blit fragment source linked to a program against the fixed vertex shader.

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.

InputTypeDescription
bufferObjectA buffer from NewBuffer to resize.
widthNumberThe target pixel width.
heightNumberThe 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);
A fresh buffer sized to 128 by 96, reusing its one texture object.

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.

InputTypeDescription
glObjectThe WebGL2 context, from the shared Context.
recordObjectA compiled record from Compiled, with its program and location cache.
nameStringThe uniform name in the fragment source.
valueNumber or ObjectA 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);
A float uniform set on a compiled program in the real context.

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.

InputTypeDescription
scaleSprites.Reactive.ValueThe reactive zoom scale the wheel drives.
offsetSprites.Reactive.ValueThe 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);
});
Wheel over the panel to change the scale toward the cursor.

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.

InputTypeDescription
activeSprites.Reactive.ValueWhether the drag overlay is shown and capturing.
offsetSprites.Reactive.ValueThe 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);
Drag over the panel to add to the offset through the capture overlay.

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.

InputTypeDescription
handleSprites.Reactive.ValueThe reactive render handle to paint.
scaleSprites.Reactive.ValueThe reactive zoom scale the wheel drives.
offsetSprites.Reactive.ValueThe reactive pan offset { x, y } the wheel and drag drive.
panActiveSprites.Reactive.ValueWhether 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);
});
A rendered gradient painted to the stage; wheel to zoom toward the cursor.

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.

InputTypeDescription
handleSprites.Reactive.ValueThe reactive render handle up to a layer.
maxNumberThe 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);
A small square thumbnail of a rendered handle, as the Layers list shows.

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.

InputTypeDescription
handleSprites.Reactive.ValueThe reactive render handle to encode.
thumbSprites.Reactive.ValueThe store field the small PNG data URL is written to.
infoSprites.Reactive.ValueThe store field the info summary is written to.
summarySprites.Reactive.ValueThe 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);
The info summary written through the thumbnail driver as the render settles.