Regrain
Film Grain That Doesn't Look Like Noise (ComfyTV Regrain)
- video
- video
AI-generated video has one tell: it's too clean. Flat, waxy, zero texture - the kind of image that screams "rendered" the second it hits a timeline. Regrain is the ComfyTV answer: it adds analog-style film grain back, but with enough control that you can make it read as stock footage grain instead of YouTube compression noise.
It's one of the ~190 stages in ComfyTV (jtydhr88's canvas-based take on ComfyUI - every operation is its own node, results flow downstream as snapshots). The Regrain node sits under ComfyTV/VideoFX and does its work through the pack's shared FX engine, which means it previews live in the node and only bakes to a file when you run a final FX Chain pass. Same grain every frame, no flicker fights.
How it works
The thing that separates this from a dumb "add noise" node is that grain is split by luminance zone. You get three separate strength knobs - shadows, midtones, highlights (each 0–1) - so you can grain up the shadows where real film grain lives while leaving highlights mostly clean, instead of dousing the whole frame. grain_size (0–4, default 0.8) sets the physical size of the grain particles, and grain_sat (0–1, default 0.4) controls how much chroma the grain carries. A seed input (default 7) keeps the pattern stable across a shot so consecutive clips don't shimmer differently.
Under the hood it builds an FX spec and hands it to the torch-based FX runner - no external dependencies, no model downloads, just the numpy/torch stack ComfyUI already ships. That's a recurring ComfyTV trait worth knowing: the pack declares zero extra Python dependencies.
Inputs and outputs
The inputs you actually touch: grain_size, shadows, midtones, highlights, grain_sat, and seed. Everything else in the schema - force_run_token, project_id, parent_output_id - is internal plumbing the frontend fills in for project bookkeeping; ignore it. Feed an optional video in, get video back out, ready to wire into the next stage or a Keying/Compose node.
Getting it installed
ComfyTV installs like any pack: search "ComfyTV" in ComfyUI Manager, or
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
then restart ComfyUI. The nodes appear under the ComfyTV category. If you're on ComfyUI Desktop or macOS, the classic cd ComfyUI/custom_nodes can land in the wrong instance - read the startup log for the running base path and clone into that absolute path instead (watch for a nested ComfyTV/ComfyTV/ layout after cloning; the inner folder needs to move up one level). A full backend restart, not a browser refresh, is what registers the nodes.
Troubleshooting
- Grain looks like static, not film. Almost always
grain_sizetoo small orshadows/highlightsboth cranked to 1. Start at defaults and raise one zone at a time. - Colors shift weirdly.
grain_satis the knob - drop it toward 0.2 for a monochrome-ish grain that won't tint your grade. - Nothing changes after Run. If all three zone sliders are at 0 the node short-circuits and passes the video through untouched (that's intentional - it's the identity case).
- Grain shimmering across cuts. Match the
seedbetween shots so the grain pattern is consistent.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| force_run_token | INT | 00–2147483647 | Internal — bumped on Run to invalidate ComfyUI's input cache. |
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| grain_size | FLOAT | 0.800–4 | — |
| shadows | FLOAT | 0.300–1 | — |
| midtones | FLOAT | 0.150–1 | — |
| highlights | FLOAT | 0.050–1 | — |
| grain_sat | FLOAT | 0.400–1 | — |
| seed | INT | 70–99999 | — |
| videoopt | COMFYTV_VIDEO | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| video | COMFYTV_VIDEO | — |