Nodes/ComfyUI_Gear/Gear · Color Grade (exr-viewer)
ComfyUI Node

Gear · Color Grade (exr-viewer)

A full color page inside ComfyUI — grade your HDR EXRs without leaving the graph

By oumad·Created 4 months ago·Updated 4 days ago· 0
Gear · Color Grade (exr-viewer)
  • hdr_linear
  • sdr_reference
  • graded_display
  • graded_linear
exposure0.0
tone_mapACES Fitted
soft_clip0.00
temperature0.00
tint0.00
lift_r0.00
lift_g0.00
lift_b0.00
gamma_r1.00
gamma_g1.00
gamma_b1.00
gain_r1.00
gain_g1.00
gain_b1.00
offset_r0.00
offset_g0.00
offset_b0.00
contrast1.00
pivot0.180
shadows0.00
highlights0.00
saturation1.00
vibrance0.00
hue_shift0
false_colorfalse

This is the pack's showpiece, and the reason to install ComfyUI_Gear in the first place. The decode nodes hand you scene-linear HDR, and the natural next step is to grade it - but poking numeric sliders on a node to "grade" footage is a miserable way to work. Gear · Color Grade embeds the exr-viewer grading UI as a modal pop-up in your browser: color wheels, lift/gamma/gain/offset, scopes, A|B compare, a batch frame scrubber. It's a slice of DaVinci's color page running inside ComfyUI, driven by WebGL2.

The workflow

Wire hdr_linear (typically from Gear · LogC3/LogC4/ACEScct Decode) into the node and run the graph once. Then click Open grade panel on the node. The modal pops up with the full exr-viewer interface, and every slider and wheel moves the WebGL canvas instantly - no graph re-runs while you work.

How it works

The grade math lives in two places that stay in sync: a GLSL fragment shader in exr-viewer/src/renderer.ts drives the live preview, and a torch port in gear/grading.py runs on backend execution when you queue. The pipeline is: exposure → white balance → ACEScct → lift/gamma/gain/offset → contrast → shadows/highlights → vibrance → saturation → hue shift → tone map → soft clip → sRGB OETF.

The node technically exposes 26 inputs, but you won't hand-type most of them - the panel writes your grade to the node's hidden widgets. The ones you might set directly are:

  • tone_map - None, Reinhard, ACES Fitted (default), AgX, Hable. Your pick of look; ACES Fitted is the safe default.
  • exposure - global EV before the grade stack.
  • soft_clip - rolls off highlights instead of hard-clipping them.
  • sdr_reference - the one optional input. Give it any display-referred IMAGE (like the decode node's tonemapped_preview) and the panel's A|B wipe compare has something to grade against.

The important bits about the panel

  • Persistence: changes are ephemeral until you hit the blue Save button. Cancel, ×, Esc, or clicking outside all discard. Saved state survives modal reopen and workflow save/load - including exact dot + master positions on the color wheels.
  • Batches: pass an [N, H, W, C] IMAGE and the panel shows a frame scrubber at the bottom. A|B compare works across the batch, swapping both EXR and SDR as you scrub.
  • LUTs: the LUT button loads any .cube file (1D LUTs unsupported). Bundled film LUTs ship in web/vendor/exr-viewer/test-luts/.

Outputs

  • graded_display - display-referred sRGB, post tone-map and OETF, 0..1. What you actually look at.
  • graded_linear - scene-linear HDR after grading, pre-tonemap. Pipe this back into a Gear decode/save node's EXR writer to bake the grade into your EXRs.

Gotchas worth knowing

End users never run npm - the prebuilt exr-viewer is committed in web/vendor/, so Manager install just works. You need a browser with WebGL2 (any modern one).

One thing that surprises people: this node deliberately never caches. Its IS_CHANGED returns a random value every call, because the panel previews an EXR written to ComfyUI's temp folder, and ComfyUI wipes temp on every restart. A cached node would leave the panel pointing at a deleted file. The cost is that the node re-executes every queue even if nothing changed - it's cheap (one small grade pass plus one EXR write), but you'll see it run. And after a restart, just re-run the graph once and reopen the panel to refresh the source EXR.

Install via ComfyUI Manager (search ComfyUI_Gear) or git clone https://github.com/oumad/ComfyUI_Gear into ComfyUI/custom_nodes, then pip install -r requirements.txt and restart. Deps stay at opencv-python, numpy, Pillow - the panel itself is pure browser code.

CategoryGear/HDR

Inputs (27)

NameTypeDefaultDescription
hdr_linearIMAGE
exposureFLOAT0.0-10–10
tone_mapCOMBOACES Fitted5 options: None, Reinhard, ACES Fitted, AgX, Hable
soft_clipFLOAT0.000–1
temperatureFLOAT0.00-1–1
tintFLOAT0.00-1–1
lift_rFLOAT0.00-1–1
lift_gFLOAT0.00-1–1
lift_bFLOAT0.00-1–1
gamma_rFLOAT1.000.1–4
gamma_gFLOAT1.000.1–4
gamma_bFLOAT1.000.1–4
gain_rFLOAT1.000–4
gain_gFLOAT1.000–4
gain_bFLOAT1.000–4
offset_rFLOAT0.00-1–1
offset_gFLOAT0.00-1–1
offset_bFLOAT0.00-1–1
contrastFLOAT1.000–4
pivotFLOAT0.1800.001–1
shadowsFLOAT0.00-2–2
highlightsFLOAT0.00-2–2
saturationFLOAT1.000–3
vibranceFLOAT0.00-2–2
hue_shiftFLOAT0-180–180
false_colorBOOLEANfalse
sdr_referenceoptIMAGE

Outputs (2)

NameTypeDescription
graded_displayIMAGE
graded_linearIMAGE