Sprites.Media.Shader

A shader image is a stack of GLSL layers rendered into an image, each layer taking the layer below as its input so they compose bottom to top. This module holds the model, the plain data the store keeps, the parameter values as a tagged union, and the pure text work that assembles each layer's full GLSL from the built-in prelude, the parameters, the shared globals and the layer code. It also holds the editor and its stage. The WebGL render driver that turns the GLSL into a texture is separate, so the editor stage shows a placeholder until it lands. The stored document format is described in reference/storage/shader/.

Sprites.Media.Shader

Sprites.Media.Shader.Editor Void

Sprites.Media.Shader.Editor(data, thumb, info)

The shader editor. It composes the editor state, the layer selection, the current tool and the panel flags, mounts the Tools window, the Move tool window and the panel windows, and holds the stage. The canvas viewport, the per-layer preview and the render loop that Sets thumb and info arrive with the WebGL driver; until then the stage shows a placeholder, so the shell and every window work against the live model now. It builds interface and returns nothing.

InputTypeDescription
dataSprites.Reactive.ValueThe document, a two-way value of { media, w, h, globals, params, layers }.
thumbSprites.Reactive.ValueA value the render loop will Set to a preview of the rendered image, once the driver lands.
infoSprites.Reactive.ValueA value the render loop will Set to the size and layer-count summary, once the driver lands.

Returns nothing.

const data = Sprites.Media.Shader.NewDocument(512, 512);
const thumb = Sprites.Reactive.Value(undefined);
const info = Sprites.Reactive.Value(undefined);
Sprites.Media.Shader.Editor(data, thumb, info);

Sprites.Media.Shader.NewDocument Value

Sprites.Media.Shader.NewDocument(width, height)

A new shader document at the given size, or the default size: the { media, w, h, globals, params, layers } shape the store keeps, with the shared globals, no image parameters and one visible layer of the starter code. A composite the store snapshots to plain when it seeds the record.

InputTypeDescription
widthSprites.Reactive.ValueThe image width in pixels, clamped to the allowed range, or the default when absent.
heightSprites.Reactive.ValueThe image height in pixels, clamped to the allowed range, or the default when absent.

Returns a reactive document object.

const data = Sprites.Media.Shader.NewDocument(256, 256);

Sprites.Media.Shader.NewLayer Value

Sprites.Media.Shader.NewLayer(name, code)

A new layer: its name, a visible flag, its GLSL code and its own parameters, none to start. A composite over ReadOnly, so a click that adds a layer passes it as a fresh reactive value the array insert commits.

InputTypeDescription
nameSprites.Reactive.ValueThe layer's name.
codeSprites.Reactive.ValueThe layer's GLSL code, which must define vec4 LayerMain().

Returns a reactive layer object.

const layer = Sprites.Media.Shader.NewLayer('Layer 1', '');

Sprites.Media.Shader.CloneLayer Value

Sprites.Media.Shader.CloneLayer(layer)

A copy of a layer: a fresh layer object holding the same name, visible flag, code and parameters. Rebuilding the object keeps the copy independent. A composite.

InputTypeDescription
layerSprites.Reactive.ValueThe layer to copy.

Returns a reactive layer object, independent of the original.

const layer = Sprites.Media.Shader.NewLayer('Layer 1', '');
const copy = Sprites.Media.Shader.CloneLayer(layer);

Sprites.Media.Shader.NewParameter Value

Sprites.Media.Shader.NewParameter(name, type, value)

A parameter object: its name, its type and its value. The name is the uniform name in the GLSL, the type one of float, vec2, vec3, vec4 or colour, and the value the tagged union that matches.

InputTypeDescription
nameSprites.Reactive.ValueThe uniform name in the GLSL.
typeSprites.Reactive.ValueOne of float, vec2, vec3, vec4 or colour.
valueSprites.Reactive.ValueThe tagged-union value that matches the type.

Returns a reactive parameter object.

const value = Sprites.Media.Shader.FloatValue(0.5);
const param = Sprites.Media.Shader.NewParameter('amount', 'float', value);

Sprites.Media.Shader.DefaultParameter Value

Sprites.Media.Shader.DefaultParameter()

A fresh parameter for the Add button: a float named param set to zero. The editor renames it and changes its type from there.

