A browser-based pixel sprite editor with palettes, animation, tiling preview, and cloud save.
- React + Vite + TypeScript (
apps/web) - Fastify + TypeScript (
apps/api) - Node CLI for agents (
apps/cli) - Postgres + Drizzle ORM
- Shared zod schemas (
packages/shared) and pixel primitives (packages/pixel)
# one-time
npm install
cp apps/api/.env.example apps/api/.env
npm run db:up # starts Postgres in Docker (port 54329)
npm run db:migrate # apply migrations
# dev
npm run dev:api # Fastify on :3001
npm run dev:web # Vite on :5173 (proxies /api → :3001)Open http://localhost:5173, register an account, and start drawing.
- Configurable grid (8–128) with pencil, eraser, fill, line, rectangle, eyedropper (brush size 1–4, shift-constrain, alt-eyedropper)
- Palette presets (PICO-8, Sweetie 16, Grayscale), custom palettes, recent colors
- Frame timeline with thumbnails + onion skin + rAF-timed animation preview
- Tiling test area: tile mode (live-updating grid) and stamp mode
- Exports: PNG frame, PNG spritesheet, animated GIF (gifenc), JSON project file
- Debounced autosave with If-Match optimistic concurrency
- CLI (
spriteman) for AI agents: project/frame/palette management, batched draw ops, PNG/GIF/spritesheet rendering, embedded pixel-art guide
Bpencil ·Eeraser ·Gfill ·Lline ·Urect ·Ieyedropper[/]brush size ·+/-zoom ·Xswap fg/bgCtrl/Cmd+Zundo ·Ctrl/Cmd+Shift+Zredo- Hold
Altwith any paint tool to eyedrop · HoldShiftto constrain to 45° / square
spriteman is a Node CLI that wraps the backend so AI agents can author
sprites programmatically. After npm install the binary is available at
node_modules/.bin/spriteman (invoke directly, or via npx spriteman).
# one-time
spriteman config set api-url http://localhost:3001 # persist once, no env var needed
spriteman login # prompts for email + password, persists
# session cookie to ~/.config/spriteman/
# …or scripted (CI / AI agents):
SPRITEMAN_EMAIL=me@example.com spriteman login --password-stdin < /tmp/password
# project + frame management
spriteman project create hero --width 32 --height 32 --fps 8
spriteman project create walk --width 32 --height 32 --frames 16 --duration 120
# creates a full 16-frame animation in one call
spriteman project use <id> # set active project (omits --project later)
spriteman frame add --duration 120
spriteman frame duplicate 0 --flip-x # mirror an existing frame horizontally
# drawing — batch via `apply` for efficiency (one GET + one PUT)
cat > /tmp/hero.json <<EOF
{ "frame": 0, "ops": [
{ "type": "clear" },
{ "type": "rect", "at": [8,8], "size": [16,16], "color": "#ffec27ff", "fill": true },
{ "type": "line", "from": [8,8], "to": [23,23], "color": "#ab5236ff" }
]}
EOF
spriteman apply /tmp/hero.json
# single-op sugar (each one round-trips once)
spriteman draw pixel --frame 0 --x 12 --y 12 --color '#ff004dff'
spriteman draw fill --frame 0 --x 0 --y 0 --color '#1d2b53ff'
# render locally (the API has no export endpoints)
spriteman render <id> --frame 0 --out frame.png
spriteman render <id> --frame 0 --scale 8 --out frame@8x.png # nearest-neighbor upscale
spriteman render <id> --frame 0 --stdout | feh - # pipe bytes instead of file
spriteman render <id> --sheet --cols 4 --out sheet.png
spriteman render <id> --gif --frames 0..3 --out down.gif # per-direction preview
spriteman render <id> --gif --out anim.gif
spriteman export <id> --out project.json
# built-in pixel-art guide for agents
spriteman guide # overview + topic list
spriteman guide palette # one topic: resolution / palette /
# shading / lines / animation /
# pitfalls / workflowEnv overrides: SPRITEMAN_API_URL (default http://localhost:3001,
matching the API server), SPRITEMAN_PROJECT (default active project),
SPRITEMAN_EMAIL (pre-fill login email).
URL resolution order (first wins): --api-url flag → SPRITEMAN_API_URL env
→ stored session → spriteman config set api-url value → :3001 default.