Sprites.Media.Sprite

The sprite editor, its state and its windows, over an integer pixel grid. The pixel grid is drawn by Sprites.Media.Sprite.Canvas, and the editor's tools live in Sprites.Media.Sprite.Tool.

Sprites.Media.Sprite

Sprites.Media.Sprite.ClampSide Number

Sprites.Media.Sprite.ClampSide(n)

Clamp a side to the allowed range, as a whole number, between MinSide and MaxSide.

InputTypeDescription
nNumberA requested side length.

Returns the clamped whole number.

const side = Sprites.Media.Sprite.ClampSide(1000);
Sprites.Ui.Dom.Text('ClampSide(1000) = ', side);
A large side clamps to the maximum, 256.

Sprites.Media.Sprite.CloneFrame Sprites.Reactive.Value

Sprites.Media.Sprite.CloneFrame(frame)

A copy of a frame: a fresh frame object whose layers are each cloned, so the copy is independent of the original. A composite over Array.Map and CloneLayer.

InputTypeDescription
frameObject or Sprites.Reactive.ValueA { layers } frame to copy.

Returns a Sprites.Reactive.Value holding the cloned { layers } frame.

const frame = Sprites.Media.Sprite.NewFrame(4, 4);
const copy = Sprites.Media.Sprite.CloneFrame(frame);
const layers = Sprites.Object.Field(copy, 'layers');
const count = Sprites.Array.Length(layers);
Sprites.Ui.Dom.Text('layers = ', count);
A cloned frame, independent of the original, with one layer.

Sprites.Media.Sprite.CloneLayer Sprites.Reactive.Value

Sprites.Media.Sprite.CloneLayer(layer)

A copy of a layer: a fresh layer object holding the same pixels and visible flag. Rebuilding the object keeps the copy independent, so editing one leaves the other be, since a paint replaces the pixels rather than changing them in place.

InputTypeDescription
layerObject or Sprites.Reactive.ValueA { pixels, visible } layer to copy.

Returns a Sprites.Reactive.Value holding the cloned { pixels, visible } layer.

const layer = Sprites.Media.Sprite.NewLayer(4, 4);
const copy = Sprites.Media.Sprite.CloneLayer(layer);
const pixels = Sprites.Object.Field(copy, 'pixels');
const count = Sprites.Array.Length(pixels);
const visible = Sprites.Object.Field(copy, 'visible');
Sprites.Ui.Dom.Text('pixels = ', count, ', visible = ', visible);
A cloned layer, its pixels and visible flag carried over.

Sprites.Media.Sprite.ColourPicker Void

Sprites.Media.Sprite.ColourPicker(visible, colour, bits, allowAlpha)

A modal wrapping Sprites.Colour.Picker. It edits a temp seeded from colour on open, so Select commits the temp to colour and Close discards it.

InputTypeDescription
visibleSprites.Reactive.ValueShows the modal while true.
colourSprites.Reactive.ValueThe packed colour Select writes.
bitsNumberThe bits per channel the sliders step over.
allowAlphaBooleanAdds an alpha row.

Returns nothing.

const orange = 0xff8000ff;
const colour = Sprites.Reactive.Value(orange);
const visible = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(visible, true, 'Edit colour');
Sprites.Media.Sprite.ColourPicker(visible, colour, 8, true);
const css = Sprites.Colour.Css(colour);
Sprites.Ui.Dom.Text('css = ', css);
Open the modal, edit, and Select to commit the colour.

Sprites.Media.Sprite.Editor Void

Sprites.Media.Sprite.Editor(data, thumb, info, optionalModes, optionalModeName, optionalSelectedColours, optionalAllColours)

The sprite editor. Builds the view on the host, the pan and zoom overlay, the Tools window, each canvas tool's own window, the four panel windows, and the Palette and Info windows. It builds interface and returns nothing; the doc fields it is given are where the edits land. data is the whole stored document, a two way { w, h, mode, frames }; the editor holds its own selected frame and layer, edits into the selected layer, and draws the current frame's visible layers flattened. On every edit it writes a fresh PNG preview to thumb and a short mode and size summary string to info. optionalSelectedColours makes an indexed editor; left out, it is freeform. optionalModes lists the machine's sprite modes, each with a colour count, a pixel aspect and a size rule; the Info window picks the mode and the size. optionalModeName is a two way value of the current mode's name. A mode with fewer colours wraps the pixels and the brush into range and shows a shorter palette.

