GIF to Sprite Sheet
A sprite sheet is only useful if the rectangles are right, and that is where most GIF converters quietly go wrong: a GIF frame is usually just the rectangle that changed since the last one, so packing those patches straight onto a sheet leaves cells that hold half a picture. This tool decodes the file in this browser tab, composites every frame in order with its transparency and disposal rules applied, and lays the whole frames out at their own size with no rescaling. You choose how many frames go across, how much padding sits between the cells and what colour is underneath, and the sheet appears as a PNG beside the original. Next to it you get the frame rectangles as JSON, each with the x, y, width, height and the delay the file itself holds, and the CSS to play the sheet back with one keyframe a frame, so uneven delays are followed rather than averaged. Nothing is uploaded and there is no account.
Drop a GIF here, or choose one below.
Every frame is decoded, composited and laid out on one sheet in this tab.
· or drop one anywhere on the stage
No GIF open yet. Choose one, or drop it on the stage.
Padding is a gutter between cells, so the step from one frame to the next is the frame size plus the padding and there is no margin around the outside. One row is the layout a CSS background position animation wants; Square keeps a long animation inside the ceilings, which are 600 frames, 16384 pixels on a side because that is where a browser canvas stops drawing, and 40 million pixels for the whole sheet, because it is held in the memory of this tab while it is written.
Common questions
- How do I turn a GIF into a sprite sheet?
- Open the GIF, choose how many frames go across, and the sheet is drawn here. The tool reads every frame, composites it onto a running canvas so the cell holds the whole picture rather than the patch that changed, and packs the frames left to right and top to bottom in the order the file holds them. Download the PNG, and take the JSON rectangles or the CSS from the rows underneath. The first screen opens with every frame in one row, which is the layout a CSS background position animation expects.
- How many columns should the sheet have?
- One row is the simplest to animate: the background position moves by one step each frame along a single axis, and most engines and CSS examples assume it. Square is there for long animations, because a 200 frame GIF in one row is thousands of pixels wide and a browser canvas stops drawing past about 16384 pixels on a side. You can also type any number of columns from 1 up to the frame count, and the sheet, the step and the rectangles all follow it.
- What is in the JSON, and can I trust the rectangles?
- The JSON names the image file, the sheet size, the columns, rows, padding and background, the cell size and the step across and down, the total duration, what the GIF's own loop block says, and then every frame in order with its index, x, y, width, height and delay in milliseconds. The rectangles are the ones the sheet was drawn from rather than a description written beside it, so cutting the PNG at those coordinates gives back each frame byte for byte. That is checked in this tool's tests by cutting a drawn sheet back up and comparing it to the frames it was built from.
- How do I animate the sheet with CSS?
- Copy the CSS row. It sets an element to the frame size, points background-image at the sheet and adds one keyframe per frame at that frame's own share of the run, with steps(1) so each position holds until the next one instead of sliding. That is what a GIF player does, so a GIF whose frames have different delays plays back with those differences intact. Where a GIF reports no delays at all, the CSS says so in a comment and runs at 100ms a frame rather than dividing the timeline by zero. A GIF with a single frame gets a background position instead, because there is nothing to play.
- Where does the padding go?
- Between the cells, and nowhere else. There is no margin around the outside, so the first frame sits at 0, 0 and the step from one frame to the next is the frame size plus the padding, the same for every column and row. That is what keeps one step true across the whole sheet, which is what a background position animation and most engine importers need. Padding is useful when a renderer samples slightly outside a cell and drags a neighbouring frame's pixels in, and this tool takes 0 to 256 pixels of it.
- Are the frames resized, cropped or re-coloured?
- No. Each cell is exactly the GIF's own canvas size, and the pixels are copied into it rather than scaled, so a 64 by 64 GIF gives 64 by 64 cells. The sheet is a PNG, which holds full colour and real transparency, so the GIF's palette is not squeezed again and a transparent GIF stays transparent. Choosing a background colour instead fills the sheet with it and draws the frames over the top, which is what you want when the target cannot handle transparency.
- Is my GIF uploaded anywhere?
- No. The file is read by a JavaScript GIF decoder running in this tab, packed by this page's own code, and drawn to a canvas here. There is no upload, no queue, no account and no request of any kind: no byte of the animation leaves this browser. The only thing kept between visits is the layout, the column count, the padding and the background you chose, stored in this browser, and the Start over button on this page forgets them.
- What are the limits, and why does a local tool have any?
- 600 frames, 25 million pixels in a single source frame, 16384 pixels on a side for the sheet and 40 million pixels for the whole sheet. The side is the browser's own canvas limit rather than ours, and the rest is memory: every frame is unpacked to full size in this tab and then held again on the sheet, four bytes a pixel, so past that point a phone stops responding instead of finishing. A layout over a limit is refused with the number it actually reached, and with the squarer layout that would fit when there is one, and a long run has a Cancel button that really stops it.
Every frame is drawn onto the sheet at its own size with no rescaling, and the CSS given uses exactly the step and frame count on screen. A GIF stores each delay in hundredths of a second, so the timings in the JSON are the file's own numbers and a browser can round the shortest ones when it plays them. Nothing is uploaded.