modaux: normal_bae
Modaux normal_bae
- image
- IMAGE
Normal maps are the quiet member of the ControlNet family. Canny gives you edges, OpenPose gives you skeletons - this node gives you a map of which direction every surface faces, rendered as a blue-and-purple RGB image. You feed it a photo and it answers "the sphere points this way, the wall points that way." That's a whole category of control that has nothing to do with outlines or people.
It's called modaux: normal_bae inside ComfyUI (search "modaux" if the node menu is hiding it), and it's the NormalBAE detector from Hugging Face's controlnet_aux library wrapped up as a single node by the ControlNet Auxiliar pack.
Why you'd reach for it
Normal maps are a lighting-conditioning tool. The classic move is relighting: redraw a scene in a completely different style or mood while the model respects where light hits and where it doesn't. They pair naturally with IC-Light workflows, and a normal map is the standard preprocessor for the control_v11p_sd15_normalbae checkpoint on SD 1.5 and the "normal" condition in SDXL's xinsir union ControlNet.
One honest warning before you fall in love: there is no normal-map ControlNet for any post-Flux base as of mid-2026. If you're on Z-Image or Flux 2, this preprocessor produces a map you have nowhere to feed it. This is an SD 1.5 / SDXL move, and on those models it's genuinely the right tool - just check your base model first.
How it works
This is one of the simplest nodes in the pack - it has no optional inputs at all. The wrapper converts your IMAGE tensor to a PIL image, runs NormalBaeDetector from controlnet_aux, and converts the result back to a tensor. The first time you run it, the weights download from lllyasviel/Annotators on Hugging Face (a scannet.pt checkpoint), so the first run is slow and needs internet.
The only inputs that matter are the two every node in this pack shares:
- detect_resolution (default 512) - the resolution the detector processes at. Lower it for speed, raise it for finer detail.
- image_resolution (default 512) - the size of the map that comes out. The detector does its work, then the output is resized to this.
The output is a single IMAGE - the normal map - which you wire straight into a ControlNet loader and then into a ControlNet Apply node ahead of the sampler.
Installing it
Install via ComfyUI Manager ("Custom Nodes" → search ControlNetAux, repo madtunebk/ComfyUI-ControlnetAux), or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/madtunebk/ComfyUI-ControlnetAux
cd ComfyUI-ControlnetAux
pip install -r requirements.txt # timm, controlnet-aux==0.0.7, mediapipe
Restart ComfyUI and the node shows up under the ControlNet Auxiliar category. The pack pins controlnet-aux==0.0.7 and pulls in mediapipe, which is a heavy dependency with its own Python-version constraints - if ComfyUI fails to start after installing, that's the usual suspect.
Where people get burned
Watch the name collision: this is not Fannovel16's comfyui_controlnet_aux ("ComfyUI ControlNet Auxiliary Preprocessors"), the big, actively-maintained pack everyone actually uses. This one is a small beta wrapper (version 0.3 beta, README literally says "Work in Progress"). If a downloaded workflow asks for AIO_Prep or LLlyasviel* nodes, it wants the other pack. Also don't trust the pack's own README here - it describes normal_bae as "image restoration," which it isn't; the code is unambiguous that it's the NormalBAE surface-normal detector.
And the honest bottom line: normals are a niche condition. For composition, canny and depth get you 90% of the way there. Reach for this one when the light is the thing you're trying to preserve, and your model is SD 1.5 or SDXL.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| detect_resolution | INT | 512256–1024 | — |
| image_resolution | INT | 512256–1024 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |