Arrange frames, set columns and padding, and export a PNG plus coordinate JSON.
A sprite sheet puts many frames on one image so a game loads one texture instead of dozens; a packed atlas also writes a data file that names every frame and gives its rectangle. Drop numbered PNGs, a GIF or an .aseprite file, pick your engine's preset, and Nerulio packs the frames in your browser (MaxRects, trim on, 2 px padding by default) and exports the PNG with that engine's data file. For a plain grid of equal cells, the classic maker is linked further down.
Drop image files hereProcess many files at onceNo upload · processed on this device
Grid sheet or packed atlas
A grid sheet gives every frame the same cell, so an engine finds frame n by arithmetic: column = n mod columns, row = n ÷ columns, rounded down. It needs no data file, but every cell is as large as the largest frame, transparent border included.
A packed atlas trims each frame to its visible pixels and fits the pieces wherever they fit. Positions are no longer predictable, so the packer writes a data file: for each frame its name, where the stored pixels are on the page (frame), where they sat on the original canvas (spriteSourceSize), the original canvas size (sourceSize) and whether the piece lies turned by 90° (rotated). The engine uses those numbers to draw the frame at full size, so a trimmed frame does not move.
Two settings protect the edges. Shape padding leaves transparent pixels between frames, and extrude repeats each frame's outermost pixels around it, so a texture filter that samples just past an edge reads the same colour instead of a neighbour. Rotation saves a little area, but only some engines turn a rotated frame back; Nerulio's presets allow it only for PixiJS and Spine, where the engine runs drew rotated frames correctly.
Page
One atlas image. Frames that do not fit the maximum size go on further pages (multipack, up to 64).
Trim
Cutting the transparent border off a frame and recording the offset, so it is drawn at its old place.
Shape padding
Transparent pixels between two frames: 2 px by default.
Extrude
Copies of a frame's edge pixels placed around it: 0 by default, 1 in the LÖVE preset.
Alias
Frames with identical visible pixels share one stored region.
Example: six 40 × 29 running frames
The six frames of a CC0 ninja run cycle (40 × 29 px each, mostly transparent), packed by Nerulio with the Phaser preset (trim on, padding 2, no rotation) and compared with other layouts:
layout page area vs strip
horizontal strip, 6 × 40 px 240 × 29 6,960 px² 100 %
packed, trim off, padding 2 82 × 91 7,462 px² 107 %
packed, trim on, padding 2 38 × 50 1,900 px² 27 %
packed, trim on, rotation 33 × 57 1,881 px² 27 %
visible pixels (6 bounding boxes) 1,591 px²
share of the trimmed page used 1,591 / 1,900 = 0.84
"run_0": { "frame": {"x":0,"y":34,"w":18,"h":15},
"spriteSourceSize": {"x":10,"y":10,"w":18,"h":15},
"sourceSize": {"w":40,"h":29}, "rotated": false, "trimmed": true }
Only 18 × 15 pixels of run_0 are stored; the engine draws them 10 px right and 10 px down inside a 40 × 29 box, exactly where they were. Trim does the saving here: without it the packed page is slightly larger than a plain strip, because padding is added between frames.
What each engine receives, and how it loads the sheet
Keep every PNG next to its data file: the data names its image (meta.image in JSON, imagePath in XML, the page line in a Spine .atlas).
File
What it is for
run.png + run.json (Phaser 3 / 4)
this.load.atlas("run", "run.png", "run.json"), then this.add.sprite(x, y, "run", "run_0"); details on the Phaser atlas page.
run.png + run.json (PixiJS 8)
const sheet = await Assets.load("run.json"), then sheet.textures["run_0"] or sheet.animations["run"]; see PixiJS spritesheet JSON.
run.tres + run.tscn (Godot 4)
A ready SpriteFrames resource and scene instead of a bare atlas; see sprite sheets in Godot.
Read the used share in Pack & Export: 0.84 means 84 % of the page is visible frame area. A low figure usually means trim is off or one frame is much larger than the rest.
Hover the rows of the Packed frames list: each shows canvas → stored size, its page and flags such as trimmed, rotated or "same as" (an alias).
In the engine, draw one trimmed frame at the same point as its untrimmed neighbour; if it is shifted, the loader ignores spriteSourceSize (see troubleshooting).
Troubleshooting
Symptom
Likely cause
How to check
Fix
Frames jump or wobble while the animation plays
Trimmed frames drawn without their offset: the loader or your code uses frame but ignores spriteSourceSize and sourceSize
Draw two frames with different trims at one point; they should line up
Use a loader that reads trim data, or pack with trim off (larger page); more in jitter after trimming
Thin lines or colour fringes at frame edges when the sprite is scaled or moves by fractions of a pixel
The texture filter reads pixels just outside the frame: a neighbour, or transparent padding
Zoom in on the edge: the line has a neighbour's colour, or is see-through
Keep shape padding at 2 or more, add extrude 1, use nearest filtering for pixel art; see atlas padding
Some frames appear sideways, mirrored or clipped
Rotation was allowed for an engine or loader that does not turn frames back
Those entries have "rotated": true
Pack with rotation off; Nerulio's Godot, Unity, Phaser, LÖVE, XML and CSS exports refuse a rotated pack
An error says sprites do not fit the page
One frame plus its padding and extrude is larger than the maximum page size
The message names the frame and its size
Raise the maximum size (up to 16384 px), allow rotation where the engine reads it, or scale that frame down
Other ways to do it
Option
When it is the better choice
A plain grid sheet (the classic maker below)
Every frame already has the same size and your engine slices by cell, for example GameMaker strips or Godot's Add Frames from Sprite Sheet. There is no data file to keep in sync.
Aseprite's own sheet export (--sheet-pack, --trim, --merge-duplicates on its command line)
The art lives in Aseprite and its JSON with tags and durations is all you need. It writes no engine bundles such as Godot SpriteFrames.
TexturePacker Pro
You need polygon packing, GPU texture formats or a command line in a build pipeline; measured against Nerulio on the TexturePacker alternative page.
The engine's own packer (Defold atlas, Spine's texture packer)
The engine packs separate images at build or export time anyway; then you only need the frame images, for example from a sheet split into PNG frames.
Versions and sources
The sizes above are the output of Nerulio's packer on the six ninja frames of the repository's test corpus, the same numbers as the 2026-09-23 head-to-head. Exports were loaded in Godot 4.7.2, Unity 6000.5.3f1, Phaser 3.90 and 4.2, PixiJS 8.21, spine-canvas 4.2 and LÖVE 11.5; Defold bob.jar 1.13.1 built the Defold files. The other tools' option names follow their documentation.
Example generated with this tool. ZIP tools show their preview; inspect the downloaded archive for every file.
Sprite Sheet Maker
Arrange frames, set columns and padding, and export a PNG plus coordinate JSON.
How it works
Add images
Adjust settings and review the result
Download a new file
Supported formats
PNG / JPG / WebP / AVIF / HEIC → PNG + JSON (ZIP) — Input decoding depends on browser support and optional engines.
What this tool does
Arrange frames, set columns and padding, and export a PNG plus coordinate JSON.
Implementation and verified quality
advanced · Studio Pack & Export: MaxRects/Skyline/Guillotine, trim/alias/extrude/multipack, colour-exact PNG writer, engine exporters. Quality qualification is in progress. Pro/Flagship quality has not been established.
Before you export
Uniform grid packing only. No rotated packing or engine-specific resource generation.
Frequently asked questions
What are this tool’s limitations?
Uniform grid packing only. No rotated packing or engine-specific resource generation.
Are my files uploaded?
This tool processes the files you open on your device without uploading them. Images you explicitly attach to community posts are uploaded separately. Optional engines and models are downloaded from third parties; those requests expose connection information such as your IP address.
Will my work be saved automatically?
No. Images and editing state stay in this tab; media output can use local temporary storage. Changing language preserves your work; reloading, closing the tab, or following a link to another page can clear it.