GIF to sprite sheet
Drop a GIF, an animated WebP or a short video and get one PNG with every frame on a grid, plus the numbers your engine asks for.
Loading
Your files stay on your device. Videos are read at up to 1024 px on the long side.
What the usual converters leave you to work out.
The numbers to type in
Under the controls you get the cell size for Unity’s Grid By Cell Size, the Hframes and Vframes for Godot, and the frame rate. Those are the three things an engine asks for and a bare PNG doesn’t tell you.
Frames come out whole
Optimised GIFs store only the pixels that changed in each frame. This tool rebuilds every frame the way a player would, including the three disposal modes, so you don’t get the half-drawn cells that simpler converters produce. Checked pixel for pixel against ImageMagick.
A VRChat emoji preset
One switch gives you the 1024×1024 sheet VRChat wants: a 2×2, 4×4 or 8×8 grid picked from your frame count, long GIFs thinned evenly to 64 frames, non-square art fitted without stretching, and a file name that carries the frame count and speed.
Files engines read directly
Besides the PNG you can take a Godot 4 SpriteFrames resource, a Sparrow XML for Friday Night Funkin’, a JSON atlas for Phaser and PixiJS, a CSS animation, or a ZIP of the separate frames.
From GIF to sheet in three moves.
- 1
Drop your GIF, animated WebP, animated PNG, MP4 or WebM on the dark panel, or press Upload. The sheet is drawn straight away.
- 2
Trim the frame range, keep every 2nd or 3rd frame if the sheet is too big, and pick a layout: grid, one row, one column or your own column count.
- 3
Press Download PNG. If your engine wants more than a picture, take the JSON atlas, Godot .tres or Sparrow XML next to it.
What a sprite sheet is, and why engines want one
A GIF is a file that plays itself. A sprite sheet is a still picture: every frame of the animation laid out in a grid, left to right and top to bottom, and it is up to the engine to show one cell at a time. That sounds like a step backwards until you try to use a GIF in a game. Unity and Godot don’t import an animated GIF as an animation, GIF is limited to 256 colours per frame, and its transparency is on or off with nothing in between. A PNG sheet has none of those limits, and it is one texture, which is what a graphics card wants.
So the job of this page is small and specific: take the frames out of a GIF, put them on a grid, and tell you the grid’s measurements.
Choosing a layout
Grid is the default and packs the frames into the squarest sheet it can. It’s the right choice when you don’t have a reason to pick another, because square textures waste the least memory.
Row puts every frame on one line. Pick it for CSS animations, where a single steps() rule can walk along the strip, and for GameMaker’s strip import. It stops being practical somewhere past twenty or thirty frames, when the strip gets wider than a texture is allowed to be.
Column is the same idea turned on its side, and Custom lets you set the column count yourself. Use it when a tutorial or an engine preset expects a particular grid, 4 columns for a four-direction walk cycle for instance.
Frames: how many you actually need
A GIF recorded from a screen or exported from a video often has 60 or more frames, and most of them are nearly identical. A sheet that carries all of them is large for no visible gain. Two controls deal with that. The range slider cuts off the start and end, which is how you isolate one move from a longer clip. “Keep every Nth frame” thins what’s left, and it hands each dropped frame’s time to the frame before it, so the animation runs at the same speed with fewer cells.
For hand-drawn pixel art I’d leave every frame in. Those animations are usually 4 to 12 frames, each one drawn on purpose, and dropping any of them shows.
Spacing, margin and trimming
Spacing adds empty pixels between cells and Margin adds them around the whole sheet. Leave both at zero unless you’ve seen thin lines of the neighbouring frame at the edge of your sprite in the game. That bleeding happens when a texture is filtered or scaled, and a gap of 1 or 2 px is the standard cure. If you add spacing, remember to give the same number to the engine: Unity calls it Padding, and the readout under the controls includes it.
Trim empty edges crops away transparent border that every frame shares. It uses one crop for all frames, so the character doesn’t shift from cell to cell, which is what goes wrong when each frame is cropped to its own contents.
Using the sheet in your engine
Unity
Select the PNG, set Texture Type to Sprite (2D and UI) and Sprite Mode to Multiple, then open the Sprite Editor and choose Slice → Grid By Cell Size. Type the cell width and height shown on this page and press Slice, then Apply. For pixel art also set Filter Mode to Point (no filter) and Compression to None, or the sprites come out soft. A particle system uses the same sheet through its Texture Sheet Animation module, where the column and row counts go into Tiles X and Y.
Godot 4
The quick way: add a Sprite2D, give it the PNG, and under Animation set Hframes and Vframes to the column and row counts. The frame property then picks the cell. For an AnimatedSprite2D, open its SpriteFrames, choose Add frames from a Sprite Sheet and enter the same two counts. Or download the Godot .tres from this page: it is a SpriteFrames resource that already lists every cell and each frame’s duration. It expects the PNG at the top of your project (res://); if you keep art in a folder, open the .tres in a text editor and change the one path line.
Phaser and PixiJS
// One PNG, cut by frame size
this.load.spritesheet("slime", "slime-sheet.png", { frameWidth: 32, frameHeight: 32 });
// Or the PNG with the JSON atlas from this page
this.load.atlas("slime", "slime-sheet.png", "slime-sheet.json");VRChat
VRChat’s animated emoji are sprite sheets with fixed rules: the image is 1024×1024, the frames are square, and the grid is 2×2 for up to 4 frames, 4×4 for up to 16, or 8×8 for up to 64. Frames read left to right, then top to bottom, and unused cells are ignored. A file named like Wave_14frames_20fps.png fills in the frame count and speed for you on upload. Switch Made for to VRChat emoji and the tool does all of that. You still need VRC+ to upload, and “Enable Sprite Sheet Mode” has to be ticked on the upload page.
When the result looks wrong
The frames look blurry in the game. The sheet is fine; the engine is smoothing it. Turn off texture filtering (Point in Unity, Nearest in Godot) and don’t scale the sheet here by anything except whole numbers above 100%.
Slicing gives the wrong number of sprites. The cell size typed into the engine doesn’t match. Read it again from the panel under the controls, and include spacing and margin if you set them.
There’s a coloured box behind every frame. The GIF had a solid background and GIFs can’t tell you which colour was meant to be see-through. Convert the sheet, then open it in the sprite sheet cutter, which can remove a background colour.
The animation plays too fast or too slow. Set the engine’s speed to the fps shown here. GIF timing is stored in hundredths of a second and browsers play anything set to 10 ms or less at 100 ms, so a GIF that claims 100 fps really plays at 10; the number on this page is the one you see on screen.
Going the other way, from a sheet back to an animation you can post or preview, is the sprite sheet to GIF page. If your frames are separate image files and not a GIF, use the sprite sheet maker.
Questions
Something else? Email hello@giftospritesheet.com.