InputTypeDescription
None.

Returns a reactive parameter object, a float named param set to zero.

const param = Sprites.Media.Shader.DefaultParameter();

Sprites.Media.Shader.FloatValue Value

Sprites.Media.Shader.FloatValue(n)

A parameter value holding a single float. The value is the tagged union { optionalFloat, optionalVec2, optionalVec3, optionalVec4 } with exactly one field present; here it is optionalFloat.

InputTypeDescription
nSprites.Reactive.ValueThe float to hold in optionalFloat.

Returns a reactive value object with optionalFloat set.

const value = Sprites.Media.Shader.FloatValue(0.5);
const n = Sprites.Object.Field(value, 'optionalFloat');
Sprites.Ui.Content.Text('optionalFloat = ', n);
A float parameter value; its optionalFloat field reads back the held number.

Sprites.Media.Shader.Vec2Value Value

Sprites.Media.Shader.Vec2Value(x, y)

A parameter value holding a vec2, as { x, y }.

InputTypeDescription
xSprites.Reactive.ValueThe x component.
ySprites.Reactive.ValueThe y component.

Returns a reactive value object with optionalVec2 set.

const value = Sprites.Media.Shader.Vec2Value(0.25, 0.75);

Sprites.Media.Shader.Vec3Value Value

Sprites.Media.Shader.Vec3Value(x, y, z)

A parameter value holding a vec3, as { x, y, z }.

InputTypeDescription
xSprites.Reactive.ValueThe x component.
ySprites.Reactive.ValueThe y component.
zSprites.Reactive.ValueThe z component.

Returns a reactive value object with optionalVec3 set.

const value = Sprites.Media.Shader.Vec3Value(0.1, 0.2, 0.3);

Sprites.Media.Shader.Vec4Value Value

Sprites.Media.Shader.Vec4Value(x, y, z, w)

A parameter value holding a vec4, as { x, y, z, w }.

InputTypeDescription
xSprites.Reactive.ValueThe x component.
ySprites.Reactive.ValueThe y component.
zSprites.Reactive.ValueThe z component.
wSprites.Reactive.ValueThe w component.

Returns a reactive value object with optionalVec4 set.

const value = Sprites.Media.Shader.Vec4Value(0.1, 0.2, 0.3, 1.0);

Sprites.Media.Shader.ColourValue Value

Sprites.Media.Shader.ColourValue(r, g, b, a)

A parameter value holding a colour, red, green, blue and alpha each 0 to 1, stored in optionalVec4 like a vec4. The colour type declares the same vec4 in GLSL; it differs only in the control the editor shows, a colour picker rather than four number fields.

InputTypeDescription
rSprites.Reactive.ValueRed, 0 to 1.
gSprites.Reactive.ValueGreen, 0 to 1.
bSprites.Reactive.ValueBlue, 0 to 1.
aSprites.Reactive.ValueAlpha, 0 to 1.

Returns a reactive value object with optionalVec4 set.

const value = Sprites.Media.Shader.ColourValue(1, 0.5, 0, 1);

Sprites.Media.Shader.DefaultValue Value

Sprites.Media.Shader.DefaultValue(type)

The default value for a parameter type: zero for a float and a vector, opaque white for a colour. A composite over Logic.Select, so switching a parameter's type in the editor can lay a value of the new shape in place.

InputTypeDescription
typeSprites.Reactive.ValueOne of float, vec2, vec3, vec4 or colour.

Returns a reactive value object matching the type.

const value = Sprites.Media.Shader.DefaultValue('vec3');

Sprites.Media.Shader.GlslType String

Sprites.Media.Shader.GlslType(type)

The GLSL type name a parameter type declares as: float, vec2, vec3 or vec4, with colour a vec4. A composite over Logic.Select, chosen from the type, so it follows the type reactively and needs no lookup table. Anything unknown falls back to float.

InputTypeDescription
typeSprites.Reactive.ValueOne of float, vec2, vec3, vec4 or colour.

Returns a reactive string, the GLSL type name.

