Sprite

A sprite defines a pixel art image using named regions. Each region maps to a color token from the palette and describes its shape geometrically.

Basic Syntax

{
  type: "sprite",
  name: "string (required)",
  size: [width, height],
  palette: "string (required)",
  regions: {
    token: { shape_definition },
    token: { shape_definition },
  },
}

Fields

FieldRequiredDescription
typeYesMust be "sprite"
nameYesUnique identifier
sizeYes[width, height] in pixels
paletteYesPalette name to use for colors
regionsYesMap of token names to region definitions

Optional Fields

FieldDescription
backgroundToken to fill empty pixels (default: _)
originAnchor point [x, y] for transforms
metadataCustom data passthrough for game engines
state-rulesName of state rules to apply

Example

{
  type: "sprite",
  name: "coin",
  size: [8, 8],
  palette: "gold",
  regions: {
    _: "background",
    outline: { stroke: [1, 1, 6, 6], round: 2 },
    gold: { fill: "inside(outline)" },
    shine: { points: [[3, 3], [4, 2]] },
  },
}

Regions

The regions field maps token names to shape definitions. Tokens must exist in the referenced palette.

Simple Shapes

regions: {
  // Individual pixels
  eye: { points: [[5, 6], [10, 6]] },

  // Filled rectangle
  body: { rect: [2, 4, 12, 8] },

  // Rectangle outline
  outline: { stroke: [0, 0, 16, 16] },

  // Filled circle
  head: { circle: [8, 4, 3] },

  // Line
  mouth: { line: [[5, 10], [10, 10]] },
}

Fill Operations

Fill inside a boundary:

regions: {
  outline: { stroke: [0, 0, 16, 16] },
  skin: { fill: "inside(outline)" },
}

Fill with exclusions:

regions: {
  outline: { stroke: [0, 0, 16, 16] },
  eye: { rect: [5, 5, 2, 2], symmetric: "x" },
  skin: {
    fill: "inside(outline)",
    except: ["eye"],
  },
}

Symmetry

Auto-mirror regions across an axis:

regions: {
  // Creates eyes at [5, 6] and [10, 6] for 16-wide sprite
  eye: {
    points: [[5, 6]],
    symmetric: "x",
  },
}

Background

The special "background" value fills all unoccupied pixels:

regions: {
  _: "background",
  // ... other regions ...
}

See Regions & Shapes for complete documentation of all shape primitives and modifiers.

Palette Options

Named Palette

Reference a palette defined earlier in the file:

{
  type: "palette",
  name: "hero_colors",
  colors: { /* ... */ },
}

{
  type: "sprite",
  name: "hero",
  palette: "hero_colors",
  size: [16, 16],
  regions: { /* ... */ },
}

Built-in Palette

Reference a built-in palette with @ prefix:

{
  type: "sprite",
  name: "retro",
  palette: "@gameboy",
  size: [8, 8],
  regions: { /* ... */ },
}

Metadata

Attach additional data for game engine integration:

{
  type: "sprite",
  name: "player_attack",
  size: [32, 32],
  palette: "hero",
  regions: { /* ... */ },
  origin: [16, 32],
  metadata: {
    boxes: {
      hurt: { x: 4, y: 0, w: 24, h: 32 },
      hit: { x: 20, y: 8, w: 20, h: 16 },
    },
  },
}

Common Metadata Fields

FieldPurpose
originSprite anchor point [x, y]
boxes.hurtDamage-receiving region
boxes.hitDamage-dealing region
boxes.collidePhysics collision boundary
boxes.triggerInteraction trigger zone

Nine-Slice

Create scalable sprites where corners stay fixed while edges and center stretch:

{
  type: "sprite",
  name: "button",
  size: [16, 16],
  palette: "ui",
  regions: { /* ... */ },
  nine_slice: {
    left: 4,
    right: 4,
    top: 4,
    bottom: 4,
  },
}

Render at different sizes:

pxl render button.pxl --nine-slice 64x32 -o button_wide.png

Transforms (Derived Sprites)

Create derived sprites by applying op-style transforms to an existing sprite:

{
  type: "sprite",
  name: "hero_outlined",
  source: "hero",
  transform: [
    { op: "sel-out", fallback: "outline" },
  ],
}

Op-style transforms support both geometric operations (mirror-h, rotate:90) and effects (sel-out, dither, shadow).

See Transforms for the full list of operations.

Note: For animated transforms (in keyframes), use CSS transform strings instead. See Animation.

Complete Example

// hero.pxl
{
  type: "palette",
  name: "hero",
  colors: {
    _: "transparent",
    outline: "#000000",
    skin: "#FFD5B4",
    hair: "#8B4513",
    eye: "#4169E1",
    shirt: "#E74C3C",
  },
  roles: {
    outline: "boundary",
    eye: "anchor",
    skin: "fill",
  },
}

{
  type: "sprite",
  name: "hero",
  size: [16, 24],
  palette: "hero",
  regions: {
    // Background
    _: "background",

    // Head
    "head-outline": { stroke: [4, 0, 8, 10], round: 2 },
    hair: { fill: "inside(head-outline)", y: [0, 4] },
    skin: {
      fill: "inside(head-outline)",
      y: [4, 10],
      except: ["eye"],
    },

    // Eyes (symmetric)
    eye: { rect: [5, 5, 2, 2], symmetric: "x" },

    // Body
    "body-outline": { stroke: [3, 10, 10, 14] },
    shirt: { fill: "inside(body-outline)" },
  },
  origin: [8, 24],
  metadata: {
    boxes: {
      collide: { x: 4, y: 10, w: 8, h: 14 },
    },
  },
}

Error Handling

Lenient Mode (Default)

ErrorBehavior
Unknown tokenRender as magenta #FF00FF
Region outside canvasClip to canvas with warning
Forward reference in fillError (must define dependencies first)
Missing paletteAll regions render white with warning

Strict Mode

All warnings become errors. Use --strict flag for CI validation.