Nodes/kubakub nodes/kubakub retime
ComfyUI Node

kubakub retime

Half-speed in-betweens without leaving ComfyUI

By kubakubkub·Created about a month ago·Updated 2 days ago· 10
kubakub retime
  • images
  • images
  • frame_count
  • fps
  • seconds
◄speed0.50►
◄frames0►
◄modeflow►
◄fps0.000►

Diffusion video has a frame rate problem. Ask for 121 frames and you get 121 frames, but if you want the motion slower - a three-second reveal stretched to six - you either generate it that way (and pay double) or you interpolate. Optical flow interpolation is the cheap answer, and it's been a solved primitive for a decade. This node wraps it.

kubakub retime changes the speed of a batch of frames, either by a factor or to an exact frame count, with in-between frames from optical flow or a plain cross-fade.

The three modes

mode = flow (default) is the interesting one. It computes optical flow between consecutive frames with OpenCV's DIS algorithm - in both directions, forward and backward - then warps each frame along that flow and blends them at the intermediate position. Bidirectional matters: one-directional warping produces visible ghosting around moving edges, because the pixels you need have moved behind something. Doing both and cross-fading hides the occlusions.

blend is a straight cross-fade. It's the honest fallback when flow gets confused - and it will get confused, on flickering content or heavy grain, where there isn't a consistent motion vector to find. A soft double-exposure looks better than a smeared mess.

nearest repeats or drops frames. No new pixels, no artefacts, just a stutter. Occasionally exactly right.

The inputs and the fps rule

images needs at least two frames. speed is the factor: 0.5 is half speed (twice the frames), 2 is double. frames overrides it with an exact output length - set it to 0 to use speed.

Then the part that confuses everyone, and the pack handles it properly. Connect the fps of the frames you're feeding in (optional, 0 = unknown) and two extra outputs appear:

  • fps - the rate to play the result at. By speed, the fps stays the same and the slow or fast motion is in the frames, because you've added frames to a longer clip. By an exact frames count, the fps becomes fps × frames out / frames in, so the clip lasts exactly as long as it did before. That's the correct behaviour for both cases, and it's the kind of thing you'd otherwise work out on paper.
  • seconds - the length of the result at that fps.

frame_count is the plain number of output frames. Without an fps input, fps and seconds both come back 0, which is not a failure - just no information.

Where it goes in the chain

This is in the 2d / post group, and the pack's framing of that group is right: everything there works on one still or a batch of frames, before an export, and no models. Same goes here - it's OpenCV, milliseconds per frame, deterministic. There's no seed and no re-roll.

The sensible order for finishing a clip is: colour match to your reference, deflicker, then retime, then burn in. Retiming last-but-one because it invents frames, and you want the frames you're interpolating between to be the corrected ones - you don't want a deflicker pass chasing jumps that your own interpolation introduced.

And if you're generating with LTX, this is a cheap way to get slow motion out of a model that's famous for speed: generate a short clip at the length LTX likes, retime to 0.4, and you have a longer shot for the cost of one generation plus interpolation. That trade - generated frames are expensive, interpolated frames are nearly free - is the whole reason this node is here.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/kubakubkub/ComfyUI_KubaNodes
python -m pip install -r ComfyUI_KubaNodes/requirements.txt

Manager → kubakub nodes, or comfy node install comfyui-kubanodes. ComfyUI 0.37.0+. OpenCV is the only added package, and it's a genuine requirement here rather than a nicety - the optical flow is OpenCV.

No models, no Blender. Works on a bare install, which is a nice change if you've been fighting Blender subprocesses all day.

Gotchas

Optical flow does not know what scene it's looking at. A hard cut inside your batch produces a wild warp on that frame pair, because the algorithm is trying to find motion in a transition. Cut your clips before retiming, not after.

Flickering content hurts flow badly. If your source is a diffusion video with brightness jitter, either deflicker it first or use blend. This is the single most common cause of "interpolation made it worse".

The flow object is per-thread in the source - shared across threads it crashes the process. That's a ComfyUI-internal detail you never see, but it's why retiming is safe to run concurrently and why you shouldn't expect a --lowvram-style thread-count trick to break it.

Frames multiply in memory. 121 frames at 4K is already a lot. Retiming to 0.25 gives you 481. If you're near your RAM ceiling, retime at a lower resolution, or split the batch.

Categorykubakub/2d/post

Inputs (5)

NameTypeDefaultDescription
imagesIMAGEThe frames to retime (at least 2).
speedFLOAT0.500.05–16Below 1 = slow motion.
framesINT00–100000Exact output length instead of speed (0 = use speed).
modeCOMBOflowflow = moving in-betweens (optical flow); blend = cross-fade; nearest = repeat / drop frames.
fpsoptFLOAT0.0000–1000Frames per second of the frames you give (0 = unknown). Only for the fps and seconds outputs.

Outputs (4)

NameTypeDescription
imagesIMAGE—
frame_countINT—
fpsFLOATThe fps to play the result at (0 = no fps given). By speed: the same fps, the slow or fast motion is in the frames. By an exact frames count: fps x frames out / frames in, so the clip lasts as long as before.
secondsFLOATLength of the result in seconds at that fps (0 = no fps given).