const type = Sprites.Reactive.Value('vec3');
const glsl = Sprites.Media.Shader.GlslType(type);
Sprites.Ui.Content.Text('GLSL type: ', glsl);
Sprites.Ui.Input.Dropdown(type, () => {
  Sprites.Ui.Input.Option('float', 'float');
  Sprites.Ui.Input.Option('vec2', 'vec2');
  Sprites.Ui.Input.Option('vec3', 'vec3');
  Sprites.Ui.Input.Option('vec4', 'vec4');
  Sprites.Ui.Input.Option('colour', 'colour');
});
The GLSL type name follows the picked parameter type; colour declares as vec4.

Sprites.Media.Shader.Declarations String

Sprites.Media.Shader.Declarations(params)

The uniform declarations for a list of parameters: one uniform <glslType> <name>; line per parameter, joined by newlines. A composite over Array.Map and Text.Join, so it follows the parameter list reactively. Used for both the image parameters and a layer's own parameters.

InputTypeDescription
paramsSprites.Reactive.ValueThe list of parameter objects to declare.

Returns a reactive string, the newline-joined uniform declarations.

const param = Sprites.Media.Shader.NewParameter('amount', 'float', Sprites.Media.Shader.FloatValue(0));
const params = Sprites.Reactive.Value([param]);
const decls = Sprites.Media.Shader.Declarations(params);

Sprites.Media.Shader.Source String

Sprites.Media.Shader.Source(data, layer)

The full GLSL for one layer, in the order the built-in prelude, the image parameter uniforms, the layer parameter uniforms, the shared globals, the layer's own code, then the built-in main that calls LayerMain. data is the document, layer the layer to build. A composite over Declarations and Text.Concat, so the source follows every parameter, the shared code and the layer code reactively; the render driver recompiles when this text changes.

InputTypeDescription
dataSprites.Reactive.ValueThe document holding the image parameters and shared globals.
layerSprites.Reactive.ValueThe layer to build, with its own parameters and code.

Returns a reactive string, the assembled GLSL for the layer.

const data = Sprites.Media.Shader.NewDocument(256, 256);
const layers = Sprites.Object.Field(data, 'layers');
const layer = Sprites.Array.At(layers, 0);
const source = Sprites.Media.Shader.Source(data, layer);
Sprites.Ui.Code.Editor(source);
The assembled GLSL for the first layer, shown in a code editor over the reactive string.

Sprites.Media.Shader.SelectedLayer Value

Sprites.Media.Shader.SelectedLayer(data, layerIndex)

A two-way value over the layer at layerIndex, reading that layer and writing an edit back into the layers list. data is the document, layerIndex the editor's selection. The layer window binds the fields of this, so editing a name, a flag, the code or a parameter lays the whole layer back into that one slot, leaving every other layer be.

InputTypeDescription
dataSprites.Reactive.ValueThe document holding the layers list.
layerIndexSprites.Reactive.ValueThe index of the layer to read and write.

Returns a two-way reactive value over the selected layer.

const data = Sprites.Media.Shader.NewDocument(256, 256);
const layerIndex = Sprites.Reactive.Value(0);
const selected = Sprites.Media.Shader.SelectedLayer(data, layerIndex);

Sprites.Media.Shader.Summary Value

Sprites.Media.Shader.Summary(width, height, layers)

The meta info summary for a shader image: its size and layer count as one short string, for the meta record a listing reads. A composite over Text.Concat and Array.Length.

InputTypeDescription
widthSprites.Reactive.ValueThe image width in pixels.
heightSprites.Reactive.ValueThe image height in pixels.
layersSprites.Reactive.ValueThe layers list, counted for the summary.

Returns a reactive string summarising the size and layer count.

const width = Sprites.Reactive.Value(512);
const height = Sprites.Reactive.Value(512);
const layers = Sprites.Reactive.Value([
  Sprites.Media.Shader.NewLayer('Layer 1', ''),
  Sprites.Media.Shader.NewLayer('Layer 2', '')
]);
const summary = Sprites.Media.Shader.Summary(width, height, layers);
Sprites.Ui.Content.Text(summary);
Sprites.Ui.Input.Number(width);
Sprites.Ui.Input.Number(height);
A size and layer-count summary; editing the width or height updates the string.

Sprites.Media.Shader.MinSide Number

The smallest a side may be, in pixels. A plain number, so it drops straight into a clamp as a constant argument.

