Luminance Guidance
'this window should be 1000 nits', as a node
- mask
- guidance_mask
- target_nits
- feather
Here's a specific HDR problem. You're upconverting an SDR frame and the global highlight expansion does a perfectly reasonable job everywhere except the one thing that matters: the practical light in the window should be blinding, pulling your eye, and instead it's just a bit brighter than the wall next to it. Blanket gain can't do that, because it doesn't know your intent.
Luminance Guidance is the node that encodes your intent. You hand it a mask over the region that should be bright and a target in nits; it outputs a guidance mask and the target value, which you wire into HDR Synthesis Engine so the masked area is driven specifically toward that brightness while everything else uses the global setting.
That's the whole node. It's three inputs and three outputs, and its entire job is to be the interface between "what I want" and the engine that does it.
The nits scale, which is where people trip
target_nits defaults to 1000, which the tooltip notes is a typical HDR10 mastering peak. But Radiance's internal scale treats 203 nits as 1.0 - the BT.2408 SDR reference white - so 1000 nits corresponds to roughly 4.93 in the pixel values. The number means nits in the widget and something else in the data. That's correct and standard, and it's also the source of most confusion when someone connects this node and wonders why "1000" didn't produce values of 1000.
Second thing: on the consumer side, the engine's guidance_nits input defaults to 0, and 0 means ignore the mask entirely. Wiring guidance_mask without setting guidance_nits in HDR Synthesis Engine does absolutely nothing. You must set both. This is the single most common "this node doesn't work" report for the pair, and it isn't a bug - a default of 0 keeps existing workflows from changing behaviour when a mask appears.
How it works
The mask is feathered with a Gaussian blur when feather is above 0. The kernel size scales with the value - roughly feather × 31, forced odd, and minimum 3 - with sigma at feather × 10. So the ramp goes from "barely a blur" at 0.05 to "a soft gradient across the whole region" at 1.0. The tooltip calls it "Gaussian feather radius. Higher = softer mask edge", and that's accurate.
The node passes the mask, the nits target and the feather value out as three separate outputs. The feather travels with them so the downstream engine can feather consistently rather than re-guessing, which is a small design nicety that saves you from getting two different softness values on the same shot.
Inputs and outputs
- mask - the region whose highlights you want driven. Usually an alpha channel, a luminance key, or a hand-painted matte over the practical lights. Interpretation is entirely up to you; the node doesn't threshold or auto-detect anything.
- target_nits - 100 to 10000, default 1000. If you're grading for a 1000-nit display, target 600–1000 for practicals; going to 10000 just means the tonemapper will do the compressing later.
- feather - 0 to 1, default 0.2.
Outputs: guidance_mask, target_nits, feather - the trio that goes to HDR Synthesis Engine. Feed guidance_mask into its guidance_mask input, and take target_nits from here to drive its guidance_nits... via a float conversion, or simply type the same number in both places and keep them in sync manually. It's a small friction point, and worth knowing before you wire it.
Installing Radiance
Manager → search Radiance → install → restart → refresh. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/fxtd-studios/radiance.git
cd radiance
python -m pip install -r requirements.txt
Windows portable: python_embeded\python.exe. No model downloads here - the node is pure mask maths. Radiance itself is GPL-3.0, ~147 visible nodes from FXTD Studios, and installs OpenEXR, OpenImageIO, OpenColorIO, diffusers and accelerate into ComfyUI's environment.
Troubleshooting
Nothing changed in the output. Check the engine's guidance_nits is set. See above - a mask with no nits target is ignored.
A visible edge at the mask boundary. Raise feather. An abrupt jump from global expansion to targeted expansion is a gradient discontinuity and the eye finds it instantly, even in a still frame.
My mask covers a huge area and everything went nuclear. That's the guidance working. Target nits applies per-pixel inside the mask; on a large region it can push the whole frame's highlights past the tonemapper's comfort. Mask tightly, on the small bright things that should pop.
The numbers confuse me. Work in ratios rather than nits while you're experimenting: 203 is your reference white, 1000 is about five times that, 4000 is about twenty. Then convert back when you hand off.
Video flicker. Per-frame operation with no temporal term. On a moving practical light the target crawls frame to frame; keep the mask fixed for the sequence rather than recomputing it.
Set expectations on the pair. This guides a heuristic highlight expansion - it moves energy into a region, it doesn't invent what was clipped there. If you need invented detail, that's the learned SDR → HDR path, and its weights are non-commercial licensed. Different tool, different licence, and worth checking before you ship.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | Region whose highlights should be driven towards target_nits, 0 to 1. | |
| target_nits | FLOAT | 1000.00100–10000 | Target brightness in nits for the masked region. 1000 nits = typical HDR10 peak. |
| feather | FLOAT | 0.200–1 | Gaussian feather radius. Higher = softer mask edge. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| guidance_mask | MASK | — |
| target_nits | FLOAT | — |
| feather | FLOAT | — |