Fluid Shot Encoder (Temporal Normalizer)
Speed ramps are poison to AI video — Fluid Shot Encoder fixes that
- images
- normalized_images
- time_map
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 atime_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_mapoutput. - 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.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Video frames [B,H,W,C] 0-1. Speed-ramped source. | |
| max_px_per_frame | FLOAT | 5.00.5–100 | Max 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)
| Name | Type | Description |
|---|---|---|
| normalized_images | IMAGE | — |
| time_map | TIMEMAP | — |