Nine sheets, eighteen animations
How Pew's sprites went from generated sheets to one tidy atlas in Godot, and why the run cycle took seven tries.
Listen to this post
Read in Dodz's voice, cloned with AI

A character sheet is not a character. To move, Pew needed frames: standing, running, jumping, shooting, aiming, dashing, getting hurt. This post is about how those frames were made and how they became something Godot can play.
One animation at a time
Each animation started as a sheet generated with a sprite preset, saved like every image as pew_<state>_vNNN.png. Two things made a huge difference in the prompts:
- Describing the pose of every frame. "Frame 3: right foot forward, arms back" instead of "a run cycle". Without it, sheets come back with repeated frames.
- Saying which hand holds the gun. Pew is right-handed: facing right, the blaster is in the hand of the arm closer to the camera. Without that line, the gun switches hands mid-animation. When Pew faces left, the game just mirrors the sprite.
Then came review. Every animation was turned into a GIF and approved on its own before moving on. The run cycle was the stubborn one: the approved sheet is pew_run_v007. Six runs before it didn't make the cut.

Nine sheets that don't agree
In the end there were nine approved sheets: idle, run, jump, shoot, run-and-shoot, aim, dash, hurt and death.

They don't agree on Pew's size. Each sheet was generated on its own, so in one Pew is a bit bigger and in another a bit smaller. Put them in a game as they are, and Pew grows and shrinks every time he changes animation.
Measuring heads
The fix is a script, build_pew_spriteframes.py. For every frame, it finds the largest blob of green skin, which is always Pew's head, and measures its width. It takes the median for each animation and rescales the whole animation so the head is the same width everywhere.
Then it puts every frame into a grid of identical cells, with the feet at the same point in every cell. That point becomes the sprite's origin in Godot, so switching from a run frame to a jump frame never makes Pew hop sideways.
Out come three files: the atlas image, a Godot SpriteFrames resource and a small JSON with the cell size and the feet position. Nine sheets turn into eighteen animations, because some sheets hold several: the aim sheet alone gives six poses (five aim directions plus crouching), and the jump sheet is split into start, rise, apex, fall and landing.
All of them, live
This website uses the same atlas, exported to WebP. These are the eighteen animations, playing right here:
idle6f · 8 fps · looprun8f · 12 fps · looprun_shoot8f · 12 fps · loopjump_start2f · 14 fpsjump_rise1f · 1 fpsjump_apex1f · 1 fpsjump_fall1f · 1 fpsland1f · 12 fpsshoot4f · 14 fpsaim_up1f · 1 fpsaim_diag_up1f · 1 fpsaim_forward1f · 1 fpsaim_diag_down1f · 1 fpsaim_down1f · 1 fpscrouch_shoot1f · 1 fpsdash4f · 16 fpshurt3f · 12 fpsdeath6f · 10 fps
The game has a preview scene that does the same thing: every animation side by side, so I can spot a bad frame before it ships.
With a Pew that can animate, the next job was making him feel good to control: making a tiny alien feel good.
