search
Search the sprite library by keyword, category, or get a random sprite. Returns a text listing of matching sprites.
queryrandomcategory
io.github.rxolvePublished by GitHub account rxolvev0.5.0Updated Nov 3, 2026
LLMs can't draw. This MCP can. Pixel art animation toolkit — draw, animate, compose, export.
Pixscii is a local pixel-art workbench that lets an assistant generate, draw, animate and export sprites and scenes as PNG images.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Follow the launch instructions in the repository.
LLMs can't draw. This MCP can. A pixel art animation toolkit for AI agents.
Sister project of artscii. While artscii provides terminal ASCII art, pixscii gives AI agents a full pixel art workbench — generate characters, animate scenes, draw sprites, and export PNGs. Offline, deterministic, zero latency.
One tool call. 3 characters, tiled background, 24 frames. 9ms.
The LLM translates a scene description into structured input. pixscii executes it instantly.
Or add to your MCP client config:
LLMs can't place pixels well, but they write coordinates fine. shapes rasterizes geometry at pixel centers with no anti-aliasing, so every pixel is one palette index. Soft fills come from ordered dithering:
Then repalette to scene-sea or scene-night for the same picture in another mood. In code: drawShapes(sprite, shapes, palette).
landscape builds a whole scene from a seed in the scene schema, so one seed is one place you can show in any mood:
Presets match the scene palettes: dawn, home, school, night, sea, storm, window, forest, dusk, stars. Layers: sky (dithered gradient), stars, sun or moon (with a halo, and glitter on water), clouds, mountains (midpoint-displacement ridge), hills (value noise), sea (waves), forest (pines and round trees), ground, rain. Default size 128×72. In code: landscape({ seed, preset }).
creature mirrors a mask filled by the seed (body, maybe-body, empty), drops stray pixels, outlines it, lights it from the top and gives it eyes. Kinds: robot, alien, critter, plus nebula (asymmetric noise cloud with caught stars). being draws a person, cat or elf at a life stage from shapes: babies have big heads and no legs, old people white hair and a cane, old elves a staff, old cats a rounder body and a lowered tail.
Both use the scene schema, so they sit on a landscape in the same palette.
Start with animate_scene for a fast draft. Drop to lower layers to refine.
Two calls: one to generate, one to assemble. Done.
Every pixel is one character. The agent reads and writes in the same alphabet:
~80 tokens for a full 16x16 sprite. The LLM reads this like source code and reasons about it spatially.
22 sprites across 4 categories:
648 procedural characters: 4 species (human, elf, dwarf, skeleton) x 3 armors x 3 weapons x 3 helms x 6 skin tones.
13 palettes: pico8 (default), grayscale, gameboy, and 10 scene moods (scene-dawn, home, school, night, sea, storm, window, forest, dusk, stars)
The scene palettes share one schema: the same 16 named slots (ink, sky-top, sky-mid, sky-low, sun, cloud, far, mid, near, ground, water, foam, accent, skin, cloth, light). Draw once with those slots, then render with any scene palette to get the same picture in another mood. In code: SCENE.ground, slotIndex(palette, 'water'), remapPalette(sprite, from, to).
6 motion types: idle, walk, attack, hurt, bounce, blink
pixscii/coreEverything that draws, composes and renders also runs without Node. pixscii/core has no Node built-ins, no sharp and no MCP:
Bundled sprites, palettes and characters load through an asset source. In Node the MCP server and CLI use the files in sprites/. Elsewhere, pass anything that can read those files:
src/core/boundary.test.ts fails if anything in core imports a Node built-in, sharp, MCP or a file outside core.
See ROADMAP.md for where pixscii is going: shapes, procedural landscapes and creatures.
MIT
Source: README.md at commit de290da
Search the sprite library by keyword, category, or get a random sprite. Returns a text listing of matching sprites.
queryrandomcategoryGet a sprite as a PNG image by its ID. Returns a scaled pixel art PNG.
idrequiredscalepaletteGenerate a procedural pixel character sprite. Same seed always produces the same character. 648 unique combinations.
helmseedrequiredskinarmorscaleweaponpalettespeciesConvert an image (URL or base64) to pixel art by quantizing to a palette. Returns both the PNG and sprite data.
scalewidthheightsourcerequiredpaletteCreate a new blank canvas for drawing. Returns canvas ID and hex grid for inspection.
fillwidthrequiredheightrequiredpaletteSet individual pixels on a canvas. Batch up to 512 pixels per call.
pixelsrequiredcanvas_idrequiredDraw a line between two points on a canvas using Bresenham's algorithm.
x1requiredx2requiredy1requiredy2requiredcolorrequiredcanvas_idrequiredDraw a rectangle on a canvas (outline or filled).
hrequiredwrequiredxrequiredyrequiredcolorrequiredfilledcanvas_idrequiredFlood fill from a point on a canvas. Returns the updated grid so you can verify the result.
xrequiredyrequiredcolorrequiredcanvas_idrequiredMirror a canvas horizontally (left half copied to right half). Returns the updated grid.
axis_xcanvas_idrequiredRead the current pixel state of a canvas as a hex character grid. For canvases >32px, provide x,y,w,h to inspect a region.
hwxycanvas_idrequiredRevert the last drawing operation on a canvas. Single-step undo.
canvas_idrequiredExport a canvas as a scaled PNG image.
scalecanvas_idrequiredCompose multiple sprites into a single scene. Place sprites at specific x,y positions on a canvas.
scalewidthrequiredheightrequiredlayersrequiredpaletteBuild a tilemap from a 2D grid of tile IDs. Each cell becomes a 16x16 tile.
gridrequiredscalepaletteStitch multiple canvases into a single PNG spritesheet. Supports horizontal, vertical, or grid layout.
gapscaleframesrequiredcolumnspalettedirectionAnimate a sprite or character with pixel motion. Returns multiple PNG frames or a spritesheet.
idseedscalemotionrequiredpaletteAnimate actors across a scene. Each actor has a pose cycle and a path of positions. Returns one PNG per frame.
delayscalewidthrequiredactorsrequiredheightrequiredpalettebackgroundCreate a full animated scene in one call. Generate characters, place them on a background, and animate them along paths. Returns multiple PNG frames.
delayscalewidthrequiredactorsrequiredframesheightrequiredpalettebackgroundList palettes and their named slots. Palettes that share a schema (e.g. "scene") use each index for the same role, so swapping between them recolors the same art for a different mood.
schemaSwitch a canvas to another palette. Within one schema the pixels stay and only the colors change; across schemas each color moves to the slot with the same name, or else the nearest color.
scalepaletterequiredcanvas_idrequiredDraw geometry as crisp pixel art: rect (with radius), circle, ellipse, polygon, line, curve. Fills can be a color, a dither of two colors, or a dithered gradient; filled shapes can have an outline. Draws on an existing canvas, or creates one. Write coordinates, not pixels.
scalewidthheightshapesrequiredpalettecanvas_idGenerate a pixel landscape from a seed: sky by time of day, sun or moon, stars, clouds, mountains, hills, sea, forest, ground, rain. Uses the "scene" palette schema, so the same seed renders in any scene-* palette. Presets: dawn, home, school, night, sea, storm, window, forest, dusk, stars. Returns a canvas you can keep drawing on.
seedrequiredtimescalewidthheightlayerspresethorizonpaletteGenerate a creature from a seed: symmetric robot, alien or critter from a mask (outlined, lit from the top, with eyes), or an asymmetric nebula. Endless variety, same seed same creature. Scene palette schema.
kindseedrequiredsizescalepaletteDraw a 24×24 person, cat or elf at a life stage: baby, adult or old (white hair, a cane or staff, a plumper cat). The seed varies hair and clothes. Scene palette schema.
seedscalestagerequiredpalettespeciesrequired90% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
animate_scene { "width": 128, "height": 48, "background": { "tiles": [["tree","grass","grass","sand","stone","wall","wall","door"]] }, "actors": [ { "seed": "hero", "species": "human", "armor": "plate", "weapon": "sword", "motion": "walk", "from": {"x":0,"y":28}, "to": {"x":96,"y":28} }, { "seed": "mage", "species": "elf", "armor": "cloth", "weapon": "staff", "motion": "walk", "from": {"x":-16,"y":30}, "to": {"x":72,"y":30} }, { "seed": "guard", "species": "skeleton", "motion": "idle", "from": {"x":108,"y":28}, "to": {"x":108,"y":28} } ], "frames": 24, "delay": 150}npx pixscii{ "mcpServers": { "pixscii": { "command": "npx", "args": ["-y", "pixscii"] } }}shapes { "width": 128, "height": 72, "palette": "scene-dusk", "shapes": [ { "type": "rect", "x": 0, "y": 0, "w": 128, "h": 46, "fill": { "gradient": ["sky-top", "sky-mid", "sky-low"] } }, { "type": "circle", "cx": 92, "cy": 40, "r": 9, "fill": "sun" }, { "type": "polygon", "points": [[0,46],[22,26],[40,38],[62,20],[90,42],[128,40],[128,48],[0,48]], "fill": "far" }, { "type": "rect", "x": 0, "y": 46, "w": 128, "h": 26, "fill": { "gradient": ["water", "near"] } }, { "type": "curve", "points": [[34,56],[44,44],[56,56]], "color": "accent" } ]}landscape { "seed": "harbor-town", "preset": "dusk" }landscape { "seed": "harbor-town", "preset": "dusk", "palette": "scene-night" }landscape { "seed": "pine-ridge", "time": "dawn", "layers": ["sky", "sun", "mountains", "forest", "ground"] }creature { "seed": "voyager-7", "kind": "robot" }being { "species": "elf", "stage": "old", "palette": "scene-forest" }Layer 1: animate_scene → full scene in one call (fast path)Layer 2: sequence/compose → manual frame composition (precise control)Layer 3: pixel/line/rect → individual pixel editing (full control)→ animate_scene { width: 80, height: 40, background: { tiles: [["grass","grass","stone","wall","door","wall"]] }, actors: [{ seed: "hero-girl", species: "human", armor: "cloth", motion: "walk", from: {x:0, y:24}, to: {x:60, y:24} }], frames: 16, delay: 120 }← 16 frame PNGs + frame_ids
→ spritesheet { frames: [frame_ids], direction: "horizontal" }← single strip PNG with all 16 frames→ create { width: 16, height: 16, fill: "." }← canvas_id + hex grid
→ rect { canvas_id, x: 3, y: 5, w: 10, h: 9, color: "1" }→ fill { canvas_id, x: 7, y: 7, color: "8" }← filled: 56 pixels, leaked: false (grid returned — agent verifies)
→ inspect { canvas_id }← agent reads grid, spots issue, fixes with pixel tool
→ export { canvas_id, scale: 4 }← 64x64 PNG0-F = PICO-8 palette colors (0=black, 7=white, 8=red, ...). = transparent 0123456789ABCDEF 0: ................ 1: .....111111..... 2: .....177771..... 3: .....177771..... 4: ...1111111111... 5: ...1888888881... 6: ...1788888881...npx pixscii import sprite.png --id my-sword --category itemsnpx pixscii export sword --scale 4 --out sword.pngimport { createEmpty, drawRect, registerPalette, getPalette, renderToRGBA } from 'pixscii/core';
registerPalette({ id: 'dusk', name: 'Dusk', colors: [ { index: 0, hex: '#1A1016', name: 'sky' }, { index: 1, hex: '#E88FB0', name: 'sun' }, { index: 2, hex: '#3A2433', name: 'ground' }, ],});
let scene = createEmpty(32, 18, 0);scene = drawRect(scene, 13, 4, 6, 6, 1, true);scene = drawRect(scene, 0, 12, 32, 6, 2, true);
const { width, height, data } = renderToRGBA(scene, getPalette('dusk'), 8);canvas.getContext('2d')!.putImageData(new ImageData(new Uint8ClampedArray(data), width, height), 0, 0);import { setAssetSource, loadPalettes } from 'pixscii/core';
setAssetSource({ readJSON: (file) => fetch(`/pixscii/sprites/${file}`).then((r) => r.json()), list: async (dir) => (dir === 'palettes' ? ['pico8.json', 'gameboy.json', 'grayscale.json'] : []),});await loadPalettes();npm installnpm run dev # Start MCP server (stdio)npm run build # Compile TypeScriptnpm test # Run testssrc/core/ pure TypeScript, runs anywhere (exported as pixscii/core)src/node/ sprites/ on disk, PNG encode and image import (sharp), CLIsrc/mcp/ MCP server and tools