Transform Keyframes (Math)
Smooth Pan and Zoom Keyframes Without the Math
- transform_data
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-outunless 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.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| start_x | INT | 0-8192–8192 | — |
| end_x | INT | 100-8192–8192 | — |
| start_y | INT | 0-8192–8192 | — |
| end_y | INT | 100-8192–8192 | — |
| start_scale | FLOAT | 1.000.01–100 | — |
| end_scale | FLOAT | 1.000.01–100 | — |
| frames_count | INT | 161–100000 | — |
| easing_mode | COMBO | ease-in-out | 4 options: linear, ease-in, ease-out, ease-in-out |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| transform_data | TRANSFORM_DATA | — |