Split an Image into Tiles — One PNG per Tile (ZIP)
When a tool wants separate images — a Tiled "Collection of Images" tileset, a level editor — cut the sheet into tile-NNN.png files. The grid is measured from the pixels and every tile is an exact region copy.
Cutting a tileset into single images takes three numbers per axis: the tile size, the margin (pixels before the first tile) and the spacing (pixels between tiles). The slicer measures them from the pixels and ranks the candidates, you confirm or type them, and it writes tiles/tile-NNN.png as exact region copies plus metadata.json with each tile's rect, column and row. Blank tiles are skipped by default and duplicates can be reported as aliases. Most engines read the whole sheet with the same margin and spacing, so single files are only needed when a tool asks for them.

- TilesMeasured· Pillow
- Padded atlasMeasured· Pillow
- Seam reportMeasured· Pillow
Tile size, margin and spacing
Tile n in column c and row r starts at x = margin + c × (tile width + spacing) and y = margin + r × (tile height + spacing). The number of columns that fit is floor((image width − margin + spacing) ÷ (tile width + spacing)); pixels left over at the right or bottom edge are ignored. Each tile is copied out of the decoded sheet as an exact rectangle, never resampled.
Measurement looks for the period of the art: per axis it builds the difference between each line and the one before, folds that profile at every period from 4 px to half the image and scores how well each fold explains it. Lines that a margin or spacing would reserve must be blank or flat, a blank first or last line inside every tile means the tile is smaller and that line is spacing ("16 px + 1 px gap" beats "17 px tiles"), and a multiple of the true period loses to its divisor. Above 4 megapixels nothing is measured and the size is typed in.
Engines take the same numbers for the whole sheet: Godot 4's TileSetAtlasSource has margins, separation and texture_region_size, Tiled's image-based tileset has margin and spacing, Phaser's addTilesetImage takes tileMargin and tileSpacing, and Unity's Sprite Editor grid slicing has Pixel Size, Offset and Padding. Only a Tiled "Collection of Images" tileset, where each tile refers to its own image file, needs the single PNGs.
- Margin
- Pixels between the image edge and the first tile.
- Spacing (separation)
- Pixels between two neighbouring tiles.
- Blank tile
- A tile whose every pixel has alpha 0; skipped by default and counted in
skippedBlank. - Alias
- A tile identical to an earlier one; written once and mapped in
aliases.
Example: a 203 × 186 sheet with 16 px tiles and 1 px spacing
The numbers the slicer uses, and the same layout in three engines:
sheet 203 × 186, tiles 16 × 16, margin 0, spacing 1
columns floor((203 − 0 + 1) / (16 + 1)) = floor(204 / 17) = 12
rows floor((186 − 0 + 1) / 17) = floor(187 / 17) = 11 → 132 tiles
tile 13 column 1, row 1 → x = 0 + 1 × 17 = 17, y = 17, 16 × 16 → tiles/tile-013.png
names 3 digits up to 1000 tiles (tile-005); 4 digits above (tile-0005 in a 1600-tile sheet)
other 100 × 64 sheet, margin 1, spacing 2 → 5 × 3 tiles at x = 1, 19, 37, 55, 73; 11 px on the right are unused
engines Godot margins (0, 0), separation (1, 1) · Tiled margin 0, spacing 1 · Phaser addTilesetImage(name, key, 16, 16, 0, 1)File names keep the tile's grid index, so when blank tiles are skipped the numbering has gaps on purpose: tile-013 is always column 1, row 1 of this sheet.
What it does
- Grid candidates (tile size, margin, spacing) measured and ranked; every number stays editable.
- One PNG per non-blank tile plus metadata.json with each tile's rect, column and row.
- Exact and near-exact duplicates reported as aliases; optional rotated and flipped variants.
- Optional padded atlas (edge extrusion) for bleeding-free rendering; long slices can be cancelled.
How to do it
- Drop the sheet.
- Check the measured grid, or type the tile size, margin and spacing.
- Choose blank skipping, duplicates and variants.
- Download the ZIP.
Check the result
- Turn on the grid lines: every line should fall in a gap or on a tile edge, never through the art.
- Open
metadata.json:tileSet.columns × rowsis the grid,countthe files written,skippedBlankanddeduplicatedexplain any difference. - Open one tile PNG: it is exactly the tile size, and its
rectinframessatisfies x = margin + col × (tile + spacing).
Troubleshooting
| Symptom | Likely cause | How to check | Fix |
|---|---|---|---|
| Every tile carries a line of its neighbour or is shifted by a pixel | Wrong margin or spacing, typically 17 px tiles instead of 16 + 1 | Grid lines cross the art instead of the gaps | Pick the other candidate in the ranked list, or type the margin and spacing |
| Fewer files than tiles in the grid | Blank tiles are skipped, or duplicates were written once as aliases | skippedBlank, deduplicated and aliases in metadata.json | Turn blank skipping or duplicate detection off to get one file per grid cell |
| The period found is 32 px but the tiles are 16 px | The art repeats a larger pattern, so a multiple of the tile scores well | Compare the scores of the 16 px and 32 px candidates | Choose the 16 px candidate or type the size |
| The tile size is not suggested at all | The image is above 4 megapixels, where the grid is not measured | The field is empty and the note says to type it | Type the tile size, margin and spacing; slicing still works |
Other ways to do it
| Option | When it is the better choice |
|---|---|
| Load the whole sheet in the engine with the margin and spacing | Almost every tilemap: Godot TileSetAtlasSource, a Tiled image-based tileset or Phaser addTilesetImage read one image and no tile files have to be managed. |
| Tileset slicer | You need an engine tileset with terrain rules for Godot, Tiled, Unity or LDtk rather than loose PNGs. |
| Unity Sprite Editor, Grid By Cell Size | The sheet is only used in Unity: Pixel Size, Offset and Padding create the sprite rects inside Unity's importer. |
Outputs and how each was checked
"Measured" means the downloaded file was opened again outside the page (Pillow, numpy or an independent parser) and the property was measured. Loading these files in a game engine was not tested.
| Target | Files | Check |
|---|---|---|
| Tiles | tiles/tile-NNN.png · metadata.json | Measured PillowEvery sliced tile equals its source region pixel for pixel (margin, spacing, blanks, duplicates). |
| Padded atlas | padded-atlas.png | Measured PillowEdge pixels duplicated outward; the recorded atlas-padding quality checks pass in Chromium and Firefox. |
| Seam report | PNG (healed) · measurements on screen | Measured PillowA wrapping tile is reported seamless, a ramp is reported as a seam, and the healed tile's mean wrap difference is below 8 levels. |
Evidence
Grid detection ranked the true grid first on 10 of 10 synthetic sheets (margin 1 / spacing 2 included); 13/13 sliced tiles byte-identical to their source regions; a 1600-tile slice finishes in 2.2 s and can be cancelled; seam verdicts measured against the tile's own interior.
Limits
- At most 4096 tiles per slice; near-duplicate grouping is capped at 2048 tiles.
- The ZIP carries no engine tileset;
metadata.jsonis the generic envelope with rects, columns and rows. - Regular grids only; above 4 megapixels the tile size is typed in instead of measured.
- Near-duplicate detection is a pixel threshold, not perceptual similarity.
- "Make seamless" changes the art inside its blend bands and synthesises nothing; before and after are shown.
- A tile smaller than 2 × 2 cannot be measured for seams.
Versions and sources
Measured for docs/TILE-LAB.md: the true grid ranked first on 10 of 10 synthetic sheets (margin 1 with spacing 2, odd 15 px, 16 × 32 tiles, outlined tiles); 13 of 13 sliced tiles byte-identical to their source regions (Chromium + Pillow); 47 of 48 tiles written with 1 blank skipped and 1 alias; 1600 tiles of 8 px sliced in 2.2 s with a working cancel. The engine parameter names follow the Godot 4.7, Tiled, Phaser and Unity documentation.
Official documentation used
Questions
Is a tile resampled?
Never: each tile is an exact region copy of the decoded sheet (13 of 13 byte-identical in the check).
What about engine tilesets with terrain rules?
For Godot, Tiled, Unity or LDtk tilesets, use the tileset slicer, which opens the Studio's Tile workspace.
Is it free, and do I need an account?
Everything on these pages is free and works without an account. There is no watermark and no export that is held back.
Are my sprites uploaded?
No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.
Does it need Aseprite or an engine plugin installed?
No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).