Sprites.Media.Image.Cells
The attribute image editor and its model. Some machines cannot colour every pixel on its own: the pixels are one bit each, ink or paper, and the ink and paper colours are set for a whole block of pixels, an attribute cell. The Spectrum and the C64 hires give each 8 by 8 cell its own ink and paper; the Oric sets ink and paper with an inline control that takes a whole 6 by 1 cell and holds along the row until the next one. So an attribute image stores a full resolution one bit mask and, at cell resolution, an ink and a paper colour grid, exactly the shape the text screen editor uses, with an editable pixel mask in place of the tiled font glyphs. The model composes the generic grid primitives to resolve the screen to packed RGBA, feeds the shared tiled canvas surface, and reuses the image editor's canvas, pan and zoom and windows. Every function composes reactive values; the raw work lives in Sprites.Grid, so this module holds no Calculate.
- Sprites.Media.Image.Cells.Paper
- Sprites.Media.Image.Cells.Ink
- Sprites.Media.Image.Cells.Tile
- Sprites.Media.Image.Cells.DefaultInk
- Sprites.Media.Image.Cells.DefaultPaper
- Sprites.Media.Image.Cells.Wide
- Sprites.Media.Image.Cells.High
- Sprites.Media.Image.Cells.NewDocument
- Sprites.Media.Image.Cells.EffectiveColour
- Sprites.Media.Image.Cells.Colourise
- Sprites.Media.Image.Cells.Resolve
- Sprites.Media.Image.Cells.Display
- Sprites.Media.Image.Cells.Thumbnail
- Sprites.Media.Image.Cells.Summary
- Sprites.Media.Image.Cells.Paint
- Sprites.Media.Image.Cells.ResizeField
- Sprites.Media.Image.Cells.ResizeAll
- Sprites.Media.Image.Cells.ToolWindow
- Sprites.Media.Image.Cells.PaletteGrid
- Sprites.Media.Image.Cells.Palette
- Sprites.Media.Image.Cells.Editor
Sprites.Media.Image.Cells.Paper Number
The paper pixel, one of the two values a mask cell holds. Paper is zero, so the mask reads as a plain one bit grid and Sprites.Grid.Two.Choose picks paper where a cell is clear.
Value 0.
Sprites.Ui.Dom.Text('Paper = ', Sprites.Media.Image.Cells.Paper);
Sprites.Media.Image.Cells.Ink Number
The ink pixel, the other value a mask cell holds. Ink is one, so a set mask cell picks the cell's ink colour.
Value 1.
Sprites.Ui.Dom.Text('Ink = ', Sprites.Media.Image.Cells.Ink);
Sprites.Media.Image.Cells.Tile Number
The tile side the resolved screen is packed into for the canvas surface. The screen is small, so the whole screen repacks on a change; the tiling is only what the surface reads.
Value 16.
Sprites.Ui.Dom.Text('Tile = ', Sprites.Media.Image.Cells.Tile);
Sprites.Media.Image.Cells.DefaultInk Number
The default ink colour index when a machine names none: white ink.
Value 7.
Sprites.Ui.Dom.Text('DefaultInk = ', Sprites.Media.Image.Cells.DefaultInk);
Sprites.Media.Image.Cells.DefaultPaper Number
The default paper colour index when a machine names none: black paper.
Value 0.
Sprites.Ui.Dom.Text('DefaultPaper = ', Sprites.Media.Image.Cells.DefaultPaper);
Sprites.Media.Image.Cells.Wide Sprites.Reactive.Value
Sprites.Media.Image.Cells.Wide(width, cellWidth)
The number of attribute cells across a screen of a pixel width, cut into cellWidth wide cells: the width over the cell width, rounded up. A composite over Sprites.Maths.
| Input | Type | Description |
|---|---|---|
width | Number or Sprites.Reactive.Value | The pixel width of the screen. |
cellWidth | Number or Sprites.Reactive.Value | The attribute cell width in pixels. |
Returns a Sprites.Reactive.Value holding the cells across.
const width = Sprites.Reactive.Value(256);
const cells = Sprites.Media.Image.Cells.Wide(width, 8);
Sprites.Ui.Input.Slider(width, 8, 320);
Sprites.Ui.Dom.Text(' cells wide = ', cells);
Sprites.Media.Image.Cells.High Sprites.Reactive.Value
Sprites.Media.Image.Cells.High(height, cellHeight)
The number of attribute cells down a screen of a pixel height, cut into cellHeight tall cells. A composite over Sprites.Maths.
| Input | Type | Description |
|---|---|---|
height | Number or Sprites.Reactive.Value | The pixel height of the screen. |
cellHeight | Number or Sprites.Reactive.Value | The attribute cell height in pixels. |
Returns a Sprites.Reactive.Value holding the cells down.
const height = Sprites.Reactive.Value(192);
const cells = Sprites.Media.Image.Cells.High(height, 8);
Sprites.Ui.Input.Slider(height, 8, 200);
Sprites.Ui.Dom.Text(' cells high = ', cells);
Sprites.Media.Image.Cells.NewDocument Object
Sprites.Media.Image.Cells.NewDocument(platform, mode, w, h, cellWidth, cellHeight, inline)
A new attribute image document: a blank one bit mask, every pixel paper, and blank ink and paper cell grids, every cell undefined so it reads the default colour. A boot factory a page hands to the store, plain data rather than a live reactive. cellWidth, cellHeight and inline are the mode's attribute shape, kept on the document so the resolve knows the cell size.
| Input | Type | Description |
|---|---|---|
platform | String | The machine name stored on the document. |
mode | String | The attribute mode name. |
w | Number | The pixel width. |
h | Number | The pixel height. |
cellWidth | Number | The attribute cell width in pixels. |
cellHeight | Number | The attribute cell height in pixels. |
inline | Boolean | True for inline attributes, false for per cell. |
Returns the plain { media, platform, mode, w, h, cellWidth, cellHeight, inline, pixels, ink, paper } document object.
const doc = Sprites.Media.Image.Cells.NewDocument('spectrum', 'Standard', 16, 16, 8, 8, false);
const mode = Sprites.Object.Field(doc, 'mode');
const w = Sprites.Object.Field(doc, 'w');
const h = Sprites.Object.Field(doc, 'h');
const pixels = Sprites.Object.Field(doc, 'pixels');
const ink = Sprites.Object.Field(doc, 'ink');
const pixelCount = Sprites.Array.Length(pixels);
const inkCount = Sprites.Array.Length(ink);
Sprites.Ui.Dom.Text(mode, ', ', w, '×', h, ', pixels ', pixelCount, ', ink cells ', inkCount);
Sprites.Media.Image.Cells.EffectiveColour Sprites.Reactive.Value
Sprites.Media.Image.Cells.EffectiveColour(colours, inline, fallback)
The resolved colour of every attribute cell, as a grid: for an inline machine each cell takes the nearest set colour to its left, or the default; for a per cell machine each cell takes its own colour, or the default when absent. A composite over Grid.Two.FillAcross, Grid.Two.Default and Sprites.Logic.Select, each one node over the whole grid.
| Input | Type | Description |
|---|---|---|
colours | Object or Sprites.Reactive.Value | A { w, h, cells } grid of colour indices, its absent cells undefined. |
inline | Boolean or Sprites.Reactive.Value | True to fill each row across from the left, false to default per cell. |
fallback | Number or Sprites.Reactive.Value | The colour index an absent cell takes. |
Returns a Sprites.Reactive.Value holding the resolved colour grid.
const colours = Sprites.Reactive.Value({ w: 3, h: 1, cells: [2, undefined, undefined] });
const inline = Sprites.Reactive.Value(true);
const resolved = Sprites.Media.Image.Cells.EffectiveColour(colours, inline, 0);
const last = Sprites.Grid.Two.At(resolved, 2, 0);
Sprites.Ui.Input.Checkbox(inline);
Sprites.Ui.Dom.Text(' inline; last cell = ', last);
Sprites.Media.Image.Cells.Colourise Sprites.Reactive.Value
Sprites.Media.Image.Cells.Colourise(colours, slots)
A colour cell grid resolved to packed RGBA: each cell's palette index mapped through the slots. A composite over Sprites.Array.Lookup, one node over the whole grid.
| Input | Type | Description |
|---|---|---|
colours | Object or Sprites.Reactive.Value | A { w, h, cells } grid of palette indices. |
slots | Array or Sprites.Reactive.Value | The palette as packed 0xRRGGBBAA integers. |
Returns a Sprites.Reactive.Value holding the { w, h, cells } grid of packed colours.
const slots = [0x000000ff, 0xff0000ff, 0x00ff00ff];
const index = Sprites.Reactive.Value(1);
const colours = Sprites.Grid.Two.Blank(1, 1, index);
const mapped = Sprites.Media.Image.Cells.Colourise(colours, slots);
const packed = Sprites.Grid.Two.At(mapped, 0, 0);
Sprites.Ui.Input.Number(index, 0, 2);
const css = Sprites.Colour.Css(packed);
Sprites.Ui.Dom.Text(' packed colour = ', css);
Sprites.Media.Image.Cells.Resolve Sprites.Reactive.Value
Sprites.Media.Image.Cells.Resolve(data, slots, defaultInk, defaultPaper)
The whole attribute image resolved to a { w, h, cells } grid of packed RGBA colours: the ink and paper grids resolved by the attribute model, coloured through the slots, stretched to pixel size, and the mask picking ink or paper per pixel. A composite over EffectiveColour, Colourise, Grid.Two.Stretch and Grid.Two.Choose, the value the canvas and the thumbnail read.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
slots | Array or Sprites.Reactive.Value | The palette as packed integers. |
defaultInk | Number or Sprites.Reactive.Value | The ink index a cell with no attribute takes. |
defaultPaper | Number or Sprites.Reactive.Value | The paper index a cell with no attribute takes. |
Returns a Sprites.Reactive.Value holding the resolved { w, h, cells } grid of packed colours.
const slots = [0x000000ff, 0xffffffff];
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 8, 8, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const paint = Sprites.Reactive.Bindingundefined, () => {
const next = Sprites.Media.Image.Cells.Paint(doc, 0, 0, 1, Sprites.Media.Image.Cells.Ink, 'ink', 1);
Sprites.Reactive.Set(doc, next);
});
const resolved = Sprites.Media.Image.Cells.Resolve(doc, slots, 1, 0);
const pixel = Sprites.Grid.Two.At(resolved, 0, 0);
Sprites.Ui.Button.Act(paint, 'Ink the top left pixel');
const css = Sprites.Colour.Css(pixel);
Sprites.Ui.Dom.Text(' top left = ', css);
Sprites.Media.Image.Cells.Display Sprites.Reactive.Value
Sprites.Media.Image.Cells.Display(data, slots, defaultInk, defaultPaper)
The attribute image resolved and packed into a tiled grid, the form the canvas surface reads. A composite over Resolve and Grid.Tiled.FromTwo.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
slots | Array or Sprites.Reactive.Value | The palette as packed integers. |
defaultInk | Number or Sprites.Reactive.Value | The default ink index. |
defaultPaper | Number or Sprites.Reactive.Value | The default paper index. |
Returns a Sprites.Reactive.Value holding the { w, h, tile, tiles } tiled grid.
const slots = [0x000000ff, 0xffffffff];
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 16, 16, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const display = Sprites.Media.Image.Cells.Display(doc, slots, 1, 0);
const pixel = Sprites.Grid.Tiled.At(display, 0, 0);
const css = Sprites.Colour.Css(pixel);
Sprites.Ui.Dom.Text('top left pixel = ', css);
Sprites.Media.Image.Cells.Thumbnail Sprites.Reactive.Value
Sprites.Media.Image.Cells.Thumbnail(data, slots, defaultInk, defaultPaper)
A PNG data URL of the resolved screen, for the saved preview. A composite over Resolve and Sprites.Image.DataUrlFromPixels. It reads every pixel, so a page runs it at a stroke's end.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
slots | Array or Sprites.Reactive.Value | The palette as packed integers. |
defaultInk | Number or Sprites.Reactive.Value | The default ink index. |
defaultPaper | Number or Sprites.Reactive.Value | The default paper index. |
Returns a Sprites.Reactive.Value holding the PNG data URL string.
const slots = [0x000000ff, 0xffffffff];
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 16, 16, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const paint = Sprites.Reactive.Bindingundefined, () => {
const next = Sprites.Media.Image.Cells.Paint(doc, 0, 0, 8, Sprites.Media.Image.Cells.Ink, 'ink', 1);
Sprites.Reactive.Set(doc, next);
});
const url = Sprites.Media.Image.Cells.Thumbnail(doc, slots, 1, 0);
Sprites.Ui.Button.Act(paint, 'Ink a corner block');
Sprites.Ui.Dom.Tag('img', () => {
Sprites.Ui.Dom.Attribute('src', url);
Sprites.Ui.Dom.Style('width', '64px');
Sprites.Ui.Dom.Style('image-rendering', 'pixelated');
});
Sprites.Media.Image.Cells.Summary Sprites.Reactive.Value
Sprites.Media.Image.Cells.Summary(modeName, w, h)
The meta info summary for an attribute image: its mode and pixel size as one short string. A composite over Sprites.Text.Concat and Sprites.Logic.Select, dropping the mode when there is none.
| Input | Type | Description |
|---|---|---|
modeName | String or Sprites.Reactive.Value | The mode name, or undefined for none. |
w | Number or Sprites.Reactive.Value | The pixel width. |
h | Number or Sprites.Reactive.Value | The pixel height. |
Returns a Sprites.Reactive.Value holding the summary string.
const width = Sprites.Reactive.Value(256);
const summary = Sprites.Media.Image.Cells.Summary('Standard', width, 192);
Sprites.Ui.Input.Slider(width, 64, 320);
Sprites.Ui.Dom.Text(' summary = ', summary);
Sprites.Media.Image.Cells.Paint Sprites.Reactive.Value
Sprites.Media.Image.Cells.Paint(data, colStart, rowStart, side, maskValue, colourKey, brush)
The document with the mask filled to a value over a pixel rectangle, and the ink or paper cells the rectangle covers filled to the brush colour. So the pencil lays ink pixels and sets the touched cells' ink; the eraser lays paper pixels and sets the touched cells' paper. maskValue is the ink or paper pixel; colourKey is 'ink' or 'paper'. A composite over Grid.Two.FillRect and Object.With.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
colStart | Number or Sprites.Reactive.Value | The left pixel column of the brush square. |
rowStart | Number or Sprites.Reactive.Value | The top pixel row of the brush square. |
side | Number or Sprites.Reactive.Value | The brush square side in pixels. |
maskValue | Number or Sprites.Reactive.Value | The ink or paper pixel the mask takes. |
colourKey | String or Sprites.Reactive.Value | The colour grid to set, 'ink' or 'paper'. |
brush | Number or Sprites.Reactive.Value | The palette index the touched cells take. |
Returns a Sprites.Reactive.Value holding the painted document.
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 16, 16, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const col = Sprites.Reactive.Value(0);
const paint = Sprites.Reactive.Bindingundefined, () => {
const next = Sprites.Media.Image.Cells.Paint(doc, col, 0, 1, Sprites.Media.Image.Cells.Ink, 'ink', 2);
Sprites.Reactive.Set(doc, next);
});
const pixels = Sprites.Object.Field(doc, 'pixels');
const pixel = Sprites.Array.At(pixels, col);
Sprites.Ui.Input.Number(col, 0, 15);
Sprites.Ui.Button.Act(paint, 'Ink this pixel');
Sprites.Ui.Dom.Text(' pixel = ', pixel);
Sprites.Media.Image.Cells.ResizeField Sprites.Reactive.Value
Sprites.Media.Image.Cells.ResizeField(data, key, oldW, oldH, width, height, pad)
One field of the document resized to a new width and height, cropping or padding with the pad value. A composite over Grid.Two.Resize, shared by the mask and the two colour grids.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
key | String or Sprites.Reactive.Value | The field to resize, 'pixels', 'ink' or 'paper'. |
oldW | Number or Sprites.Reactive.Value | The field's current width in cells. |
oldH | Number or Sprites.Reactive.Value | The field's current height in cells. |
width | Number or Sprites.Reactive.Value | The new width in cells. |
height | Number or Sprites.Reactive.Value | The new height in cells. |
pad | Any or Sprites.Reactive.Value | The value for new area. |
Returns a Sprites.Reactive.Value holding the resized field's cells array.
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 8, 8, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const width = Sprites.Reactive.Value(8);
const cells = Sprites.Media.Image.Cells.ResizeField(doc, 'pixels', 8, 8, width, 8, Sprites.Media.Image.Cells.Paper);
const count = Sprites.Array.Length(cells);
Sprites.Ui.Input.Slider(width, 4, 16);
Sprites.Ui.Dom.Text(' mask pixels = ', count);
Sprites.Media.Image.Cells.ResizeAll Sprites.Reactive.Value
Sprites.Media.Image.Cells.ResizeAll(data, width, height)
The same document resized to a new pixel width and height: the mask resized at pixel resolution, the ink and paper grids resized at cell resolution, so all three stay in step. A composite over ResizeField, keeping the platform, mode and attribute shape.
| Input | Type | Description |
|---|---|---|
data | Object or Sprites.Reactive.Value | The attribute document. |
width | Number or Sprites.Reactive.Value | The new pixel width. |
height | Number or Sprites.Reactive.Value | The new pixel height. |
Returns a Sprites.Reactive.Value holding the resized document.
const document = Sprites.Media.Image.Cells.NewDocument('demo', 'Standard', 16, 16, 8, 8, false);
const doc = Sprites.Reactive.Binding(document);
const width = Sprites.Reactive.Value(16);
const resized = Sprites.Media.Image.Cells.ResizeAll(doc, width, 16);
const w = Sprites.Object.Field(resized, 'w');
const inkCells = Sprites.Object.Field(resized, 'ink');
const inkCount = Sprites.Array.Length(inkCells);
Sprites.Ui.Input.Slider(width, 8, 32);
Sprites.Ui.Dom.Text(' width = ', w, ', ink cells = ', inkCount);
Sprites.Media.Image.Cells.ToolWindow Void
Sprites.Media.Image.Cells.ToolWindow(selectedToolName, fileVisible, historyVisible)
The tools window: a slim floating window docked to the stage's top left, holding the Move and Draw tool selector and the File and History window openers. A composite over the shared sprite tool parts. It builds a floating window, so the example gates it behind a button.
| Input | Type | Description |
|---|---|---|
selectedToolName | Sprites.Reactive.Value | The two way current tool name, 'move' or 'draw'. |
fileVisible | Sprites.Reactive.Value | The File window show flag the opener sets. |
historyVisible | Sprites.Reactive.Value | The History window show flag the opener sets. |
Returns nothing; it builds a floating window.
const open = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(open, true, 'Open the tools window');
Sprites.Reactive.If(open, () => {
const tool = Sprites.Reactive.Value('draw');
const fileVisible = Sprites.Reactive.Value(false);
const historyVisible = Sprites.Reactive.Value(false);
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Class('editor-stage');
Sprites.Ui.Dom.Style('height', '260px');
Sprites.Media.Image.Cells.ToolWindow(tool, fileVisible, historyVisible);
});
Sprites.Ui.Dom.Text(' tool = ', tool);
});
Sprites.Media.Image.Cells.PaletteGrid Void
Sprites.Media.Image.Cells.PaletteGrid(label, brush, slots)
One labelled swatch grid of the palette bound to a colour index: the Ink or the Paper picker. label names it; brush is the two way colour index; slots is the palette. A composite over Sprites.Media.Sprite.Tool.Labelled and Sprites.Colour.Palette.
| Input | Type | Description |
|---|---|---|
label | String or Sprites.Reactive.Value | The grid's label, Ink or Paper. |
brush | Sprites.Reactive.Value | The two way palette index a click sets. |
slots | Array or Sprites.Reactive.Value | The palette as packed integers. |
Returns nothing; it builds a labelled swatch grid.
const slots = [0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffffffff];
const brush = Sprites.Reactive.Value(1);
Sprites.Media.Image.Cells.PaletteGrid('Ink', brush, slots);
Sprites.Ui.Dom.Text(' ink index = ', brush);
Sprites.Media.Image.Cells.Palette Void
Sprites.Media.Image.Cells.Palette(visible, inkBrush, paperBrush, slots)
The Palette window: a floating panel docked to the stage's bottom left, holding an Ink swatch grid over a Paper swatch grid, each a click setting that brush's colour index. visible is the show flag the Draw window's colour square toggles; inkBrush and paperBrush are the two way indices; slots is the palette. A composite. It builds a floating window, so the example gates it behind a button.
| Input | Type | Description |
|---|---|---|
visible | Sprites.Reactive.Value | The show flag the window follows. |
inkBrush | Sprites.Reactive.Value | The two way ink palette index. |
paperBrush | Sprites.Reactive.Value | The two way paper palette index. |
slots | Array or Sprites.Reactive.Value | The palette as packed integers. |
Returns nothing; it builds a floating window.
const slots = [0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffffffff];
const inkBrush = Sprites.Reactive.Value(3);
const paperBrush = Sprites.Reactive.Value(0);
const visible = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(visible, true, 'Open the palette');
Sprites.Reactive.If(visible, () => {
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Class('editor-stage');
Sprites.Ui.Dom.Style('height', '320px');
Sprites.Media.Image.Cells.Palette(visible, inkBrush, paperBrush, slots);
});
});
Sprites.Ui.Dom.Text(' ink = ', inkBrush, ', paper = ', paperBrush);
Sprites.Media.Image.Cells.Editor Void
Sprites.Media.Image.Cells.Editor(data, thumb, info, modes, optionalModeName, slots, optionalDefaultInk, optionalDefaultPaper)
The attribute image editor. Builds the canvas view on the host, the pan and zoom overlay, the tools window, the draw window, the palette window, the file and history panels, and the info window. It reuses the image editor's canvas surface and the shared sprite windows, so an attribute screen drives them the way a full colour image does. It builds interface and returns nothing; the doc fields it is given are where the edits land.
| Input | Type | Description |
|---|---|---|
data | Sprites.Reactive.Value | The two way attribute document. |
thumb | Sprites.Reactive.Value | A value the editor Sets to a fresh PNG data URL at a stroke's end. |
info | Sprites.Reactive.Value | A value the editor Sets to a short mode and size summary. |
modes | Array | The machine's image modes, each an attribute mode with allowedSizes and the attribute shape. |
optionalModeName | Sprites.Reactive.Value | A two way value of the current mode's name, or absent. |
slots | Array | The machine's palette as packed integers; a cell holds an index into it. |
optionalDefaultInk | Number | The ink a cell shows with no attribute, or absent for the default. |
optionalDefaultPaper | Number | The paper a cell shows with no attribute, or absent for the default. |
Returns nothing; it builds the full editor interface. The example reads the Spectrum config plainly, then gates the editor behind a button so the windows do not cover the page on load.
const modes = Sprites.Platform.Spectrum.Image.Modes;
const slots = Sprites.Platform.Spectrum.Image.Slots;
const defaultInk = Sprites.Platform.Spectrum.Image.DefaultInk;
const defaultPaper = Sprites.Platform.Spectrum.Image.DefaultPaper;
const open = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(open, true, 'Open the editor');
Sprites.Reactive.If(open, () => {
const start = Sprites.Media.Image.Cells.NewDocument('spectrum', 'Standard', 64, 64, 8, 8, false);
const data = Sprites.Reactive.Value(start);
const thumb = Sprites.Reactive.Value(undefined);
const info = Sprites.Reactive.Value(undefined);
const modeName = Sprites.Object.Field(data, 'mode');
Sprites.Ui.Dom.Tag('div', () => {
Sprites.Ui.Dom.Class('editor-stage');
Sprites.Ui.Dom.Style('height', '420px');
Sprites.Media.Image.Cells.Editor(data, thumb, info, modes, modeName, slots, defaultInk, defaultPaper);
});
});