Loop a video
Make your video loop without the visible jump
- image
- audio
- image
- audio
- new_frame_count
You've made a clip you want to run on repeat - a wallpaper-style loop, an ambient background, a bumper that sits in a social post forever. If you just set loop_count: 999 on VHS_VideoCombine, the seam where the last frame meets the first one jumps. That's what this node fixes. It's the second of five in the TKVideoZoom pack, and like its siblings it's pure frame math - no model, no downloads, nothing to train.
Seamless loops are a genuinely live want around here, and this is one of the few nodes that does it in-graph instead of handing the clip off to a video editor.
How it works
The trick is spreading the seam out over time instead of letting it sit at one hard cut. The node takes the first fps / 2 frames and the last fps / 2 frames - half a second of footage - and blends them against the opposite end of the clip, so the loop point becomes a gradual transition instead of an abrupt one. The fps input (8–60, default 16) doesn't change playback speed; it just defines how long that blend region is.
The three loop_type modes:
- cross fade - start blends into the end (and vice versa) over the half-second window. The classic "no visible jump" option.
- fade - same blending, but toward black at both ends, so the loop breathes through a quick fade instead of cutting.
- ping pong - plays the clip forward, then appends the reversed sequence. No blending at all; the loop point is a reflection, which looks natural for motion that has a direction (a walk, a pan) because the turnaround reads as intentional.
Inputs and outputs
Required inputs are image, audio, fps, and loop_type. Both image and audio come straight off a VHS_LoadVideo node. There's genuinely one decision here: which loop_type. Cross fade is the safe default; ping pong if the shot has directional motion.
Outputs are image, audio, and new_frame_count - an INT with the length of the looped clip. That last one is the hidden gift: wire it into anything that wants to know the new length, and with ping pong you can see the count double (the output really is ~2× the input frames).
The wiring is the standard TKVideoZoom pattern:
VHS_LoadVideo ──image──> TKVideoSmoothLooper ──image──> VHS_VideoCombine
└─audio─> └─audio─> └─audio
The one trap: audio
audio passes through byte-for-byte untouched. With ping pong your video doubles in length but the audio doesn't - it'll play once over a twice-as-long clip, then the rest is silent. Same with a longer cross-faded loop. For a true looping clip you either accept the audio as a single pass (fine for silent/ambient loops), handle looping in VHS_VideoCombine's own loop_count on the audio side, or re-export audio separately. It's worth knowing going in, because it looks like a bug the first time it happens.
Install
ComfyUI Manager → search "TKVideoZoom" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/trashkollector/TKVideoZoom
Restart. No models, no API keys, and the only real dependency is OpenCV, which you already have if VHS_LoadVideo works. Skip the pack's requirements.txt torch pins - stock ComfyUI + cv2 is all this needs.
One gotcha shared with the whole pack: nodes import under the custom_nodes.TKVideoZoom module, so if any node in the pack fails to load (usually a missing cv2), all five vanish from your menu at once. If TKVideoSmoothLooper is missing, the others are too - fix the import, and they all come back together.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| audio | AUDIO | — | |
| fps | FLOAT | 16 | — |
| loop_type | COMBO | 3 options: ping pong, cross fade, fade |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| audio | AUDIO | — |
| new_frame_count | INT | — |