Skip to content

Tiling Normal Map Seams — Generate It with Wrap Edges

A bright or dark line along the border of a repeating texture usually means the normal map was generated as if the border were an edge: the kernel clamped at the image border instead of reading the pixels on the opposite side, so the border slopes where the surface should simply continue.

Drop a sprite, a sprite sheet or a tileable texture (PNG)
Runs in your browser. Files are not uploaded.
Studio Texture workspace: an imported ambientCG normal map read as DirectX with high confidence; nothing changes until the convention is confirmed
The real Studio with a CC0 asset (ambientCG).
Exports to
  • Godot 4 2D lightsVerified· Godot 4.7.2
  • Unity 6 URP 2DVerified· Unity 6000.5.3f1 (URP 17.5)
  • PNG set + JSONPlain files

What it does

  • For pictures with no transparent pixels the Studio suggests Tileable texture, whose edges are Wrap: every kernel reads across the border from the opposite side.
  • The wrap test in the Check panel generates the map again from the texture shifted by half and compares the two; 0 means seamless.
  • The albedo's own seam ratio (1 ≈ no visible seam) shows when the picture itself does not tile, because no normal map can hide a seam in the colour.
  • Tile 3×3 (T) repeats the lit texture so you can move a light across the border and look for the line.
  • Height maps work the same way: from the 8-bit brick height map the Wrap result was 8.8° from ambientCG's own normal map (7.7° when read as a height map), with roll error 0.

How to do it

  1. Drop the tileable texture (or its height map) into the Texture workspace.
  2. Keep Tileable texture, or set Edges to Wrap in the Normal map panel.
  3. Open the Check panel: the wrap test should read 0; if the albedo seam ratio is high, fix the picture first.
  4. Press T for the 3×3 view, switch to Lit and drag a light across the border.
  5. Export for Godot 4, Unity 6 or as the PNG set.

Edge modes and what happens at the border

Edge modeUse it forWhen the texture repeats
ClampSprites with a transparent outlineThe border pixel is repeated; the slope breaks at the join and shows as a lit line
WrapTileable textures (suggested when nothing is transparent)Samples come from the opposite side; wrap test 0, no line
MirrorPictures that will not repeat but should not get a rimReflected at the border, not the next tile; a faint line can remain
Wrap, but the albedo has a seamNothing: fix the albedo firstThe normal map is seamless, the colour still shows the join

Roll error on the same CC0 bricks (0 = wrap-correct): Nerulio 0 · Laigter 1.14 default 63.8, Tile preset 0 · PBR Forge 0.57, Tile 0.24 · NormalMap-Online 0 on this asset.

Engine exports and how each was checked

"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.

TargetFilesCheck
Godot 4 2D lights_lit.tscn · CanvasTexture .tres · normal / specular PNGVerified Godot 4.7.2Six real CC0 cases rendered by Godot (gl_compatibility): every checked frame within 1/255 of the Studio's lit preview. The same render with green flipped is 3.8–37 levels off, so the check can see a wrong convention.
Unity 6 URP 2DPNG · nerulio-texture.json · Editor/NerulioNormalMapImporter.csVerified Unity 6000.5.3f1 (URP 17.5)12 of 12 runs (6 cases in Gamma and Linear colour space): the lighting URP applied matches the exported normal map (mean error 0.0037–0.0085). URP draws its own light falloff, so brightness is Unity's, not the preview's.
PNG set + JSONalbedo · _n (OpenGL) · _n_dx (DirectX) · 16-bit height · AO · specular · manifestPlain filesPlain files for any engine or tool; no engine run is claimed for them.

Evidence

Godot 4.7.2 rendered 6 real CC0 cases (pixel art, an HD sprite, a tileable texture, an imported DirectX map): every checked frame within 1/255 of the Studio's preview. Unity 6000.5 URP 2D: 12 of 12 runs pass (6 cases × Gamma and Linear). OpenGL/DirectX detection on real maps of known convention: 128 full 1K maps 100 % right, and not one wrong "high" verdict in 1,562 samples (a naive "green-high means OpenGL" rule gets 46 %).

Limits

  • On a picture without transparent edges (a tileable texture) a flipped red channel cannot be told apart from a DirectX green; the Check panel says so and offers Flip red.
  • A sheet is lit as one picture until its frames are cut in the Sprite workspace; the Texture workspace does not cut frames.
  • The rim light is preview only, and Unity gets no specular map (Godot does).
  • Unity draws its own light falloff: the exported normal map is verified in Unity, the brightness curve is Unity's.

Questions

Why did the seam appear only after I made the normal map?

The colour tiled, but the generator treated the border as the edge of a sprite, so the last pixels got a slope or a rim. Laigter's default, for example, leaves a 3 px tilted band on every side; its Tile preset removes it.

Can the Studio repair a normal map that already has a seam?

No. Generate it again here from the albedo or the height map with Wrap; the Studio does not patch the border of an existing normal map.

When is Mirror the right edge mode?

For a picture that will not repeat but should not get a rim at its border. On a repeating texture, Mirror reads a reflection instead of the next tile, so a faint line can remain.

The wrap test says 0 but I still see a line.

Then the line is in the colour: check the albedo seam ratio, or run the picture through the seamless tile checker and fix the albedo before generating again.

Is it free, and do I need an account?

Everything on these pages is free and works without an account. There is no watermark and no export that is held back.

Are my sprites uploaded?

No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.

Does it need Aseprite or an engine plugin installed?

No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).