Turn a flat sprite into one that reacts to 2D lights. Drop it in, shape the height with a few sliders, watch the lit preview follow your mouse, then download the normal map. Runs in the browser, nothing is uploaded.
A PNG with a transparent background gives the best result, because the silhouette is what the bevel is built from. Opaque tiles work too, they just skip the bevel and take their height from the art itself.
Bevel radius and edge curve round the silhouette off. Shading lifts bright pixels, so highlights read as raised. Detail cuts a small groove wherever two colours meet, which makes the pixel art's own lines catch the light.
The lit preview follows your mouse. When it looks right, download the normal map, the height map, or a ready-made Godot CanvasTexture that wires both together.
The download is a standard tangent-space normal map: red is left to right, green is up and down, blue is towards the camera. Flat areas are the familiar lilac (128, 128, 255). Transparent pixels stay transparent unless you turn on Opaque background.
Make a CanvasTexture, set diffuse_texture to the sprite and normal_texture to the _n.png, put it on a Sprite2D, then add a PointLight2D. Or download the .tres, drop it next to the sprite (named the same as the sprite file) and it is already wired.
[resource]
diffuse_texture = ExtResource("1")
normal_texture = ExtResource("2")Select the sprite, open the Sprite Editor, switch to Secondary Textures and add one named _NormalMap pointing at the _n.png. 2D lights from the URP 2D renderer pick it up with no shader work.
Sprite Editor
Secondary Textures
name: _NormalMap
texture: hero_n.pngLoad the normal map alongside the sprite, switch the sprite to the lights pipeline and add a light. Enable the lights plugin in the scene.
this.load.image('hero', ['hero.png', 'hero_n.png']);
hero.setPipeline('Light2D');
this.lights.enable().setAmbientColor(0x555555);
this.lights.addLight(x, y, 200);No built-in normal maps, so sample the _n.png as a second texture in a shader and do the dot product yourself. Decode with n = tex * 2.0 - 1.0. Turn on Flip Y here if your shader expects green to point down.
vec3 n = texture2D(u_normal, uv).rgb * 2.0 - 1.0; float d = max(0.0, dot(normalize(n), l));
Y convention: OpenGL (green up) is the default and is what Godot, Unity and Phaser want. Some shaders and older DirectX pipelines expect green down. If the top of the sprite lights up when the light is underneath it, flip Y and re-download.
Yes. It runs in your browser, nothing leaves your machine, and there is no account, watermark or limit on exports.
Same job, no install. Those are desktop apps with more brushes and layers. This tool covers the common case: a sprite, a bevel, a bit of shading and a lit preview, done in seconds, with a Godot export. If you need hand-painted heights, they are still the right tools.
OpenGL by default, where green means up. Godot, Unity and Phaser all expect that. Turn on Flip Y for engines and shaders that follow the DirectX convention, where green points down. If the lighting looks inverted from top to bottom, this toggle is the fix.
The bevel is built from the distance to the transparent edge, so that is where the rounded rim comes from. A fully opaque image still works, it just takes its height from the shading and detail terms alone, which is what you want for a tile.
Yes. Download it, paint on it in any editor (white is high, black is low), then use it in your engine's own normal-from-height step. Or re-run this tool with different slider values. It is deterministic: the same sprite and the same settings always give the same map.
Add a clean 1 to 4 px outline to any sprite, outside or inside the silhouette.
Key out a solid background so the bevel has a silhouette to work from.
Split a sheet into frames, then give each one its own normal map.
Open SpriteLab to keep building with your sprites.