pixel-art

Pixel art w/ era palettes (NES, Game Boy, PICO-8).

  • creative
  • pixel-art
  • arcade
  • snes
  • nes
  • gameboy
  • retro
  • image
  • video

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/optional-skills/creative/pixel-art'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
---name: pixel-artdescription: "Pixel art w/ era palettes (NES, Game Boy, PICO-8)."version: 2.0.0author: dodo-reachlicense: MITplatforms: [linux, macos, windows]metadata:  hermes:    tags: [creative, pixel-art, arcade, snes, nes, gameboy, retro, image, video]    category: creative    credits:      - "Hardware palettes and animation loops ported from Synero/pixel-art-studio (MIT) — https://github.com/Synero/pixel-art-studio"--- # Pixel Art Convert any image into retro pixel art, then optionally animate it into a shortMP4 or GIF with era-appropriate effects (rain, fireflies, snow, embers). Two scripts ship with this skill: - `scripts/pixel_art.py` — photo → pixel-art PNG (Floyd-Steinberg dithering)- `scripts/pixel_art_video.py` — pixel-art PNG → animated MP4 (+ optional GIF) Each is importable or runnable directly. Presets snap to hardware paletteswhen you want era-accurate colors (NES, Game Boy, PICO-8, etc.), or useadaptive N-color quantization for arcade/SNES-style looks. ## When to Use - User wants retro pixel art from a source image- User asks for NES / Game Boy / PICO-8 / C64 / arcade / SNES styling- User wants a short looping animation (rain scene, night sky, snow, etc.)- Posters, album covers, social posts, sprites, characters, avatars ## Workflow Before generating, confirm the style with the user. Different presets producevery different outputs and regenerating is costly. ### Step 1 — Offer a style Call `clarify` with 4 representative presets. Pick the set based on what theuser asked for — don't just dump all 14. Default menu when the user's intent is unclear: ```pythonclarify(    question="Which pixel-art style do you want?",    choices=[        "arcade — bold, chunky 80s cabinet feel (16 colors, 8px)",        "nes — Nintendo 8-bit hardware palette (54 colors, 8px)",        "gameboy — 4-shade green Game Boy DMG",        "snes — cleaner 16-bit look (32 colors, 4px)",    ],)``` When the user already named an era (e.g. "80s arcade", "Gameboy"), skip`clarify` and use the matching preset directly. ### Step 2 — Offer animation (optional) If the user asked for a video/GIF, or the output might benefit from motion,ask which scene: ```pythonclarify(    question="Want to animate it? Pick a scene or skip.",    choices=[        "night — stars + fireflies + leaves",        "urban — rain + neon pulse",        "snow — falling snowflakes",        "skip — just the image",    ],)``` Do NOT call `clarify` more than twice in a row. One for style, one for scene ifanimation is on the table. If the user explicitly asked for a specific styleand scene in their message, skip `clarify` entirely. ### Step 3 — Generate Run `pixel_art()` first; if animation was requested, chain into`pixel_art_video()` on the result. ## Preset Catalog | Preset | Era | Palette | Block | Best for ||--------|-----|---------|-------|----------|| `arcade` | 80s arcade | adaptive 16 | 8px | Bold posters, hero art || `snes` | 16-bit | adaptive 32 | 4px | Characters, detailed scenes || `nes` | 8-bit | NES (54) | 8px | True NES look || `gameboy` | DMG handheld | 4 green shades | 8px | Monochrome Game Boy || `gameboy_pocket` | Pocket handheld | 4 grey shades | 8px | Mono GB Pocket || `pico8` | PICO-8 | 16 fixed | 6px | Fantasy-console look || `c64` | Commodore 64 | 16 fixed | 8px | 8-bit home computer || `apple2` | Apple II hi-res | 6 fixed | 10px | Extreme retro, 6 colors || `teletext` | BBC Teletext | 8 pure | 10px | Chunky primary colors || `mspaint` | Windows MS Paint | 24 fixed | 8px | Nostalgic desktop || `mono_green` | CRT phosphor | 2 green | 6px | Terminal/CRT aesthetic || `mono_amber` | CRT amber | 2 amber | 6px | Amber monitor look || `neon` | Cyberpunk | 10 neons | 6px | Vaporwave/cyber || `pastel` | Soft pastel | 10 pastels | 6px | Kawaii / gentle | Named palettes live in `scripts/palettes.py` (see `references/palettes.md` forthe complete list — 28 named palettes total). Any preset can be overridden: ```pythonpixel_art("in.png", "out.png", preset="snes", palette="PICO_8", block=6)``` ## Scene Catalog (for video) | Scene | Effects ||-------|---------|| `night` | Twinkling stars + fireflies + drifting leaves || `dusk` | Fireflies + sparkles || `tavern` | Dust motes + warm sparkles || `indoor` | Dust motes || `urban` | Rain + neon pulse || `nature` | Leaves + fireflies || `magic` | Sparkles + fireflies || `storm` | Rain + lightning || `underwater` | Bubbles + light sparkles || `fire` | Embers + sparkles || `snow` | Snowflakes + sparkles || `desert` | Heat shimmer + dust | ## Invocation Patterns ### Python (import) ```pythonimport sysimport ossys.path.insert(0, os.path.expanduser("~/.hermes/skills/creative/pixel-art/scripts"))from pixel_art import pixel_artfrom pixel_art_video import pixel_art_video # 1. Convert to pixel artpixel_art("/path/to/photo.jpg", "/tmp/pixel.png", preset="nes") # 2. Animate (optional)pixel_art_video(    "/tmp/pixel.png",    "/tmp/pixel.mp4",    scene="night",    duration=6,    fps=15,    seed=42,    export_gif=True,)``` ### CLI ```bashcd ~/.hermes/skills/creative/pixel-art/scripts python pixel_art.py in.jpg out.png --preset gameboypython pixel_art.py in.jpg out.png --preset snes --palette PICO_8 --block 6 python pixel_art_video.py out.png out.mp4 --scene night --duration 6 --gif``` ## Pipeline Rationale **Pixel conversion:**1. Boost contrast/color/sharpness (stronger for smaller palettes)2. Posterize to simplify tonal regions before quantization3. Downscale by `block` with `Image.NEAREST` (hard pixels, no interpolation)4. Quantize with Floyd-Steinberg dithering — against either an adaptive   N-color palette OR a named hardware palette5. Upscale back with `Image.NEAREST` Quantizing AFTER downscale keeps dithering aligned with the final pixel grid.Quantizing before would waste error-diffusion on detail that disappears. **Video overlay:**- Copies the base frame each tick (static background)- Overlays stateless-per-frame particle draws (one function per effect)- Encodes via ffmpeg `libx264 -pix_fmt yuv420p -crf 18`- Optional GIF via `palettegen` + `paletteuse` ## Dependencies - Python 3.9+- Pillow (`pip install Pillow`)- ffmpeg on PATH (only needed for video — Hermes installs package this) ## Pitfalls - Pallet keys are case-sensitive (`"NES"`, `"PICO_8"`, `"GAMEBOY_ORIGINAL"`).- Very small sources (<100px wide) collapse under 8-10px blocks. Upscale the  source first if it's tiny.- Fractional `block` or `palette` will break quantization — keep them positive ints.- Animation particle counts are tuned for ~640x480 canvases. On very large  images you may want a second pass with a different seed for density.- `mono_green` / `mono_amber` force `color=0.0` (desaturate). If you override  and keep chroma, the 2-color palette can produce stripes on smooth regions.- `clarify` loop: call it at most twice per turn (style, then scene). Don't  pepper the user with more picks. ## Verification - PNG is created at the output path- Clear square pixel blocks visible at the preset's block size- Color count matches preset (eyeball the image or run `Image.open(p).getcolors()`)- Video is a valid MP4 (`ffprobe` can open it) with non-zero size ## Attribution Named hardware palettes and the procedural animation loops in `pixel_art_video.py`are ported from [pixel-art-studio](https://github.com/Synero/pixel-art-studio)(MIT). See `ATTRIBUTION.md` in this skill directory for details. 
Discovery context

Discovered by repository scan. No exact path reference found in the snapshot’s root AGENTS.md.