Pixel art as code. js file; get PNGs, sprite sheets with JSON, animated GIFs, and a live browser viewer that replays the painting step by step as you save.
The project's README from github.com/augusto-scarvalho/claude-pxl. As one markdown file: README.md.
Pixel art as code. Write a compact .px.js file; get PNGs, sprite sheets with JSON, animated
GIFs, and a live browser viewer that replays the painting step by step as you save.
Built for AI agents (it ships as a ready-made agent skill) and pleasant for people too. No runtime dependencies, no build step: just Node ≥ 22.18.
This is a fork of crsolver/claude-pxl. Fork differences: what it adds, in one page.
Every image above is generated from a file in examples/.
Getting started · Working with an agent · Reference · All docs · Showcases
git clone https://github.com/augusto-scarvalho/claude-pxl.git
cd claude-pxl
node bin/pxl.js serve examples/shop.px.js # live viewer at http://127.0.0.1:4321/
Or run it without cloning:
npx github:augusto-scarvalho/claude-pxl build art.px.js
Write art.px.js:
pal({ k: "#1b1630", g: "#8ccf63", G: "#4c8a44", w: "#fff6e0", r: "#e2585e", R: "#a63a4c" })
// Write the left half; mirror it and outline it automatically.
sprite("slime", { mx: true, outline: "k" }, `
....ggg
..ggGGg
.ggGwGg
gggkwgg
GGGGGGG`)
sprite("slime_red", { base: "slime", swap: { g: "r", G: "R" } }) // a recolor in one line
sheet("chars", ["slime*"], { pad: 1 })
node bin/pxl.js build art.px.js
out/sprites/slime.png out/sprites/slime_red.png the art, at 1x
out/chars.png out/chars.json sprite sheet + TexturePacker-style JSON
out/_preview/*.png upscaled previews with a pixel grid
pxl serve opens a viewer that rebuilds on every save and replays the asset you edited op by op, so
you (or whoever is watching an agent work) can see the art being painted. It also writes the same
out/ files as build.
Getting started goes on from here: an animation, a scene, what a build writes, which command to use when, and learning from a reference.
This repository is an agent skill. SKILL.md teaches the workflow (write, look with shot, fix
everything in one turn, check, build); the reference and the guides are read a section at a time
with pxl help, so the agent pays only for what the task needs.
Claude Code: clone it into your skills folder, then ask Claude to draw something.
# all projects
git clone https://github.com/augusto-scarvalho/claude-pxl.git ~/.claude/skills/pxl-pixel-art
# or just one project
git clone https://github.com/augusto-scarvalho/claude-pxl.git .claude/skills/pxl-pixel-art
Other agents (Codex, Cursor, …): point them at SKILL.md and tell them the CLI is
node <path to pxl>/bin/pxl.js.
Ask the agent to start pxl serve so you can watch it paint in your browser.
Working with an agent covers writing a brief, what a session costs (measured),
one agent or a pipeline for a big scene, and reviewing what it made.
pxl build <art.px.js> [--out DIR] [--only a,b] [--scale N] [--share N] [--no-preview] [--aseprite] [--list] [--every N] [--profile]
pxl serve <art.px.js> [--port 4321] [--out DIR | --no-out] [--no-preview]
pxl ascii <art.px.js> <name> print an asset as palette keys with x/y rulers (--frame N: one frame)
pxl list <art.px.js> a map of the file: each asset and function's lines, its comment, what it makes
pxl describe <art.px.js> <name> a whole scene as text: what is where, what covers it, how it moves
pxl check <art.px.js> [name...] every check describe makes, on every frame: warnings; and hand-drawn lines to look at
pxl shot <art.px.js> <name> frames side by side, a region enlarged, --vs HEAD --diff; with several
names, other files', PNGs or clips, a row each (--at again: a column each)
pxl shot <ref.gif | video> a reference's frames on one sheet, at 1x (--frames 0-11 for some)
pxl steps <art.px.js> <name> how it was painted, step by step; --at x,y: what painted that pixel
pxl compare <art.px.js> <name> <ref.png> silhouette rows against a reference (--shrink N, --offset x,y)
pxl blind <art.px.js> <name...> facing labels checked by a reader who doesn't know them (--check answers.json)
pxl study <picture|gif|video> learn from finished art or a reference: palette, ramps, outlines, the faults
of its lines, light, perspective, parallax, its moving pieces cut out with
their spacing, and what to use in pxl for each (--px N: its pixel size)
pxl help [name] what the reference says about an op or option, or a guide's section
pxl alone prints every command with its options.
pxl means node bin/pxl.js in a clone, or npx github:augusto-scarvalho/claude-pxl. Art files can be .js or
.ts (types/pxl.d.ts gives editor completion).
shade() / light(), shades() for a hue-shifted ramp
from one color._parts, stamp, anti-aliasing as by hand (aa).mono for a score),
scatter brushes, tilemaps, random groups with reproducible seeds.stamp(..., { smear })); parts half a pixel along
(stamp(..., { sub: true })) for an idle without the single-pixel bob.rig() skeleton first (slots, stand-ins, parts ordered by facing, turned with
twin parts), ik for poses, register by the pelvis (see characters.md).lighting.md).perspective()), ground
(plane()), hills (terrain()), things built of solid shapes and their shadows (solids(),
shadows()), faces you are inside of (mesh()); see scenes.md.scroll()), clouds(), smoke and steam (plume())..tmj), Aseprite files to keep editing.file:line:col and the asset/layer/op path, with "did you mean…" hints.And around the DSL, tools to look with (an agent's eyes, cheap in text): shot builds one asset
and writes a picture with what changed, describe reads a scene as text, check warns before you
hand over, steps names the line that painted a pixel, and study reads a reference back into
pxl's terms. What they say is in Getting started.
| For | Read |
|---|---|
| a first sprite, an animation and a scene by hand | docs/getting-started.md |
| running an agent with pxl: briefs, costs, pipelines, review | docs/agents.md |
| which model and effort to draw with: one scene, eight ways | docs/model-study.md |
| every op and option | reference.md, or pxl help <name> |
| the agent's workflow and the examples table | SKILL.md |
| scenes, perspective, parallax, shadows | scenes.md |
| characters, animation with parts, rigs | characters.md |
| lamps, walls that block light, normal maps | lighting.md |
| turning a sprite by any angle, 8 or 16 directions | rotation.md |
| what this fork adds to the original | docs/fork-differences.md |
| what is still open | BACKLOG.md |
Long projects made with pxl by agents, most over rounds of a curator's notes. Each is a folder in
examples/ to read and copy.
The first long project made with pxl, by an agent working with a curator over many rounds of
feedback: a 320×240 animated jungle in examples/tropical/. A waterfall
churns its pool and sends foam down a river that winds under a plank bridge. A dirt trail is laid
with a terrain tileset. Big trees, palms and the understory throw shadows laid flat on the ground,
and grass and weeds cover the whole floor. In the trees, a jaguar lies on a branch and a monkey
swings; a macaw, a frog and butterflies are around, and an Indigenous girl breathes on the trail.
What the agent kept getting wrong on the way became pxl features (cast shadows, relight,
tilemap corners) and notes in SKILL.md and characters.md.
The trees, palms and big leaves are reduced from "[LPC] Jungle" by bluecarrot16, Lanea Zimmerman
(Sharm), Sevarihk, Hyptosis and others, and from Sevarihk's "Animated Palm Tree Sprite", both
CC-BY 4.0: they keep that license, so credit their authors when you reuse them (full list in
examples/tropical/refs/CREDITS.md). Everything else in the
scene, the trail's tileset included, is drawn in code and MIT like the rest of the repository.
The second long project, in examples/halloween/: a 320×180 night scene lit
only by lighting(), with a cold moonlit ambient and lamps on everything that glows (jack-o'-lanterns
flickering out of step, string lights, the crypt's door, a witch's cauldron, a mirror ball over the
dance floor). Eight monsters loop on one 2-second cycle: a skeleton whose bones are drawn between
joints, a vampire whose cape opens like bat wings, a mummy doing the Egyptian, a zombie doing
Thriller, a ghost, a witch stirring, a Frankenstein DJ and a werewolf howling at the moon. Figures
near the strongest lights throw their silhouettes away from them (cast from a point light). Making
it led to pxl describe (a whole scene as text an agent reads at once: where each object shows, its
gaps, what covers it, how it stands out after lighting, how it moves; --diff after an edit) and
to a GIF encoder that keeps small figures' colors in lit scenes. Everything is drawn in code, MIT.
The third, in examples/sunset/: a 320×180 backlit scene. A fresh agent made
the first version from the skill alone; a curator's notes then went into the tent, the sleeping bag
and the sky. With the sun low ahead, everything facing us is in shadow, edges toward the sun glow,
and shadows run long toward us, each one laid away from the sun's point on the horizon. The tent's
canvas glows where the light comes through it, darker wherever the cloth doubles (seams, patches,
the ridge tape), and its unpegged corner lifts in the wind. The sky loops in 19.2 s while
everything else repeats every 1.2 s. Its clouds drift a whole pixel at even intervals, slower near
the horizon. Scrolling a wrapping strip would make the loop as long as the strip's width over the
speed, so each cloud instead thins away once a loop and re-forms where it started, out of step with
the others. A skein of birds crosses toward the sun, and a faint aura breathes around it. Everything
is drawn in code, MIT.
The fourth, in examples/rig/: a 72 px knight built the way
characters.md §11 describes. A rig() lays out its slots first (joints, boxes,
the body's sides) and shows a stand-in for each part not drawn yet; each part is then drawn on its
own from plates, each lit on its own layer, and drops in. The rig orders the parts from the way the
knight faces, so the near arm is in front and the far one behind; turn makes the same knight
facing left, relit for the same light, and the red knight is that one recolored. The shield is a
part with two faces: facing right we see its inside (straps, grip), facing left its cross; it
hangs from the hand and lies along the forearm. Assets say which way they face and how tall they
really are, the scene says where its horizon, eye and light are, and pxl describe checks every
placement against them: which way it faces, whether it's a mirror image, its size where it
stands, whether its feet are on the ground, which side it's lit from. Then they fight: each pose
is a rig of its own, its sword arm, sword and legs drawn from the pose's joints (two-bone IK, the
feet flat on the ground), and a 96-frame list of poses is the bout, with the sparks, the dust, the
marshal's signal and the fanfare on the same clock.
The fifth, in examples/cyberpunk/: one brief, a 320×180 street at dusk in
the spirit of Cyberpunk 2077's Night City (sun-bleached megablocks, dusty yellow haze, freeways,
holo-ads, traffic and people; original art, no real logos), made twice from the skill alone. On
top, one agent: 85 turns in 31 minutes, a 36 s loop. Below, a pipeline: a planner wrote the
palette, a plan with every part's box, light and timing, and the scene file; eight forks of it drew
the sky, towers, freeway, shops, signs, street, traffic and crowd at once, each in its own file;
a last fork put them together. The pipeline came out denser, with more people, cars and shops, but
less coherent, and cost about five times the tokens and twice the time: worth offering for a big
scene, not a default. Its plan is there to read (pipeline/plan.md).
examples/perspective/road.px.js: the sertão at sunset, everything
laid out in meters and projected by perspective(), so every cactus, stake and boulder is the size it
should be where it stands; the ground drawn by plane() pixel by pixel from where each pixel looks.
Each thing is built once as parts (trunks, arms, twigs, crowns), and the same parts draw it and cast
its long shadow, so a mandacaru's shadow has its arms and the walker's walks with them. The walker
holds their size for a whole step and shrinks only when the next foot lands; under 15 px they switch
to sprites drawn by hand for each size (14, 12, 10 ... 5 px), picked by stamp's fit.
Below, park.px.js: the camera turned 40° (yaw), two vanishing points,
at two in the afternoon. Benches, hedges, trees and lamp posts are shapes in meters (solid.box,
stick, blob, cone): solids() draws them far to near and shadows() sweeps the same shapes
onto the ground from the one sun. People and the dog are bodies in meters posed by a gait computed in 3D, so
they're right from any angle the paths give them and cast their own short shadows; the children run
behind the ice-cream cart because everything is drawn far to near, and the loop closes because both
paths end behind a hedge.
Then extinction.px.js: the camera tilted up 18° (pitch), three
vanishing points: the horizon set low (row 150 of 180) and the burning araucarias lean in toward a third
point high above the picture (vertical()). The volcano is terrain(), a heightfield ray-marched
through the same camera; its lava rivers run down the steepest way; the dinosaurs are profiles in
meters on a run worked out in 3D, their legs painted round by capsule(), each covering more than
the picture's width in the loop so their coming back is never seen. Trees, logs and scrub burn with
flame(), every fire leaning with the one wind.
examples/parallax/train.px.js: the camera rides along with the train,
so the train stands still and the land runs past behind it. Each plane is a strip drawn once with
wrap: "x" and placed every frame further along: in the 12 s loop the hills go by 320 px, the
pasture 640, the trackside 1280 and the grass in front 1920, each strip round a whole number of times;
the ridge on the horizon, too slow to go round, drifts 32 px in the loop while its outline crossfades
into itself. The drivers turn a whole
number of times a loop with the rods on their crank pins, and every puff of smoke is left behind at
the speed of the ground, so the last frame runs into the first.
examples/perspective/race.px.js: a street race from the driver's
seat. The road is plane() through a camera at 1 m that bends with it (bend). The rivals are drawn
by hand from behind at seven sizes, the camera picking the nearest (fit), and drawn whole in
perspective as they draw level, their long shadows thrown by shadows() from the low sun; the serra
is three ranges paling with distance, each rising out of the sea at a headland. The cockpit, after a
Supra A80's, and its steering wheel are modelled in 3D in meters and drawn through the same camera by
mesh() (cockpit.px.js): each face toned by how it lies to
the sun, outlined where it ends in front of another. Each mirror is another camera looking back. Our
speed is a profile in time whose integral moves everything, so the loop still closes; before the burst
the right hand leaves the wheel to change gear. Each hand is a puppet of joints read off photographs
of a hand gripping, set on the rim every frame, its fingers painted round by capsule; the sleeves
are shaded as crumpled cloth.
npm install # dev only: typescript, @types/node
npm run check # type check + tests
node scripts/gallery.ts # regenerate docs/gallery
node scripts/calibrate.ts [asset ...] [--summary] [--vs <rev>] # pxl study against the examples' own source
src/core/ engine, no Node APIs: image, palette + ramps, canvas ops, build, trace, project
src/node/ vm sandbox loader, PNG/GIF encoders, outputs, CLI, live server
src/viewer/ browser viewer (served type-stripped; no bundler)
types/ pxl.d.ts globals for editor support in .px.ts files
scripts/ build.js (dist/ for npm installs), gallery.ts, calibrate.ts
examples/ example art files
test/ node:test suites
In a clone the CLI runs the TypeScript sources directly. When installed as a package it runs
dist/, which npm install / npm pack generate via scripts/build.js (Node won't strip types
inside node_modules).
Pixel art as code. js file; get PNGs, sprite sheets with JSON, animated GIFs, and a live browser viewer that replays the painting step by step as you save.