Pixels
Back to the reference

Pixels

Pictures generated in code instead of on a canvas: procedural art, textures for shaders, and pictures that change while the game runs.

25 symbols

blitPixelsfunctionnacatamalon

blitPixels(target: TPixels, source: TPixels, x: number, y: number, options: { flipX, flipY }) => TPixels

Lays one picture over another, the way a sprite is drawn over a background: a transparent pixel of source leaves what was there, an opaque one replaces it, and one in between mixes the two.

It is how a sprite is put together from parts (a car from a body, wheels and a driver) or stamped many times over a bigger picture.

Parameters

targetTPixels

The picture drawn on.

sourceTPixels

The picture drawn.

xnumber

Where source's top-left corner lands in target.

ynumber

Where source's top-left corner lands in target.

options{ flipX, flipY }

flipX and flipY mirror source as it is drawn.

View source · pixels/draw.ts:275

createPixelsfunctionnacatamalon

createPixels(width: number, height: number, fill?: TColor) => TPixels

A new picture to paint on in code, transparent or filled with one colour: what to use instead of a <canvas> whenever a picture has to be generated rather than drawn.

Drawn art (characters, tiles, backgrounds) is made in a pixel-art editor and loaded with useLoadTexture. This is for the pictures nobody draws by hand: procedural variations, placeholders, noise and masks for a shader, a picture that changes while the game runs, or art made by an agent that has no image editor. A canvas only exists in a browser; this runs the same there, on the native runtime and in a test.

It lives in memory only: paint it with fillRect, drawLine, fillGradient and the rest, then make it a texture with createPixelTexture. It needs no game, so a build script or a test can make one too.

Parameters

widthnumber

In pixels, at least 1.

heightnumber

In pixels, at least 1.

filloptionalTColor

The colour every pixel starts as. Left out, fully transparent.

Example

const tile = createPixels(16, 16, getColor('#2a6b3a'));
fillRect(tile, 0, 15, 16, 1, getColor('#1a4a28'));
View source · pixels/create_pixels.ts:34

createPixelTexturefunctionnacatamalon

createPixelTexture(source: TLoadedPixels | TPixels, paint: TPixelPaint, options?: TPixelTextureOptions) => TTexture
createPixelTexture(source: TLoadedPixels | TPixels, options?: TPixelTextureOptions) => TTexture

Turns a picture into a texture a sprite, a model's material or a shader shows like any image loaded from a file.

It is how a game turns a generated picture into something it can show, with no image file and no page: a procedural sky, a rock texture from noise for a model, a mask for a shader, a placeholder while the real art is drawn. Art someone drew is loaded with useLoadTexture instead. It works the same in the browser and on the native runtime, because nothing here draws with the page. Use it instead of a <canvas>: a canvas only exists in a browser.

The picture can be:

  • One painted in code (createPixels). The texture is ready at once and keeps reading from the picture: paint on it again and call updatePixelTexture to show the change (a minimap filling in, a floor with a crater in it). paint, if given, is applied to it first.
  • A drawn picture loaded to be processed (useLoadPixels). The texture comes back at once, still loading, the way one from useLoadTexture does, and whatever shows it appears when the file has arrived. paint then receives a copy of the picture, so the loaded one, shared by everyone who loaded the file, is never changed: a palette swap, a white silhouette for a hit, an outline.

Asked again for a key it already made at the same size, it gives that texture back with the new picture uploaded into it, so a scene that restarts does not pile up textures.

A scene document can name a texture made here but cannot carry it, since there is no file to fetch: make it again under the same key before loading the document.

Parameters

sourceTLoadedPixels | TPixels

The picture: one from createPixels, or one from useLoadPixels.

paintTPixelPaint

Changes the picture before it is uploaded. With a loaded picture it gets a copy.

optionsoptionalTPixelTextureOptions

key to keep it by name.

Example

const Level = () => {
    // Painted in code.
    const art = createPixels(16, 16, getColor('#1d2b53'));
    fillCircle(art, 8, 8, 6, getColor('#ffec27'));
    createSprite({ texture: createPixelTexture(art), width: 64, height: 64 });

    // A drawn sprite in another colour, made from the one file.
    const hero = useLoadPixels({ src: '/assets/hero.png' });
    const red = createPixelTexture(hero, (p) => swapColors(p, [[getColor('#3a7bff'), getColor('#e23d3d')]]));
    createSprite({ texture: red, width: 32, height: 32 });
    return createScene();
};
View source · gameobjects/pixel_texture/create_pixel_texture.ts:125

drawCirclefunctionnacatamalon

drawCircle(pixels: TPixels, cx: number, cy: number, radius: number, color: TColor) => TPixels

Draws the outline of a circle, one pixel thick, with no gaps and no pixel drawn twice.

Parameters

pixelsTPixels

The picture.

cxnumber

Its centre, from the left.

cynumber

Its centre, from the top.

radiusnumber

In pixels.

colorTColor

Its colour.

View source · pixels/draw.ts:226

drawLinefunctionnacatamalon

drawLine(pixels: TPixels, x0: number, y0: number, x1: number, y1: number, color: TColor) => TPixels

Draws a line one pixel thick between two points, with the stepped edge of the era and no smoothing: each pixel is either on the line or not.

Parameters

pixelsTPixels

The picture.

x0number

Where it starts, from the left.

y0number

Where it starts, from the top.

x1number

Where it ends, from the left.

y1number

Where it ends, from the top.

colorTColor

Its colour.

View source · pixels/draw.ts:111

fillCheckerfunctionnacatamalon

fillChecker(pixels: TPixels, size: number, a: TColor, b: TColor) => TPixels

Fills the picture with a checkerboard: the first texture every 3D scene is tried with, because it shows at a glance whether a surface is stretched, mirrored or seen from the wrong side.

Parameters

pixelsTPixels

The picture.

sizenumber

How many pixels wide one square is.

aTColor

The colour of the top-left square.

bTColor

The other colour.

View source · pixels/fill.ts:254

fillCirclefunctionnacatamalon

fillCircle(pixels: TPixels, cx: number, cy: number, radius: number, color: TColor) => TPixels

Fills a circle. Its edge is stepped, one pixel or none, the way a circle drawn by hand on a grid looks, and it is exactly the edge drawCircle draws for the same radius.

Painted with a transparent colour, it cuts a round hole: the crater in a destructible floor.

Parameters

pixelsTPixels

The picture.

cxnumber

Its centre, from the left.

cynumber

Its centre, from the top.

radiusnumber

In pixels. 0 is a single pixel.

colorTColor

What it is filled with.

Example

const sun = createPixels(33, 33);
fillCircle(sun, 16, 16, 15, getColor('#ffd75a'));
View source · pixels/draw.ts:172

fillGradientfunctionnacatamalon

fillGradient(pixels: TPixels, options: TFillGradientOptions) => TPixels

Fills the picture with a gradient, smooth or cut into the flat bands of a sky from the era, with an ordered dither between the bands if you want it.

Parameters

pixelsTPixels

The picture.

optionsTFillGradientOptions

The colours, the direction and how it is stepped.

Example

const sky = createPixels(320, 120);
fillGradient(sky, {
    colors: ['#140a33', '#5a1667', '#e0446e', '#ffb36b'].map((hex) => getColor(hex)),
    bands: 12,
    dither: true,
});
View source · pixels/fill.ts:80

fillNoisefunctionnacatamalon

fillNoise(pixels: TPixels, options: TFillNoiseOptions) => TPixels

Fills the picture with smooth noise: clouds, rock, water, a height map for terrain, or a texture for a shader to read.

It tiles without a seam: the right edge runs on into the left one and the bottom into the top, so a model can repeat it (wrap: 'repeat') with no visible joins. For that, the blobs are fitted to a whole number across the picture, so scale is followed as closely as that allows.

Parameters

pixelsTPixels

The picture.

optionsTFillNoiseOptions

Which noise, how big and between which colours.

Example

// A tiling rock texture for a model.
const rock = fillNoise(createPixels(64, 64), {
    seed: 7, scale: 16, octaves: 4, from: getColor('#2b2730'), to: getColor('#8a8090'),
});
createMaterial({ name: 'rock', shader: 'mesh3d', texture: createPixelTexture(rock), wrap: 'repeat' });
View source · pixels/fill.ts:187

fillRectfunctionnacatamalon