InputTypeDescription
dataSprites.Reactive.ValueThe whole stored document, a two way { w, h, mode, frames } of frames of layers of pixels. The editor edits the selected layer and shows the current frame's visible layers flattened.
thumbSprites.Reactive.ValueThe editor Sets a fresh PNG data URL of the pixels here on every edit.
infoSprites.Reactive.ValueThe editor Sets a short mode and size summary string here on every edit, for the meta record a listing reads.
optionalModesArrayOptional. The machine's sprite modes; left out, one free-size mode is used.
optionalModeNameSprites.Reactive.ValueOptional. A two way value of the current mode's name.
optionalSelectedColoursArrayOptional. Slot colours as packed integers; makes the editor indexed.
optionalAllColoursObjectOptional. Where a slot edit draws from: { palette } or { bitsPerChannel }.

Each mode in optionalModes is { name, colours, pixelAspect } plus one size rule: allowedWidths and allowedHeights for two dropdowns, allowedSizes (an array of [width, height]) for one dropdown, or neither for typed width and height, bounded by minWidth, maxWidth, minHeight and maxHeight.

Returns nothing.

const on = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(on, true, 'Launch editor');
Sprites.Reactive.If(on, () => {
  Sprites.Ui.Dom.Tag('div', () => {
    Sprites.Ui.Dom.Style('height', '260px');
    const fresh = Sprites.Media.Sprite.New(16, 16);
    const blank = Sprites.Reactive.read(fresh);
    const data = Sprites.Reactive.Value(blank);
    const thumb = Sprites.Reactive.Value(undefined);
    const info = Sprites.Reactive.Value(undefined);
    Sprites.Media.Sprite.Editor(data, thumb, info);
  });
});
A freeform editor, with its Tools, Palette and Info windows.

Sprites.Media.Sprite.New Object

Sprites.Media.Sprite.New(w, h)

A fresh grid, its cells all transparent. New builds a { w, h, cells } grid whose cells are a flat list in row order, length w times h, every cell the transparent value.

InputTypeDescription
wNumberThe width in pixels.
hNumberThe height in pixels.

Returns the new grid, all cells transparent.

const grid = Sprites.Media.Sprite.New(4, 4);
const cells = Sprites.Object.Field(grid, 'cells');
const first = Sprites.Array.At(cells, 0);
const empty = Sprites.Logic.Equals(first, Sprites.Media.Sprite.Transparent);
const count = Sprites.Array.Length(cells);
Sprites.Ui.Dom.Text(count, ' cells, first transparent = ', empty);
Sixteen cells, each transparent.

Sprites.Media.Sprite.FitPan Sprites.Reactive.Value

Sprites.Media.Sprite.FitPan(width, height, aspect)

The pan that centres the whole sprite: half its drawn width and half its height, with the width stretched by the pixel aspect. A calculation helper, so the view follows the size and aspect on its own.

InputTypeDescription
widthNumber or Sprites.Reactive.ValueThe sprite width in pixels.
heightNumber or Sprites.Reactive.ValueThe sprite height in pixels.
aspectNumber or Sprites.Reactive.ValueThe pixel aspect the width is stretched by.

Returns a read-only Sprites.Reactive.Value holding the centre { x, y } point.

const pan = Sprites.Media.Sprite.FitPan(16, 8, 2);
const x = Sprites.Object.Field(pan, 'x');
const y = Sprites.Object.Field(pan, 'y');
Sprites.Ui.Dom.Text('x = ', x, ', y = ', y);
A sixteen-wide, two-aspect sprite centres at sixteen across, four down.

Sprites.Media.Sprite.FitShow Sprites.Reactive.Value

Sprites.Media.Sprite.FitShow(width, height, aspect)

The show that spans the wider of the two drawn axes, with a small margin, so the whole sprite stays in view. A calculation helper.

InputTypeDescription
widthNumber or Sprites.Reactive.ValueThe sprite width in pixels.
heightNumber or Sprites.Reactive.ValueThe sprite height in pixels.
aspectNumber or Sprites.Reactive.ValueThe pixel aspect the width is stretched by.

Returns a read-only Sprites.Reactive.Value holding the units to show across.

const show = Sprites.Media.Sprite.FitShow(16, 8, 2);
Sprites.Ui.Dom.Text('FitShow(16, 8, 2) = ', show);
The wider drawn axis, thirty two, plus a four-unit margin.

Sprites.Media.Sprite.FrameThumbnail Sprites.Reactive.Value

Sprites.Media.Sprite.FrameThumbnail(frame, width, height, optionalPaletteSlots, aspect)

A PNG data URL of one frame, its visible layers flattened and drawn through the palette and pixel aspect, as a reactive value that follows the frame, for a frame card's preview. A composite over Grid.Two.Flatten and Thumbnail.

InputTypeDescription
frameObject or Sprites.Reactive.ValueA { layers } frame, its layers over the width and height.
widthNumber or Sprites.Reactive.ValueThe document width, shared by every layer.
heightNumber or Sprites.Reactive.ValueThe document height, shared by every layer.
optionalPaletteSlotsArray or Sprites.Reactive.ValueOptional. The slot colours when the sprite is indexed; left out, a cell is a packed colour already.
aspectNumber or Sprites.Reactive.ValueThe pixel aspect baked into the image.

Returns a read-only Sprites.Reactive.Value holding a PNG data URL string.

const bottom = { pixels: [0xff4444ff, 0xff4444ff, 0xff4444ff, 0xff4444ff], visible: true };
const top = { pixels: [undefined, 0x4444ffff, undefined, undefined], visible: true };
const frame = { layers: [bottom, top] };
const url = Sprites.Media.Sprite.FrameThumbnail(frame, 2, 2, undefined, 1);
Sprites.Ui.Dom.Tag('img', () => {
  Sprites.Ui.Dom.Attribute('src', url);
  Sprites.Ui.Dom.Style('width', '64px');
  Sprites.Ui.Dom.Style('height', '64px');
  Sprites.Ui.Dom.Style('image-rendering', 'pixelated');
});
A frame's visible layers flattened and drawn to an image.

Sprites.Image.Draw.Grid Void

Sprites.Image.Draw.Grid(x1, y1, x2, y2, xDivisions, yDivisions)

A thin line around every pixel of the sprite, drawn inside a Vector. The sprite editor's canvas draws its pixel grid this way, styling the lines with Sprites.Image.Draw.LineStyle over a Sprites.Image.Draw.Grid across the sprite bounds.

InputTypeDescription
x1, y1Number or Sprites.Reactive.ValueThe top left of the grid.
x2, y2Number or Sprites.Reactive.ValueThe bottom right of the grid.
xDivisions, yDivisionsNumber or Sprites.Reactive.ValueThe cells across and down.

Returns nothing.

const pan = Sprites.Reactive.Value({ x: 4, y: 4 });
const show = Sprites.Reactive.Value(10);
Sprites.Ui.Dom.Tag('div', () => {
  Sprites.Ui.Dom.Style('height', '160px');
  Sprites.Ui.Image.Vector(pan, show, () => {
    Sprites.Image.Draw.LineStyle(0.04, 'rgba(0, 0, 0, 0.5)', () => {
      Sprites.Image.Draw.Grid(0, 0, 8, 8, 8, 8);
    });
  });
});
An eight by eight grid, the same lines the canvas draws.

Sprites.Maths.Multiply Sprites.Reactive.Value

Sprites.Maths.Multiply(k, aspect)

The drawn x of grid line k: its column stretched by the pixel aspect. The canvas grid places each vertical line by multiplying the column index by the aspect, so a wide-pixel mode spreads the columns apart.

InputTypeDescription
kNumber or Sprites.Reactive.ValueThe grid line index across the width.
aspectNumber or Sprites.Reactive.ValueThe pixel aspect the column is stretched by.

Returns a read-only Sprites.Reactive.Value, the drawn x of the line.

const x = Sprites.Maths.Multiply(3, 2);
Sprites.Ui.Dom.Text('column 3 at aspect 2 draws at x = ', x);
Line three over a two-wide pixel draws at six.

Sprites.Maths.Increment Sprites.Reactive.Value

Sprites.Maths.Increment(height)

The count of grid lines down the height, one past each row. The canvas grid draws one line above the first row and one below each row, so an h-row sprite needs h plus one lines, the height incremented.

InputTypeDescription
heightNumber or Sprites.Reactive.ValueThe sprite height in cells.

Returns a read-only Sprites.Reactive.Value, the grid line count down.

const rows = Sprites.Maths.Increment(8);
Sprites.Ui.Dom.Text('an 8-row sprite needs ', rows, ' lines down');
An eight-row sprite needs nine lines down.

Sprites.Media.Sprite.Info Void

Sprites.Media.Sprite.Info(modes, modeIndex, state, width, height)

The Info window: an always-present floating panel docked to the stage's bottom right. It holds a Mode dropdown and, below it, the size controls for the current mode. Picking a mode sets the colour count and the pixel aspect, and resets the size when the current one falls outside the mode.

InputTypeDescription
modesArrayThe sprite modes to choose from.
modeIndexSprites.Reactive.ValueThe index of the current mode, set by the dropdown.
stateSprites.Reactive.ValueThe sprite state, resized by the size controls.
width, heightSprites.Reactive.ValueThe size in pixels, for the free and dropdown controls.

Returns nothing.

const modes = [
  { name: 'High-res', colours: 2, pixelAspect: 1, allowedSizes: [[24, 21]] },
  { name: 'Multicolour', colours: 4, pixelAspect: 2, allowedSizes: [[12, 21]] },
];
const modeIndex = Sprites.Reactive.Value(0);
const sprite = Sprites.Media.Sprite.New(24, 21);
const state = Sprites.Reactive.Value(sprite);
const width = Sprites.Object.Field(state, 'w');
const height = Sprites.Object.Field(state, 'h');
Sprites.Media.Sprite.Info(modes, modeIndex, state, width, height);
Sprites.Ui.Dom.Text('mode = ', modeIndex);
The floating Info window picks the mode and the size.

Sprites.Media.Sprite.LayerThumbnail Sprites.Reactive.Value

Sprites.Media.Sprite.LayerThumbnail(layer, width, height, optionalPaletteSlots, aspect)

A PNG data URL of one layer, drawn at the document size through the palette and pixel aspect, as a reactive value that follows the layer's pixels, for a layer card's preview. A composite over Thumbnail.

InputTypeDescription
layerObject or Sprites.Reactive.ValueA { pixels, visible } layer over the width and height.
widthNumber or Sprites.Reactive.ValueThe document width.
heightNumber or Sprites.Reactive.ValueThe document height.
optionalPaletteSlotsArray or Sprites.Reactive.ValueOptional. The slot colours when the sprite is indexed; left out, a cell is a packed colour already.
aspectNumber or Sprites.Reactive.ValueThe pixel aspect baked into the image.

Returns a read-only Sprites.Reactive.Value holding a PNG data URL string.

const layer = { pixels: [0xff4444ff, undefined, undefined, 0x4444ffff], visible: true };
const url = Sprites.Media.Sprite.LayerThumbnail(layer, 2, 2, undefined, 1);
Sprites.Ui.Dom.Tag('img', () => {
  Sprites.Ui.Dom.Attribute('src', url);
  Sprites.Ui.Dom.Style('width', '64px');
  Sprites.Ui.Dom.Style('height', '64px');
  Sprites.Ui.Dom.Style('image-rendering', 'pixelated');
});
One layer's pixels drawn to an image at the document size.

Sprites.Media.Sprite.MaxSide Number

Sprites.Media.Sprite.MaxSide

The largest a sprite side may be. A constant, not a function, used with MinSide to clamp a requested width or height.

Value 256.

Sprites.Ui.Dom.Text('MaxSide = ', Sprites.Media.Sprite.MaxSide);
The largest a side may be.

Sprites.Media.Sprite.MinSide Number

Sprites.Media.Sprite.MinSide

The smallest a sprite side may be. A constant, not a function, used with MaxSide to clamp a requested width or height.

Value 1.

Sprites.Ui.Dom.Text('MinSide = ', Sprites.Media.Sprite.MinSide);
The smallest a side may be.

Sprites.Media.Sprite.ModeFitSize Sprites.Reactive.Value

Sprites.Media.Sprite.ModeFitSize(mode, width, height)

The size a mode allows, given the current width and height: a reactive { w, h }. A mode with allowedSizes keeps the current pair when it is one of them, else the first pair; a mode with allowedWidths or allowedHeights keeps the current side when it is allowed, else the first allowed value; a mode with none keeps the current size. A composite, reading the same in the mode lens as it does going forward.

InputTypeDescription
modeObject or Sprites.Reactive.ValueThe mode, with allowedSizes, or allowedWidths and allowedHeights, or none.
widthNumber or Sprites.Reactive.ValueThe current width in pixels.
heightNumber or Sprites.Reactive.ValueThe current height in pixels.

Returns a read-only Sprites.Reactive.Value holding the allowed { w, h } size.

const mode = { allowedSizes: [[24, 21], [12, 21]] };
const size = Sprites.Media.Sprite.ModeFitSize(mode, 40, 40);
const w = Sprites.Object.Field(size, 'w');
const h = Sprites.Object.Field(size, 'h');
Sprites.Ui.Dom.Text('w = ', w, ', h = ', h);
A size outside the mode falls to its first allowed pair, 24 by 21.

Sprites.Media.Sprite.New Object

Sprites.Media.Sprite.New(w, h)

A new sprite state at the given size, or 32 by 32, empty. The state is { w, h, cells }.

InputTypeDescription
wNumberThe width, clamped. Defaults to 32.
hNumberThe height, clamped. Defaults to 32.

Returns the new sprite state.

const sprite = Sprites.Media.Sprite.New(8, 8);
const line = Sprites.Reactive.Calculate(() => {
  const s = Sprites.Reactive.Calculate.Get(sprite);
  return 'New(8, 8): ' + s.w + ' by ' + s.h + ', ' + s.cells.length + ' cells';
});
Sprites.Ui.Dom.Text(line);
An eight by eight sprite has sixty four cells.

Sprites.Media.Sprite.NewDocument Object

