H3RelayRemovalWindow
The clean boundary frame that stops a removal drifting
- source
- anchor
- previous
- source_window
- anchor
- history_frames
- history_audio
Here's the problem a windowed person removal actually has to solve. You are removing someone one second at a time. Window two starts where window one stopped - but window one's last frame is generated, so the person is already gone. If window two is conditioned only on the original footage, it starts from a frame where the person still exists, and the seam is a visible and audible pop.
H3RelayRemovalWindow is the fix. It's internal - generated once per window by H3 Relay Person Remover when it expands into native nodes - and its whole purpose is to hand the sampler the right reference at the right offset.
The four outputs
source_window- the slice of green-masked source this window edits, padded to the window length by repeating the last frame if the clip runs out. This is the video reference<Video 1>.anchor- the clean boundary frame. On window one that'sclean_first_frame; on every later window it's framestartof what the model already generated, i.e. the person-already-removed picture. This is the image reference, and it's what keeps the reconstruction continuous instead of restarting.history_frames- up to 18 frames of generated video ending at that boundary, so the continuation has real temporal context rather than a naked first frame.history_audio- the same stretch of generated audio, sliced at 24 fps sample offsets, so the audio doesn't reset at every window either.
Note what's not here: the source person's pixels are never handed forward as a guide. The source is the thing being edited; the generated frames are the thing being continued. Mixing those two up is the difference between a clean removal and a window that re-invents a slightly different person each second.
Inputs
Required: source (the masked frames), anchor (the clean first frame) and start (this window's source-frame index). Optional: previous (the running state) and window_frames (default 22; must be a legal H3 size - 22, 39, 56 … 362).
Without previous, there is no generated history yet, so the node returns the anchor frame as both the anchor and the one-frame "history", plus a single silent 48 kHz sample of placeholder audio. That's the honest zero-history case, and it's only correct for window one.
With previous, the node demands a real boundary. It raises Missing generated boundary/history for source window if start is below 17 or beyond the end of what's been generated - the minimum start comes from the 18-frame history needing a boundary at frame 17 or later for continuations.
Why 22 frames, and why that number is load-bearing
H3's temporal grid is 17n+5. The removal default of 22 frames is not arbitrary: the continuation needs 18 frames of history, so a five-frame H3 clip simply cannot supply it. The author's own testing kept 22 as the proven default and treats larger windows as experiments - in a 77-frame test with 39-frame windows the opening window still contained the person even though the assembly and timing were correct. Bigger windows also mean a bigger in-memory latent, so the memory cost rises with the thing you were trying to save time on.
The planner walks windows window_frames - 1 frames apart (21 by default), shifting the final window backwards when needed and trimming the repeated boundary from the delivered output. For a 124-frame source the starts are 0, 21, 42, 63, 84, 102.
Install
Part of the pack:
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/akatz-ai/h3-relay.git
Manager → H3 Relay works too. You need ComfyUI 0.32.0+ with native H3 and SAM 3 nodes, FFmpeg on PATH, the Ref2VA/Qwen/VAE/SAM3 weights from the pack's manifest, and - still pending public release - the Person Remover LoRA, without which the graph won't run end-to-end.
Snags
- The removal flickers at a seam. Look at the preview cards either side. Usually the boundary frame is fine but the history is short because you reduced
window_frameswithout changing the history contract - the pack keeps history at 18 for every window size. - Source padded, output looks frozen. Tail padding repeats the last real frame to fill the H3 grid; assembly trims it back to your source frame count. If it survives into the output, the parent's
source_countis wrong. - First window keeps the person. Most often the mask, not the window logic - preview the green-masked source before blaming the render. Past 22 frames it can also be genuine model behaviour.
- GPU memory spikes with window size. This node's cheaper than the sampler, but it hands over a bigger latent. Stay at 22 unless you have headroom and patience.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| source | IMAGE | — | |
| anchor | IMAGE | — | |
| start | INT | 0 | — |
| previousopt | H3_REMOVAL_STATE | — | |
| window_framesopt | INT | 22 | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| source_window | IMAGE | — |
| anchor | IMAGE | — |
| history_frames | IMAGE | — |
| history_audio | AUDIO | — |