Getting started
pxart is pixel art as text. A sprite is a small plain-text file: a palette, then a grid of characters. It renders to PNG. Language models can write it, git can diff it, and you can read it.
This page installs pxart, has you write a sprite, look at it, break it, and animate it. That takes five minutes. The tutorials then go further, one feature at a time.
Install
pxart needs Python 3.9 or newer. Its only dependency is Pillow.
pip install git+https://github.com/thethirdbearsolutions/pxart
pxart -hIt's also a single file. If you'd rather not install anything, download
pxart.py and run
python3 pxart.py -h.
Write a sprite
Make a file called face.px and type this into it:
# a small face
k #3f2631
g #43e1b3
y #fee761
....kkkk....
...kggggk...
..kgyggygk..
...kggggk...
....kkkk....- Each palette line is a key, one character, followed by a color:
#rrggbb,#rrggbbaa, ortransparent. - The grid uses those keys, one character per pixel.
.is always transparent and is never listed. - Every row has to be the same width. The sprite's size is the grid's size, so there's nothing to declare or count.
- Lines starting with
#are comments.
Look at it
pxart render face.px -o face.preview.png --pngwrote face.png (--png: face.px at 1x)
wrote face.preview.pngrender draws a preview for looking at while you edit. Every pixel is drawn as a block,
with a grid, coordinate rulers, and a grey checkerboard where the pixels are transparent.
--png also writes the sprite at 1x, which is the file a game would use.
pxart is built around a loop: write some rows, render them, look, fix, and render again. Every step is plain text in and a picture out, so you can take that loop yourself, give it to a language model, or do both.
Break it on purpose
Change one g to a q, a key the palette doesn't have, and check the file:
pxart check face.pxFAIL face.px: 1 error(s)
face.px:8: E_UNKNOWN_KEY (row 2, x=[8]): keys 'q' aren't in the paletteEvery problem in a file is reported at once, each with a stable code, a line number and the pixel it's at. Errors lists every code.
Animate it
One file can hold several grids. Name each with @frame. Frames whose ids share a
parent path form an animation, and @anim sets its timing:
# a small face that blinks
pxart 1
k #3f2631
g #43e1b3
y #fee761
@anim face/blink ms=400
@frame face/blink/0
....kkkk....
...kggggk...
..kgyggygk..
...kggggk...
....kkkk....
@frame face/blink/1 ms=120
....kkkk....
...kggggk...
..kgkggkgk..
...kggggk...
....kkkk....Without -o, anim prints what changed between each pair of frames and writes nothing.
After it removes any whole-body movement, it counts the pixels that are left:
pxart anim blink.px face/blink/0 400ms vs face/blink/1: shift +0,+0 then 2px (7%)
face/blink/1 120ms vs face/blink/0: shift +0,+0 then 2px (7%)Here only the two eyes changed. In a walk cycle, the same numbers show whether the legs
really move, or whether the sprite just bobs up and down. Add -o blink.gif to write
the GIF and a strip of the frames.
Where next
- The tutorials: nine short walkthroughs, from the format to palette variants, drawing tools, tilemaps, and exporting to Aseprite and Tiled. Each one ends with a picture you made.
- The .px format: the whole format, including frames, pivots,
shared palettes,
@variantrecolors and palette slots. - Commands at a glance: every command in a paragraph, grouped by what it's for.
- Reference:
pxart helpfor each command, as the tool prints it.
site/src/content/getting-started.md in the repository.Edit on GitHub