Sprites.Media.Sprite.NewDocument(w, h, optionalMode)

A new sprite document at the given size in the given mode: the { w, h, mode, frames } shape the store keeps, its one frame holding one visible layer of the blank pixels. A boot factory a page hands to the store, so it snapshots the blank grid plain here rather than staying a live reactive.

InputTypeDescription
wNumberThe width, clamped. Defaults to 32.
hNumberThe height, clamped. Defaults to 32.
optionalModeString or undefinedOptional. The mode name stored on the document.

Returns the new { w, h, mode, frames } document.

const doc = Sprites.Media.Sprite.NewDocument(8, 8, 'High-res');
const w = Sprites.Object.Field(doc, 'w');
const h = Sprites.Object.Field(doc, 'h');
const frames = Sprites.Object.Field(doc, 'frames');
const mode = Sprites.Object.Field(doc, 'mode');
const frameCount = Sprites.Array.Length(frames);
Sprites.Ui.Dom.Text(w, ' by ', h, ', ', frameCount, ' frame, mode ', mode);
An eight by eight document with one frame and one layer.

Sprites.Media.Sprite.NewFrame Sprites.Reactive.Value

Sprites.Media.Sprite.NewFrame(width, height)

A new blank frame at the given size: one background layer, blank and visible. A composite, for a click that adds or seeds a frame.

InputTypeDescription
widthNumber or Sprites.Reactive.ValueThe width in pixels.
heightNumber or Sprites.Reactive.ValueThe height in pixels.

Returns a Sprites.Reactive.Value holding a { layers } frame with one blank layer.

const frame = Sprites.Media.Sprite.NewFrame(8, 8);
const layers = Sprites.Object.Field(frame, 'layers');
const count = Sprites.Array.Length(layers);
Sprites.Ui.Dom.Text('layers = ', count);
A blank frame with one visible background layer.

Sprites.Media.Sprite.NewLayer Sprites.Reactive.Value

Sprites.Media.Sprite.NewLayer(width, height)

A new blank layer at the given size: one visible layer of transparent pixels, its grid built with the grid primitive. A composite, so a click that adds a layer passes it as a fresh reactive value the array insert commits.

InputTypeDescription
widthNumber or Sprites.Reactive.ValueThe width in pixels.
heightNumber or Sprites.Reactive.ValueThe height in pixels.

Returns a Sprites.Reactive.Value holding a { pixels, visible } layer.

const layer = Sprites.Media.Sprite.NewLayer(8, 8);
const pixels = Sprites.Object.Field(layer, 'pixels');
const count = Sprites.Array.Length(pixels);
const visible = Sprites.Object.Field(layer, 'visible');
Sprites.Ui.Dom.Text('pixels = ', count, ', visible = ', visible);
A blank layer of sixty four transparent pixels, visible.

Sprites.Grid.Two.Set Sprites.Reactive.Value

Sprites.Grid.Two.Set(grid, col, row, colour)

Paint one cell to a colour. A sprite is a Sprites.Grid.Two, so a single-cell paint is Sprites.Grid.Two.Set: it returns a new grid, or the same one when the cell falls outside the grid or already holds that colour, so an unchanged paint sets nothing.

InputTypeDescription
gridObject or Sprites.Reactive.ValueThe { w, h, cells } sprite.
colNumberThe column.
rowNumberThe row.
colourNumber or undefinedA cell value, or the transparent value to clear.

Returns the new or unchanged grid.

const blank = Sprites.Media.Sprite.New(8, 8);
const painted = Sprites.Grid.Two.Set(blank, 2, 3, Sprites.Media.Sprite.White);
const cell = Sprites.Grid.Two.At(painted, 2, 3);
Sprites.Ui.Dom.Text('cell (2,3) = ', cell);
One cell now holds the packed white value.

Sprites.Grid.Two.FillRect Sprites.Reactive.Value

Sprites.Grid.Two.FillRect(grid, col, row, rectWidth, rectHeight, colour)

Paint every cell a brush covers to a colour, or the transparent value to erase. The editor's brush is a square of Sprites.Grid.Two.FillRect: a radius one brush is a three by three rect from one cell up and left of the centre. Cells outside the grid are clipped. Returns a new grid, or the same one when nothing changes.

InputTypeDescription
gridObject or Sprites.Reactive.ValueThe { w, h, cells } sprite.
colNumberThe top left column.
rowNumberThe top left row.
rectWidthNumberThe cells across.
rectHeightNumberThe cells down.
colourNumber or undefinedA cell value, or the transparent value to erase.

Returns the new or unchanged grid.

