Aseprite is where sprite animation is actually authored: frames on a timeline, grouped into named tags (walk, idle, hurt), each with a playback direction and a per-frame duration in milliseconds. That timeline is real design work — and until now none of it survived the trip to the SNES. gfx4snes turns a spritesheet into tiles and, with -P, into metasprite geometry, but it has no concept of a tag or a duration. So the animation was retyped by hand into DECLARE_ANIM_CLIP() calls, one frame at a time — the single most tedious, error-prone step left in the sprite pipeline.
aseprite2snes closes that gap. It reads the JSON Aseprite writes with --data --list-tags and emits a C header of ready-to-use AnimClip tables for the anim.h player — one clip per tag, frame indices and per-frame tick durations included, playback direction folded into the frame order, looping vs one-shot derived from the tag.
aseprite2snes is the animation half of a two-tool sprite step, paired with gfx4snes -P:
gfx4snes owns the pixels and the metasprite table; aseprite2snes owns the timeline that indexes it. The two outputs meet at the frame value: a clip's frame i selects metasprite i.
The full three-step pipeline for one animated sprite:
Given tags walk (per-frame timing), idle (uniform) and hurt (ping-pong, play once), you get an AnimClip per tag plus an index enum and a pointer table over all clips:
A uniform-duration clip uses the AnimClip.speed field with a NULL duration array; a clip whose frames differ in length carries a parallel durations[]. Include the header after <snes.h> — it needs AnimClip, ANIM_LOOP and ANIM_ONCE from anim.h.
Drive it by state, indexing the pointer table:
| Aseprite | Becomes | Notes |
|---|---|---|
| a tag name | one AnimClip <prefix>_<name> | plus an <PREFIX>_ANIM_<NAME> enum index |
| from…to | the clip's frames[] | values are metasprite indices; -t multiplies |
| per-frame duration (ms) | durations[] in ticks | converted at -f fps, clamped to 1…255 |
| uniform durations | AnimClip.speed, NULL durations | collapses the array automatically |
| direction | frame order | forward, reverse, pingpong, pingpong_reverse |
| repeat = 1 | ANIM_ONCE | 0 / absent / >1 → ANIM_LOOP |
pingpong runs out and back without repeating either endpoint. With no --list-tags metadata the tool emits a single clip named all over every frame and warns. Tag and prefix names are sanitised to C identifiers.
v1 is the animation layer only; it never touches image data. Decomposing frames into metasprites, laying out tiles and computing OAM tile numbers are owned by gfx4snes -P — see gfx4snes — images to tiles, palettes & maps. An out-of-range tag range, missing frames, or malformed JSON is a hard error with a non-zero exit.