CPA Stitch
Hiding the seams between 49-frame LTX chunks
- chunk_0
- chunk_1
- chunk_2
- chunk_3
- chunk_4
- chunk_5
- chunk_6
- chunk_7
- chunk_8
- chunk_9
- chunk_10
- chunk_11
- chunk_12
- chunk_13
- chunk_14
- chunk_15
- chunk_16
- chunk_17
- chunk_18
- chunk_19
- chunk_20
- chunk_21
- chunk_22
- chunk_23
- alpha
CPA Stitch is what turns a pile of separately-rendered alpha chunks back into one continuous matte. If you've ever rendered a shot in pieces and spent an evening hunting a visible pop every 40 frames, this node exists to make sure you don't.
The constraint it's solving is baked into LTX: alpha-gen renders 49 frames at a time - its frame count has to be 8n+1 - so a 247-frame shot is six passes, not one. The pack overlaps neighbouring chunks and cross-fades them. The author's own note is that the joins end up measuring steadier than the rest of the shot, which is a nice accident of averaging two renders.
Inputs
plan is a JSON string the generator writes: frame count, height, width, chunk length, and the start frame of each chunk. You don't author it by hand - it's how the node knows which chunk belongs where in the timeline without you wiring up dozens of index nodes.
Then chunk_0 through chunk_23: up to 24 optional MASK inputs, positionally matched to the plan's start list. Twenty-four is the hard ceiling here and the reason the whole pipeline caps out around 960 frames at default settings - beyond that the generator stops with a message telling you to lower overlap frames or split the shot.
Each chunk is trimmed to the plan's dimensions, converted to float and averaged to a single channel if you hand it a 4-channel IMAGE - an older graph's output, which the node still tolerates.
How the blend works
Triangular, not linear. For frame k inside chunk i, the weight ramps up over the chunk's leading overlap and down over its trailing one, based on how many frames that chunk actually shares with its neighbours; the first chunk has no ramp-in and the last no ramp-out. Take the minimum of the two ramps and you've got a weight that's 1.0 in the chunk's solid middle and falls off on both overlap shoulders.
Then the accumulation is a weighted average - sum of frame × weight over sum of weights - rather than a max or a straight replace. That's the important choice. Max-combining alpha would leave a visible step wherever one chunk's edge sat a pixel inside the other's. Averaging tapers the transition across the whole overlap, and because the weights are normalised, exposure and density don't shift at the joins.
The output is one alpha MASK covering the whole processed range, h × w, float16. Straight into the final blend - or into the native-4K merge step, if you're on a plate that went through tiles.
Why float16 and not float32
Same reason as everywhere else in this pack: a 242-frame 1080p float32 alpha is 6 GB of RAM for a channel that VAE decoding has already rounded. The precision that matters is upstream, where the plate goes into the generative pass - the author's notes are explicit that a single 8-bit rounding of the isolated plate made LTX sample a visibly different edge, so anything feeding LTX stays full precision and anything coming out of the decoder can be half.
Install
Ships with the pack:
cd ComfyUI/custom_nodes
git clone https://github.com/rik-python/ComfyUI-Comfy-Pro-Alpha-Generator.git
pip install -r ComfyUI-Comfy-Pro-Alpha-Generator/requirements.txt
Restart ComfyUI. No models, no downloads, nothing to configure - the pack's requirements (opencv-python-headless, transformers, huggingface_hub, av) are for the other stages. ComfyUI 0.38 or newer, since the whole pack is built on the V3 node API, and the licence is non-commercial unless you buy one.
When a seam still shows
If you can see a join, the fix isn't here - it's the overlap frames setting on the generator, which defaults to 9 shared frames (a new chunk every 40). Raising it to 17 costs you more chunks, which costs time, and it's the right move if a join is visible in motion. The README's suggestion to check a preview before committing to a full render is the practical version of this advice: a pop you can't see at 49 frames is usually a pop that isn't there.
And the ceiling catches people. More than 24 chunks and the render refuses to start; you'll see the frame count and the required chunks in the error. Long shots get split into runs, which is fine - just keep the first_frame numbering consistent so the two halves sit together again in comp.
One thing this node won't fix: frames before your pick. The matte starts where you clicked, so everything earlier is empty and stays empty through the stitch. Pick early, or split the shot.
Inputs (25)
| Name | Type | Default | Description |
|---|---|---|---|
| plan | STRING | — | |
| chunk_0opt | MASK | — | |
| chunk_1opt | MASK | — | |
| chunk_2opt | MASK | — | |
| chunk_3opt | MASK | — | |
| chunk_4opt | MASK | — | |
| chunk_5opt | MASK | — | |
| chunk_6opt | MASK | — | |
| chunk_7opt | MASK | — | |
| chunk_8opt | MASK | — | |
| chunk_9opt | MASK | — | |
| chunk_10opt | MASK | — | |
| chunk_11opt | MASK | — | |
| chunk_12opt | MASK | — | |
| chunk_13opt | MASK | — | |
| chunk_14opt | MASK | — | |
| chunk_15opt | MASK | — | |
| chunk_16opt | MASK | — | |
| chunk_17opt | MASK | — | |
| chunk_18opt | MASK | — | |
| chunk_19opt | MASK | — | |
| chunk_20opt | MASK | — | |
| chunk_21opt | MASK | — | |
| chunk_22opt | MASK | — | |
| chunk_23opt | MASK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| alpha | MASK | — |