const blank = Sprites.Media.Sprite.New(8, 8);
const painted = Sprites.Grid.Two.FillRect(blank, 2, 2, 3, 3, Sprites.Media.Sprite.White);
const centre = Sprites.Grid.Two.At(painted, 3, 3);
Sprites.Ui.Dom.Text('brush centre (3,3) = ', centre);
A radius one brush paints a three by three square of nine cells.

Sprites.Media.Sprite.Palette Void

Sprites.Media.Sprite.Palette(indexed, slots, brush, visible, edit)

The Palette window: a floating panel docked to the stage's bottom left. Indexed, it holds a Sprites.Colour.Palette of the slot colours and an Edit button; freeform, it holds a Sprites.Colour.Picker inline.

InputTypeDescription
indexedBooleanShow slots (true) or the inline picker (false).
slotsSprites.Reactive.ValueThe slot colours, when indexed.
brushSprites.Reactive.ValueThe painted value: a slot index, or a packed colour.
visibleSprites.Reactive.ValueShows the window while true.
editFunction or undefinedOpens the slot editor when given.

Returns nothing.

const colours = [0xff4444ff, 0x44ff44ff, 0x4444ffff, 0xffff44ff];
const slots = Sprites.Reactive.Value(colours);
const brush = Sprites.Reactive.Value(0);
const visible = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(visible, true, 'Show palette window');
Sprites.Media.Sprite.Palette(true, slots, brush, visible);
Sprites.Ui.Dom.Text('brush index = ', brush);
Pick a slot in the floating Palette window.

Sprites.Media.Sprite.PalettePicker Void

Sprites.Media.Sprite.PalettePicker(visible, index, palette)

A modal wrapping Sprites.Colour.Palette. index is a binding it sets, on Select, to the position of the chosen colour in palette; Close leaves it.

InputTypeDescription
visibleSprites.Reactive.ValueShows the modal while true.
indexSprites.Reactive.ValueThe position Select writes.
paletteArrayThe packed colours to choose from.

Returns nothing.

const index = Sprites.Reactive.Value(0);
const palette = [0xff4444ff, 0x44ff44ff, 0x4444ffff, 0xffff44ff];
const visible = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(visible, true, 'Pick a colour');
Sprites.Media.Sprite.PalettePicker(visible, index, palette);
Sprites.Ui.Dom.Text('index = ', index);
Select writes the chosen position to the binding.

Sprites.Media.Sprite.PixelsToRGBA Sprites.Reactive.Value

Sprites.Media.Sprite.PixelsToRGBA(pixels, optionalPalette)

The sprite as a grid of packed RGBA colours. With no palette the sprite is freeform: a cell is the packed colour already and a transparent cell is already undefined, so the pixels stand as they are. With a palette the sprite is indexed: a cell is a slot index, so each cell resolves to the slot's packed colour, keeping a transparent cell transparent. The view and the thumbnail both draw from this, so a packed colour is the one pixel form everything reads.

InputTypeDescription
pixelsGrid or Sprites.Reactive.ValueThe sprite's pixels grid, packed colours or slot indices.
optionalPaletteArray or Sprites.Reactive.ValueOptional. The slot colours for an indexed sprite; left out, a cell is a packed colour already.

Returns a Sprites.Reactive.Value holding the grid of packed RGBA colours.

const palette = [0xff4444ff, 0x4444ffff];
const pixels = { w: 2, h: 1, cells: [0, 1] };
const rgba = Sprites.Media.Sprite.PixelsToRGBA(pixels, palette);
const cell00 = Sprites.Grid.Two.At(rgba, 0, 0);
const cell10 = Sprites.Grid.Two.At(rgba, 1, 0);
Sprites.Ui.Dom.Text('cell (0,0) = ', cell00, ', cell (1,0) = ', cell10);
Slot indices resolved to their palette's packed colours.

Sprites.Grid.Two.Resize Sprites.Reactive.Value

Sprites.Grid.Two.Resize(grid, nw, nh, pad)

Resize the grid to nw by nh, keeping the cells that still fit and filling new area with pad. A sprite is a Sprites.Grid.Two, so one layer resizes with Sprites.Grid.Two.Resize, padding new area with the transparent value; ResizeAll runs it over every layer of the document.

InputTypeDescription
gridObject or Sprites.Reactive.ValueThe { w, h, cells } sprite.
nwNumberThe new width.
nhNumberThe new height.
padAnyThe cell for new area, the transparent value here.

Returns the resized grid.

const blank = Sprites.Media.Sprite.New(8, 8);
const resized = Sprites.Grid.Two.Resize(blank, 4, 16, Sprites.Media.Sprite.Transparent);
const width = Sprites.Grid.Two.Width(resized);
const height = Sprites.Grid.Two.Height(resized);
Sprites.Ui.Dom.Text('resized to ', width, ' by ', height);
The grid takes the new size.

Sprites.Media.Sprite.ResizeAll Sprites.Reactive.Value

Sprites.Media.Sprite.ResizeAll(data, width, height, pad)

The same document resized so every layer of every frame is the new width and height, cropping or padding each layer's pixels with pad. Width and height live on the document, shared by every layer, so a size or mode change resizes them all together. A composite over Array.Map, Grid.Two.Resize and ReadOnly, keeping the mode and each layer's visible flag.

InputTypeDescription
dataObject or Sprites.Reactive.ValueThe { w, h, mode, frames } document.
widthNumber or Sprites.Reactive.ValueThe new width for every layer.
heightNumber or Sprites.Reactive.ValueThe new height for every layer.
padAny or Sprites.Reactive.ValueThe pixel for the new area when growing.

Returns a Sprites.Reactive.Value holding the resized document.

const doc = Sprites.Media.Sprite.NewDocument(8, 8);
const resized = Sprites.Media.Sprite.ResizeAll(doc, 4, 16, undefined);
const w = Sprites.Object.Field(resized, 'w');
const h = Sprites.Object.Field(resized, 'h');
Sprites.Ui.Dom.Text('size = ', w, ' by ', h);
Every layer of every frame resized to four by sixteen.

Sprites.Media.Sprite.SelectedGrid Sprites.Reactive.Value

Sprites.Media.Sprite.SelectedGrid(data, frameIndex, layerIndex)

A two way { w, h, cells } grid over the layer at layerIndex of the frame at frameIndex. data is the two way stored { w, h, mode, frames } value; frameIndex and layerIndex are the editor's selection. Reading composes the grid from the width, height and that layer's pixels, so the editor edits one flat layer. Writing lays the edited pixels back into that one layer through the frames list, keeping the layer's visible flag and every other frame, layer, the size and the mode, so a paint touches only the selected layer.

InputTypeDescription
dataSprites.Reactive.ValueThe two way { w, h, mode, frames } document it reads and writes.
frameIndexNumber or Sprites.Reactive.ValueThe selected frame.
layerIndexNumber or Sprites.Reactive.ValueThe selected layer within the frame.

Returns a two-way Sprites.Reactive.Value over the selected layer's { w, h, cells } grid.

const pixels = Array(64).fill(Sprites.Media.Sprite.Transparent);
pixels[3 * 8 + 2] = Sprites.Media.Sprite.White;
const layer = { pixels: pixels, visible: true };
const frame = { layers: [layer] };
const blank = { w: 8, h: 8, mode: undefined, frames: [frame] };
const data = Sprites.Reactive.Value(blank);
const grid = Sprites.Media.Sprite.SelectedGrid(data, 0, 0);
const width = Sprites.Grid.Two.Width(grid);
const height = Sprites.Grid.Two.Height(grid);
const cell23 = Sprites.Grid.Two.At(grid, 2, 3);
Sprites.Ui.Dom.Text('size = ', width, ' by ', height, ', cell (2,3) = ', cell23);
Painting the selected grid writes back into the one layer.

Sprites.Media.Sprite.StageTop Number

Sprites.Media.Sprite.StageTop

The top edge, in viewport pixels, where the editor's top-docked windows open: a little below where the sprite stage begins, so the Tools window and each tool window open inside the stage rather than over the title and name rows above it. A starting corner only; the windows drag from there. A constant, not a function.

Value 163.

Sprites.Ui.Dom.Text('StageTop = ', Sprites.Media.Sprite.StageTop);
Where the editor's top-docked windows open.

Sprites.Media.Sprite.Summary String

Sprites.Media.Sprite.Summary(modeName, grid)

The meta info summary for a sprite: its mode and size as one short string, for the meta record a listing reads. A plain reader for use inside a reverse handler: it reads the mode name and the grid's sides and joins them, dropping the mode when there is none.

InputTypeDescription
modeNameString or Sprites.Reactive.ValueThe mode name, or empty for no mode.
gridObjectA snapshot { w, h } grid.

Returns the summary string, like "High-res · 24×21".

const summary = Sprites.Media.Sprite.Summary('High-res', { w: 24, h: 21 });
Sprites.Ui.Dom.Text('summary = ', summary);
The mode and size joined into one short string.

Sprites.Media.Sprite.Thumbnail String

Sprites.Media.Sprite.Thumbnail(sprite, optionalPaletteSlots, optionalAspectRatio)

A PNG data URL of the sprite's pixels, one image pixel per sprite pixel, transparent where a cell is empty. optionalPaletteSlots maps indexed pixels through a palette to packed colours, and is omitted when the pixels already hold packed colours. optionalAspectRatio stretches the pixels to match a wide or tall pixel mode. A plain value helper over a snapshot, so it can run in a save handler to keep a stored thumbnail current with the pixels.

