Quick answer: Black lines between tiles are caused by texture filtering bleeding adjacent pixels or by sub-pixel camera movement. The GPU samples between texels when using linear filtering, pulling in transparent or black pixels from the texture edge.
Here is how to fix Godot sprites black lines gaps between tiles. You have laid out a beautiful tilemap in Godot 4, but when you run the project you see thin black lines flickering between your tiles. The seams appear and disappear as the camera moves, sometimes only visible at certain zoom levels. This is one of the most common visual bugs in 2D Godot projects, and it has a straightforward fix once you understand what causes it.
The Symptom
When you run your scene, you notice thin dark lines — usually black or transparent — appearing at the seams between tiles in your TileMap. The lines are often just one pixel wide. They may flicker in and out as the camera scrolls or as the player moves. Sometimes the gaps only appear at specific viewport resolutions or when the camera position lands on a sub-pixel coordinate.
The problem is especially visible with pixel art tilesets where the contrast between tile edges and the background color is high. If your background is dark, you may see lighter lines instead. The common thread is that there are visible seams where tiles should meet seamlessly.
You might also notice the lines get worse when you zoom the camera in or out, or when you use a viewport stretch mode that scales the rendering. Moving the camera at fractional positions — such as when using smooth follow — tends to make the artifacts more frequent.
What Causes This
The root cause is texture filtering and sub-pixel sampling. When Godot renders your tilemap, the GPU needs to determine which color to display for each screen pixel. If the texture filter mode is set to Linear (the default for non-pixel-art projects), the GPU interpolates between neighboring texels. When a tile boundary falls between two screen pixels, the GPU samples beyond the tile edge and pulls in pixels from the adjacent area — which may be transparent black (rgba(0, 0, 0, 0)) if there is no padding around the tile in the atlas texture.
There are three main contributors to this problem:
- Linear texture filtering — The default filter mode interpolates between texels, which causes bleed at tile edges. For pixel art and tiled games, you almost always want
Nearestfiltering instead. - Sub-pixel camera positioning — When your Camera2D position is not aligned to whole pixel values, the GPU must render tiles at fractional positions. This shifts where tile boundaries fall relative to screen pixels, creating visible seams.
- Missing atlas margin and padding — If your tileset atlas has tiles packed edge-to-edge with no buffer pixels, even tiny sampling errors will pull in data from neighboring tiles or from the transparent border of the texture.
The Fix
There are four steps to completely eliminate tile seams in Godot 4. Apply all of them for the most robust result.
Step 1: Set the texture filter to Nearest. Open Project → Project Settings → Rendering → Textures and set Default Texture Filter to Nearest. This tells the GPU to pick the single closest texel instead of blending between neighbors, which eliminates edge bleeding entirely for pixel art.
# You can also set this per-node in code
extends TileMapLayer
func _ready():
texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
Step 2: Enable pixel snapping. Go to Project → Project Settings → Rendering → 2D and enable both Snap 2D Transforms to Pixel and Snap 2D Vertices to Pixel. This forces all 2D nodes to render at integer pixel positions, preventing sub-pixel alignment issues.
# In Project Settings (project.godot), these correspond to:
# rendering/2d/snap/snap_2d_transforms_to_pixel = true
# rendering/2d/snap/snap_2d_vertices_to_pixel = true
# You can also snap your camera position manually:
extends Camera2D
func _process(delta):
var target = get_target_position()
global_position = target.round()
Step 3: Add atlas margin and padding. Open your TileSet resource in the inspector. Under the atlas setup, increase the Separation (padding between tiles) and Texture Region Size margin. If you are using an external tileset image, re-export it with 1–2 pixels of extruded edges around each tile. Many tile editors like Aseprite or Tiled have an "extrude edges" export option that duplicates the border pixels outward.
# When creating a TileSet in code, set margins:
var tile_set = TileSet.new()
var source = TileSetAtlasSource.new()
source.texture = preload("res://tiles/tileset.png")
source.margins = Vector2i(1, 1)
source.separation = Vector2i(2, 2)
source.texture_region_size = Vector2i(16, 16)
tile_set.add_source(source)
Step 4: Configure your viewport stretch mode. In Project → Project Settings → Display → Window → Stretch, set Mode to canvas_items or viewport. The viewport mode renders at your base resolution and then scales up, which gives the cleanest result for pixel art. Set Aspect to keep to avoid distortion.
Why This Works
Each of these steps addresses a different part of the rendering pipeline where seams can be introduced. Nearest filtering prevents the GPU from ever sampling beyond a tile boundary, because it always picks the single closest texel rather than blending. Pixel snapping ensures that tile boundaries always fall exactly on screen pixel boundaries, so there is no ambiguity about which texel to sample. Atlas padding adds a safety net: even if a tiny sampling overshoot occurs, the extruded edge pixels contain the same color as the tile edge, so the bleed is invisible. Viewport mode ensures that the internal rendering resolution matches your tile grid, so the scale factor does not introduce fractional positioning.
Together, these four settings make tile seams virtually impossible. The most critical is the texture filter — switching from Linear to Nearest alone fixes the problem for most projects. The other settings provide defense in depth for edge cases like non-integer zoom levels or high-DPI displays.
"I spent two days thinking my tileset was exported wrong. Turns out it was one checkbox in Project Settings. Nearest filter fixed everything."
Related Issues
If your sprites look blurry rather than showing black lines, you may be dealing with a related but different filtering issue. See Fix: Godot 2D Sprites Blurry When Scaled for a walkthrough of import filter settings and nearest-neighbor configuration.
Z-ordering problems can sometimes look like visual artifacts at tile boundaries. If tiles appear to overlap incorrectly or flicker between layers, check out Fix: Z-Index Not Working Correctly in Godot 2D for a guide on layer ordering.
For particle effects that interact with your tilemap but are not rendering, see Fix: Godot Particles2D Not Visible or Not Emitting.
One checkbox. No more seams.