Nodes/Comfyui-PT-Keyframe-Camera/Keyframe Camera (Pan & Zoom)
ComfyUI Node

Keyframe Camera (Pan & Zoom)

Pan, Zoom, and Rotate Any Image Sequence Before Your Video Model Butchers It

By ptmaster·Created about a year ago·Updated about a year ago· 24
Keyframe Camera (Pan & Zoom)
  • images
  • images
  • masks
start_frame0
end_frame24
start_horizontal_shift0
start_vertical_shift0
start_rotation0
start_zoom1.00
end_horizontal_shift100
end_vertical_shift0
end_rotation0
end_zoom1.00
zoom_origincenter
pad_modecolor
bg_color0, 0, 0

Ask a video model for "camera slowly pushes in" and you're gambling. Half the frames will push in, a few will do a weird lurch, and one will decide it's a close-up now. PT Keyframe Camera is the way to stop asking and start telling: it performs the camera move itself, pixel by pixel, and hands your pipeline a sequence that has already moved.

What it actually is

Despite the Hollywood framing in the README, this is a dead-simple image-processing node - no model, no API key, no weights, no hallucination. You feed it a batch of frames and it pans, zooms, and rotates between a start state and an end state, outputting the transformed sequence. The classic use, and the one the author's README is built around: take a single image, repeat it into frames, apply a camera move here, then feed the result into a Wan I2V workflow as a VACE control signal (depth or skeleton). Your camera move is now anchored in the control data, so the video model has to honor it instead of inventing one. It also works standalone to make motion-reference clips, or chained several deep for a handheld multi-shot feel - the author literally suggests stringing a few together to fake a shoulder-mounted camera.

How it works

Linear interpolation, nothing more. The node computes progress from start_frame and end_frame (0 before the start frame, 1.0 after, linear between), then lerps every parameter toward its "end" twin. Each frame gets bilinearly resized to its zoom level, rotated around center via grid sampling, and pasted onto a canvas of the original dimensions. Whatever the move exposes is filled according to pad_mode. It's fast and deterministic - this node is not your bottleneck, ever.

The inputs that matter

  • start_frame / end_frame - the timing of the move, not a frame subset. Every frame comes back; frames before start_frame hold the start values, frames after end_frame hold the end values. If you feed it 97 frames, you get 97 back.
  • start_horizontal_shift / end_horizontal_shift and the two vertical twins - sign is everything: positive = right/down, negative = left/up. This is the README's own #1 FAQ; get it backwards and your pan runs the wrong way and you'll swear the node is broken.
  • start_zoom / end_zoom - 1.0 means no zoom. Push-in is start < end.
  • zoom_origin - where zoom pivots: center, top-left, top-right, bottom-left, bottom-right.
  • pad_mode - "color" fills exposed borders with bg_color (default 0, 0, 0, a comma-separated RGB string - and the parser quietly falls back to black if you feed it garbage). "edge" extends the edge pixels instead, which is what you want when black bars would confuse a control model downstream.
  • start_rotation / end_rotation - ±360°. One gotcha: rotation expands the canvas to the rotated bounding box, so the corners become background. Budget that when you pick pad_mode.

The output you shouldn't ignore

It returns both images and masks. The mask is 0 where the transformed frame covers the canvas and 1 over the background - exactly what you need for compositing the original behind the move or telling a VACE/inpainting stage where the real content lives. A lot of people wire up only the images and then wonder why their edges look wrong.

Install

This is the easiest install you'll do all month. ComfyUI Manager → search "Comfyui-PT-Keyframe-Camera" (or "Keyframe Camera"), or:

cd ComfyUI/custom_nodes
git clone https://github.com/ptmaster/Comfyui-PT-Keyframe-Camera

Then restart ComfyUI. There's no requirements.txt, no model downloads, nothing beyond torch, which ComfyUI already ships. One note: it appears under the KJNodes/animation category, but it's not part of the KJNodes pack - it just borrows the shelf space, so don't go hunting for it in KJNodes' repo. The README is Chinese-first; if you need the details, let a translator chew on it.

Common gotchas

  • Wrong direction - check shift signs before anything else.
  • Black edges on control outputs - switch pad_mode to edge.
  • Shift ceiling - shifts cap at MAX_RESOLUTION (8192, a constant in the source). Only matters for absurd pans.
  • Output length - this node never truncates your sequence. If you're generating a specific frame count, do that before this node, not after.
CategoryKJNodes/animation

Inputs (14)

NameTypeDefaultDescription
imagesIMAGE
start_frameINT00–9999999
end_frameINT240–9999999
start_horizontal_shiftINT0-8192–8192Horizontal shift at start frame (positive=right, negative=left)
start_vertical_shiftINT0-8192–8192Vertical shift at start frame (positive=down, negative=up)
start_rotationINT0-360–360Rotation angle at start frame (degrees)
start_zoomFLOAT1.000.01–10
end_horizontal_shiftINT100-8192–8192Horizontal shift at end frame (positive=right, negative=left)
end_vertical_shiftINT0-8192–8192Vertical shift at end frame (positive=down, negative=up)
end_rotationINT0-360–360Rotation angle at end frame (degrees)
end_zoomFLOAT1.000.01–10
zoom_originCOMBOcenter5 options: center, top-left, top-right, bottom-left, bottom-right
pad_modeCOMBOcolor2 options: color, edge
bg_colorSTRING0, 0, 0RGB values (0-255) separated by commas

Outputs (2)

NameTypeDescription
imagesIMAGE
masksMASK