AM Grade
Nuke's Grade math, without the Nuke
- image
- video
- image
- video
If you've ever graded a shot in Nuke or DaVinci, AM Grade will feel like home. It's the exact Nuke Grade operator - blackpoint, whitepoint, lift, gain, multiply, offset, gamma - reimplemented in torch so it runs inside ComfyUI. For everyone else: this is the "proper" color grade, the one with real blackpoint and whitepoint controls instead of just a brightness slider. You use it when AM Color Correct's six friendly knobs aren't enough and you want to actually re-map the tonal range.
It's part of comfyui-am-vfx-tools ("AM VFX Tools" category), Adrian Meyer's 13-node VFX toolkit - the public slice of an internal studio pipeline. The Grade nodes are the pack's answer to "my generated plate needs to survive next to real footage."
How it works
The math is straight from Nuke, documented in the source:
A = multiply * (gain - lift) / (whitepoint - blackpoint)
B = offset + lift - A * blackpoint
out = sign(A*x + B) * pow(|A*x + B|, 1/gamma)
In plain terms: it re-maps the range between blackpoint and whitepoint, applies lift and gain (which together with multiply set the slope), then offset, then a gamma curve on top. There's also a reverse toggle that runs the whole thing backwards - grade in, get the original out - which is the trick for round-tripping: apply a grade to a plate, run a model, apply the reverse to land back in original color. The sign-preserving pow is the subtle bit; without it, gamma ≠ 1 turns any negative intermediate value (common once you move blackpoint or offset) into NaN.
The inputs that matter
Ten widgets, but the beginner set is four:
blackpoint/whitepoint- the low and high end of the range you're re-mapping. Defaults 0 and 1.gain- multiply on the whole range; this is your exposure knob.lift- lifts the blacks (additive, applied with gain).
Then multiply, offset, gamma (the curve), reverse, and two clamps: black_clamp (default on, clips negatives to 0) and white_clamp (default off). White clamp being off by default is deliberate - it keeps scene-linear highlights above 1.0 alive, which is what you want in a VFX pipeline.
Inputs are image and optional video (lazy per-frame, alpha untouched, image ignored when video is wired). Outputs: image (same shape/channels) and video.
Installing it
One install gets all 13 nodes:
cd ComfyUI/custom_nodes
git clone https://github.com/am-pipeline-prod/comfyui-am-vfx-tools.git
cd comfyui-am-vfx-tools
pip install -r requirements.txt
Restart ComfyUI. Or search comfyui-am-vfx-tools in ComfyUI Manager. The pack's real dependencies - OpenImageIO, OpenColorIO ≥ 2.5, PyAV, OpenCV headless - come from that pip line.
Where people get burned
The one that bites everyone: this grade assumes you're working in the pack's linear float world, not 8-bit sRGB. Blackpoint/whitepoint of 0 and 1 assume the pixel range is meaningful. If you feed it a gamma-encoded image straight from a VAE, you'll get a grade that technically runs and visually looks wrong. The intended path is to bring images in through AM Read Image with a proper colorspace transform (or run AM OCIO Colorspace first), so the node works on linear data. Also remember black_clamp is on by default - if your highlights are clipping and you don't want it, that's the white_clamp toggle, and if blacks are getting crushed to 0 unexpectedly, that's black_clamp.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| blackpoint | FLOAT | 0.000 | — |
| whitepoint | FLOAT | 1.000 | — |
| lift | FLOAT | 0.000 | — |
| gain | FLOAT | 1.000 | — |
| multiply | FLOAT | 1.000 | — |
| offset | FLOAT | 0.000 | — |
| gamma | FLOAT | 1.000 | — |
| reverse | BOOLEAN | false | — |
| black_clamp | BOOLEAN | true | — |
| white_clamp | BOOLEAN | false | — |
| imageopt | IMAGE | Image batch to grade. | |
| videoopt | VIDEO | Optional VIDEO input. When wired, returns a lazy `GradedVideo` wrapper applying the grade per-frame on consumption — no IMAGE materialisation here. Alpha (when present) passes through untouched. `image` is ignored when `video` is wired. See invariant 28. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Graded image batch (same shape and channels as the input). |
| video | VIDEO | Lazy VIDEO output — emits a `GradedVideo` wrapper when `video` is wired, else a zero-copy `VideoFromComponents` around the IMAGE batch. None when no input is wired. |