ComfyUI Node

Film Grain

The cheapest 'un-AI' in the finishing stack

By criskb·Created 7 months ago·Updated 5 months ago· 0
Film Grain
  • image
  • mask
  • image
  • mask
  • film_info
settings_json{"film_grain_strength":0.0,"film_grain_size":32.0,"film_grain_seed":42,"film_grain_chroma":0.35,"vignette_strength":0.0,"vignette_roundness":1.2,"mask_feather":12.0,"invert_mask":false}

The post-processing KB has a whole argument for why film grain is the single cheapest move for breaking the "AI look": real cameras and film have noise, AI output doesn't, and adding a little back is the fastest way to make a generated frame read as captured rather than rendered. x1Film bundles that trick - grain plus an optional vignette - into one node in the MKRShift finishing pack, and it does both properly enough that it's the one I reach for at the end of a grade.

It's part of MKRShift Nodes by Cris K B, under MKRShift Nodes/VFX/Stylize.

How it works

The grain is a procedural additive-noise pass, not a re-gen or a texture lookup. A seeded noise field (film_grain_seed, default 42) is generated at film_grain_size scale, blurred up to the film-grain frequency, and added over the image at film_grain_strength. The film_grain_chroma knob (default 0.35) is the detail most grain nodes get wrong: real film grain isn't just luminance noise, it has a color component - dye clouds in the film stock - so you can mix in chroma noise that reads as "film" rather than "static." If you keep film_grain_strength at 0, the node does nothing to your image - you have to turn it on.

The vignette half is separate and optional: vignette_strength (default 0) darkens the frame edges, with vignette_roundness (default 1.2) controlling how circular vs. rectangular the falloff is. A faint vignette is a classic finishing move - it pulls the eye to the center and kills the "flat AI canvas" feel. Both effects share the node's mask system.

The inputs that matter

Inside the settings_json:

  • film_grain_strength - 0 to 1.5; realistically 0.1–0.3 is where subtle lives.
  • film_grain_size - the grain's pixel scale (default 32). Smaller = finer grain.
  • film_grain_seed - randomize to get different grain per frame.
  • film_grain_chroma - how much color noise to mix in (default 0.35).
  • vignette_strength / vignette_roundness - the edge darkening.

Optional mask input with mask_feather / invert_mask, and outputs image, mask, and a film_info string.

Installing it

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

Restart ComfyUI, or install via ComfyUI Manager (search MKRShift_Nodes). No requirements.txt, no models, no keys.

The trap

Defaults are zero for both effects, so if you load the node and see "nothing happened," that's by design - the pack made the safe default, you supply the intent. The real mistake is grain that's too big or too strong: at film_grain_strength above ~0.4 and a large film_grain_size, it stops reading as film and starts reading as a bad Instagram filter. Start at 0.15 strength, size 32, chroma 0.3, and nudge up only until the "AI smoothness" dies. And for video, re-seed per frame - static grain looks like a dirty sensor, animated grain looks like film.

CategoryMKRShift Nodes/VFX/Stylize

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"film_grain_strength":0.0,"film_grain_size":32.0,"film_grain_seed":42,"film_grain_chroma":0.35,"vignette_strength":0.0,"vignette_roundness":1.2,"mask_feather":12.0,"invert_mask":false}
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
film_infoSTRING