Colorist Film Grain
Film grain that reads like film, not like added noise
- image
- image
If your AI video has that telltale sterile look, the cheapest single fix in the book is grain - the KB's post-processing notes call it "the cheapest single move for breaking the AI look," and the community agrees. But most grain nodes lay one flat gray layer over the whole frame, which is how you end up with "AI video plus speckle" instead of footage that reads as shot. Colorist Film Grain is the one that models what 35mm actually does. It ships from Atomic-Trash's small ComfyUI-ColoristFilmGrain pack, alongside its companion Colorist Halation node, and it's aimed squarely at video: drop it after a VideoHelperSuite Load Video, run the whole clip as one batch.
How it works
The node treats the frame like three separate emulsion dye layers. Noise is generated per channel - blue grainiest (weighted 1.35 vs red's 0.85), with blue clumps running larger - so you get the faint chromatic shimmer of real stock instead of flat gray speckle. That noise is then shaped with a difference of Gaussians: a fine blur minus a broader one removes the large-scale blotch and leaves only the crisp, even sparkle of a real film spectrum.
Two details are what separate this from every other grain node. First, the amplitude is signal-dependent - sqrt(I*(1-I)), peaking in the midtones with a floor so grain never fully clears the shadows or highlights. That midtone curve is the single biggest reason this reads as film and not as "noise added in post." Second, it's added, not overlaid: signed grain added to the image, the way film density actually fluctuates. For video it's also temporally alive - grain_motion crossfades a stack of noise keyframes with a constant-power cos/sin blend, so the field drifts frame to frame without pulsing. All torch, no extra dependencies; noise is generated on CPU for reproducible seeds.
The inputs that matter
A beginner genuinely touches three of the nine:
strength(0–1, default 0.15) - how much grain. Start low; a whisper does more for the film read than a storm.grain_size(0.5–4.0, default 0.65) - clump size. Smaller is fine 35mm, larger trends toward coarser old stock / 16mm.grain_motion(0–1, default 1) - temporal life. 1 is fresh grain every frame, 0 freezes one plate (great for stills or testing).
Worth knowing: chroma_amt (default 0.25) is the per-channel color part - set it to 0 for a true B&W stock look, and luma_amt (default 0.85) is the shared achromatic grain. blend_mode defaults to add, which is the film-true path; overlay and soft_light are stylistic. shadow_bias tilts the curve toward the shadows, and seed makes the same field repeatable. The single output is image, which feeds straight into Video Combine or a preview node.
Installing it
No model downloads, no heavy dependencies - just torch, which you already have. Easiest route: ComfyUI Manager → Install Custom Nodes, search "Colorist Film Grain." Or drop it in by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Atomic-Trash/ComfyUI-ColoristFilmGrain
Restart ComfyUI and both nodes appear under image/postprocessing. The example workflows in the repo (colorist_film_grain.json) show the full Load Video → grain → Video Combine chain.
Where people get burned
The main gotcha is memory. A moving grain field uses a fresh noise plate per frame, so on long or high-res timelines you'll eat VRAM - render in batches (VideoHelperSuite has a batch manager) or pull grain_motion down toward frozen. The other trap is downstream: fine grain is the hardest thing for a codec to keep. Master to ProRes or a 10-bit high-bitrate file, and for h264 use a low crf (around 12), or the encoder smears your carefully-made grain back into the soft look you started with. And if you're using the companion halation node, it goes before this one - halation is image formation, grain sits on top.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| grain_size | FLOAT | 0.650.5–4 | — |
| strength | FLOAT | 0.150–1 | — |
| shadow_bias | FLOAT | 0.000–1 | — |
| luma_amt | FLOAT | 0.850–1 | — |
| chroma_amt | FLOAT | 0.250–1 | — |
| blend_mode | COMBO | 3 options: add, overlay, soft_light | |
| seed | INT | 00–18446744073709550000 | — |
| grain_motion | FLOAT | 1.000–1 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |