Skip to main content

Basic Drawing

The PALETTE Register#

WASM-4 can only display 4 colors on screen at a time. This palette's RGB values are stored in the PALETTE memory register, and can be modified.

For example, to change the palette to Ice Cream GB:

store<u32>(w4.PALETTE, 0xfff6d3, 0 * sizeof<u32>());store<u32>(w4.PALETTE, 0xf9a875, 1 * sizeof<u32>());store<u32>(w4.PALETTE, 0xeb6b6f, 2 * sizeof<u32>());store<u32>(w4.PALETTE, 0x7c3f58, 3 * sizeof<u32>());

The default Gameboy-ish palette looks like this:

Color 1
Color 2
Color 3
Color 4

The first color in the palette register is used as the screen background color.

The DRAW_COLORS Register#

All drawing functions are affected by the DRAW_COLORS memory register. DRAW_COLORS is a 16 bit value that can store up to 4 colors.

For example, rect() uses the first draw color for the fill color, and the second draw color as the outline color. To draw a light-green (palette color 2) rectangle with a black (palette color 4) outline:

store<u16>(w4.DRAW_COLORS, 0x42);w4.rect(10, 10, 32, 32);

A value of 0 in a draw color means it will be transparent. For example, to draw a black outlined rectangle with no fill, set DRAW_COLORS to 0x40.

Drawing Text#

To draw some text at position (10, 10):

w4.text("Hello world!", 10, 10);

DRAW_COLORS color 1 is used as the text color, DRAW_COLORS color 2 is used as the background color.


There is no way to use a custom font with this function. To draw text with custom fonts, handle the drawing yourself by looping over each character and drawing a sprite.

Other Shapes#

For info on other shape drawing functions like line() and oval(), see the Functions reference.

Direct Framebuffer Access#

The FRAMEBUFFER memory region contains the framebuffer, with each byte containing 4 pixels (2 bits per pixel). For example, to clear the entire screen to palette color 3:

memory.fill(w4.FRAMEBUFFER, 3 | (3 << 2) | (3 << 4) | (3 << 6), 160*160/4);

Advanced users can implement their own drawing functions by carefully manipulating the framebuffer. For example, to implement a pixel() function that draws a single pixel:

function pixel (x: i32, y: i32): void {    // The byte index into the framebuffer that contains (x, y)    const idx = (y*160 + x) >> 2;
    // Calculate the bits within the byte that corresponds to our position    const shift = u8((x & 0b11) << 1);    const mask = u8(0b11 << shift);
    // Use the first DRAW_COLOR as the pixel color    const color = u8(load<u16>(w4.DRAW_COLORS) & 0b11);
    // Write to the framebuffer    store<u8>(w4.FRAMEBUFFER + idx, (color << shift) | (load<u8>(w4.FRAMEBUFFER + idx) & ~mask));}