Skip to content

Normal Map for a Sprite Sheet — Every Frame on Its Own

Run a normal map generator over a whole sprite sheet and it sees one picture, not an animation: frames that sit close together share their blur and edge distances, and the relief of a pose changes with its neighbours. Here the sheet is cut into frames in the Sprite workspace first, and the Texture workspace makes the normal map of every frame on its own with the same settings in pixels, so the relief holds still while the animation plays.

Drop a sprite, a sprite sheet or a tileable texture (PNG)
Runs in your browser. Files are not uploaded.
Studio Texture workspace: a pixel-art torch cut into 6 frames, lit by a point light with its generated normal map
The real Studio with a CC0 asset (OpenGameArt).
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

  • Frames come from the Sprite workspace (Apply); the Texture workspace does not cut frames itself, and a sheet without frames is lit as one picture.
  • The distance transform, blur and kernels never read across a frame border; tests/normals.test.mjs checks that a frame's map does not depend on its neighbours and moves with the sprite.
  • Bevel width, depth and detail are absolute pixels, never rescaled per frame; pixel-art frames up to 128 px get a suggested 1.5 px rim.
  • Lights are placed in frame pixels, so every frame is lit alike; Enter plays the animation lit, and ` switches between the whole sheet and one frame.
  • Height brush (B) strokes stay inside the frame they started in, one undo step each.

How to do it

  1. Drop the sprite sheet; it opens in the Sprite workspace.
  2. Check the grid and animations and press Apply.
  3. Open the Texture tab: a normal map for every frame is generated at once.
  4. Adjust bevel and detail, place lights with the Lights tool (L), and press Enter to watch the animation lit.
  5. Export (Ctrl+E) for Godot 4, Unity 6 URP 2D or as a PNG set.

Whole-sheet versus per-frame normal maps

One pass over the whole sheetPer frame (this workspace)
Bevel near frame bordersedge distance can reach into a neighbouring framemeasured inside each frame only
Blur and detailcan bleed from one frame into the nextstop at the frame border
Same drawing in two framesmay get a different reliefgets the same relief, moved with the sprite
Light positionin sheet pixels: frames in different places are lit differentlyin frame pixels: every frame lit alike
Exportone normal map image; engine setup by handGodot scene with an AnimationPlayer; Unity sprite rects plus _NormalMap

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 not make one normal map of the whole sheet?

When frames touch or sit close together, a whole-sheet pass lets the blur and the edge distance run from one frame into the next, so the same drawing gets a different relief depending on its neighbours, and the animation shimmers. Per-frame processing gives each pose the same result wherever it sits on the sheet.

Does the Godot export play the animation?

Yes. <name>_lit.tscn has a Sprite2D with a CanvasTexture, CanvasModulate for the ambient light, one PointLight2D per light and an AnimationPlayer over the frames. Godot 4.7.2 matched the Studio's reference within 1/255 on every checked frame, including through that AnimationPlayer.

And in Unity?

The Unity 6 URP 2D bundle sets the sprite rects from its JSON and adds the normal map as the _NormalMap secondary texture (linear, uncompressed, never resampled). It passed 12 of 12 runs in Unity 6000.5.3f1; the brightness curve is URP's own.

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).