HDR Preview KJ
View HDR IC-LoRA output without it looking washed out
- image
- image
If you've run one of the newer HDR IC-LoRA workflows (Lightricks shipped one for LTX-2.3 built specifically to break the 8-bit SDR ceiling every video model has been stuck at), you've probably noticed the raw VAE-decoded output doesn't look like a normal image. It's LogC3-compressed - a log color space that packs a much wider dynamic range into a standard [0,1] tensor, and it looks flat and desaturated until something decompresses it properly. HDRPreviewKJ is that something: an exposure/tonemap viewer built specifically for this class of output, with sliders that respond in real time instead of forcing you to re-queue the whole workflow every time you nudge exposure.
The trick is where the math runs. Slider changes are decompressed, tonemapped, and converted to sRGB live in a WebGL shader in your browser - instant feedback, no GPU queue. The same math also runs server-side so the actual IMAGE output is a correctly baked sRGB result, but that output only updates when you re-queue the workflow, not on every slider tweak.
How it works
Decompression (undoing the log encoding), exposure adjustment, saturation, a Reinhard tonemap (the standard way to compress a wide dynamic range down into a viewable 0–1 range without just clipping the highlights), then a final sRGB conversion - all four steps chained, running twice: once instantly in your browser for feel, once for real on the server to produce the actual saved output.
The inputs and outputs that matter
image- your LogC3-compressed HDR batch, straight out of the VAE decode of an HDR IC-LoRA workflow, before any other decompression step.exposure(default 0, range ±10) - the slider you'll actually touch. Positive brightens, negative darkens; because this runs in log space, small moves have a bigger visible effect than a normal brightness slider.saturation(default 1, 0–2) - how vivid the tonemapped result looks; 0 is grayscale, 1 is neutral.
Two optional inputs round it out: fps (default 24) for realtime video preview playback speed, and input_space (defaults to logc3), a dropdown in case the pack later supports other HDR encodings.
The single output is image - the baked sRGB result at whatever exposure/saturation you had set when you last queued the workflow. Note this node is flagged as an output node itself, so it's meant to sit at the end of your chain, not feed further processing.
How to install it
Via ComfyUI Manager: search "KJNodes for ComfyUI," install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/kijai/ComfyUI-KJNodes
pip install -r ComfyUI-KJNodes/requirements.txt
then restart. The realtime preview needs a browser capable of running WebGL shaders - any reasonably modern browser handles this fine, but a very locked-down or headless browser context might not render the live slider preview (the baked server-side output still works regardless).
Common issues & troubleshooting
The preview updates instantly but the saved image looks stuck on old settings. That's expected behavior, not a bug - the live slider preview is browser-side only. Re-queue the workflow to bake your final exposure/saturation choice into the actual IMAGE output.
Feeding it a normal (non-HDR) image looks wrong. This node assumes LogC3 input specifically - a standard sRGB image run through it will get double-processed and look off. Only use it on the direct output of an HDR-trained decode step, before any other tonemapping.
Everything looks flat even after exposure adjustment. Try saturation alongside exposure - a correctly exposed but desaturated image is still a common symptom of under-decompressed log footage, and the two sliders are meant to be used together, not one at a time.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | LogC3-compressed HDR image/video in [0,1], or linear HDR if 'input_space' is 'linear'. | |
| exposure | FLOAT | 0.00-10–10 | Exposure in EV stops. 0 = no change, +1 = 2x brighter. |
| saturation | FLOAT | 1.000–2 | Saturation multiplier. 0 = grayscale, 1 = unchanged, 2 = 2x. |
| fpsopt | FLOAT | 24.01–120 | Playback frame rate for video (batch) inputs. |
| input_spaceopt | COMBO | logc3 | Color space of input. 'logc3' = ARRI LogC3 compressed HDR; 'linear' = linear HDR directly; 'srgb' = already-graded sRGB image (skips Reinhard tonemap). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Tonemapped sRGB image, ready for preview/save. |