Nodes/MKRShift_Nodes/Highlight Roll-Off
ComfyUI Node

Highlight Roll-Off

A filmic shoulder without leaving the graph

By criskb·Created 7 months ago·Updated 5 months ago· 0
Highlight Roll-Off
  • image
  • mask
  • image
  • mask
  • highlight_rolloff_info
settings_json{"pivot":0.68,"softness":0.1,"amount":0.65,"preserve_color":true,"mix":1.0,"mask_feather":12.0,"invert_mask":false}

Every real camera compresses highlights before they clip - it's called a filmic "shoulder," the part of the tone curve where brightness rises more and more slowly until it eases into white. Digital output doesn't do this, which is why AI images clip to hard, ugly whites so often. Highlight Roll-Off is the MKRShift node that adds that shoulder back on a finished frame: it takes the top of your curve and rounds it off, so bright areas compress smoothly toward white instead of slamming into a wall.

It's in MKRShift Nodes/Color/Finish, and its sibling is x1HighlightRecovery. Recovery rebuilds detail inside already-clipped regions; Roll-Off is more prophylactic - you run it to stop highlights from clipping in the first place, or to soften the ones that are already borderline. Think of it as the deterministic version of the "film look" people keep prompting for, applied to pixels rather than prayed for in a prompt.

How it works

The math is a soft-knee compression on luminance. Pick a pivot - the luma level where the roll-off begins (default 0.68, so roughly the top third of the range). Pixels above it are measured by how far they overshoot, then that overshoot is compressed with a curve whose steepness amount controls (default 0.65). softness feathers the transition so you get a gradual bend rather than a visible kink in the curve.

The preserve_color toggle changes how the compressed luminance is painted back:

  • On (the default), the node scales each pixel's RGB by the ratio of new-to-old luminance. Colors stay put; only brightness moves. This is the "proper" grade - nothing shifts hue.
  • Off, it subtracts the compressed delta equally from all channels, which darkens highlights in a more blunt, desaturated way.

Either way, the effect only touches the region above the pivot, blended in by mix and scoped by the optional mask.

What you'll actually set

It's a settings-JSON bundle node - the knobs live in one multiline string: pivot, softness, amount, preserve_color, mix, plus the pack-standard mask_feather/invert_mask. The two that do 90% of the work:

  • pivot - where the roll-off kicks in. Lower it and you compress more of the range; you can push a washed sky back down to 0.55 and instantly get a moodier frame.
  • amount - how hard the compression bites. Watch the highlights, not the midtones.

Outputs are the rolled-off image, a mask of the affected highlight region (handy for a before/after compare or to chain into another grade), and a highlight_rolloff_info string with the resolved settings.

Installing it

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

then restart ComfyUI, or install via ComfyUI Manager by searching MKRShift_Nodes. No pip requirements, no model files - this family is pure numpy/torch.

One practical tip: stack it after your main grade, not before. If you roll off first and then crank contrast, you'll re-clip the highlights you just saved. And don't expect it to fix a truly blown region on its own - roll-off tames the top of the curve, but it can't rebuild pixels that were clipped to flat white before you got here. That's the job for the Recovery node sitting next to it in the menu.

CategoryMKRShift Nodes/Color/Finish

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"pivot":0.68,"softness":0.1,"amount":0.65,"preserve_color":true,"mix":1.0,"mask_feather":12.0,"invert_mask":false}
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
highlight_rolloff_infoSTRING