Sprite Sheet Generator

Pack images into one sprite sheet with a JSON or CSS map. Every sprite keeps its own pixels.

Drag & drop files here, or

PNG JPG WebP GIF BMP AVIF Up to 256 images • Processed in browser • Nothing leaves your device

Runs in your browser

Original Size, Exact Rects

No sprite is scaled to fit. Each is drawn at its own pixel size, and the map gives the rect it sits in, so no frame shows a sliver of its neighbour.

Checked Before Download

The PNG is decoded again and every sprite is compared with its rect. The JSON is parsed back frame by frame. A mismatch stops the download with a message.

Privacy-First

Images are read and packed on your own device. Nothing is uploaded, nothing is stored, and no account is needed.

Advertisement

How it works

What a sprite sheet is for

A sprite sheet puts many small images into one file and records where each one sits. A game engine loads one texture instead of hundreds and swaps frames by moving a rectangle. A web page loads one request for all its icons and shows each one with CSS background-position. The picture is only half of it: the map of rectangles is what the engine or the stylesheet actually reads.

Why the rect has to be exact

If a frame rectangle is one pixel off, every frame shows a thin line of its neighbour, and scaling the sprite in the engine makes it worse. This page never scales a sprite to make it fit. Each is drawn at its own pixel size, the map is written from the same placements, and spacing keeps a clear gap so texture filtering does not blend edges together.

Compact, grid, row or column

Compact packs sprites into shelves, tallest first, for the smallest sheet; the sheet order changes but the map keeps every name. Grid gives equal cells the size of the largest sprite in your order, which is what Phaser load.spritesheet expects with frameWidth and frameHeight; smaller sprites are centred in their cell. Row and column keep your order in a single strip, handy for CSS hover pairs.

JSON hash, JSON array or CSS

The JSON files follow the TexturePacker layout: a frame rect, sourceSize, and a meta block with the sheet size. Hash keys frames by file name and is the form PixiJS reads; Phaser reads both hash and array, where array lists frames in order. Grid sheets also carry the cell size in meta.grid. CSS gives one .sprite rule and one class per sprite with its width, height and background-position. Every JSON map is parsed back and compared before it is downloaded.

Frequently Asked Questions

How do I make a sprite sheet from separate images?

Upload the images, pick a layout and spacing, and download the ZIP. It holds the PNG sheet, a JSON map in hash and array form and a CSS file. You can rename sprites and change their order before you download.

Does the tool resize my sprites?

No. Every sprite is drawn at its own pixel size, and the map gives the exact rectangle it occupies. If the sheet would be too large for a browser to export, the page says so and offers nothing to download rather than shrinking your art. One browser limit applies: a canvas stores colour premultiplied by alpha, so a partly transparent pixel can shift its colour by a few levels. Alpha is kept exactly, and fully opaque pixels are checked to match exactly before download.

Which JSON format should I choose for Phaser or PixiJS?

Choose JSON (hash) for PixiJS, which reads the frames object keyed by name. Phaser loads either hash or array as an atlas, PNG and JSON together. For a grid of equal animation frames you can instead load the PNG as a spritesheet with frameWidth and frameHeight, which the grid layout reports in meta.grid.

What does spacing do?

It leaves a transparent gap between sprites. When an engine scales or filters a texture, pixels next to a frame edge can bleed in; one or two pixels of spacing stops that. Spacing is never added around the outside of the sheet.

When do I need a power-of-two size?

Older WebGL 1 setups and some engines need textures such as 256, 512 or 1024 pixels on a side for mipmaps or wrapping. Tick the option and the sheet is enlarged with transparent space to the next power of two; the sprites and their rects do not move.

Why did a name change?

Two sprites cannot share a JSON key or a CSS class, so a duplicate gets -2, -3 and so on. CSS classes also keep only letters, digits, dashes and underscores. The report counts how many names were changed.

What happens with animated GIF or WebP files?

Only the first frame is used, the one the browser shows when it draws the image. To split an animation into frames first, use the GIF splitter, then pack the frames here.

Are my images uploaded?

No. The images are read and packed on a canvas in your own browser. There is no server call, no storage and no account, and closing the tab discards everything.