Live demo → https://aschoelzhorn.github.io/spriteanvil
A browser-based tool for viewing, editing, and exporting pixel-art sprite assets for ESP32/Arduino display projects (LED panels, TFT, OLED).
No install required — use it instantly in the browser via GitHub Pages, or run it locally in Docker.
| Sprites & Zoom | Animation Strip |
|---|---|
| BW Icons (1-bit) | Font Charmap & Preview |
|---|---|
| Sprite Editor | |
|---|---|
| Parse | Drag & drop or paste .h or .c files (select multiple, or drop a whole folder) containing uint16_t / unsigned short / unsigned char / uint32_t (ARGB/ABGR/ARGB32) C arrays |
| Tabs | Sprites and Fonts tabs keep the two workflows separate; controls and Export ZIP adapt per tab |
| Render | RGB565 → RGB888 canvas preview with zoom (1–64 px) and optional pixel grid; uint32_t ARGB/ARGB32 arrays are auto-converted to RGB565 |
| Pixel inspector | Hover over any sprite canvas to see pixel coordinates, RGB565 hex value, and decoded RGB colour |
| 1-bit bitmaps | Monochrome unsigned char XBM/PROGMEM bitmaps rendered with per-sprite FG and BG color pickers (with transparent-BG toggle) |
| Transparency | Checkerboard pattern or a custom solid colour for transparent pixels (0xFEFE or alpha=0 in ARGB32) |
| Animation | Multi-frame arrays play as live animation — ▶/⏸ toggle + per-animation FPS slider |
| Strip view | Animation frames shown as a single side-by-side canvas or as individual canvases |
| Validation | Per-sprite ✅/❌ pixel-count check; |
| Multi-file | Select or drop multiple .h files / a whole folder — prompted once to Add or Replace, then all files are loaded in batch |
| Export ZIP | Original source files + per-sprite split .h + .png preview + root assets.h |
| Save PNG | Per-sprite PNG N× (current zoom) and PNG 1× (native size) buttons on every sprite card |
| Sprite Editor | Open a dedicated editor in a new tab, draw with Pen/Eraser/Bucket/Picker, and export clean sprite headers |
| Fonts | Parse and preview Adafruit GFX font files — glyph charmap + live text preview with colour picker |
| Font subsetting | Subset any loaded font to only the characters you need and download a ready-to-use .h file |
No setup needed — just open the live demo:
https://aschoelzhorn.github.io/spriteanvil
docker compose upThen open http://localhost:8080 in your browser.
The parser handles all common Arduino/ESP32 asset patterns without modification:
// 1. RGB565 colour array — named size companion (case-insensitive)
const unsigned short BLOCK[361] = { … };
const byte BLOCK_SIZE[2] = {19, 19};
// 2. PROGMEM + empty brackets
const uint16_t MARIO_IDLE [] PROGMEM = { … };
const byte MARIO_IDLE_SIZE[2] = {13, 16};
// 3. #define width/height macros (used by TFT_eSPI, OLED libraries)
#define logo_width 240
#define logo_height 240
static const uint16_t logo_bits [] PROGMEM = { … };
// 4. Monochrome 1-bit bitmaps (XBM / u8g2 / Adafruit OLED style)
// Bits are LSB-first, rows padded to byte boundary
#define icon_width 45
#define icon_height 45
static const unsigned char steam_bits [] PROGMEM = { 0x00, 0xf8, … };
// 5. 32-bit ARGB/ABGR/ARGB32 arrays (e.g. Piskel export, GIMP)
// Alpha=0 is treated as transparent; ABGR (Piskel) and ARGB are auto-converted to RGB565
const uint32_t mushroom2_data[361] = {
0xFF000000, 0xFF111111, 0x00000000, // ...
};
// 6. Named colour constants resolved automatically
const unsigned short M_RED = 0xF801;
const unsigned short TRANSPARENT = 0xFEFE;
// 7. 2-D frame animation array
const uint16_t _PACMAN_CONST [][25] PROGMEM = {
{ /* frame 0 */ … },
{ /* frame 1 */ … }
};The parser determines width × height using the first matching strategy:
_SIZEbyte array —const byte MY_SPRITE_SIZE[2] = {w, h};#definemacros —#define NAME_width W/#define NAME_height H, matched by prefix (longest first)- Square fallback —
sqrt(pixel_count)(a⚠️ warning is shown in the validation panel)
0xFEFE (or the symbol TRANSPARENT) is treated as transparent. For uint32_t ARGB arrays, alpha=0 is also treated as transparent.
Use the BG selector to choose how transparent pixels are displayed:
- Checkerboard — grey checker pattern (Photoshop-style)
- Solid color — fill with any colour (useful for sprites that are hard to see on a checker)
Use Open Sprite Editor in the top toolbar, or click Edit on any sprite card/frame to open the editor in a new tab with sprite data preloaded.
The editor is designed for quick pixel-level touchups and header generation:
- Tool bar above canvas with Pen, Eraser, Bucket Fill, and Picker
- Checkerboard transparency background aligned with the main app rendering (one checker cell per sprite pixel at active zoom)
- Transparent paint mode to paint
0xFEFEdirectly - Smart parser for pasted C arrays, including named constants,
TRANSPARENT, and_SIZE[2]dimensions - Export options: Generate/copy/download
.h, plus Save PNG (zoom) and Save PNG (1x) - Header visibility logic: generated header output stays hidden until generated and is auto-invalidated after edits
spriteanvil/
├── web/
│ ├── index.html # UI
│ ├── app.js # Parser, renderer, animation, export
│ ├── styles.css # Main app styles
│ ├── editor.html # Standalone sprite editor UI
│ ├── editor.js # Standalone editor logic (draw, parse, export)
│ └── editor.css # Standalone editor styles
├── Dockerfile # nginx:alpine serving web/
├── docker-compose.yml # Port 8080
└── examples/
├── mario_assets.h # LED panel: Mario sprites (named constants, PROGMEM)
├── pacman_assets.h # LED panel: Pacman animation (2-D frame array)
├── story_dune_assets.h # LED panel: Dune backgrounds (64×64, lowercase _size)
├── fonts/
│ ├── mario_Super_Mario_Bros__24pt7b.h # GFX font (Super Mario Bros)
│ └── pacman_hour_font.h # GFX font (Pacman hour digits)
├── icons/ # OLED 1-bit monochrome icon sets
│ ├── icon.h # Status bar icons (11×9, shared #define)
│ ├── icon_big.h
│ ├── icon_shared.h # Multi-define: rancilio/gaggia/ecm logos
│ ├── icon_simple.h
│ ├── icon_smiley.h
│ └── icon_winter.h
└── oled/ # Color OLED/TFT RGB565 images (TFT_eSPI style)
├── icon_ecm_color.h # 240×240 RGB565, #define macros
├── icon_gaggia_color.h # 216×131 RGB565
├── icon_generic_color.h # 240×240 RGB565
├── icon_rancilio_color.h
The tool also parses Adafruit GFX-compatible font headers. These are the GFXfont structs used by the Arduino GFX / Adafruit GFX library:
const uint8_t MyFontBitmaps[] PROGMEM = { … }; // packed 1-bit glyph bitmaps
const GFXglyph MyFontGlyphs[] PROGMEM = {
{ bitmapOffset, width, height, xAdvance, xOffset, yOffset },
…
};
const GFXfont MyFont PROGMEM = {
(uint8_t *)MyFontBitmaps,
(GFXglyph *)MyFontGlyphs,
0x20, 0x7E, // first, last codepoint
13 // yAdvance
};Once loaded, each font is shown in the Fonts tab with:
- A font metrics row — Leading (yAdvance), Baseline offset, and cell height
- A glyph charmap — every character baseline-aligned in uniform cells so digits and symbols sit on the same optical baseline
- A live text preview — type any string to see it rendered pixel-accurately
- A colour picker to change the glyph foreground colour
- A Subset & Export .h panel — pick characters to keep (quick-set buttons or free-type), set the C identifier name, and download a minimal
.hwith only the needed glyphs
SpriteAnvil is a viewer/exporter — it does not create or edit font glyphs. For that, use one of these dedicated editors:
| Editor | Notes |
|---|---|
| Adafruit GFX Font Customiser | Convert TTF/OTF to GFX font, adjust glyphs |
| gfxfont editor | Online glyph editor, import/export .h |
| gfx-fe | Feature-rich editor — Chromium-based browser only |
The Subset & Export .h panel (collapsed by default under each font card) lets you trim a font down to save flash memory on the microcontroller:
- Click a quick-set button (Digits, + colon, + date, Uppercase, Lowercase, Printable, Full font) or type any characters into the input
- The glyph count updates live — gaps in the codepoint range are kept as zero-size spacers (fully GFX-compatible)
- Set the C identifier name (default:
FontName_sub) - Click ⬇ Download .h — the file contains packed
Bitmaps[],Glyphs[], and theGFXfontstruct, ready to#include
assets.zip
├── assets.h # Root include (original source files)
├── <original_filename>.h # Original source file(s), unchanged
└── sprites/
├── block.h # Per-sprite header (preserves PROGMEM, type, SIZE)
├── block.png # PNG preview at current zoom
├── mario_idle.h
├── mario_idle.png
└── …
Split .h files preserve the original declaration style — uint16_t vs unsigned short, PROGMEM attribute, and the _SIZE companion array.
| Control | Description |
|---|---|
| Drag & drop / click dropzone | Load one or more .h files, or drop an entire folder — all .h files are collected recursively |
| Sprites / Fonts tab | Switch between the two views; tab labels show loaded counts |
| Sprites tab drop prompt | Prompted once — Add or Replace sprites; fonts in the same file always auto-replace same-named |
| Fonts tab drop | Same-named fonts auto-replaced; new fonts added; any sprites in the file are added silently |
| Paste + Parse button | Parse code pasted into the text area |
| Zoom slider (Sprites) | 1–64 px per pixel — independent from font zoom |
| Zoom slider (Fonts) | 1–64 px per pixel — independent from sprite zoom |
| Grid checkbox | Pixel grid overlay (auto-hidden below 4 px zoom) |
| Frames as strip checkbox | Show animation frames in one canvas or individually |
| BG selector (Sprites) | Checkerboard or solid colour for transparent sprite pixels |
| BG selector (Fonts) | Checkerboard or solid colour for font preview canvases |
| ▶ / ⏸ button | Play / pause animation per sprite group |
| FPS slider | Animation speed 1–30 fps per sprite group |
| Export ZIP | Download everything as a ZIP archive |
| PNG N× / PNG 1× buttons | Save a single sprite as PNG at current zoom (label updates live) or at native 1 px per sprite pixel |
| Hover over sprite canvas | Pixel inspector tooltip: coordinates, 0xRRRR hex, rgb(r,g,b) and colour swatch |
| FG / BG color pickers | Per 1-bit sprite: set foreground (bit=1) and background (bit=0) colours; Transp. BG checkbox makes background pixels transparent |
| Font colour picker | Change the glyph foreground colour for a loaded font |
| Font text input | Type preview text to render the font at current zoom |
| Subset & Export .h | Trim font to selected characters; download minimal .h file |
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request