Atlas Adherence Score π
Did the model move the camera, or just wobble?
- bundle
- generated
- control
- adherence
- margin_over_control
- drift_plot
- report
Everyone who has generated a "camera move" with a video model knows the feeling: the frame changes, it's pretty, and you have no idea whether the camera went where you asked or whether the model just hallucinated a slow drift in roughly that direction. Atlas Adherence Score π is the node that gives you a number instead of a feeling.
What it actually measures
It scores how well a generative video model obeyed a camera, restricted to the pixels where Atlas knows the true answer. That restriction is the whole trick. As the pack's own catalog puts it, a generated move cannot be solved: on a real test the source plate registered at 1022 SIFT inliers while every frame of a generated LTX CrossView move collapsed to 12β20 and was refused, because video diffusion re-synthesises the fine texture that feature matching depends on. Any metric that needs to register on generated frames is dead on arrival.
So you don't register. You take the conditioning bundle - which already knows where every pixel is supposed to land - and compare the generated frames against the deterministic reprojection, only in VALID pixels (the ones Atlas has real appearance for). The headline is gradient ZNCC over VALID, chosen because generated frames come back sRGB-encoded and often graded: gradients kill the exposure offset, normalisation kills the gain, and what survives is whether the structure ended up where Atlas said it would.
The control arm is not optional
There's one required input people skip and then complain about. control is a full second arm: the same prompt, seed, steps and frame count, with the geometric conditioning removed. It's a required socket rather than a polite note in the docs because an adherence figure with nothing to compare against can't support a claim in either direction. The graph enforces what a report could only request.
Same philosophy on the other side. A clip that repeats its first frame scores near-perfect adherence in VALID, because a static plate agrees with the reprojection wherever the move is small. So the node measures parallax_response - agreement against frame i minus agreement against frame 0 - and raises when it isn't positive. It also synthesises a static arm internally, so the headline is always reported as a margin over the cheat's ceiling. refuse_degenerate (default on) is what raises. If you turn it off to see why a run is degenerate, the number it then prints isn't evidence of anything.
Inputs and outputs
Required: bundle (from AtlasConditioningBundle - carries the reprojection and the class map), generated (frames made WITH Atlas conditioning, one per bundle frame), control (the prompt-only arm).
The optional ones that matter: min_parallax_px (1.5) excludes frames whose median measured parallax is below the threshold from the aggregate - a zoom sits there by definition, since it moves pixels without moving the eye. bootstrap_seed (0) seeds the paired bootstrap. refuse_degenerate (true).
Outputs: adherence (FLOAT), margin_over_control (FLOAT), drift_plot (IMAGE), report (JSON). It's an output node, so it runs on queue. Quote margin_over_control, not raw adherence - and note what the report deliberately doesn't do: ghost coverage is a separate question with a separate answer, and it's never folded into adherence. Masked SSIM and raw MAE/PSNR are diagnostics, not headline numbers, because two correlated headlines invite cherry-picking.
Install
ComfyUI Manager β search the registry entry atlas-camera, or:
cd <ComfyUI>/custom_nodes
git clone https://github.com/mikejamesvfx/atlas-camera.git
Restart ComfyUI. Core nodes need no pip step (pack is pure Python; ComfyUI already ships numpy/Pillow/torch). MIT licensed, Python 3.10+. Upstream of this node you need a solve with projection geometry, so the practical dependency is AtlasDeriveProjectionGeometry (or clean-plate layers) and a conditioning bundle. The learned solve and depth paths want the [neural] extra.
Where people get burned
- No control arm = no result. Build it in the same graph, same seed, conditioning unplugged. It's a second half of the workflow, not a checkbox.
- Short, small moves. If your path frames all fall under
min_parallax_px, the aggregate is empty and the node is right to say so, not broken. - Reading a flattering raw score. Near-perfect adherence on a static clip is the exact failure mode the parallax-response check exists to catch.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| bundle | ATLAS_CONDITIONING | From AtlasConditioningBundle β carries the deterministic reprojection and the class map this is scored against. | |
| generated | IMAGE | The arm under test: frames generated WITH Atlas conditioning. One frame per bundle frame. | |
| control | IMAGE | The prompt-only arm: same prompt, seed, steps and frame count, no geometric conditioning. REQUIRED β without it the headline number cannot support a claim either way. | |
| min_parallax_pxopt | FLOAT | 1.50β64 | Frames whose median measured parallax is below this are reported but excluded from the aggregate. A zoom sits here by definition: it moves pixels without moving the eye, so there is nothing for a camera to get right. |
| bootstrap_seedopt | INT | 00β2147483647 | β |
| refuse_degenerateopt | BOOLEAN | true | Raise when parallax_response is not positive. Turn this off ONLY to inspect why a run is degenerate β the number it then reports is not evidence of anything. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| adherence | FLOAT | β |
| margin_over_control | FLOAT | β |
| drift_plot | IMAGE | β |
| report | STRING | β |