ComfyUI Node

TF Region Map

The semantic parts that edits actually operate on

By KorayUlusan·Created 3 days ago·Updated about 21 hours ago· 1
TF Region Map
  • levels
  • regions
  • map
  • level
level2
cosine_threshold0.90
size512

In the Trajectory Forcing paper, edits are written in terms of regions R - semantic parts of the image that share a feature identity - not in terms of arbitrary sets of pixels or tokens. TF Region Map is where those R come from. It takes one level of a trajectory and clusters its 16×16 token grid into connected regions by cosine similarity of the DINOv2 features, and those clusters turn out to line up with the things you'd want to edit: the background, the subject, its parts. Every downstream selection tool and edit node in this pack can snap to these regions, and that's the point - edit a whole region, not an arbitrary scribble.

The mechanism is straightforward: tokens whose feature vectors are close (by cosine) get unioned into connected components, and cosine_threshold (default 0.9, range 0.5–0.99) decides how close "close" is. Raise it and you get more, smaller regions; lower it and clusters merge into larger ones. The 0.9 default is chosen to match the editing environment this pack wraps, so start there and only move it when a region boundary clearly doesn't match what you'd call an object part. level picks which hierarchy rung to cluster - default 2, the subparts level and the pack's usual editing canvas - and size is just the preview resolution.

Its three outputs are where the design gets clever. regions (the TF_REGIONS socket) feeds any node that can snap to regions: TF Tokens From Coords, TF Tokens From Mask, TF Level Canvas (which draws the boundaries), TF Shape Edit, and TF Sweep Edit. map is an IMAGE of the region coloring so you can look at what you got. And level - an INT output carrying the level these regions describe - exists to be wired into an edit node's level input so the two cannot drift apart. That's not paranoia; it's the single most common edit bug in this pack. A selection snapped to level 2's regions applied at level 3 lands on the wrong semantic parts with no error, and the README's troubleshooting section exists largely for this. Wire the level output and the problem can't happen.

The error messages when it does go wrong are unusually good, worth knowing by sight: "built from level N's regions but is being applied at level M" means exactly what it says - point TF Region Map at the level you're editing. A region map also inherently describes one level, which is why TF Sweep Edit refuses to sweep the level axis when you've wired regions in for a shape edit.

The honest caveat: region maps are a property of a specific level of a specific trajectory, so they don't transfer. Regenerate the trajectory or edit a different level and you need a fresh map. That's not a bug - it's what makes "region" a meaningful concept here rather than a fixed grid partition.

Install

Same as every TF node: Manager → search Trajectory Forcing, or git clone https://github.com/korayulusan/ComfyUI-TrajectoryForcing into ComfyUI/custom_nodes/. Pack-wide realities apply - JAX inside ComfyUI, own Python 3.11 venv on CUDA 12, requirements.txt empty on purpose, install.py adds the JAX stack or declines with a reason. When it declines, README's env/setup.sh is the route. Quick health check:

cd ComfyUI/custom_nodes/ComfyUI-TrajectoryForcing
python -m tf_nodes.doctor

Pair this node with TF Latent Preview (PCA) at the same level and you'll see the same structure twice - once as false color, once as numbered clusters - which is the fastest way to learn what cosine similarity means visually in this space.

CategoryTrajectoryForcing/select

Inputs (4)

NameTypeDefaultDescription
levelsTF_LEVELS
levelINT20–3Hierarchy level, 0 = coarsest (object/background) to 3 = finest.
cosine_thresholdFLOAT0.900.5–0.99Higher splits into more, smaller regions. 0.9 matches the editing env's default.
sizeINT512128–2048

Outputs (3)

NameTypeDescription
regionsTF_REGIONS
mapIMAGE
levelINTThe level these regions describe. Wire it into the edit node's 'level' so the two cannot drift apart.