fillRect(pixels: TPixels, x: number, y: number, width: number, height: number, color: TColor) => TPixels

Fills a rectangle with one colour, cut to the picture's edges.

Parameters

pixelsTPixels

The picture.

xnumber

Its left edge.

ynumber

Its top edge.

widthnumber

How wide, in pixels.

heightnumber

How tall, in pixels.

colorTColor

What it is filled with.

Example

const bar = createPixels(64, 6, getColor('#200a0a'));
fillRect(bar, 1, 1, 40, 4, getColor('#e23d3d'));
View source · pixels/draw.ts:81

getPixelfunctionnacatamalon

getPixel(pixels: TPixels, x: number, y: number) => TColor

Reads one pixel. Outside the picture it is fully transparent black.

Reading the picture is also how a game asks questions of it: whether a pixel of a destructible floor is still solid, which colour a minimap shows somewhere.

Parameters

pixelsTPixels

The picture.

xnumber

From the left edge, in pixels.

ynumber

From the top edge, in pixels.

View source · pixels/draw.ts:49

mapPixelsfunctionnacatamalon

mapPixels(pixels: TPixels, fn: (color: TColor, x: number, y: number) => TColor) => TPixels

Works out every pixel again from what it is and where it is: for anything the other functions do not draw. A recolour, a shading by height, a pattern of your own.

Parameters

pixelsTPixels

The picture.

fn(color: TColor, x: number, y: number) => TColor

Given each pixel's colour and position, returns what it becomes.

Example

// Brick: rows of 8 pixels, every other row shifted by half a brick, with a darker mortar line.
mapPixels(wall, (color, x, y) =>
    y % 8 === 0 || (x + (Math.floor(y / 8) % 2) * 8) % 16 === 0 ? mortar : brick);
View source · pixels/draw.ts:343

setPixelfunctionnacatamalon

setPixel(pixels: TPixels, x: number, y: number, color: TColor) => TPixels

Sets one pixel. Outside the picture it does nothing.

Parameters

pixelsTPixels

The picture.

xnumber

From the left edge, in pixels.

ynumber

From the top edge, in pixels.

colorTColor

What it becomes, replacing what was there.

View source · pixels/draw.ts:25

swapColorsfunctionnacatamalon

swapColors(pixels: TPixels, pairs: typeOperator) => TPixels

Replaces colours with others, exactly: every pixel that is one of the from colours, alpha included, becomes its to. Every other pixel is left alone.

It is the palette swap of the consoles of the era: one drawn enemy, and the red, blue and gold versions made from it, with no extra picture drawn. Swaps are worked out from the picture as it was, so swapping red for blue and blue for red at once trades them rather than turning both blue.

Parameters

pixelsTPixels

The picture, changed in place.

pairstypeOperator

Each colour to replace, and what replaces it.

Example

const hero = useLoadPixels({ src: '/assets/hero.png' });
const red = createPixelTexture(hero, (p) => swapColors(p, [[getColor('#3a7bff'), getColor('#e23d3d')]]));
View source · pixels/edit.ts:44

updatePixelTexturefunctionnacatamalon

updatePixelTexture(texture: TTexture, region?: TPixelRegion) => void

Shows what has been painted on a picture since its texture was made or last updated.

Only the part asked for is sent to the graphics card, so a game that changes a little of a big picture every frame (a crater, a revealed patch of map) passes region and stays cheap. Left out, the whole picture is sent.

Parameters

textureTTexture

A texture createPixelTexture made.

regionoptionalTPixelRegion

The rectangle that changed, in the picture's pixels. It is cut to the picture.

Example

fillCircle(ground, hitX, hitY, 6, getColor('transparent'));
updatePixelTexture(groundTexture, { x: hitX - 6, y: hitY - 6, width: 13, height: 13 });
View source · gameobjects/pixel_texture/create_pixel_texture.ts:273

useLoadPixelsfunctionhooknacatamalon

useLoadPixels(options: TUseLoadPixelsOptions) => TLoadedPixels

Loads a drawn picture as pixels, to process it in code: a palette swap, a white silhouette for a hit, an outline, a collision mask taken from the drawing, a level read from an image.

