TS Film Emulation
Cinematic film looks without leaving the graph
- image
- IMAGE
AI images have a tell, and it's usually not the hands - it's the color. Perfect, sterile, no grain, everything evenly lit and evenly graded. TS Film Emulation is the one-stop fix: pick a Kodak Portra, Fuji, or Cineon-style preset, and your render suddenly has a memory of having been shot on film.
It's the kind of node you bolt onto the end of a pipeline and forget about. Wire IMAGE in, get a graded IMAGE out, no model download, no API, works on every frame of a video batch. If you've ever gone down the rabbit hole of hunting .cube LUTs on random forums, this also gives you a clean home for them.
How it works
The node does three deterministic things, all pure pixel math:
- A film preset or a LUT. The
film_presetdropdown has built-in analog looks (Kodak, Fuji, Cineon-style), or you can flip to "External LUT" and pick any.cubefile from themodels/luts/folder - drop the file in there, and it appears inlut_choiceafter a refresh. That folder is where your own downloaded LUTs go, and the node reads them at runtime. - Gamma + contrast.
gamma_correctionapplies the LUT in sRGB space (keep it on - that's the recommended path for most.cubefiles), andcontrast_curveis a mid-gray pivot where 1.0 is unchanged, above 1.0 is punchier. - Grain.
grain_intensityandgrain_sizeadd film grain, which is the single cheapest move for killing the AI look - the post-processing doc makes the point that film grain is where the community's strongest "how to break the plastic look" arguments live.
There's also warmth (positive warms, negative cools) if the preset is close but the white balance isn't, and film_strength / lut_strength to blend any of it back toward the original.
The inputs that matter
Honestly, for most people: film_preset, and then film_strength if you want the look dialed down to 50%. Everything else is refinement. grain_intensity at its 0.02 default is subtle; crank it if you want it visible, or set it to 0 for a clean-but-graded image. contrast_curve around 1.1–1.2 is the usual "punch it up" range - don't chase 3.0, you'll just crush your shadows.
One output, IMAGE, which drops straight into a preview or saver.
Installing it
Part of comfyui-timesaver - install via ComfyUI Manager (search "Timesaver") or:
cd ComfyUI/custom_nodes
git clone https://github.com/AlexYez/comfyui-timesaver
cd comfyui-timesaver
python -m pip install -r requirements.txt
Restart ComfyUI and it's there. No weights to download. If you want external LUTs, create models/luts/ and drop .cube files in.
Gotchas
The biggest surprise is that LUTs only show up in the dropdown if they're in the right folder - a .cube sitting in input/ is invisible to this node. And remember the LUT folder resolution: the pack looks in its own bundled luts/ directory first, then models/luts/, so when you drop your own files in, put them in ComfyUI/models/luts/ where extra_model_paths.yaml and the rest of ComfyUI expect them. Other than that, it's a fire-and-forget node - the kind you install once, use in every workflow, and eventually stop noticing, which is exactly the compliment a color node wants.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Image to apply the film look to. | |
| enable | BOOLEAN | true | If disabled, the image passes through unchanged. |
| film_preset | COMBO | Built-in analog film look. Choose 'External LUT' to use a .cube LUT from lut_choice instead. | |
| lut_choice | COMBO | External .cube LUT file (from the luts folder) applied when film_preset is 'External LUT'. 'None' = no LUT. | |
| lut_strength | FLOAT | 1.000–1 | Blend amount of the external LUT. 0 = original, 1 = full LUT. |
| gamma_correction | BOOLEAN | true | Apply the LUT in sRGB space (recommended for most .cube LUTs). |
| film_strength | FLOAT | 1.000–1 | Blend amount of the selected film preset. 0 = original, 1 = full preset. |
| contrast_curve | FLOAT | 1.000–3 | Contrast around mid-gray. 1 = unchanged, >1 = more contrast. |
| warmth | FLOAT | 0.00-1–1 | Warm/cool shift. Positive warms (red up, blue down), negative cools. |
| grain_intensity | FLOAT | 0.020–0.5 | Strength of added film grain. 0 = no grain. |
| grain_size | FLOAT | 0.50.5–5 | Scale of the grain particles. Higher values give coarser grain. |
| fade | FLOAT | 0.000–0.5 | Lifts blacks toward gray for a faded, matte film look. 0 = off. |
| shadow_saturation | FLOAT | 0.800–2 | Color saturation in the shadows. 1 = unchanged, <1 = desaturated. |
| highlight_saturation | FLOAT | 0.850–2 | Color saturation in the highlights. 1 = unchanged, <1 = desaturated. |
| grain_speedopt | FLOAT | 1.000.05–1 | For clips: how often the grain pattern is redrawn. 1.0 = a new pattern every frame (lively, digital). 0.5 = one pattern held for two frames, 0.25 for four — closer to scanned film, where the grain does not race the action. No effect on a single image. |
| grain_seedopt | INT | 00–4294967295 | Seed for the grain. The same seed gives the same grain on the same frames, so a re-render matches the take you graded. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |