This guide is grounded in Vibe Fighter, a Phaser 4 versus fighter (TypeScript + Vite) with best-of-three rounds, meter-charged specials and multi-hit supers — and a three-fighter roster where every frame of art is Spriterrific-generated.
A fighter is a move set, not a character portrait
Fighting games are the stress test for AI sprite generation: one character needs a dozen-plus animations that all read as the same person, share one frame grid, and land their strikes where hitboxes expect them. Each Vibe Fighter character carries idle, walk-forward, walk-backward, crouch, jump, block-high, block-low, hit-high, light and heavy attacks, knockdown, and a two-part special — all derived from a single approved character anchor:





The workflow that keeps this coherent is anchor-gated: generate the character anchor first, approve it, and only then fan out the move set as action jobs against that anchor. Getting the anchor right is a 30-credit decision; getting it wrong after generating twelve moves is not.
Special moves are custom actions
There is no "uppercut" preset. Specials are custom actions: you give the move your own name, point actionBaselines at the closest standard motion, and steer it with a one-line actionContext. The red brawler's meter special — a rising spin the game calls Cyclone Uppercut — rides the attack baseline; its charge-up pose rides crouch. The jiu-jitsu fighter's Spinarooni works the same way:


The custom name flows through to every artifact path, so special.png and attack.png never collide. Here's the Cyclone Uppercut's full 12-frame sheet on the standard 5-column grid — longer moves simply leave trailing cells empty, and your animation config plays frames, not grid cells:

One facing, two players, mirrored hitboxes
All Vibe Fighter art is generated facing west and mirrored at runtime — the right-side player is setFlipX(true). What makes that safe for a fighting game is that the frame grid is fixed: hit, hurt and block boxes are authored per frame against the 256×256 cell (in a dedicated "character gym" scene), and mirroring is pure arithmetic:
/** Mirror a per-frame box when the fighter faces east. */
const mirrorX = (box: Box, flipX: boolean): number =>
flipX ? FRAME_WIDTH - (box.x + box.width) : box.x;
Every sheet shares the same foot anchor (bottom-center, pixel 128×255), so a setOrigin(0.5, ~1) sprite stays planted through crouches, jumps and knockdowns. The Phaser loading pattern is identical to the one in the Phaser sprite generator guide.
Scaling to a roster
Consistency across a roster comes from the same anchor-first discipline, repeated. Each fighter started from its own concept reference image, generated with a style-preserving anchor pass, then ran the same move-set recipe:



Two practical lessons from the project's run records: describe motion as a contract, not choreography — a start pose, the verb, and an end pose beat a shot-by-shot description, especially for knockdowns — and when a single frame drifts off-model, skip it in your frame spans or re-cut the sheet with the free frame picker instead of regenerating the move.
Cost for a fighter
A character job (anchor + first two animations) is 290 credits from a prompt; every further move is a 100-credit action job. That prices a minimal fighter (idle, both walks, one attack, hit, knockdown) around 700 credits and a full 13-move roster character around 1,400 — with failed steps refunding automatically. New accounts start with 500 free credits, and the $12/month Starter plan's 1,500 monthly credits cover roughly one full fighter a month (pricing).