Match Cut By Motion
A cheap way to find where two clips join seamlessly
- video_a
- video_b
- best_frame_b
- match_score
- summary
The classic cut, automated the cheap way
A match cut is when you cut from clip A to clip B at the moment both have similar framing and similar motion - think the bone-to-spaceship moment in 2001, minus the artistry. MKRMatchCutByMotion is the node that finds the right frame in B to cut to so the join doesn't feel like a jarring jump.
It comes from MKRShift_Nodes, the utility pack by Cris K B, and it sits in the video/edit area. No models, no optical-flow library - it's numpy on grayscale frames, which is exactly why it's fast.
How it works
The logic is simple and readable if you peek at the source:
- It takes the last frame of
video_aas your reference, plus the second-to-last frame to measure the motion that was happening at the moment of the cut. - It walks the first
search_window_framesframes (default 48) ofvideo_b. - For each candidate frame it scores two things: how different its brightness (luma) is from A's last frame, and how different its motion magnitude is from the motion at the end of A. Motion magnitude here is just the average per-pixel brightness change from the previous frame - crude, but it captures "is stuff moving, and how much."
- The final score is
luma_difference + 0.5 × motion_difference. Lower is better. The frame with the lowest score wins.
So it's a heuristic, and an honest one - it matches overall brightness and overall motion energy, not shapes or content. Two clips of a busy street will "match" each other even if different cars are in them. That's fine for a jump-cut smoothing tool and wrong for a semantic match cut. Know what you're getting.
The outputs
Three, and none of them is a video - this node finds the cut, it doesn't make it:
best_frame_b(INT) - the frame index in B where the cut should land. This is the number you feed into a trim or a frame-range node.match_score(FLOAT) - the score at that frame; lower is better. Use it to decide whether the match is worth using at all (a high score means there's no good cut point, and forcing it will look worse than a straight cut).summary(STRING) - JSON with the chosen index, score, window size, and warnings.
If either input has fewer than 2 frames, you get best_frame_b = 0, a huge score, and a warning.
Install and using it
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart, or install "MKRShift Nodes" via ComfyUI Manager. No pip deps, no models. It decodes video, so ffmpeg needs to be on PATH.
The honest workflow: run it, look at match_score, and let it narrow a manual edit rather than trusting it blind. The 0.5 motion weight is a fixed tuning choice in the source - if your footage is mostly static, the motion term barely matters and it's basically a luma matcher, which is fine. Where people get burned is expecting a finished edit out of it. It's a suggestion node, and it's very good at being one.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| video_a | * | — | |
| video_b | * | — | |
| search_window_frames | INT | 481–10000 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| best_frame_b | INT | — |
| match_score | FLOAT | — |
| summary | STRING | — |