To just show a drawn picture, use useLoadTexture: that is the normal way, and faster, because the picture goes straight to the graphics card. This is for when the game has to read or change the drawing first. It reads PNG files, decoded in plain JavaScript with no canvas, so it works the same in the browser and on the native runtime.

It hands back a record at once, still loading, the way every loader does; useLoader counts it. Give it straight to createPixelTexture with a function that changes it: the texture appears by itself when the file arrives, and the function works on a copy. Once status is 'ready', its pixels can be read as well (with getPixel) but not painted on: the picture is shared by every scene that loads the same file.

Parameters

optionsTUseLoadPixelsOptions

Where the file is, and the name to keep it under.

Example

const Level = () => {
    const hero = useLoadPixels({ src: '/assets/hero.png' });
    const gold = createPixelTexture(hero, (p) => swapColors(p, [[getColor('#3a7bff'), getColor('#ffd75a')]]));
    createSprite({ texture: gold, width: 32, height: 32 });
    return createScene();
};
View source · hooks/loaders/use_load_pixels.ts:57

TFillGradientOptionstypenacatamalon

What fillGradient is asked for.

Properties

fromoptionalTColor

The colour it starts at. With to, a gradient between two colours.

tooptionalTColor

The colour it ends at.

colorsoptionaltypeOperator

Several colours, evenly spaced, in place of from and to: a sunset from deep blue through purple and red to orange.

directionoptional'down' | 'right'

'down' (default) runs from the top edge to the bottom one; 'right' from left to right.

bandsoptionalnumber

How many flat steps it is cut into, the way a sky was drawn when a game had few colours to spare. Left out or below 2, it is smooth.

ditheroptionalboolean

Breaks the line between two steps with the ordered pattern the dither() effect uses, so the steps blend into each other instead of meeting in a hard edge. Only with bands.

regionoptionalTPixelRegion

Only this rectangle is painted, and the gradient runs across it. Left out, the whole picture.

View source · pixels/fill.ts:24

TFillNoiseOptionstypenacatamalon

What fillNoise is asked for.

Properties

seedoptionalnumber

Which noise. The same seed always gives the same picture. Default 1.

scaleoptionalnumber

How big its blobs are, in pixels. Default 8.

octavesoptionalnumber

How many layers of finer detail are added, each half the size and half as strong. Default 1; 4 or so for clouds and rock.

fromoptionalTColor

The colour of the lowest values. Default black.

tooptionalTColor

The colour of the highest values. Default white.

View source · pixels/fill.ts:138

TLoadedPixelstypenacatamalon

A picture file loaded as pixels, to process in code: what useLoadPixels hands back.

pixels is null until status is 'ready'. Read it as much as you like (a collision mask, a level drawn as an image); to change it, hand the record to createPixelTexture with a function, which paints on a copy. The picture is shared by everyone who loaded the same file, so painting on it directly would change it for all of them.

Properties

type'loaded-pixels'
keystring

What it is cached under in this game. The src unless a key was given.

srcstring

Where the file comes from.

pixelsTPixels | null

The picture, once it has arrived.

View source · loaders/pixels/types/t_loaded_pixels.ts:16

TPixelstypenacatamalon

A picture held in memory, to paint on in code and then hand to createPixelTexture: the engine's replacement for drawing on a <canvas>, which only exists in a browser. Drawn art is loaded with useLoadTexture instead; this is for pictures that are generated.

Four bytes a pixel (red, green, blue, alpha, each 0 to 255), row after row, with row 0 at the top: the same way round as an image file and as the game's own y. Nothing in it touches the graphics card, the page or a game, so the same picture can be painted in a scene, in a test, in a build script or on the native runtime and comes out byte for byte the same.

data is yours to read and write directly when the painting functions are not enough; it is width × height × 4 long and never replaced.

Properties

type'pixels'
widthnumber
heightnumber
dataUint8Array
View source · pixels/types/t_pixels.ts:18

TPixelTextureOptionstypenacatamalon

What createPixelTexture is asked for.

Properties

keyoptionalstring

A name, so the texture outlives the scene that made it and another scene can find it with createSprite({ key }). Left out, it belongs to the part of the scene that made it and goes when that goes.

View source · gameobjects/pixel_texture/create_pixel_texture.ts:64