Sprites.Ui.Content.Text('MinSide = ', Sprites.Media.Shader.MinSide);
The smallest side a shader image may take.

Sprites.Media.Shader.MaxSide Number

The largest a side may be, in pixels. A plain number, so it drops straight into a clamp as a constant argument.

Sprites.Ui.Content.Text('MaxSide = ', Sprites.Media.Shader.MaxSide);
The largest side a shader image may take.

Sprites.Media.Shader.DefaultWidth Number

The default new image width, in pixels. A square, large enough to read a shader on. A plain number, so it drops straight into a new document as a constant argument.

Sprites.Ui.Content.Text('DefaultWidth = ', Sprites.Media.Shader.DefaultWidth);
The width a fresh shader image starts at.

Sprites.Media.Shader.DefaultHeight Number

The default new image height, in pixels. A square, large enough to read a shader on. A plain number, so it drops straight into a new document as a constant argument.

Sprites.Ui.Content.Text('DefaultHeight = ', Sprites.Media.Shader.DefaultHeight);
The height a fresh shader image starts at.

Sprites.Media.Shader.Header String

The built-in prelude every layer's GLSL opens with: the version and precision, the two built-in uniforms, the fragment output, and the built-in per-fragment values the layer code may read. uInput is the texture the layer below rendered, uResolution the image size in pixels. Resolution, Pixel, Uv and Unit are filled by the main below before it calls LayerMain, so the layer code reads them as plain globals. A plain string, so it drops straight into the source assembly as a constant.

const header = Sprites.Reactive.Value(Sprites.Media.Shader.Header);
Sprites.Ui.Code.Editor(header);
The prelude that opens every layer's GLSL, shown in a code editor.

Sprites.Media.Shader.DefaultCode String

The code a fresh layer starts with: a LayerMain that lays a soft opaque tint, so a new layer renders something and shows the shape a LayerMain takes. It returns its own colour; the built-in main composites it over the layer below, so a lower alpha here would let the layer below show through. It must define vec4 LayerMain(), the function the built-in main calls.

const code = Sprites.Reactive.Value(Sprites.Media.Shader.DefaultCode);
Sprites.Ui.Code.Editor(code);
The starter LayerMain a fresh layer opens with, shown in a code editor.

Sprites.Media.Shader.DefaultGlobals String

The shared global code a fresh image starts with: helpers every layer can call, added to each layer's GLSL ahead of the layer's own code.

const globals = Sprites.Reactive.Value(Sprites.Media.Shader.DefaultGlobals);
Sprites.Ui.Code.Editor(globals);
The shared helpers a fresh image opens with, shown in a code editor.

Sprites.Media.Shader.ClampSide Sprites.Reactive.Value

Sprites.Media.Shader.ClampSide(n)

Clamp a side to the allowed range, as a whole number. A composite: round, then hold between the smallest and largest a side may be.

InputTypeDescription
nSprites.Reactive.ValueThe side to round and clamp, in pixels.

Returns a reactive number, the side rounded and held between MinSide and MaxSide.

const n = Sprites.Reactive.Value(8000);
const side = Sprites.Media.Shader.ClampSide(n);
Sprites.Ui.Input.Number(n);
Sprites.Ui.Content.Text('Clamped side: ', side);
A side rounded and clamped to the allowed range; edit the number to see it held.

Sprites.Media.Shader.Placeholder Void

Sprites.Media.Shader.Placeholder(width, height)

The stage placeholder: a panel that fills the canvas area and names the render size, standing in for the WebGL canvas until the render driver lands. It keeps the shell usable and testable now, the windows, the model and the GLSL composition, without waiting on the driver. width and height are the reactive document size, shown so a size change reads back here.

InputTypeDescription
widthSprites.Reactive.ValueThe reactive document width, in pixels.
heightSprites.Reactive.ValueThe reactive document height, in pixels.

Returns nothing.

const width = Sprites.Reactive.Value(512);
const height = Sprites.Reactive.Value(512);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Style('position', 'relative');
  Sprites.Ui.Dom.Style('height', '160px');
  Sprites.Media.Shader.Placeholder(width, height);
});
Sprites.Ui.Input.Number(width);
Sprites.Ui.Input.Number(height);
The stage placeholder naming the render size; edit the width or height to see it read back.