CPA TileMerge
Feather-blending 4K strands back into one alpha
- tile_0
- tile_1
- tile_2
- tile_3
- tile_4
- tile_5
- tile_6
- tile_7
- tile_8
- tile_9
- tile_10
- tile_11
- tile_12
- tile_13
- tile_14
- tile_15
- tile_16
- tile_17
- tile_18
- tile_19
- tile_20
- tile_21
- tile_22
- tile_23
- tile_24
- tile_25
- tile_26
- tile_27
- tile_28
- tile_29
- tile_30
- tile_31
- tile_32
- tile_33
- tile_34
- tile_35
- tile_36
- tile_37
- tile_38
- tile_39
- tile_40
- tile_41
- tile_42
- tile_43
- tile_44
- tile_45
- tile_46
- tile_47
- tile_48
- tile_49
- tile_50
- tile_51
- tile_52
- tile_53
- tile_54
- tile_55
- tile_56
- tile_57
- tile_58
- tile_59
- tile_60
- tile_61
- tile_62
- tile_63
- tiles
- coverage
CPA TileMerge is the closing bracket on the native-4K feature: it takes the per-tile alpha renders and blends them into full-resolution frames, plus a second output saying how much of each pixel is actually backed by a rendered tile.
If you've ever tiled an upscale, you know the failure mode this node is guarding against - visible rectangular seams where two tiles met, because someone blended them with an equal-weight average instead of a proper falloff. Alpha makes it worse than colour: a seam in a matte is a line that survives into the comp.
Inputs
plan is JSON written by the pack's native-edges stage, and it carries four things: the frame count n, the native W and H, the full tile grid as (x, y, w, h) rectangles, and used - the indices of the tiles that actually got rendered. That last list is the important one. Tiles are chosen per shot by finding the ones that touch the subject's edge band on any frame, so a wide shot with a small subject might need three tiles out of twenty.
Then tile_0 through tile_63, MASK inputs positionally matched to used. Sixty-four is the ceiling, which works out to roughly 10K-wide plates; past that the pipeline asks you to switch native edges off or crop.
Outputs
tiles is the blended native-resolution alpha - the feathers already applied, one full-frame mask per frame of the range.
coverage is the honest one, and it's what makes the merge trustworthy. It's rendered weight divided by the weight the whole grid would have contributed, so it's 1.0 in the middle of a rendered tile, and it fades out where a rendered tile overlaps one that was never rendered. No hard step at that border. Because the tile set is fixed for the whole range, this is computed once and stored as a single frame rather than per frame.
The merge step downstream uses coverage to decide how much to trust the tiles. That's the design in one line: the proxy alpha keeps the subject's solid core and every big decision, and the tiles supply strands only where they actually have them.
How the feathering works
Each tile's weight ramps only where it genuinely overlaps a neighbour - half of the overlap distance - and stays flat at the plate border. So a tile at the frame edge isn't faded for no reason, and two tiles sharing a strip cross-fade across exactly that strip. The blend accumulates weighted sums and then divides by total weight, which means the alpha is normalised: no density bump in the overlap, no dip.
One consequence worth knowing: the tile set is chosen for the whole shot, not per frame. If your subject drifts into a corner on frame 200, the tile that covers that corner was already rendered for the entire range, or it wasn't rendered at all. That's a deliberate memory trade - per-frame tile selection would mean a different graph for every frame.
Install
Part of the pack - nothing separate to fetch:
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 of its own; it's pure numpy on masks that other stages produced. You'll want the two companion packs - ComfyUI-SAM3 and ComfyUI-LTXVideo - for anything upstream of it to run, and roughly 25 GB of LTX-2.5 weights for the render itself. ComfyUI 0.38+, and the pack's licence is non-commercial unless you arrange otherwise with the author.
Where it goes wrong
Two failures, both loud.
More than 64 tiles and the pipeline refuses with the plate size and the tile count. That's about 10K wide, so you'd need to be doing something unusual - but if you are, crop or switch native_edges off rather than waiting for a render to die.
And if SAM3 never found the subject across the whole range, zero tiles get rendered and this node isn't called at all; the final stage just keeps the scaled-up proxy alpha. That's the graceful path, and it's why a 4K render can finish suspiciously fast - check the console's native edges: N of M tiles line before you trust a matte that arrived early.
The subtler issue isn't a bug. Edges near another person deliberately keep the proxy result, because a tile only sees part of the frame and makes worse decisions about who's in front. If you're staring at one 1080p-soft edge on an otherwise crisp 4K matte, look for a shoulder or a hand in the frame - that edge was never going to be sharp.
The honest summary
This is the node that makes the 4K claim real, and the pack's own numbers show you what you're paying: 58 minutes and 97 GB of RAM for a 242-frame UHD shot with native edges on, against 19 minutes and 73 GB with them off. It gains most on single strands, flyaways and fur; thick hair barely moves. So the switch is a genuine creative decision, not a quality slider to leave cranked. Turn it on for finals with fine hair against a background, off for triage and for braids.
Inputs (65)
| Name | Type | Default | Description |
|---|---|---|---|
| plan | STRING | — | |
| tile_0opt | MASK | — | |
| tile_1opt | MASK | — | |
| tile_2opt | MASK | — | |
| tile_3opt | MASK | — | |
| tile_4opt | MASK | — | |
| tile_5opt | MASK | — | |
| tile_6opt | MASK | — | |
| tile_7opt | MASK | — | |
| tile_8opt | MASK | — | |
| tile_9opt | MASK | — | |
| tile_10opt | MASK | — | |
| tile_11opt | MASK | — | |
| tile_12opt | MASK | — | |
| tile_13opt | MASK | — | |
| tile_14opt | MASK | — | |
| tile_15opt | MASK | — | |
| tile_16opt | MASK | — | |
| tile_17opt | MASK | — | |
| tile_18opt | MASK | — | |
| tile_19opt | MASK | — | |
| tile_20opt | MASK | — | |
| tile_21opt | MASK | — | |
| tile_22opt | MASK | — | |
| tile_23opt | MASK | — | |
| tile_24opt | MASK | — | |
| tile_25opt | MASK | — | |
| tile_26opt | MASK | — | |
| tile_27opt | MASK | — | |
| tile_28opt | MASK | — | |
| tile_29opt | MASK | — | |
| tile_30opt | MASK | — | |
| tile_31opt | MASK | — | |
| tile_32opt | MASK | — | |
| tile_33opt | MASK | — | |
| tile_34opt | MASK | — | |
| tile_35opt | MASK | — | |
| tile_36opt | MASK | — | |
| tile_37opt | MASK | — | |
| tile_38opt | MASK | — | |
| tile_39opt | MASK | — | |
| tile_40opt | MASK | — | |
| tile_41opt | MASK | — | |
| tile_42opt | MASK | — | |
| tile_43opt | MASK | — | |
| tile_44opt | MASK | — | |
| tile_45opt | MASK | — | |
| tile_46opt | MASK | — | |
| tile_47opt | MASK | — | |
| tile_48opt | MASK | — | |
| tile_49opt | MASK | — | |
| tile_50opt | MASK | — | |
| tile_51opt | MASK | — | |
| tile_52opt | MASK | — | |
| tile_53opt | MASK | — | |
| tile_54opt | MASK | — | |
| tile_55opt | MASK | — | |
| tile_56opt | MASK | — | |
| tile_57opt | MASK | — | |
| tile_58opt | MASK | — | |
| tile_59opt | MASK | — | |
| tile_60opt | MASK | — | |
| tile_61opt | MASK | — | |
| tile_62opt | MASK | — | |
| tile_63opt | MASK | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| tiles | MASK | — |
| coverage | MASK | — |