TLDR: To get consistent 12-stage pixel-art progression, chain each stage's init_image from the previous output. Tune init_image_strength by zone — ~335 to hold the character steady, ~300 to let it drift gradually forward.

the setup

I'm building a gym tracker PWA — a simple Progressive Web App (a mobile website that installs like a native app) with a dumb-fun twist.

Your workout avatar starts scrawny. Gets jacked. Twelve stages, Level 1 to Level 12.

Same red hair, same blue gym shorts throughout. Just progressively more built.

what I tried first

I wrote a parametric code-drawn sprite generator. It worked.

He looked like a rectangle that had been to the gym.

Then I found PixelLab (pixellab.ai, an AI pixel-art generator). First generation… the difference was immediately obvious. The commit message says it plainly: feat(sprites): replace code-drawn dad with PixelLab AI sprite set.

Moved on and never looked back.

the real wall

One good sprite is easy. Twelve that look like the same character — showing a believable, progressive body transformation? That's the actual problem.

Two things broke on me.

The model always adds abs. (This one was maddening.) I wanted the dad genuinely scrawny at Level 1. No muscle whatsoever. But PixelLab defaults to fit. Even with heavy negative prompts — "muscular, abs, six-pack, wide shoulders" — the result kept coming back with a six-pack. The model has strong priors about what a shirtless guy looks like.

Generating each stage independently → character drift. Twelve separate text-to-image calls, and by Level 12 he barely looked like Level 1's brother. Slightly different hair, different proportions, subtle pose shifts. Not a progression. Just twelve different guys.

So what worked?

the fix that worked — the cumulative chain

Each stage's init_image is the previous stage's output. So:

  • Generate the skinny anchor (L1)
  • L2 uses L1 as its starting image
  • L3 uses L2's output
  • …all the way to L12

That one structural change bought MASSIVE consistency.

The strength parameter is where you fine-tune. PixelLab's init_image_strength goes 1–999. Higher = more locked to the prior frame. Two zones I found:

  • L1–5 (stay skinny, no muscle creep): strength ~335. High continuity — barely deviates from the input.
  • L6–12 (ramp to jacked): strength ~300, with progressively more muscular prompts ("slightly toned""lean athlete""muscular""very muscular jacked").

For the skinny anchor itself — genuinely the hardest part — I img2img'd (image-to-image, using an existing image as the starting point) the fit reference sprite downward at strength ~180–240, flipping the prompt hard: "skinny scrawny lanky young man, soft flat stomach no muscle, narrow shoulders, thin arms". Iterated 2–3 strength values, kept the skinniest that still held the red hair and gym shorts.

Sprites are 96×144 px, no_background: true, endpoint generate-image-bitforge. Each generation is inexpensive.

the mistake hiding in the repo

While fixing the early stages, I ran the old code-drawn generator — sprites/gen_sprites.py, the script PixelLab had literally replaced — because it was sitting right there in the tree.

Clobbered every AI sprite with procedural art. PNGs dropped 7KB → 1.5KB.

The reaction: "This looks horrible, you dropped the API generated sprites and did what?"

Recovery: git checkout 9a560a7 -- sprites/. Then regenerated correctly.

A generator script in your repo is a hypothesis, not the source of truth. One git log -- sprites/ before touching anything would have caught it. The commit history said in plain English that gen_sprites.py was the old tool PixelLab replaced. I just didn't look.

why this matters to me

The chain technique genuinely solves consistent progression. I'd reach for it any time you want gradual, controlled transformation of the same character across a sequence — not just pixel art.

Here's the honest close, though: even after regenerating all 12 stages correctly, the quality still wasn't quite there. I looked at the sprites and called them "so bad" — and we're now seriously looking at commissioning a real pixel artist to draw the exact concept by hand.

The technique is sound. The output ceiling of AI pixel art for a bespoke concept like this may still fall short of what a human delivers. Know that going in. The chain won't save you if the quality bar is above what the model can hit.

But if AI sprites are good enough for your project? Chain the stages, tune the strength, and make your negative prompt for the skinny anchor unusually aggressive. That's what actually works.