Zura · Reset Tracking at Cuts
Stop your tracker from chasing one person across two shots
- images
- shot_frames
- shot_first_frames
- tracking_segments
Cut detection is one line of maths and a surprising amount of consequence. When the shot cuts from your actor to a different person, a tracker that's held an identity across the edit will happily keep the box it had - on someone else's face. This node splits the frame batch at the cuts before tracking runs, so each shot gets its own detection pass.
The description says it plainly: "Split hard cuts before native tracking, then review every shot for the correct person." Note the second half. This node doesn't know who your actor is. It just refuses to let the tracker guess.
Inputs and outputs
One input, images - a batch you'd normally be about to feed to native tracking. It goes through cut analysis on cheap CPU thumbnails: frames are downscaled to 32×32 in blocks of 32, so a long clip doesn't get duplicated in memory just to find the edits. The threshold is fixed at 0.2, and unlike the sampler's cut_threshold there's no widget to tune it here.
Three outputs, and the first two are lists:
shot_frames- one image batch per shot. This is the output you map over native tracking with ComfyUI's list behaviour, so each shot gets tracked independently.shot_first_frames- one single-frame batch per shot, in the same order. Useful for per-shot detection, prompts, or a quick visual check of what each shot opens on.tracking_segments- a metadata object describing the segments. It travels alongside the masks so a later node can rejoin them without guessing where the cuts were.
That third output is the important one structurally. The companion node Zura · Rejoin Tracked Shots consumes it and rebuilds one mask over the full timeline - and it checks, hard, that the segments cover the source exactly once, in order, contiguous, with cuts matching segment starts. You get an error instead of a silently misaligned mask.
How the segments are built
Frames are compared on their thumbnails, cut positions come out as frame indices, and the boundaries become [0, *cuts, count] - so the first segment always starts at 0 and the last one always ends at the final frame. Each segment carries start, end and frames. A cut at frame 0 or at the very last frame is rejected as invalid rather than producing a zero-length segment.
The pack uses the same detector in the Wan sampler's Detect cuts shot mode, which is not a coincidence: shots here and shots there are meant to mean the same thing, so the mask you tracked per shot lines up with the windows the renderer restarts continuation at. That consistency is the real value. A cut that's a cut for the mask but a continuation for the sampler is a guaranteed artefact.
Install
Ships with the pack:
cd ComfyUI/custom_nodes && git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
pip install -r ComfyUI_zura_nodes/requirements.txt
Or Zura Nodes from ComfyUI Manager, then restart. This node itself is pure PyTorch on CPU - no model downloads, no extra packs. You'll need whatever native detection/tracking nodes you're mapping over, and those come from ComfyUI-WanAnimatePreprocess (and any segmentation pack you're using), which the pack lists as a real dependency for the WanAnimate path.
Common issues
A fast flash or a whip pan got treated as a cut. That's the fixed 0.2 threshold and the 32×32 thumbnail comparison doing their job slightly too well. There's no dial here. If it's a problem, split manually - the Wan sampler's Manual cuts mode takes explicit frame numbers, and you can build the mask segments to match - or accept that a two-frame false cut costs you one extra detection pass and a hard restart in continuity.
"Tracking frames must be an IMAGE batch." Something upstream is passing a list or a single frame where a batch is expected. If you're already downstream of another list-mapping node, you're now handling per-shot batches, and this node doesn't want that - it wants the whole timeline.
Downstream node complains that segments don't cover all frames. You edited or resampled the frames between this node and the rejoin. The segment metadata is validated against the actual frame count, so any clip that got trimmed, padded or re-decoded in between fails the check rather than producing a mask that's off by a few frames at one cut.
Every shot detected as one shot on a hard cut. A dissolve isn't a cut. This is structural detection, not semantic - a slow crossfade may genuinely not trip it, and that's a limitation of the approach, not a bug.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| shot_frames | IMAGE | — |
| shot_first_frames | IMAGE | — |
| tracking_segments | GENJ_TRACK_SEGMENTS | — |