Nodes/ComfyUI-CustomNodePacks/Fluid Shot Encoder (Temporal Normalizer)
ComfyUI Node

Fluid Shot Encoder (Temporal Normalizer)

Speed ramps are poison to AI video — Fluid Shot Encoder fixes that

By Code2Collapse·Created 6 months ago·Updated a day ago· 52
Fluid Shot Encoder (Temporal Normalizer)
  • images
  • normalized_images
  • time_map
max_px_per_frame5.0

Fluid Shot Encoder (Temporal Normalizer) solves a problem you meet the first time you run an AI video model on anything but boring constant-speed footage: fast motion breaks video diffusion models. Wan and friends are trained on footage where things move a bounded amount per frame. Feed them a speed ramp - a slow push that suddenly whips across a scene - and the fast section comes back warped, doubled, or mush. The model simply isn't built for that much inter-frame displacement.

This node's answer is elegant: it measures the actual motion per frame (optical flow), and where the motion exceeds your chosen limit, it inserts flow-warped in-between frames so every step of the output stays under the cap. Feed the result to your video model, then use the pack's Fluid Shot Decoder to restore the original timing on the other side. You get AI-processed video that preserves your speed ramp instead of fighting it.

It's part of the MEC/Temporal family in ComfyUI-CustomNodePacks, the ~72-node pack from Code2Collapse (Likhith-24, active on r/comfyui).

How it works

  • It computes the optical flow between consecutive frames and takes the 95th-percentile displacement as the motion estimate.
  • max_px_per_frame (default 5.0) is the ceiling: if a frame pair moves more than that, it warps intermediate frames along the flow - backward-warping both endpoints and cross-fading - until each step is under the limit.
  • The output is normalized_images (the expanded batch) plus a time_map (TIMEMAP type) recording, for every output frame, which source frame + fractional position it corresponds to.

That time map is the crucial bit - it's the receipt the Decoder uses to pull the original frames back out. If flow computation fails on a pair, the node degrades gracefully (linear blend, then duplicate) and logs a warning instead of crashing.

The input that matters: max_px_per_frame. Lower = smoother but more inserted frames (slower, and the decoder throws more away); higher = closer to your source. 5px is a sensible default for typical 512-1024px video; drop toward 2-3 for fast action you really care about.

Wiring it

[Video with speed ramp] → Fluid Shot Encoder
                            ├── normalized_images → [Wan/any video sampler] → processed
                            └── time_map ──────────────────────────────────→ Fluid Shot Decoder
                                     processed (expanded batch) → Fluid Shot Decoder → original timing

Encoder and Decoder are a pair - don't feed a time_map into anything else, and don't run the Decoder without the Encoder's map (it raises a clear error if the map isn't a Fluid Shot TIMEMAP).

Installing it

Ships in ComfyUI-CustomNodePacks. ComfyUI Manager → search "CustomNodePacks", or:

cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git

It needs opencv-python (the flow and warp are cv2) - that's a required pack dependency, so install it if missing:

pip install opencv-python>=4.7.0 scipy>=1.10.0

(Install just what's missing; the README warns the full requirements.txt can overwrite ComfyUI's torch.) Restart ComfyUI.

Common issues

  • "time_map is not a Fluid Shot TIMEMAP" - you wired the wrong thing into the Decoder, or a stale map. Re-wire from the Encoder's time_map output.
  • Batch length mismatch at the Decoder - AI models trim or pad frames (Wan famously wants 4n+1). The Decoder detects this and rescales the map proportionally rather than erroring - so a slight frame-count shift degrades gracefully.
  • Inserted frames look soft - flow-warped in-betweens are interpolations, not new content; that's expected. The Decoder removes them on the way back out, so the final output only contains real source frames.

The honest take: this is a niche but genuinely clever workflow-level fix, and the Encoder/Decoder pairing is the kind of "do the temporal bookkeeping for the user" thinking that most packs skip. If you never shoot speed ramps, you won't need it - if you do, nothing else in the ecosystem does this.

CategoryMEC/Temporal

Inputs (2)

NameTypeDefaultDescription
imagesIMAGEVideo frames [B,H,W,C] 0-1. Speed-ramped source.
max_px_per_frameFLOAT5.00.5–100Max allowed pixel displacement between consecutive output frames (95th-percentile optical-flow magnitude). Fast sections get flow-warped in-betweens until each step is under this.

Outputs (2)

NameTypeDescription
normalized_imagesIMAGE
time_mapTIMEMAP