Jaconir
Game Dev LabStep 3 of 9

Sprite Sheet Generator

Pack multiple sprites into optimized texture atlases for Godot, Unity and modern 2D engines.

Workspace

Upload once · inspect the atlas · export for your engine

No sprites yet

Generated atlas

Your packed atlas preview

Dense pack

Your atlas will appear here

Upload PNG / JPEG / WebP. Packing stays in your browser.

Frame strip

Drag to reorder · order maps left→right, top→bottom in grid mode

Your imported frames will appear here in order.

Upload

PNG · JPEG · WebP

Layout

How sprites are arranged on the atlas

Bin-packs each sprite tightly. Best default for mixed sizes and photos.

Selected sprite

Hover or click a packed sprite to inspect it.
Settings
Show
Atlas Size
--
Occupancy
0%

Optimization insights

Production metrics from the current atlas — not marketing copy.

Pack sprites to see efficiency, GPU memory, and suggestions.

Engine compatibility

Supported exports and import notes for common 2D engines.

GO

Godot

AtlasTexture · SpriteFrames

  • Import as AtlasTexture
  • Filter clip + padding
  • Mipmaps off for pixel art

Use the Godot bundle — editor script builds AtlasTextures from trim-aware regions.

UN

Unity

Sprite Atlas · Multiple mode

  • Pixels Per Unit 100
  • Point filter for pixel art
  • Sprite Mode: Multiple

Drop the Unity bundle into Assets/ and run the helper to apply sprite metadata.

GA

GameMaker

Texture pages · PNG

  • Import PNG atlas
  • Map frames via JSON
  • Watch page size limits

Export PNG + JSON, then assign frames on a texture page.

PH

Phaser

Atlas JSON · Multi-atlas

  • Phaser 3 atlas JSON
  • Load with this.load.atlas
  • Trim offsets preserved

Phaser preset JSON loads directly with the atlas PNG.

CO

Construct

Sprite sheet · PNG

  • Import as sprite sheet
  • Match frame size
  • Use padding carefully

Use the PNG atlas; define frames from the exported JSON sizes.

Learn & best practices

Production advice from shipped 2D games

Padding

Keep 1–2px between sprites so bilinear samples never bleed. Extrude 1px duplicates edge colors into the gap.

Texture bleeding

Bleeding shows as colored fringes. Fix with padding + extrude, or Point filtering for pixel art.

Filtering

Pixel art → Point / Nearest. Smooth HD → Bilinear with enough padding. Never mix both on one atlas without care.

Power-of-two atlases

Prefer 512² / 1024² / 2048² when targeting older GPUs, mipmaps, or compressed formats.

Mipmaps

Enable only if sprites shrink on screen. Mipmaps + zero padding = bleed. Prefer POT + padding first.

Animation optimisation

Keep frame order stable. Grid packing preserves cell rhythm for AnimationPlayer / Animator clips.

Draw calls

Sprites that share one atlas can batch. Split atlases by material/shader, not by character pose.

GPU memory

RGBA8 ≈ width × height × 4 bytes. A 2048² atlas is ~16 MB uncompressed — trim and pack before upscaling max size.

Texture compression

Compress in-engine (ETC2 / ASTC / DXT). Export clean PNG here; let the engine compressor handle blocks.

Common mistakes

  • Zero padding with bilinear filtering — classic bleed.
  • One enormous 8192 atlas for a handful of UI icons.
  • Packing UI and world sprites on one sheet then forcing different filters.
  • Ignoring trim offsets so animations jitter after import.

Common presets

Click a preset to update packing configuration instantly

Continue your game dev workflow

Idea → level → art → collision → audio → progression

More free browser-based game development tools

Game Dev Lab

How to make a sprite sheet from separate images

