Nodes/Image Processing Suite for ComfyUI/Transform Keyframes (Math)
ComfyUI Node

Transform Keyframes (Math)

Smooth Pan and Zoom Keyframes Without the Math

By marcoc2·Created 2 years ago·Updated 5 months ago· 1
Transform Keyframes (Math)
    • transform_data
    start_x0
    end_x100
    start_y0
    end_y100
    start_scale1.00
    end_scale1.00
    frames_count16
    easing_modeease-in-out

    The Ken Burns effect - a slow pan or zoom over an image - is one of the highest-ROI animations in video generation: a still photo becomes a "camera move" with about three minutes of work. The hard part isn't compositing, it's generating the per-frame positions: you want x/y/scale values for frame 1, frame 2, all the way to frame N, and you want them to ease in and out so the motion doesn't feel like a robot sliding a card. AnotherTransformKeyframes does exactly that math, and hands the result to the pack's compositor. It's the "make it move" node of the AnotherUtils animation stack.

    It's from marcoc2/ComfyUI-AnotherUtils, and it's deliberately simple: a start value, an end value, a frame count, an easing curve. If your whole animation is "pan from here to there," this is the node - the AnotherTransformOrchestrator sibling exists only when you want a long sequence of randomized segments instead of one clean move.

    How it works

    It's a linear interpolation with a curve applied. You define start and end for X, Y, and scale, plus the total frame count. For each frame it normalizes the time t = i / (frames - 1), runs it through the selected easing function, and lerps each parameter. The easing options are the standard four: linear, ease-in, ease-out, and ease-in-out (the default - slow start, slow stop, which is what makes camera moves feel cinematic rather than mechanical). The result is a list of per-frame dicts - {x, y, scale} - passed along as TRANSFORM_DATA.

    The inputs

    The full set is start/end X, start/end Y, start/end scale, frames_count, and easing_mode. In practice you'll set these:

    • start_x/end_x, start_y/end_y - the pan path in pixels. Remember these are destination-coordinate offsets, so positive X moves the source right (and the pack's compositor interprets them that way).
    • start_scale/end_scale - zoom, where 1.0 is 100%. Pan with 1.0→1.15 for a slow push-in, 1.15→1.0 for a pull-back.
    • frames_count - how many frames to generate, i.e. your clip length at your chosen FPS.
    • easing_mode - ease-in-out unless you have a reason not to.

    What comes out

    A single transform_data output of type TRANSFORM_DATA - the per-frame list. It feeds directly into AnotherAnimatedCompositeMasked, which does the actual compositing of your image over the background using those values.

    Installing it

    Standard AnotherUtils install:

    cd ComfyUI/custom_nodes
    git clone https://github.com/marcoc2/ComfyUI-AnotherUtils.git
    

    Restart ComfyUI, or search "AnotherUtils" in ComfyUI Manager. No models, no dependencies.

    Where people get burned

    The classic mistake is treating scale as a percentage - it's a multiplier, so "zoom to 115%" means 1.15, not 115. The second is forgetting the compositor's anchor mode: with center anchoring (the default), your x/y is the layer's center point, so a pan "to the right" needs coordinates that account for the half-width offset or the layer drifts oddly. And remember this node only generates the numbers - no compositing happens until you wire transform_data into AnotherAnimatedCompositeMasked. A very common dead end is generating keyframes, seeing nothing happen, and realizing the wire to the compositor was never connected.

    CategoryAnotherUtils/animation

    Inputs (8)

    NameTypeDefaultDescription
    start_xINT0-8192–8192
    end_xINT100-8192–8192
    start_yINT0-8192–8192
    end_yINT100-8192–8192
    start_scaleFLOAT1.000.01–100
    end_scaleFLOAT1.000.01–100
    frames_countINT161–100000
    easing_modeCOMBOease-in-out4 options: linear, ease-in, ease-out, ease-in-out

    Outputs (1)

    NameTypeDescription
    transform_dataTRANSFORM_DATA