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 6 months ago·Updated about a month ago· 7
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—