Six steps from a folder of frames to an atlas your engine can read, using the Packer tab above.

  1. Drop your frames into the Packer

    The Packer tab takes PNG, JPEG and WebP files, as many at a time as you like. Every file is cropped to its visible pixels the moment it loads — there is no trim checkbox to find, because packing untrimmed art wastes atlas space in every case. If your sprites sit on a flat opaque background instead of transparency, the loader samples the four corners and, when they agree, floods that colour away from the border before cropping. No account, no upload: the files are read into a canvas in the page.

  2. Choose a packing style before you tune anything else

    This is the one decision that changes the output shape. Dense pack fills space, fitting each sprite into the tightest gap left by the ones before it, which produces the smallest atlas for mixed sprite sizes. Grid rows builds a uniform cell sized to your largest sprite and drops every frame into one, which wastes some space but keeps cell coordinates predictable — what an animation timeline needs. Pick Grid rows for a walk cycle, Dense pack for a pile of UI icons.

  3. Reorder the frame strip so playback order survives the export

    Drag thumbnails in the frame strip, or sort the whole set A–Z or Z–A. Frame order is written into the exported metadata in strip order, so idle_00 through idle_07 arriving in that sequence is what makes the clip play correctly on the other side. Getting this right here saves reordering frames by hand inside Godot or Unity later.

  4. Set padding and extrude for your filtering mode

    Padding is empty space around each sprite, 0 to 64px. Extrude, 0 to 8px, repeats the sprite’s own outer pixel row outward into that space so a filtered sample that strays past the edge still reads the right colour. The two add together into the gap the packer leaves on all four sides. Pixel art with nearest-neighbour filtering is fine on 1px padding and 1px extrude; smooth-filtered HD art with mipmaps wants more. Zero of both plus bilinear filtering is the single most common cause of coloured seams around sprites.

  5. Cap the atlas with Max Texture Size and Atlas Shape

    Max texture size is 1024, 2048, 4096 or 8192 — pick the smallest your frames fit in, because an atlas costs GPU memory for its whole area whether or not sprites occupy it. Atlas Shape controls the rounding: square power-of-two for engines and compressed formats that want it, rectangular power-of-two, or any size when nothing downstream cares. If a layout cannot fit, the tool says which size it needed rather than silently cropping.

  6. Export the format your engine actually reads

    PNG alone is half an atlas — the other half is the frame table. Choose an export preset (Generic JSON Hash, Phaser 3 atlas JSON, or a Godot or Unity import spec) and take the ZIP bundle: it carries the PNG, the spec, and for Godot or Unity an editor script plus a README that names the files it expects. XML and CSS are there separately for pipelines that want them — the CSS output gives background-position rules for web sprites rather than game frames.

How to slice an existing sprite sheet into frames

The Slicer tab runs the pipeline backwards — for asset packs that shipped a sheet and no metadata.

  1. Upload the sheet you already have

    The Slicer tab is the opposite direction: one existing sprite sheet in, individual frames out. Use it for asset-pack sheets with no metadata, for sheets whose JSON you have lost, or to rebuild clips from a sheet somebody else packed.

  2. Pick a slice mode that matches how the sheet was built

    Auto-detect finds frames by walking connected visible pixels, bridging gaps up to two pixels so antialiased edges and thin limbs do not split into separate frames; it then groups the detected boxes into rows and orders each row left to right. Rows / Columns is right for a sheet you know is a regular grid — it defaults to 4×4. Fixed Frame Size is for a sheet with a known cell, defaulting to 64×64. Auto-detect on a tightly packed sheet with touching sprites will merge neighbours; a regular sheet is better served by one of the two manual modes.

  3. Group frames into named animations

    Auto-detect assumes the usual convention that one row is one animation, so it creates a group per detected row with the first called Idle. Rename them, add more, and move frames between them. The names matter: exported PNGs are written as run_00.png, run_01.png and so on from the group name, which is the naming your engine importer will key off.

  4. Check the animation on the timeline before exporting

    Set FPS and play the active group. This catches the two things a still grid hides: a frame in the wrong position, and a frame whose box is a few pixels off so the sprite jitters. Fix the rectangle in the Selected Frame panel by editing x, y, w and h directly. The preview updates no faster than once every 40ms, so above about 25 FPS it stops being a faithful speed reference while remaining useful for spotting a bad frame.

  5. Export frames plus a manifest for your engine

    The ZIP holds one PNG per frame plus a manifest — generic JSON, a Godot SpriteFrames spec with a generate_sprite_frames.gd helper, or a Unity clip spec with JaconirGenerateAnimationClips.cs. The manifest is what turns a folder of numbered PNGs back into named animations with frame order intact, rather than something you reassemble by hand.

What the packing settings actually do

The reasoning behind each control, and the cases where the obvious setting is the wrong one.

