Nodes/MKRShift_Nodes/Color Balance
ComfyUI Node

Color Balance

Slope/offset/power grading without the color cast

By criskb·Created 7 months ago·Updated 5 months ago· 0
Color Balance
  • image
  • mask
  • image
  • mask
  • color_balance_info
settings_json{"slope_r":1.0,"slope_g":1.0,"slope_b":1.0,"offset_r":0.0,"offset_g":0.0,"offset_b":0.0,"power_r":1.0,"power_g":1.0,"power_b":1.0,"saturation":1.0,"mix":1.0,"preserve_luma":true,"mask_feather":12.0,"invert_mask":false}

Most "color balance" sliders are a blunt additive tint. x1ColorBalance is built on the slope/offset/power model - the same math behind ASC CDL grades - which is how colorists move a look without wrecking the whites. It sits in MKRShift Nodes' Color/Grade branch alongside the pack's color wheels and mesh warp nodes, and it's the deterministic, maskable workhorse of that section.

The pack is young (zero impressions, no community chatter I could find), so the honest framing is: fresh, clean, unproven-by-crowd code. But the grading nodes share one genuinely nice design decision - every settings_json widget gets a frontend panel, so you're dragging sliders, not typing JSON.

How it works

The pipeline, straight from the source: multiply by per-channel slope (scales the signal), add per-channel offset (shifts blacks), raise to per-channel power (the gamma-like curve), then apply saturation and blend by mix. The power step is the reason this feels like a grade instead of a tint - it reshapes the tone response per channel without moving the black point the way an additive tint does. That's the additive-vs-power distinction worth internalizing if you've been reaching for brightness offsets.

Two switches matter beyond the triplets:

  • preserve_luma - rescales the result so the output luminance matches the input. This is the "don't wreck my exposure while I fix the cast" button, and it's on by default for good reason.
  • The optional mask + mask_feather - grade only part of the frame, like an HSL qualifier without the selection UI.

Outputs: image, mask (the grade matte, not your input mask), color_balance_info (resolved settings).

Inputs that matter

  • slope_r/g/b - the first knob to reach for; slight channel imbalance here is a warm/cool cast fix
  • power_r/g/b - the curve control; this is where contrast-y per-channel shaping happens
  • offset_r/g/b - shifts shadows; go easy, it lifts blacks fast
  • saturation and mix - global seasoning and the safety valve

Installing

ComfyUI Manager → search MKRShift Nodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes

Restart ComfyUI. No models, no new dependencies.

Where people get burned

  • Offsets on clipped highlights. Offset is additive, so it pushes brights toward the clip hard. Fix a cast with slope first; use offset for shadow work.
  • preserve_luma off when you don't want it. If your grade keeps changing overall exposure in ways you didn't ask for, it's usually this toggle.
  • The mask output is the grade matte, not the input mask. Same pack-wide trap.
  • A corrupted settings_json falls back to defaults silently - if the whole look resets, that's the smell.

It's the "fix the cast without the wash" node - a one-node CDL-style grade that stays reproducible and plays nice with the rest of the pack's Color branch.

CategoryMKRShift Nodes/Color/Grade

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"slope_r":1.0,"slope_g":1.0,"slope_b":1.0,"offset_r":0.0,"offset_g":0.0,"offset_b":0.0,"power_r":1.0,"power_g":1.0,"power_b":1.0,"saturation":1.0,"mix":1.0,"preserve_luma":true,"mask_feather":12.0,"invert_mask":false}
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
color_balance_infoSTRING