PAGAN
Pixel Art Grammar And Notation

You speak English.
Your agent speaks PAGAN.

PAGAN is a language for game art: palettes, sprites, tiles, 3D models, animations and style rules, written as plain text. Your AI agent writes it, PAGAN checks and renders it, and your game gets engine-ready sprites.

  • MIT-licensed, free
  • Runs locally, offline
  • No account, no credits
  • The art is yours

Looking for 3D? Try KILN: smooth, stylised 3D models as text. For audio, SEGAN. Both are PAGAN's sister libraries.

16 headings, one light, from this 61-line filemodels/ship.model.yaml
name: ship
description: >
  Player ship: a wooden two-masted brig. Oak hull with a raised stern castle (lit brass lanterns),
  forecastle, bowsprit. Square sails braced to catch the wind on both masts, a jib to the bowsprit,
  red pennants. Top-down 3/4 view, no water (it sits on a moving sea). 16 headings so it turns
  smoothly; the pennants flutter in the "sail" animation.
size: [92, 70]
pivot: [46, 46]
origin: [32, 0, 0]          # the hull's centre at the waterline lands on the pivot
directions: 16
outline: auto
status: draft
style_version: 1
tags: [player, vehicle, ship]

materials:
  hull: { keys: ["3", "4", "5", "7"] }
  deck: { keys: ["4", "5", "6"] }
  rail: { keys: ["1", "2"] }
  mast: { keys: ["1", "2", "4"] }
  lamp: { keys: ["e"] }                       # one key = unshaded: lanterns glow
  trim: { ramp: gold }
  sail: { keys: ["8", "9", "a", "b"], two_sided: true }
  flag: { ramp: red }

parts:
  - hull: { from: [0, 0, 0], length: 64, beam: 19, height: 7, bow: 0.4, stern: 0.1, material: hull, top: deck, rim: rail }
  - box: { from: [0, -6, 7], to: [12, 6, 10], material: hull, top: deck, rim: rail }      # stern castle
  - box: { from: [51, -5, 7], to: [56, 5, 8], material: hull, top: deck, rim: rail }       # forecastle
  - box: { from: [1, -9, 3], to: [50, -9, 3], material: trim }                             # gold stripe
    mirror: true
  - box: { from: [16, -9, 5], to: [17, -9, 6], material: rail }                            # gun ports
    mirror: true
  - box: { from: [26, -9, 5], to: [27, -9, 6], material: rail }
    mirror: true
  - box: { from: [36, -9, 5], to: [37, -9, 6], material: rail }
    mirror: true
  - box: { from: [30, -2, 7], to: [35, 2, 7], material: rail }                              # cargo hatch
  - box: { from: [-1, 2, 8], to: [-1, 3, 9], material: lamp }                             # stern lanterns
    mirror: true
  - cylinder: { base: [24, 0, 7], height: 36, material: mast }                             # main mast
  - cylinder: { base: [45, 0, 7], height: 30, material: mast }                             # fore mast
  - line: { from: [60, 0, 8], to: [73, 0, 14], material: mast }                            # bowsprit
  - sail: { at: [24, 0, 12], width: 20, height: 13, bulge: 2.2, brace: 30, material: sail, yard: mast }
  - sail: { at: [24, 0, 27], width: 15, height: 9, bulge: 1.8, brace: 30, material: sail, yard: mast }
  - sail: { at: [45, 0, 11], width: 17, height: 11, bulge: 2, brace: 30, material: sail, yard: mast }
  - sail: { at: [45, 0, 24], width: 12, height: 8, bulge: 1.6, brace: 30, material: sail, yard: mast }
  - triangle: { points: [[48, 0, 10], [70, 0, 13], [46, 0, 34]], material: sail }             # jib
  - box: { from: [20, 0, 41], to: [24, 0, 42], material: flag }                                # pennants
    id: pennant
  - box: { from: [42, 0, 35], to: [44, 0, 36], material: flag }
    id: fore_pennant

animations:
  sail:
    fps: 6
    poses:
      - {}
      - { pennant: { offset: [0, 1, 0] }, fore_pennant: { offset: [0, 1, 0] } }
      - {}
      - { pennant: { offset: [0, -1, 0] }, fore_pennant: { offset: [0, -1, 0] } }
