How to Make a Pixel Art Spritesheet
What a spritesheet is, how to lay out frames in a uniform grid, why registration and padding matter, power-of-two sizing, and how to export one for Unity or Godot.
A spritesheet packs many frames or sprites into one image. Instead of shipping forty separate PNGs for a walk cycle, you ship one sheet and tell the engine how to slice it. This guide covers how to lay one out cleanly so it imports without headaches.
What a spritesheet is, and why use one
A spritesheet (or sprite atlas) is a single image holding a grid of sprites. Each cell is one frame of an animation, or one item in a set. The engine reads the sheet, cuts it into regions, and plays or draws them.
The reasons to use one are practical:
- Fewer files to manage in your project.
- Faster rendering, because the GPU keeps one texture in memory instead of swapping between many.
- It is what engines expect. Unity, Godot, and most frameworks have a built-in importer for sheets.
Use a uniform cell size
The simplest and most reliable layout is a uniform grid: every frame sits in a box of exactly the same size. If your character is 32×32, every cell is 32×32, even when a particular frame does not fill it.
Uniform cells make slicing trivial. You tell the engine "the cell is 32×32" and it finds every frame automatically. The moment your cells vary in size, you are into manual atlas data, which is more work and more error-prone.
Register every frame to the same anchor
This is the detail beginners miss, and it is the one that causes jitter. Within each uniform cell, the character must sit at the same position relative to a fixed anchor, usually the feet or the center.
If the character's feet are on row 30 in one frame and row 28 in the next, it will bob up and down when the animation plays, even though each frame looks fine on its own. Pick a baseline, keep the feet glued to it, and let the arms and head move above it. Onion-skinning (seeing the previous frame faintly behind the current one) makes this easy to control.
Lay out animations in rows
A common, readable convention is one animation per row and one frame per column:
- Row 0: idle frames
- Row 1: walk frames
- Row 2: attack frames
Read left to right, top to bottom. It keeps the sheet human-readable and maps cleanly onto how engines index frames.
Mind padding and bleeding
When a sprite is scaled or filtered, the color from a neighboring cell can leak across the edge. This shows up as thin seams along your sprites. Two habits prevent it:
- Add a gutter of one or two transparent pixels between cells if you will scale the sheet or use anything other than nearest-neighbor sampling.
- Keep filtering set to nearest-neighbor (point) in your engine for pixel art, and disable mipmaps. This alone fixes most bleeding for integer-scaled sprites.
For strict pixel art rendered at integer scale with point sampling, you can often pack cells edge to edge with no gutter. Add padding when in doubt.
Power-of-two sizing
Older GPUs and some engines prefer texture dimensions that are powers of two (256, 512, 1024). It is less of a hard requirement than it used to be, but power-of-two sheets compress and mipmap predictably and never trigger a resize warning. If it is easy, size your final sheet to a power of two. If not, most modern engines handle non-power-of-two textures fine.
Trimmed atlases versus fixed grids
There are two philosophies:
- A fixed grid wastes some space (empty cells around small frames) but is dead simple to slice. Best for hand-authored animation.
- A trimmed, packed atlas crops each sprite tight and stores its offsets in a data file (JSON or similar). It saves texture space and suits large item sets, but needs a tool to generate and an importer that reads the data.
Start with a fixed grid. Reach for packed atlases only when texture size becomes a real problem.
Name and order frames sensibly
Keep frames in playback order in the sheet so the engine indexes them naturally. If you export per-animation sheets, name them clearly (hero_walk, hero_attack) so your import step stays obvious months later.
Export and import
When you export a sheet, note the cell size and the number of columns and rows, because that is exactly what the importer asks for.
- Unity: set the texture to Sprite (2D), Sprite Mode to Multiple, filter to Point, compression to None, then use the Sprite Editor's Grid by Cell Size slice with your cell dimensions.
- Godot: use an AnimatedSprite2D or a SpriteFrames resource, or a TileSet, and set the region or cell size to match.
Keeping the cell size uniform is what makes both of these a two-click operation.
Build one in Spritegen
Spritegen builds animation frames on a fixed grid, so every frame is already the same exact size with no blur. Animate by hand in the timeline with onion-skinning to keep your registration tight, or use a one-click motion preset to rough out frames, then export a spritesheet packed into one image. You can also export native formats for Aseprite, Unity, and Godot when you want the sheet to drop straight into a project.
A good first exercise: make a four-frame idle or a two-frame walk on a 32×32 canvas, export it as a sheet, and slice it in your engine. Once that loop works end to end, longer animations are just more frames.
Make it in Spritegen — free
Hand-draw on a real grid or generate sprites with AI. The editor and PNG export are free, with 10 AI credits a month.