Back to creative
creative v2.0.0 5.5 min read 217 lines

pixel-art

Convert images into retro pixel art with hardware-accurate palettes (NES, Game Boy, PICO-8, C64, etc.), and animate them into short videos. Presets cover arcade, SNES, and 10+ era-correct looks. Use `clarify` to let the user pick a style before generating.

dodo-reach
MIT

Pixel Art

Convert any image into retro pixel art, then optionally animate it into a short
MP4 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 palettes
when you want era-accurate colors (NES, Game Boy, PICO-8, etc.), or use
adaptive 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 produce
very different outputs and regenerating is costly.

Step 1 — Offer a style

Call clarify with 4 representative presets. Pick the set based on what the
user asked for — don't just dump all 14.

Default menu when the user's intent is unclear:

clarify(
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:

clarify(
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 if
animation is on the table. If the user explicitly asked for a specific style
and 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 for
the complete list — 28 named palettes total). Any preset can be overridden:

pixel_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)

import sys
sys.path.insert(0, "/home/teknium/.hermes/skills/creative/pixel-art/scripts")
from pixel_art import pixel_art
from pixel_art_video import pixel_art_video

1. Convert to pixel art


pixel_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

cd /home/teknium/.hermes/skills/creative/pixel-art/scripts

python pixel_art.py in.jpg out.png --preset gameboy
python 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:

  • Boost contrast/color/sharpness (stronger for smaller palettes)
  • Posterize to simplify tonal regions before quantization
  • Downscale by block with Image.NEAREST (hard pixels, no interpolation)
  • Quantize with Floyd-Steinberg dithering — against either an adaptive
N-color palette OR a named hardware palette
  • 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
(MIT). See ATTRIBUTION.md in this skill directory for details.

Related Skills / 관련 스킬

ace-step-music

Kaggle T4 GPU에서 ACE-Step 1.5 터보로 가사 없는 인스트루멘탈 음악 생성 — 30초~60초 곡, 프롬프트 기반

creative v1.0.0

architecture-diagram

Generate dark-themed SVG diagrams of software systems and cloud infrastructure as standalone HTML files with inline SVG graphics. Semantic component colors (cyan=frontend, emerald=backend, violet=database, amber=cloud/AWS, rose=security, orange=message bus), JetBrains Mono font, grid background. Best suited for software architecture, cloud/VPC topology, microservice maps, service-mesh diagrams, database + API layer diagrams, security groups, message buses — anything that fits a tech-infra deck with a dark aesthetic. If a more specialized diagramming skill exists for the subject (scientific, educational, hand-drawn, animated, etc.), prefer that — otherwise this skill can also serve as a general-purpose SVG diagram fallback. Based on Cocoon AI's architecture-diagram-generator (MIT).

ascii-art

pyfiglet(571폰트), cowsay, boxes, toilet 등으로 ASCII 아트 생성. API 키 불필요.

ascii-video

ASCII 아트 비디오 프로덕션 파이프라인 — 비디오/오디오/이미지를 컬러 ASCII 캐릭터 비디오(MP4, GIF)로 변환