How Dense pack decides where a sprite goesMaxRects · best short side fit
The atlas starts as one free rectangle. Each sprite is placed into the free rectangle where the tighter of the two leftover dimensions is smallest — the best short side fit rule — with the longer leftover side breaking ties. That rectangle is then split around the placement and any free rectangle fully contained in another is discarded, so the list of candidate gaps stays small. In practice it means a sprite prefers a slot it nearly fills exactly, which is what keeps long thin offcuts from accumulating. Sprites are never rotated to fit: some packers gain a few percent that way, but a rotated frame has to be un-rotated by the engine, and every exported frame here is upright.
What Grid rows actually buildscell = largest trimmed sprite
The cell is as wide as your widest trimmed sprite and as tall as your tallest, so one oversized frame inflates every cell on the sheet. Inside its cell each sprite is centred horizontally and aligned to the bottom — not the middle. That is deliberate: bottom alignment keeps a character’s feet on the same line across a walk cycle, which is the difference between a clean animation and one that bobs. If a frame looks offset in-engine, check whether you packed it in Grid rows and are reading the cell as centred.
Sprites per row, and what "auto" is optimising
Leave sprites per row on auto and the packer tries every column count from one up to your frame count, discards any that overflow the max texture size, and keeps the best of what remains: densest fill first, then the layout closest to square, then more columns as a tiebreak. Set a number yourself when the sheet has to match a layout somebody else expects — a 4-wide strip, say. If you ask for a count that cannot fit, the error tells you the pixel size it needed so you can choose between fewer per row, a larger max size, or a free atlas shape.
Trimming, and why the metadata matters more than the cropspriteSourceSize · sourceSize
Cropping transparent margins shrinks the atlas, but it also moves every sprite relative to its original frame, and an engine that does not know by how much will draw your animation out of alignment. In Dense pack the exported entry carries the original uncropped dimensions in sourceSize and the crop offset in spriteSourceSize, so the engine can put the sprite back where the artist drew it. Grid rows does not need that, because its cells are already uniform, so it reports the cell for both. The practical consequence: if you trim aggressively and your animation jitters after import, the importer is ignoring spriteSourceSize, not packing wrong.
The automatic background knockout, and when it bites±10 per channel
When all four corners of an uploaded image are opaque and within ten values of each other on every channel, the loader treats that colour as the background and floods it away from the border before trimming. That turns a JPEG screenshot or a magenta-keyed sheet into usable transparent art with no extra step. Two cases to know about: a sprite that genuinely contains a large region of the background colour connected to the border loses it, and JPEG compression noise can push pixels past the ten-value tolerance and leave a faint halo. Both are reasons to work from PNG with real transparency when you have the choice.
Reading the optimization metrics honestlyExcellent ≥85% · Good ≥70% · Fair ≥50%
Packing efficiency is the total area actually covered by sprite pixels divided by the whole atlas area, so padding, extrude and power-of-two rounding all count against it — a score of 100% is not achievable and not the target. Grid rows scores lower than Dense pack on the same frames by design, because the empty parts of each uniform cell are counted as waste; that is a cost you accept for stable cells, not a problem to fix. Estimated GPU memory is width × height × 4 bytes, the uncompressed RGBA footprint, which is why halving the max texture size matters more for memory than squeezing out a few percent of occupancy. Trimmed pixels reports how much of your source art was empty margin, and a high number means your export pipeline is padding frames before they ever reach the packer.
One atlas or several
The reason to pack at all is batching: sprites drawn from one texture can go out in one draw call, while a hundred loose PNGs mean a hundred texture binds. The useful split is by material and filtering, not by subject — put every sprite that shares a shader and a filter mode together, even across characters, and keep anything that needs a different filter on its own sheet. Pixel art on nearest-neighbour and smooth art on bilinear on one atlas forces a compromise that will look wrong somewhere. Mobile is where this stops being theoretical: a 2048² RGBA atlas is sixteen megabytes of VRAM before compression.
Uncompressed RGBA memory cost of a full square atlas at each supported max texture size
Max texture sizeSquare atlasUncompressed RGBA
1024 px1024×10244 MB
2048 px2048×204816 MB
4096 px4096×409664 MB
8192 px8192×8192256 MB

Each row is the figure the insights panel reports as estimated GPU memory for a full square atlas at that cap — width × height × 4 bytes, before any in-engine block compression. Every doubling of the cap quadruples the cost, which is why the smallest size your frames fit in is worth more than a few percent of extra occupancy.

Frequently asked questions

Is this sprite sheet maker free, and is there a watermark?

Free with no watermark, no account, and no sign-in. The packer, the slicer, the preview and the ZIP export all run in your browser, so there is nothing to pay for and nothing to register. Exported PNGs are exactly what the packer drew.

How do I make a sprite sheet online from separate images?

Open the Packer tab, drop in your PNG, JPEG or WebP frames, choose Dense pack for mixed sizes or Grid rows for animation cells, set padding and extrude for your filtering mode, then export the PNG together with a metadata preset for your engine. The frames are trimmed and arranged automatically; the only decisions that really matter are packing style and padding.

What image formats can I upload?

PNG, JPEG and WebP. PNG with real transparency gives the best results because trimming works from the alpha channel directly. JPEG and flat-background images still work — the loader detects a uniform opaque background from the four corners and removes it before trimming — but JPEG compression noise around sprite edges can survive that and show up as a faint halo.

How many sprites can it pack at once?

Packing runs on your own machine, so the limit is your device rather than a server quota. Hundreds of frames are routine. Very large sets of a thousand or more take longer, mostly in decoding the source images and generating the ZIP, and a large atlas needs the memory to hold it as a canvas.

What is the difference between Dense pack and Grid rows?

Dense pack fits each sprite into the tightest leftover gap, producing the smallest sheet for sprites of mixed sizes. Grid rows builds one uniform cell sized to your largest sprite and puts every frame in one, which uses more space but gives you predictable coordinates. Use Grid rows for animation strips where a timeline reads frames by cell index, and Dense pack for icons, FX and anything where only total size matters.

Why do my sprites have coloured edges or seams in-engine?

That is texture bleeding: the GPU sampled slightly outside a sprite’s rectangle and picked up a neighbour. Add padding so neighbours are not adjacent, and add extrude so the pixels just outside each sprite repeat its own edge colour rather than being empty. For pixel art, also switch the texture to nearest-neighbour or point filtering and turn mipmaps off — bilinear filtering with mipmaps and no padding is the configuration that bleeds worst.

What does extrude do that padding does not?

Padding separates sprites with empty space; a stray sample lands on transparency and you get a dark or light fringe. Extrude copies each sprite’s outermost row and column outward into that space, so a stray sample reads the sprite’s own colour and the fringe disappears. They solve the same problem from opposite directions and are normally used together — 1px of each covers most pixel art.

Does trimming break my animation alignment?

Not if the importer reads the metadata. Each trimmed frame is exported with its original uncropped size and the offset it was cropped by, which is enough for the engine to place it exactly where the artist drew it. If an animation jitters after import, the importer is discarding that offset. Packing in Grid rows avoids the question entirely, since every cell is the same size.

Are sprites rotated to save space?

No. Every frame is exported upright and the metadata always reports no rotation. Allowing rotation can shrink an atlas by a few percent, but it requires the engine to un-rotate each frame at draw time and it makes the sheet much harder to read by eye when something goes wrong.

What atlas sizes and shapes can I produce?

Max texture size can be 1024, 2048, 4096 or 8192 pixels. Atlas shape can be square power-of-two, rectangular power-of-two, or any size at all. Power-of-two matters for older GPUs, for mipmapping and for most block compression formats; if none of those apply, any size wastes less space. Pick the smallest max size your frames fit in — an atlas costs GPU memory for its whole area regardless of occupancy.

Can I slice an existing sprite sheet back into frames?

Yes, that is the Slicer tab. Upload one sheet and either let auto-detect find frames from the visible pixels, or give it a row and column count, or a fixed frame size. You can then group frames into named animations, scrub them on a timeline at a chosen frame rate, correct any rectangle by hand, and export individual PNGs with a manifest. It is the practical answer to an asset pack that shipped a sheet and no metadata.

Which engines and formats does the export cover?

From the packer: a PNG atlas plus generic JSON, Phaser 3 atlas JSON, or a Godot or Unity import spec, and separately XML and CSS. The Godot and Unity bundles include an editor script and a README naming the files it expects, so the import is a run rather than a manual rebuild. From the slicer: numbered PNGs plus a generic JSON manifest, a Godot SpriteFrames spec, or a Unity animation clip spec. CSS output is for web sprites and gives background-position rules rather than game frame data.

Will packing into one atlas actually make my game faster?

It reduces draw calls and texture binds, which is usually the win on mobile and on anything drawing a lot of 2D. Sprites sharing one texture can be batched into a single call; the same sprites as separate files cannot. The gain depends on how many separate textures you started with — going from a hundred loose PNGs to two atlases is significant, going from three atlases to two is not. Split atlases by shader and filter mode rather than by character, or the batching you gained is lost again.

Is anything uploaded to a server?

No. Reading the files, trimming, packing, slicing, the live preview and building the ZIP all happen in the page. There is no upload step, no account, and nothing is stored after you close the tab, which also means unreleased art never leaves your machine.

Read next