VHS Effect v2
The VHS node that models the actual tape signal
- images
- IMAGE
v1 of the VHS node is fun, but it's essentially noise and blur - a cartoon of a VHS tape. VHS_Effect_v2 is where DJZ-Nodes starts modeling the actual analog signal chain: filter-based frequency cuts, real ringing, and tape-speed profiles that change the character of the image. If v1 is "VHS cosplay," this is the one that looks like a genuine digitized tape. It's the version people who care about the look end up on.
What's actually happening
The core trick is that it processes the image in YIQ color space (luma + two chroma components, closer to how NTSC video is actually stored) and runs it through a simulated composite-video path:
- tape_speed - SP / LP / EP changes the luma and chroma frequency cutoffs and the chroma delay, mimicking how a real VCR's head reads slower tape speeds. EP (extended play) is the most degraded - you can literally hear it in the image.
- composite_preemphasis (0-8) - models the pre-emphasis boost a VCR applies before recording; crank it for that harsh, crunchy edge on detail.
- vhs_out_sharpen - the post-decode sharpening, which is how you get that slightly "too sharp then smeared" VHS texture.
- video_noise / chroma_noise / chroma_phase_noise - three separate noise sources (luma snow, chroma grain, and hue-wobble). The phase noise is the one that makes colors shift subtly like a tracking wobble.
- enable_ringing + ringing_power - ringing is the "echo" ghosting around bright edges, the signature VHS artifact. It applies a precomputed ring pattern (loaded from the pack's
ringPattern.npy, generated on the fly if missing) and usesscipy.signal.lfilterfor the actual filter response.
The output is an IMAGE batch, same resolution as the input, so it slots anywhere a processed frame sequence goes.
The inputs you'll actually set
Honestly, most of the signal params are "leave the defaults, pick a tape speed." The ones worth touching:
- tape_speed - the single biggest character knob. SP is barely-there, EP is full nostalgia.
- color_bleeding - how far chroma smears. Default 5; 8-10 for heavy bleeding.
- video_noise - the luma snow level (up to 4200).
- enable_ringing - if the ghosting reads as ugly rather than nostalgic, turn it off first before dialing intensity.
Installing
Part of DJZ-Nodes (Drift Johnson / MushroomFleet):
cd ComfyUI/custom_nodes
git clone https://github.com/MushroomFleet/DJZ-Nodes
cd DJZ-Nodes
pip install -r requirements.txt
Or "DJZ-Nodes" in ComfyUI Manager. The V2 path needs scipy for the lfilter ringing - it's not explicitly in the pack's requirements.txt, but it's effectively always present in a torch environment, so you likely have it. If the node fails to import, pip install scipy fixes it in ten seconds.
Versus v1 and v3
v1 is simpler but cartoonish. v3 keeps v2's signal core and layers on horizontal noise lines and band distortion - the "tracking is dying" look. If you want a clean-but-real VHS texture, v2 with tape_speed SP/LP is the sweet spot; go v3 when you want visible tracking artifacts. One real gotcha with v2: there's no seed input, so the noise isn't reproducible run-to-run - bake the output if you need a locked shot.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| composite_preemphasis | FLOAT | 4.00–8 | — |
| vhs_out_sharpen | FLOAT | 2.51–5 | — |
| color_bleeding | FLOAT | 5.00–10 | — |
| video_noise | FLOAT | 10000–4200 | — |
| chroma_noise | FLOAT | 50000–16384 | — |
| chroma_phase_noise | FLOAT | 250–50 | — |
| enable_ringing | BOOLEAN | true | — |
| ringing_power | INT | 22–7 | — |
| tape_speed | COMBO | 3 options: SP, LP, EP |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |