Sprite Sheet Maker
Drop your frames in, pack them into a single sprite sheet, and download the sheet together with a coordinate file that gives every frame its exact position. It all runs on your own device — no upload, no sign-up, and you can watch the animation play before you save anything.
- 1 Drop your frames
- 2 Pick a layout
- 3 Download sheet + coordinates
Drop your frames here
or · PNG, JPG/JPEG, WebP or GIF
How to use this sprite sheet maker
1 · Add your frames in the order they should play
Drop every frame in at once, or add them in a few batches — they stay in the order you added them, and that order is what the animation preview plays and what the coordinate file lists.
2 · Choose how they are laid out
Auto grid makes the sheet roughly square. Fixed columns is what you want for a walk cycle with a known number of frames per row. One row gives a horizontal strip and One column a vertical one. Spacing adds a gap around every frame so scaling does not bleed pixels from the neighbour.
3 · Export the sheet and the coordinates together
The PNG is the packed image. The JSON gives every frame its x, y, width and height plus the original source size, so engines that expect a TexturePacker-style atlas can read it. The CSS file gives you one class per frame and a ready-made @keyframes block that steps through them.
Pack images into a texture atlas in your browser
Same job as a desktop texture packer, none of the install
A texture packer takes a folder of separate sprites and writes out one atlas image plus a data file describing where each sprite landed. That is exactly what this page does, except it happens in a browser tab: your files never leave the machine, there is no licence key and no trial window.
Watch it move before you download
Three packers that offer a CSS export — spritesheetmaker.com, toolbuddy.io and finalparsec — each handed me a stylesheet with one class per frame and a background-position, and nothing that animates: 0 @keyframes, 0 animation declarations and 0 steps( across all three files. Playback is yours to write, and frame order is the one thing a static file cannot show you. The preview above plays the sheet back at the speed you pick, so a swapped or upside-down frame shows up immediately instead of after you have wired it into a project.
Going the other way
Already have a sheet and need the single images back? Split a sprite sheet into single images →
How big will the sheet be? The size rule this tool actually uses
The sheet size is not a preset and not a guess: it follows from four things you control — the widest frame, the tallest frame, the spacing and the layout. The rule below is the one in this page's own code, and every number after it came out of the tool and was read back from the downloaded PNG and JSON.
The formula
- Cell size — one cell is as wide as the widest frame and as tall as the tallest frame. Each frame is centred inside its cell, so a 64×64 frame and a 48×72 frame share a cell of 64×72.
- Columns — Auto grid:
ceil(sqrt(frames)); One row: the frame count; One column: 1; Fixed columns: the number you type. - Rows —
ceil(frames / columns). - Sheet width —
columns × cellW + (columns + 1) × spacing. - Sheet height —
rows × cellH + (rows + 1) × spacing.
The + 1 is why spacing can look doubled: you get one gap between each pair of cells plus one gap at each outer edge. With spacing 0 the outer gap disappears.
Measured: twelve 64×64 frames
Twelve frames, Auto grid, no trimming. Each row was exported with the download buttons and then read back from the files themselves, so the PNG column is the actual file size, not a prediction.
| Settings | Columns × rows | Sheet | PNG file | JSON meta |
|---|---|---|---|---|
| Spacing 0 | 4 × 3 | 256 × 192 | 256 × 192 | 256 × 192 · padding 0 · 4 columns · 3 rows |
| Spacing 2 | 4 × 3 | 266 × 200 | 266 × 200 | 266 × 200 · padding 2 · 4 columns · 3 rows |
| Spacing 2 + power of two | 4 × 3 | 512 × 256 | 512 × 256 | 512 × 256 · padding 2 · 4 columns · 3 rows |
Check the middle row by hand: 4 × 64 + 5 × 2 = 266 wide and 3 × 64 + 4 × 2 = 200 tall. The first frame sits at x = 2, y = 2, and the JSON gives it "frame":{"x":2,"y":2,"w":64,"h":64} — the same pixel you land on in the PNG.
Max width caps columns, and only in Auto grid
The control is narrower than it sounds. It computes floor((maxWidth − spacing) / (cellW + spacing)) and uses that as the column count when it is smaller than the automatic one. Height is never capped, and the other three layouts ignore it completely. Twelve 256×256 frames with spacing 2:
| Layout | Max width | Result | What it shows |
|---|---|---|---|
| Auto grid | 1024 | 3 × 4, 776 × 1034 | The cap binds: 3 columns instead of 4, and the height still passes 1024 |
| Fixed columns, 6 | 1024 | 6 × 2, 1550 × 518 | Ignored: the sheet ends up wider than the limit |
| One row | 1024 | 12 × 1, 3098 × 260 | Ignored: every frame stays on one row |
Read it as a column cap for Auto grid, not as a guaranteed canvas limit. When you need a hard maximum, switch to Fixed columns and work out the width from the formula before exporting.
Power of two grows the canvas, it does not resize the sprites
With Round sheet to power of two on, the final width and height are each rounded up to the next power of two — 266 becomes 512 and 200 becomes 256. The frames are not scaled, resampled or stretched: every frame keeps its own pixel size and its JSON rectangle, and the extra area stays transparent. That is why the same twelve frames can produce a 512×256 file with a wide empty margin on the right and bottom.
Two things worth planning for: that empty area is real texture memory in your engine, and a padded sheet no longer matches a hand-written background-size unless you update it to the padded size.
One sheet per export
Each download is a single atlas. The tool does not split a large pack into several pages on its own, and it does not pick a texture size for your engine. If your project has a texture limit — 2048 or 4096 because that is what your target hardware or engine profile allows — treat that number as your own constraint and plan the grid around it:
- Pack fewer frames per sheet and export in batches, keeping the frame order in the JSON.
- Use Fixed columns so the width is predictable instead of automatic.
- Trim transparent edges, which shrinks the cell size and with it the whole sheet.
Those limits differ between engines, devices and renderers, so check your own target instead of assuming one number applies everywhere.
Questions
Is this a TexturePacker alternative?
It covers the everyday job — pack sprites, get an atlas and a coordinate file. It does not try to match a full desktop texture packer: there is no polygon packing, no per-platform preset bundles and no command line. If you need those, use a desktop packer. If you need an atlas right now, this page is faster.
Are my images uploaded anywhere?
No. Every step — reading the files, measuring transparency, drawing the sheet, playing the preview — happens in your browser with JavaScript. Nothing is sent to a server, and there is no account to sign in to.
What is in the coordinate file?
For each frame: the filename, the rectangle it occupies on the sheet (x, y, width, height), the original source size, and the offset used when trimming is on. The sheet size, column count, row count and spacing are recorded under meta.
Why are my frames all the same cell size?
Every frame sits inside a cell as wide as the widest frame and as tall as the tallest one, centred. Uniform cells mean an engine can find frame n with simple arithmetic instead of reading every rectangle. Turn on Trim transparent edges to measure only the visible pixels of each frame.
Will transparency be kept?
Yes. The sheet is drawn on a transparent canvas and exported as PNG, so alpha is preserved. The checkerboard behind the preview is just there so you can see which areas are empty.
Does Max width apply to Fixed columns or One row?
No. Max width only affects Auto grid, and even there it caps the column count, never the height. Fixed columns, One row and One column build the grid from the layout you chose and ignore the control, so the finished sheet can be wider than the number in the field.
Does power of two resize my sprites?
No. It rounds the final canvas width and height up to the next power of two and leaves every frame at its original pixel size, with the extra area transparent. The coordinate file reports the padded sheet size, so use that size for background-size and for your engine's texture settings.
How do I use the CSS file?
Give an element both cmi-sheet and cmi-anim, keep sprite-sheet.png next to the CSS, and it steps through the frames once per second. Change animation-duration to speed it up or slow it down; the per-frame classes let you show a single frame instead.