ResizeTrajectories
Resize your motion trajectories to match the resized frames
- trajectories
If you've ever annotated motion - drawing a path for a subject to follow through a video - you know the coordinates live in the pixel space of the source frame. Change the resolution and every one of those points points at the wrong place. That's the entire job of ResizeTrajectories: it takes trajectory data as a JSON string and scales every point by the same ratio you used on the frames, so your paths stay glued to the same spots.
It ships in the same pack as ResizeImageBatch, the "payload" that powers Zeptaframe - an AI-native video editor that implements the Go-with-the-Flow technique, where you control generation by specifying motion flows instead of typing prompts. In that pipeline the editor resizes frames, and the trajectories have to follow or the whole control signal drifts off the subject. This node is that follow.
How it works
The source is short enough to read in a sitting. You give it the original frame size, the new frame size, and the JSON, and it does the math you'd do by hand:
scale_x = output_width / input_width
scale_y = output_height / input_height
Then it walks the structure - for each trajectory, for each point, multiply x and y by the scale factors, round to integers, and hand the whole thing back as JSON. No interpolation, no smoothing, just proportional rescaling.
The inputs that matter
- input_width / input_height - the resolution the trajectories were drawn on. Note that
input_heightisforceInput: there's no widget, you must wire it from an INT source. That's a deliberate design, not a bug. - output_width / output_height - the target resolution. Match these to whatever you resized the frames to (easy if you take them from ResizeImageBatch's
widthandheightoutputs). - trajectories - the JSON string. The code expects a list of trajectories, each a list of
{"x": ..., "y": ...}points. Get the shape wrong and it throws or silently produces garbage.
Output: one trajectories string with the rescaled JSON - feed it straight back into whatever consumes trajectory data downstream.
Where people get burned
- The rounding is truncation, not rounding. The code uses
int(), so a point at 1.9 becomes 1. On a big downscale individual points can drift by a pixel or two. Usually invisible; not great if you need sub-pixel precision. - The format is strict. This isn't a general "scale any JSON" tool. It's hardcoded to the list-of-trajectories /
x,yshape. If your data uses different keys or is a flat list of points, it won't do what you want. - It can't infer the source size. You supply
input_widthandinput_heightby hand, and if they're wrong, everything scales wrong. There's no "read it from the image" option - wire the size in from the image node yourself.
Installing it
Same pack, same steps as ResizeImageBatch. ComfyUI Manager: search ComfyUI-ResizeZeptaPayload, install, restart. Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/Pablerdo/ComfyUI-ResizeZeptaPayload
# restart ComfyUI
No models to download. The repo's requirements.txt lists a pile of extras, but the shipped code only uses what ComfyUI already ships - skip the pip step.
Honest assessment: this is a genuinely thin utility, and outside the Zeptaframe / Go-with-the-Flow world (or your own custom motion-control pipeline) you don't need it. But if you are generating video from motion trajectories, it's the thing that keeps your annotations valid after a resolution change - and the fact that you could rewrite it in fifteen minutes tells you exactly how much node is here.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| input_width | INT | 1024 | — |
| input_height | INT | — | |
| output_width | INT | 1024 | — |
| output_height | INT | 1024 | — |
| trajectories | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| trajectories | STRING | — |