Skip to main content

Sprite Sheet Splitter and Joiner

Two halves of the same job on one page. Give it a sheet and say how it is laid out — either the grid it uses or the size of one frame — and every cell comes back as a numbered file in a zip, with a red grid drawn over your sheet first so you can see the alignment is right before you commit. Or hand it loose frames and it packs them onto one sheet on a uniform grid with the padding you ask for. Both directions run on decoded bitmaps inside this page; nothing is uploaded.

Drop a sprite sheet

One file, up to 50.0 MB. Say how it is laid out and every frame is cut here in the browser, then zipped locally.

Frames

Nothing loaded yet. Drop a sheet above — up to 400 frames are cut from it inside this browser tab and handed back as one zip, numbered in animation order.

Animate it once it is cut

Frames are one way to animate. Moda animates real vector artwork on a timeline instead.

Try Moda free →

Why splitting and joining are one page and not two

They are the same grid arithmetic read in opposite directions, over the same four numbers — columns, rows, margin, spacing — with the same caps and the same failure modes. Anything true of one is true of the other: that a cell size has to be uniform, that a padded sheet has to have its padding subtracted before the division, that PNG is the only sane output because sprites have transparency. Two pages here would have carried the same explanation twice under different headings, and they would have split the audience that arrives needing to do both — re-cut a sheet, drop a frame, pack it back up.

Grid or frame size — pick the one you actually know

People arrive knowing exactly one of these. If the sheet came from an asset pack the readme usually says "8 columns, 4 rows"; if it came out of an animation tool it usually says "64×64 frames". Splitting by grid divides the sheet by the counts, which is exact and cannot leave a remainder. Splitting by frame size fits as many whole frames as it can and ignores whatever is left over at the far edge, which is what you want when a sheet has a stray dimension. The red overlay is the check: if the boxes do not sit on the sprites, the numbers are wrong, and you can see that before you download 64 files.

Margin and spacing are not the same thing, and both matter

Margin is the blank border around the whole sheet; spacing is the gutter between adjacent frames. Sheets from texture packers usually have both, because a gutter stops a GPU sampling a neighbouring frame’s pixels along a shared edge — the classic "bleeding" artefact where a sprite has a thin line of the frame next to it down one side. Getting these wrong is the most common reason a split looks almost right, with every frame offset by a pixel or two more than the last. If your frames drift progressively across the sheet, the spacing is what you are missing.

One cell size, and why the packing is deliberately dumb

The joiner puts everything on a uniform grid: the cell is the size of the largest frame, and smaller frames are centred in their cell rather than stretched. This is not the tightest possible packing, and that is the point — a sprite runtime finds frame N by multiplying an index by a fixed cell size, so a grid is directly usable while a tightly packed atlas is not usable at all without the JSON map that says where everything went. If you need atlas packing, you need a packer that emits that map. If you need a sheet an engine or a CSS `background-position` can walk through, this is the layout that works.

Frequently asked questions

Are my images uploaded?

No. The sheet or the frames are decoded into bitmaps in this page, cut or packed on a canvas here, and encoded here. The zip is assembled in the browser too, which is why the frames come back as one archive: browsers block a page that tries to start sixty-four separate downloads.

What order are the frames in?

Left to right, then top to bottom, which is how essentially every sprite sheet is read. Filenames carry a zero-padded index, so sorting the folder by name gives you animation order rather than putting frame 10 immediately after frame 1. In the other direction, frames are laid onto the sheet in the order you added them — so if the order matters, name them so your file picker hands them over sorted.

Why is there a limit on the number of frames?

Splitting is capped at 400 frames and joining at 120. Each split frame is its own canvas, encode, and zip entry, and each joined frame is a separate file to decode, so the work is linear in the count — a sheet with a mistyped frame size can describe a million frames and would never finish. The plan refuses up front and names the number rather than starting something that cannot end.

Should I save frames as PNG or JPG?

PNG, unless you are certain there is no transparency anywhere on the sheet. Sprites are almost always cut out against a transparent background, and JPG has no alpha channel — a sprite saved as JPG comes back with a solid rectangle behind it, which is usually only noticed after it is in the game. PNG is also lossless, so a frame survives being cut and re-packed any number of times without degrading.

Can it export a JSON atlas map?

No. The layout here is a plain uniform grid, which is exactly the case that needs no map: the cell size and the column count are all a runtime requires to find any frame. A JSON map earns its place when frames are packed at varying sizes and rotations, and that is a different tool with a different output format.

Related tools

← All tools