Nodes/DJZ-Nodes/VHS Effect v2
ComfyUI Node

VHS Effect v2

The VHS node that models the actual tape signal

By MushroomFleet·Created 2 years ago·Updated 5 months ago· 78
VHS Effect v2
  • images
  • IMAGE
composite_preemphasis4.0
vhs_out_sharpen2.5
color_bleeding5.0
video_noise1000
chroma_noise5000
chroma_phase_noise25
enable_ringingtrue
ringing_power2
tape_speed

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 uses scipy.signal.lfilter for 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.

Categoryimage/effects

Inputs (10)

NameTypeDefaultDescription
imagesIMAGE
composite_preemphasisFLOAT4.00–8
vhs_out_sharpenFLOAT2.51–5
color_bleedingFLOAT5.00–10
video_noiseFLOAT10000–4200
chroma_noiseFLOAT50000–16384
chroma_phase_noiseFLOAT250–50
enable_ringingBOOLEANtrue
ringing_powerINT22–7
tape_speedCOMBO3 options: SP, LP, EP

Outputs (1)

NameTypeDescription
IMAGEIMAGE