The translation layer

You don't learn PAGAN. Your agent does.

With the PAGAN skill (Claude) or the MCP server (any agent), your AI agent becomes the translator between what you want and the art your game loads.

  1. You English

    "A zombie that shambles towards the player."

  2. Agent Claude + PAGAN skill / MCP
    • writes zombie.model.yaml
    • runs pagan lint
    • looks at the preview
    • fixes what's off
  3. PAGAN the compiler
    • renders 8 headings
    • 6-frame walk cycle
    • one camera, one light
    • byte-identical builds
  4. Your game any engine
    • zombie.png
    • zombie.tres
    • manifest.json
Interactive demo

Watch an agent make game art

Choose your own adventure: pick what you're building, then what to ask for next. Start over to take another path. Each reply shows the art, what the agent wrote, and the files your game gets.

A scripted conversation. The art, source files, diffs, lint results and build output are real PAGAN output, rebuilt from the source files in this site's repo.

Let your agent do it

An agent building your game calls PAGAN like a service

While you play-test, an orchestrator agent asks PAGAN for the art it needs, reads back the manifest and wires the sprite into the scene. manifest.json is the contract, so it works for any engine; Godot resources come for free.

  1. orchestrator → paganwrite_asset zombie.model.yaml

    "Wave 2 needs an enemy: top-down, 8 directions, walk + attack."

  2. pagan → orchestrator{"ok": true, "errors": 0, "warnings": 0, preview: image}

    It looks at the preview, then calls build.

  3. pagan → gamesprites/zombie.png · zombie.tres · manifest.json

    7 files, frame rects, 8 headings × walk + attack, pivot.

  4. orchestrator → gameEnemy.tscn: sprite_frames = zombie.tres, offset = Vector2(0,-17)

    The zombie appears in wave 2.

Wave 2 · zombie.tres · walk_sw

Why PAGAN

Built for a whole game's worth of art

Everything below is real build output from the demo projects, drawn in your browser from the same PNG sheets and manifest a game loads.

1 Art as source code

The agent writes text you can read, diff, review and keep in git. "16 headings so it turns smoothly" is a one-line change, and the review is a normal pull request.

models/ship.model.yaml
@@ -2,12 +2,12 @@ description: >   Player ship: a wooden two-masted brig. Oak hull with a raised stern castle (lit brass lanterns),   forecastle, bowsprit. Square sails braced to catch the wind on both masts, a jib to the bowsprit,-  red pennants. Top-down 3/4 view, no water (it sits on a moving sea). 8 headings; the pennants-  flutter in the "sail" animation.+  red pennants. Top-down 3/4 view, no water (it sits on a moving sea). 16 headings so it turns+  smoothly; the pennants flutter in the "sail" animation. size: [92, 70] pivot: [46, 46] origin: [32, 0, 0]          # the hull's centre at the waterline lands on the pivot-directions: 8+directions: 16 outline: auto status: draft style_version: 1

2 3D in, perfect 2D out

One voxel model gives every heading and every animation frame, lit by one project-wide light and seen through one camera. No drift between directions, ever. 1 to 32 headings.

3 One style, everywhere, forever

Palettes with ramps, a project light and style versions. "Make the night darker" ispagan palette adjust grave --lightness -0.07 --saturation 0.85, and every asset follows.

The graveyard ground and headstones, built from the palette

4 It checks its own work

The linter catches orphan pixels, ramp misuse, clipped outlines and animations that pop. The agent reads the findings and fixes them. A real one, from the zombie's first attack:

W007 attack_se_1 -> attack_se_2: 63% of pixels change

The 5-frame attack's changes row: most pixels change between frames

Fixed: 9 smaller steps, 0 warnings

The 9-frame attack's changes row: only the arms and head change

5 Animation that doesn't jitter

Poses move parts by whole voxels, so the torso stays on exactly the same pixels while the legs drag. The changes row shows what moved; lint W007 measures it.

6 Variants and team colours

Recolours with identical geometry. The manifest carries a hex → hex swap table for each, so a game can recolour one sheet in a shader. These are recoloured in your browser that way.

7 Free, open, local

MIT-licensed. Runs on your machine, offline. No account, no credits, no API key, no cloud. Builds are deterministic: the same sources give byte-identical files.

8 Built for agents

A Claude skill that teaches the whole workflow, an MCP server for any agent, --json on every command, and a long-term memory in the project: BRIEF.md, STYLE.md, asset status and a style changelog.

9 Engine-ready

manifest.json describes every sheet: frame rects, animations, fps, pivots, headings, tiles, variant swaps, normal maps. Any engine can read it. For Godot 4, PAGAN also writes SpriteFrames and TileSet resources, verified by loading them in headless Godot.

manifest.json (shortened)
{
 "zombie": {
  "kind": "model",
  "sheet": "res://assets/generated/sprites/zombie.png",
  "size": [44, 48],
  "pivot": [22, 41],
  "godot_offset": [0, -17],
  "headings": ["e", "ne", "n", "nw", "w", "sw", "s", "se"],
  "frames": {
   "e": [0, 0, 44, 48],
   "…": "127 more"
  },
  "animations": {
   "walk_se": {
    "fps": 6,
    "frames": ["walk_se_0", "walk_se_1", "walk_se_2", "walk_se_3", "walk_se_4", "walk_se_5"],
    "loop": true
   },
   "…": "23 more"
  }
 }
}
# Godot 4
var zombie := AnimatedSprite2D.new()
zombie.sprite_frames = load("res://assets/generated/sprites/zombie.tres")
zombie.centered = true
zombie.offset = Vector2(0, -17)   # manifest: godot_offset
zombie.play("walk_" + heading)   # one animation per heading

10 3D games, too

Free cameras, kill cams, undersides: the same model file also builds as a real mesh (glTF), one node per part, with its animations and the hit zones, joints and "detachable" flags game code reads. A ramp shader keeps engine lighting on the palette: the sun picks the shade exactly as PAGAN's renderer does. This is the zombie's actual .glb, drawn in your browser by that rule. Drag it, look from below.

1,724 triangles · 16 voxels per metre · ground textures from tilesets · previews from any angle (pagan preview --orbit)

models/zombie.model.yaml
rig:
  head:      { pivot: [3, 0, 28], meta: { hitzone: head, damage: 3 } }
  left_arm:  { pivot: [1, 7, 24], meta: { hitzone: arm, detachable: true } }
  right_arm: { pivot: [1, -7, 24], meta: { hitzone: arm, detachable: true } }
  left_leg:  { meta: { hitzone: leg } }
  right_leg: { meta: { hitzone: leg } }
pagan preview --orbit: the zombie from 8 sides, at elevations from below the horizon to straight down
manifest.json (shortened)
{
 "zombie": {
  "mesh": {
   "glb": "models/zombie.glb",
   "voxel_size": 0.0625,
   "triangles": 1724,
   "parts": {
    "head": {
     "node": "body/head",
     "meta": {
      "damage": 3,
      "hitzone": "head"
     }
    },
    "…": "4 more"
   },
   "animations": {
    "walk": {
     "fps": 6,
     "loop": true,
     "frames": 6
    },
    "…": "1 more"
   }
  }
 }
}
# Godot 4
var zombie := load("res://assets/generated/models/zombie.tscn").instantiate()
zombie.look_at(player.global_position, Vector3.UP, true)   # its front is +Z
zombie.get_node("AnimationPlayer").play("walk")
# a hit: which part? the rig's meta is each node's metadata
var zone = hit_node.get_meta("extras").get("hitzone")       # "head", "arm", "leg"
How it compares

Three kinds of tool

Facts as of October 2026, from each tool's own documentation. Pick what fits your game.

Image-model generatorsPixelLab, Ludo, Sprite AI, Retro Diffusion, SpriteLabPixel-pushing MCP serverspixel-mcp, pixscii, Aseprite MCPsPAGAN
How art is madeA diffusion model paints from your promptThe agent sets pixels or draws shapes through tool callsThe agent writes a source file in a text notation that PAGAN compiles
Art is stored asPNGsPNGs or .aseprite filesText in git: diffable, reviewable, editable by hand or by agent
Cost / accessSubscriptions or credits, cloud, accountFree; some need Aseprite (paid)Free, MIT, offline
Consistent rotations4/8 directions generated by a modelDrawn by hand per direction3D voxel models rendered exactly in 1-32 headings with one camera and light
Animation consistencyModel-generated framesManualParts move by whole voxels; lint measures frame-to-frame change; previews highlight every changed pixel
Style across a gamePer prompt / style referencesNoneProject-wide palettes, ramps, camera, light and style versions; change one setting, every asset updates
Quality checksNoneNoneA linter the agent reads and fixes (orphan pixels, jitter, ramp misuse, outline clipping…)
Engine outputPNG sheets, some JSON atlasesPNGmanifest.json for any engine; Godot SpriteFrames / TileSet; normal maps; palette-swap tables
Long-term projectNoneNoneBRIEF.md + STYLE.md memory, asset status, style changelog
DeterministicNoYesYes: byte-identical builds

Where PAGAN loses: it isn't a painter. For one-off, organic, illustration-heavy art, a diffusion tool is faster. PAGAN wins on a whole game's worth of consistent, animated, rotatable, maintainable assets.

Install

One line, then ask

Requires Python 3.11+. Pin a tag so your art builds the same way next year (v0.8.0 is current).

$ pip install "pagan @ git+https://github.com/lukasgolino/PAGAN@v0.8.0"  # install PAGAN (Python 3.11+)
$ pagan skill install  # copy the skill into this repo's .claude/skills/

Then ask Claude: "I'm making a naval exploration game; make the player's ship, three masts, 8 headings."

Open source

Free, for good

PAGAN is MIT-licensed. Every released version stays free to use, change and ship, commercially or not. No account, no telemetry, no cloud: it runs on your machine.

  • Source, issues and releases on GitHub
  • Current release: v0.8.0, see the changelog
  • Contributing: open an issue first for notation changes; every feature lands with tests, output stays byte-identical, and anything that changes rendered pixels gets a version bump.
  • Game repos pin a tag, so your art never changes under you.
  • Sister libraries: KILN (smooth 3D models) and SEGAN (audio), same design, same workflow.
The PAGAN icon, a speech bubble of pixels

MIT · free forever · made with PAGAN

FAQ

Straight answers

Is PAGAN an AI image generator?

No. PAGAN doesn't paint: it compiles. Your AI agent writes PAGAN source files (palettes, grids, voxel models, animations); PAGAN checks them and renders them. The quality comes from the agent's modelling and PAGAN's renderer, not from a diffusion model, so results are exact, repeatable and editable.

When should I use a diffusion tool instead?

For one-off, organic, illustration-heavy art (a painted portrait, a splash screen), an image model is faster. PAGAN wins when you need a whole game's worth of assets that match: consistent headings, animations that don't jitter, one palette, and changes that reach every asset at once.

Which agents work with it?

Any agent that speaks MCP (Claude Desktop, Claude Code, Cursor, your own). The PAGAN skill, which teaches the full workflow, is for Claude. Without either, the CLI's --json output is easy for any program to drive.

Is it only for pixel art?

No. Flat, vector-like arcade art works too: polygon shapes with rims, drawn at 2x and smoothed on build (supersample). Pixel art is the default.

Does it work for 3D games?

Yes. Besides sprites in 1-32 headings, every 3D model can build as a real mesh (binary glTF, .glb): one node per part with joints, hit-zone metadata and animations, a palette ramp texture, and for Godot a scene with a shader that keeps the engine's lighting on the palette. Tilesets can export repeatable ground and wall textures. You pick the voxel size (texel density) for your game once.

Which engines?

Any: manifest.json describes every sheet, frame, animation, pivot and colour swap. Godot 4 gets SpriteFrames and TileSet resources out of the box.

Who owns the art?

You do. PAGAN is MIT-licensed and runs locally; nothing is uploaded and nothing is claimed.

Is the demo a live AI?

No. It's a scripted conversation, so it can't make things up. But every image, source file, diff, lint result and file listing in it is real PAGAN output, rebuilt from the project files in this site's repository.

More in the docs.