Pixel Encoding

Etherean pixel art uses a compact 2-bit-per-pixel encoding that stores a 40x40 image in exactly 400 bytes. This applies to both avatars (Body) and soul generative art.

Format

Bit Layout

Byte N contains pixels [N*4, N*4+1, N*4+2, N*4+3]
Bits: [7:6] = pixel N*4
      [5:4] = pixel N*4+1
      [3:2] = pixel N*4+2
      [1:0] = pixel N*4+3

Pixel index 0 = color at bits [7:6] of byte 0
Pixel index 1599 = color at bits [1:0] of byte 399

Decoding

const pixelIndex = y * 40 + x;
const byteIndex = Math.floor(pixelIndex / 4);
const bitShift = (3 - (pixelIndex % 4)) * 2;
const colorIndex = (bytes[byteIndex] >> bitShift) & 0x03;

Palettes

Color index 0-3 maps to the 4 colors in the chosen palette. Palettes are defined as arrays of 4 hex color strings. Soul generative art inherits the parent Etherean's palette.

Rendering

Client-side rendering uses canvas.putImageData() with an RGBA buffer:

// Decode 400 bytes -> 6400 bytes RGBA
const rgba = new Uint8ClampedArray(1600 * 4);
for (let i = 0; i < 1600; i++) {
  const colorIndex = decode2bpp(bytes, i);
  const [r, g, b] = palette[colorIndex];
  rgba[i * 4] = r;
  rgba[i * 4 + 1] = g;
  rgba[i * 4 + 2] = b;
  rgba[i * 4 + 3] = 255;
}
ctx.putImageData(new ImageData(rgba, 40, 40), 0, 0);

Display at larger sizes uses CSS image-rendering: pixelated to preserve the crisp pixel art look. Export resolution is 10x (400x400px).

Onchain SVG

The contract's tokenURI() generates an SVG with one <rect> per pixel. This is 1,600 rect elements in a 40x40 viewBox. The SVG is base64-encoded and embedded in the JSON metadata. No external resources needed.

Pixel Encoding — ETHEREAN Docs