Nodes/Compensate Drift (Auto Align First+Last)/Compensate Drift (Auto Align First+Last)
ComfyUI Node

Compensate Drift (Auto Align First+Last)

Your loop drifts because the camera moved. This node measures it and locks every frame down

By amagicai·Created 21 days ago·Updated 21 days ago· 0
Compensate Drift (Auto Align First+Last)
  • images
  • images
max_features300
min_matches15
anchor_frameauto
transformaffine
interplog
upscale_methodbicubic
drop_last_frames1
mix_first_lastoff

Here's the failure mode that sent you here: you generated a clip with a fixed first frame and last frame - the Wan2GP / first-last-frame trick, the AnimateDiff-era loop habit - and when it plays back, the framing slowly drifts. The camera creeps in, or out, or pans a hair, and by the last frame it doesn't line up with the first, so your "seamless loop" has a visible jump where the wrap should be. Older fixes for this just applied a blind programmatic zoom, which never matches what the model actually did.

Compensate Drift (Auto Align First+Last) is the version that actually looks. It matches the first frame and last frame to each other, works out the real geometric motion between them, and warps every intermediate frame so the whole batch shares one framing.

What it actually does

Mechanically it's a passthrough: IMAGE batch in, IMAGE batch out, one node sitting between your VAE Decode and the video writer. Inside, it runs ORB feature detection on the first and last frames, brute-force matches the Hamming descriptors, keeps only confident matches with Lowe's ratio test (the closest match has to beat the second-closest by ~30%), then fits a global transform with RANSAC. Nothing is assumed about the motion - it can be zoom, pan, rotation, shear, or any affine mix, in either direction.

The clever bit is the anchor. It picks whichever endpoint is more zoomed-in (you can see which way the drift went in the console log as last->first framing det=...). Anchoring to the more zoomed-in frame means every per-frame warp is a magnification - it crops away border detail rather than re-synthesizing pixels that don't exist. Zoom the other way and you get soft, hallucinated edges at the borders.

Per-frame transforms are interpolated in the affine Lie algebra (interp = "log", the default) rather than by lerping matrix coefficients, so a zoom ramps its scale factor exponentially and the motion looks like constant velocity. You mostly never touch this; just know linear makes the zoom decelerate as it approaches the target.

Inputs that matter

Almost all the defaults are sane. The ones worth your attention:

  • transform (affine default, similarity, radial). Affine handles full x/y scale and shear. Drop to similarity if your footage is noisy - it's a rigid-ish 4-dof fit that can't chase phantom stretch. radial is a different animal: it corrects barrel/pincushion distortion only, and it's mutually exclusive with the affine family, because a zoom and a radial distortion are mathematically confounded. Pick whichever actually describes your footage.
  • anchor_frame (auto default). auto anchors to the more zoomed-in endpoint. Force first or last only if you want the whole clip re-framed to that one.
  • drop_last_frames (default 1) trims trailing frames - which is exactly what you want, since the last frame is redundant once it's aligned to the first.
  • mix_first_last (off default). Set this to on and the output's first frame becomes the 50/50 average of the aligned first and the dropped last. That hides the last few pixels of interpolation noise at the wrap. Costs a touch of softening in frame 0; worth it for a real loop.

Everything flows out one output, images, straight into your video encoder.

Installing it

No models, no heavy deps - it only needs torch and opencv-python, which ComfyUI already ships, so this is the rare painless install:

cd <your-ComfyUI-dir>/custom_nodes
git clone https://github.com/amagicai/seamless_loop.git

Then restart ComfyUI. ComfyUI Manager also finds it if you search "seamless_loop". The node shows up under image/batch as "Compensate Drift (Auto Align First+Last)".

Where people get burned

Mostly by expecting it to fix the other kind of drift. This node registers camera/framing motion - it will happily correct a subtle zoom. It will not fix a first frame and last frame that are different scenes, or where the subject visibly morphs between endpoints. If the drift is semantic content change (the thing that makes long chained video fall apart), ORB matching will find few or no good correspondences, the batch passes through unchanged, and you'll see it in the logs. Flat, featureless frames (clear sky, blank walls) hit the same fallback - fewer than min_matches keypoints means no registration, though drop_last_frames still applies.

That's also the clue when output looks identical to input: it's not broken, it's the graceful-failure path doing its job. Check the console for lines prefixed [seamless_loop] - they log match counts, the anchor chosen, and whether the loop closed. Two honest caveats: the warps run through OpenCV on CPU float32, so a long high-res batch takes a while (the data isn't quantized to 8-bit, so precision survives), and if your footage is already loopable, the 50/50 first-frame blend is the only change you'll notice.

Categoryimage/batch

Inputs (9)

NameTypeDefaultDescription
imagesIMAGE
max_featuresINT30020–5000
min_matchesINT155–500
anchor_frameCOMBOauto3 options: auto, first, last
transformCOMBOaffine3 options: affine, similarity, radial
interpCOMBOlog2 options: log, linear
upscale_methodCOMBObicubic5 options: nearest-exact, bilinear, area, bicubic, lanczos
drop_last_framesINT10–1000
mix_first_lastCOMBOoff2 options: off, on

Outputs (1)

NameTypeDescription
imagesIMAGE