The thin seams and color halos that show up around sprites in-game are texture bleeding: neighboring frames leaking in when the GPU samples your sheet. Fix it with padding (a transparent gutter between frames), extruding edge pixels into that gutter, and keeping the sheet on power-of-two dimensions. Trimming empty space then buys the memory back. Get these four right and your sheet is engine-proof.
Where the Flickering Line Comes From
You drew a clean 32x32 character. You packed twelve frames into a sprite sheet. You dropped it into your engine, hit play, and now there is a faint one-pixel line of the next frame flickering along the right edge of your walk cycle.
You zoom into the source PNG. The art is fine. Every pixel is where you left it. So where is the line coming from?
It comes from how the GPU reads your sheet rather than from how you drew it, which is why the fix lives in the packing step and not in your art tool. This one class of problem accounts for most "my sprites look broken in-engine but fine in my editor" reports.
![]()
Why Texture Bleeding Happens
When your engine draws one frame from a sprite sheet, it does not copy pixels. It tells the GPU: "sample the texture from UV coordinate (0.25, 0.0) to (0.33, 0.125)." Those are floating-point coordinates between 0 and 1, not whole pixels.
Two things then conspire against you:
- Floating-point rounding. The math that converts a frame rectangle into UV coordinates rarely lands on an exact pixel boundary. A coordinate that should be 0.250000 ends up 0.249997. The GPU rounds, and sometimes it rounds into the adjacent frame.
- Bilinear filtering. If your texture uses linear filtering (the default in most engines), the GPU blends each output pixel from the four nearest source texels. At the edge of a frame, two of those four texels belong to the neighbor. The neighbor's color bleeds across the seam.
Put those together and the boundary between two tightly packed frames becomes a coin flip. Some frames look clean; some show a one-pixel halo of whatever sat next to them on the sheet. The tighter you pack, the worse it gets.
Why it looks fine in your editor: Image editors display textures at integer scale with point sampling: one source pixel maps to one (or N) screen pixels, no blending across frame boundaries. Game engines sample with sub-pixel UVs and filtering. That is the entire reason the bug only appears at runtime.
Fix One: Padding (The Gutter)
The first and most important fix is padding, also called a gutter or border. Leave empty transparent space between every frame on the sheet, typically 2 pixels.
Now when the GPU's rounding or filtering reaches past a frame's edge, it grabs transparent pixels instead of the neighbor's art. A transparent halo is invisible. Problem hidden.
How much padding?
- 1 px covers point/nearest sampling with no mipmaps. Risky the moment anything scales.
- 2 px is the safe default for bilinear filtering without mipmaps. Use it unless you have a reason not to.
- 2 px per mip level if you generate mipmaps, since each level halves resolution and doubles how far a sample can reach.
In the editor, Padding in the Grid Layout panel takes a horizontal and a vertical value in pixels per side, and the cell-size chip in the top bar updates to show the new cell footprint so you can see exactly what you are asking the GPU to sample.

Set padding before you export, not after. Padding changes cell size, which changes every frame rectangle in the exported metadata. Re-exporting is free; re-slicing in your engine is not.
Fix Two: Edge Extrusion (Bleeding On Purpose)
Padding solves bleeding into a frame. But it creates a subtler problem at the frame's own outer edge: when filtering blends your sprite's border pixel with the adjacent transparent gutter, the color gets diluted toward transparent. The result is a faint dark or pale fringe around the sprite itself.
The fix is extrusion (sometimes called bleed): copy each frame's edge pixels outward into the gutter by one or two pixels. Now when filtering blends across the boundary, it blends your sprite's color with more of the same color instead of with transparency. The fringe disappears.
So the ideal gutter is not empty at all. It holds a duplicate of the nearest edge pixel:
[ frame pixels ][ extruded copy of edge ][ transparent padding ][ next frame ]
Most packing tools call this "extrude" and let you set it independently of padding. Use both: extrude 1-2 px, then pad 1-2 px on top.
Fix Three: Power-of-Two Dimensions
A texture whose width and height are both powers of two (256, 512, 1024, 2048) is called a POT texture. Non-power-of-two (NPOT) is 640x480, 300x300, anything else.
Why it still matters in 2026:
- Mipmaps require it on many targets. Mipmaps are precomputed half-size copies the GPU uses when a texture is drawn small. The chain only works cleanly when each level halves to a whole number, which POT guarantees.
- Memory alignment. GPUs allocate and address POT textures more efficiently. A 513x513 texture often gets silently rounded up to 1024x1024 in VRAM anyway, so you pay for the big size and use a quarter of it.
- Older mobile and WebGL targets flatly reject NPOT textures with mipmaps or repeat wrapping.
Only the final sheet needs to be power-of-two, not the individual frames. Pack your frames, then size the canvas up to the next POT and leave the remainder transparent.
The trade-off: POT canvases waste space. A sheet that needs 1100x900 jumps to 2048x1024, more than double the pixels and most of them empty. On modern desktop and recent mobile you can usually ship NPOT safely if you disable mipmaps and use clamp wrapping. Target POT when you support old hardware or need mipmaps; allow NPOT when you control the platform.
Fix Four: Trimming (Buying the Space Back)
Padding and POT both add wasted space. Trimming claws it back.
Most sprites are mostly empty: a 64x64 frame holding a 30x40 character is more than half air. Trimming crops each frame down to its tight bounding box before packing, then records the offset so the engine can re-center it at draw time.
The payoff compounds: trimmed frames pack tighter, a tighter pack needs a smaller canvas, and a smaller canvas is more likely to fit under the next power-of-two threshold. It is common to drop a 2048x2048 sheet to 1024x1024, a 4x memory saving, purely by trimming whitespace.
The cost is that your engine must support trimmed atlases, meaning it reads the per-frame offset and pivot. Godot's AtlasTexture, Unity's sprite atlas, and every JSON-based packer format carry that data, so if yours does, trim.
Flip the top bar from Grid to Packed and the editor runs MaxRects bin packing over the same frames, reporting the resulting canvas size and how much of it is actually used.

A low fill percentage is a signal, not a failure: it usually means untrimmed frames, or a canvas that just got rounded up to the next power of two. Turn on Trim Transparent and repack before you conclude the packer is doing badly.
Putting It Together: A Packing Checklist
A production-ready sprite sheet, in order of operations:
- Trim every frame to its bounding box, recording offsets.
- Pack trimmed frames, leaving a 2 px gutter between each.
- Extrude edge pixels 1-2 px into the gutter.
- Size the final canvas up to the next power-of-two (if targeting mipmaps or old hardware).
- Export the PNG alongside a metadata file (JSON, XML, or your engine's native atlas format) carrying frame rects, trim offsets, and pivots.
Skip any one of these and a specific artifact shows up: skip padding and you get bleed-in, skip extrusion and you get edge fringe, skip POT and you get rejected textures or wasted VRAM, skip trimming and you waste memory and pack passes.
Pack a clean sprite sheet without the artifacts.
Drop in your frames and the generator handles layout, padding, and a tight grid, then exports a ready-to-import PNG plus metadata. No bleeding, no guesswork.
One Last Sanity Check
If you ship a sheet and still see seams, the culprit is almost always one of two settings on the engine side, not the sheet:
- Filtering mode. For pixel art you usually want point/nearest filtering, not bilinear. That alone removes most bleeding because there is no blending across the seam.
- Texture compression. Block compression formats (DXT, ETC, ASTC) compress in 4x4 blocks and can smear color across frame boundaries that do not align to the block grid. Disable compression for pixel art sheets, or align frames to 4-pixel boundaries.
Get the packing right and the import settings right, and the line stops flickering for good.
Try it in the editor
Everything in this guide runs in the browser. No install, no account, and your images never leave your device.