InputTypeDescription
spriteGridThe sprite's pixels grid, a Sprites.Grid.Two of packed colours or palette indices.
optionalPaletteSlotsArrayOptional. A palette mapping pixel indices to packed colours, for indexed modes; omit when the pixels are already packed colours.
optionalAspectRatioNumberOptional, default 1. The pixel aspect: above 1 draws each pixel wider, below 1 taller.

Returns a PNG data URL string.

const red = 0xff4444ff;
const blue = 0x4444ffff;
const blank = Sprites.Media.Sprite.New(4, 4);
const withRed = Sprites.Grid.Two.Set(blank, 1, 1, red);
const painted = Sprites.Grid.Two.Set(withRed, 2, 2, blue);
const url = Sprites.Media.Sprite.Thumbnail(painted, undefined, 1);
Sprites.Ui.Dom.Tag('img', () => {
  Sprites.Ui.Dom.Attribute('src', url);
  Sprites.Ui.Dom.Style('width', '64px');
  Sprites.Ui.Dom.Style('height', '64px');
  Sprites.Ui.Dom.Style('image-rendering', 'pixelated');
});
A saved sprite rendered to a data URL and shown as an image.

Sprites.Media.Sprite.Transparent Number

Sprites.Media.Sprite.Transparent

The transparent cell: an absent value, undefined. A cell holds this where nothing is painted, and a resize or an erase writes it. Naming it keeps the absent value intentional and reads as transparent at every use. A constant, not a function.

Value undefined.

const empty = Sprites.Logic.Equals(Sprites.Media.Sprite.Transparent, undefined);
Sprites.Ui.Dom.Text('Transparent is undefined = ', empty);
The absent value a cell holds where nothing is painted.

Sprites.Media.Sprite.White Number

Sprites.Media.Sprite.White

Opaque white as a packed colour, the freeform brush default. A constant, not a function.

Value the packed colour Sprites.Colour.Pack(255, 255, 255, 255).

Sprites.Ui.Dom.Text('White = ', Sprites.Media.Sprite.White);
The packed value of opaque white.

Sprites.Media.Sprite.WithLayers Sprites.Reactive.Value

Sprites.Media.Sprite.WithLayers(frames, frameIndex, layers)

A frames list with the frame at frameIndex given a new layers list. A composite, for a layer edit: the layers of a frame past the first are only reachable through the frames list, so a layer change lays a new frames list a Set of frames commits.

InputTypeDescription
framesArray or Sprites.Reactive.ValueThe frames list, each a { layers } frame.
frameIndexNumber or Sprites.Reactive.ValueThe frame whose layers are replaced.
layersArray or Sprites.Reactive.ValueThe new layers list for that frame.

Returns a Sprites.Reactive.Value holding the frames list with the one frame's layers replaced.

const base = { pixels: Array(16).fill(Sprites.Media.Sprite.Transparent), visible: true };
const extra = { pixels: Array(16).fill(Sprites.Media.Sprite.Transparent), visible: true };
const frames = [{ layers: [base] }];
const layers = [base, extra];
const updated = Sprites.Media.Sprite.WithLayers(frames, 0, layers);
const frame = Sprites.Array.At(updated, 0);
const frameLayers = Sprites.Object.Field(frame, 'layers');
const count = Sprites.Array.Length(frameLayers);
Sprites.Ui.Dom.Text('layers = ', count);
The first frame given a two layer list through the frames list.

Sprites.Media.Sprite.WrapColours Sprites.Reactive.Value

Sprites.Media.Sprite.WrapColours(data, count)

The same document with every pixel of every layer folded into a colour count, a transparent pixel staying transparent, so a mode with fewer colours wraps the pixels of all the layers into range at once. A composite over Array.Map, Sprites.Maths.Modulo and Sprites.Logic.Select, keeping the size, the mode and each layer's visible flag.

InputTypeDescription
dataObject or Sprites.Reactive.ValueThe { w, h, mode, frames } document.
countNumber or Sprites.Reactive.ValueThe colour count each pixel index is folded into, 0 to count minus one.

Returns a Sprites.Reactive.Value holding the document with every pixel wrapped into range.

const layer = { pixels: [0, 5, 6, 7], visible: true };
const doc = { w: 2, h: 2, mode: undefined, frames: [{ layers: [layer] }] };
const wrapped = Sprites.Media.Sprite.WrapColours(doc, 4);
const line = Sprites.Reactive.Calculate(() => {
  const d = Sprites.Reactive.Calculate.Get(wrapped);
  return d.frames[0].layers[0].pixels.join(', ');
});
Sprites.Ui.Dom.Text('pixels = ', line);
Pixel indices folded into a count of four, 0, 1, 2, 3.