TF Save Levels
Keep the trajectory that every comparison depends on
- levels
- path
A trajectory costs GPU time to sample, and it's the thing every edit is measured against - so losing one is more than an inconvenience, it's losing the reference point for the whole experiment. TF Save Levels writes a trajectory to output/trajectory_forcing/<name>.npz, and it saves more than the four latent arrays: class, seed, and the full edit history ride along. When you load it back, you're getting the exact object you saved, not a picture of it.
The .npz format is the right choice here and worth appreciating. It's the raw latents - every level of the trajectory - so a loaded trajectory isn't a compressed approximation you have to re-decode into some other representation. TF Load Levels hands it back as a proper TF_LEVELS socket that flows into TF Compare Levels, TF Resume From Level, or TF Decode Levels just like a freshly generated one. What it does not carry is the pipeline - that's why loaded trajectories are the case where you wire pipeline explicitly into decode or resume nodes; the pack's rule "most nodes need no pipeline wire" has exactly one exception and this is it.
Inputs are minimal: levels (what you're saving), name (default trajectory), and overwrite (off by default - when off, the node appends -001, -002, ... rather than replacing an existing file, so you can't nuke a baseline by accident). The path output tells you exactly where it landed, which is worth reading once so you know where to look. Files accumulate under output/trajectory_forcing/ and TF Load Levels builds its dropdown from that folder.
Where people actually get burned: the dropdown list is built when ComfyUI sends its node definitions, so a trajectory saved since the page loaded won't appear in TF Load Levels until you refresh (the tooltip literally says press R). And if you're about to remove and reinstall the pack rather than update it, the README's warning applies - the whole extension directory, including anything auto-fetched and your .env, lives under custom_nodes/, so back up what you need before deleting. Saves themselves live in ComfyUI's output folder, which is the one place that survives a pack reinstall.
The habit worth forming: save the baseline trajectory before you start editing. A comparison between two edits only means something if both sides can be reproduced or reloaded, and the pack's own docstring says it plainly - being able to reload the exact trajectory an earlier run used is what makes a comparison between two edits mean anything across a restart or in a different workflow. Pair it with TFSaveImages and TFSaveReport and a run leaves behind three files that tell the whole story: the latent object, the pictures, and the numbers.
Install
Standard for the pack: Manager → search Trajectory Forcing, or git clone https://github.com/korayulusan/ComfyUI-TrajectoryForcing into custom_nodes/. This node itself is pure file IO - but the pack still runs JAX inside ComfyUI and wants its own Python 3.11 environment on CUDA 12, with requirements.txt empty on purpose so Manager can't rewrite your torch. install.py adds the JAX stack or declines with a printed reason; declining is normal and README's env/setup.sh is the fallback. When in doubt:
cd ComfyUI/custom_nodes/ComfyUI-TrajectoryForcing
python -m tf_nodes.doctor
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| levels | TF_LEVELS | — | |
| name | STRING | trajectory | — |
| overwrite | BOOLEAN | false | Off appends -001, -002, ... rather than replacing an existing file. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| path | STRING | — |