How to use it
- Choose “Separate frames” and drop your PNG/JPG/WebP frames, or choose “Sprite sheet to slice”, drop one sheet and check the detected grid. Adjust cell width/height, spacing, margin and offset until the orange boxes sit on the sprites, or use “Detect islands” for irregular layouts, then click “Use N frames”.
- Reorder frames with the arrows, duplicate holds, remove mistakes. The preview plays the sequence at the chosen frames per second.
- Pick a palette or system. For “Reduce to N colours” set the count; for the retro systems the limits are applied automatically. Try a dithering pattern and the Lab, weighted or plain RGB matching to see which keeps the look best.
- Set the sheet layout – columns (0 = square-ish), spacing and padding in pixels, and the export scale.
- Download the sheet PNG, the frames ZIP or the JSON, or copy the JSON / CSS straight into your project.
Example
A 96 × 32 px strip with three 32 × 32 walk frames is dropped as a sheet. No gutters are found, but 32 divides both sides, so the grid is set to 32 × 32 and “Use 3 frames” produces walk_001–walk_003. With “Game Boy (DMG)” every pixel becomes one of four greens by brightness; the preview runs at 8 fps (125 ms per frame). Columns 3, scale ×2 gives a 192 × 64 px sheet, and the JSON lists frame 2 at x = 64, y = 0, 64 × 64 with duration 125.
How the conversion works
grid cell i,j : x = margin + offsetX + i × (cellW + spacing), y = margin + offsetY + j × (cellH + spacing)
sheet width : padding × 2 + columns × cellW × scale + (columns − 1) × spacing
nearest colour : argmin over the palette of ΔE (CIE76 Lab), redmean-weighted RGB or plain RGB distance
error diffusion: Floyd–Steinberg 7/16 3/16 5/16 1/16 · Atkinson 6 × 1/8 (serpentine rows)
ordered : colour + (Bayer[y mod n][x mod n] + 0.5) / n² − 0.5) × spread, spread = 200 / ∛(palette size), 10–64Auto-detection projects the sheet onto its axes: rows and columns that are fully transparent (or the colour of all four corners) are gutters, the runs between them give the cell size, their pitch the spacing and the first run the offset. Without gutters the largest of 8, 16, 24, 32, 48, 64, 96 or 128 px that divides both sides is used; “Detect islands” instead flood-fills connected sprites (1 px gaps bridged) and returns their bounding boxes in reading order.
Palette reduction samples the opaque pixels of all frames together (median cut, up to 262,144 samples, then three k-means passes) so the whole sheet shares one palette. The retro systems first map every pixel to the fixed hardware palette, then enforce the attribute rules per frame: each cell keeps its most used colours and the rest are remapped to the nearest allowed entry; the NES modes choose four sub-palettes greedily by the number of pixels they cover, then assign each block the sub-palette with the lowest error. C64 multicolour halves the horizontal resolution before mapping and doubles it back afterwards. Screen size limits (160 × 144, 256 × 240, 320 × 200, 256 × 192) and sprite-count limits are not enforced.
Sources: NESdev wiki – PPU palettes and attribute tables, C64-Wiki – Multicolor and hires bitmap modes, ZX Spectrum screen attributes, Floyd & Steinberg (1976), Atkinson dithering, Bayer ordered dithering.
Questions
- My sheet has no transparency – the sprites sit on a magenta or white background. What do I do?
- Tick “Make a colour transparent”, click “Pick the top-left pixel” (or type the hex value) and raise the tolerance a little for JPEG sources. The slicer already treats a solid corner colour as empty when detecting the grid.
- Why do some frames lose colours in NES or C64 mode?
- That is the hardware rule at work: a C64 hires cell can hold only two colours and an NES background block only one of four 3-colour sub-palettes plus the backdrop. Colours that do not fit are replaced by the nearest allowed one. Larger, flatter colour areas and ordered dithering survive these limits best.
- Are the frames resized?
- No. Frames keep their pixel size; the sheet cell is the largest frame and smaller frames sit at the top-left of their cell. The export scale multiplies everything by a whole number with nearest-neighbour sampling, so pixels stay crisp.
- Which engines read the JSON?
- The format follows the TexturePacker “JSON array” shape: a frames list with name, frame {x, y, w, h}, sourceSize and duration, plus a meta block with the image name, size, scale and palette. Phaser, PixiJS, Godot importers and most custom loaders can consume it; the CSS export covers plain web pages.