NativeXYZTotalCalculator
Know your sweep is 992 images before you queue it
- total_images
Three axes, one number you should have checked first
Parameter sweeps are how you stop guessing. When someone posts a 62-sampler × 16-scheduler grid on a new model and comes back with "use euler and anything but Karras," that's roughly a thousand images of work producing one sentence of usable advice. Fine trade. What isn't fine is queueing a sweep without knowing its size, then discovering at hour six that your "quick comparison" is 992 renders because the Z axis had more entries than you eyeballed.
NativeXYZTotalCalculator exists to print that number first. Give it three axis lists and it multiplies their lengths: X times Y times Z, the total image count of the plot.
What it actually does with the number
The multiply is the boring half. The interesting half is where the result goes, and it isn't the output socket.
The node computes the product, floors it at 1, stores it in a class-level variable on itself, and prints a formatted block to the console:
======================================
[XYZ Calculator] Grid calculation successful!
[XYZ Calculator] Formula: X(4) * Y(8) * Z(3) = 96 images.
======================================
That stored value is read by the pack's ImageCounterNode, which counts images as they flow past and prints [XYZ Plot] Progress: Image #37 of 96 plus a percentage. So the calculator is where the "of 96" comes from - via shared module state, not a wire.
Mechanically it's the rest of the pack's "native" trick: INPUT_IS_LIST = True, so ComfyUI hands over each entire axis list in one call instead of iterating per item. Anything that isn't a list counts as 1 - a safe fallback rather than a crash.
Inputs and outputs
Three required inputs, all STRING, all meant to be native lists:
x_axis_list,y_axis_list,z_axis_list- your three axes, wired from list-emitting nodes: the pack's own list maker, its dynamic selector family, or anything with a list output. Feed plain strings and you get 1 × 1 × 1 = 1.
One output:
total_images(INT) - the product. Wire it into any INT input if you want it downstream, because leaving it floating is the next trap.
The trap: unwired means unexecuted
ComfyUI runs output nodes and works backward through whatever feeds them. A node whose outputs feed nothing isn't on any of those chains, so it never executes. This node's most useful behaviour is a side effect, so either wire total_images into something real or accept that the class variable stays at 1 and the progress line degrades to a bare Image #n.
Two more bites, both from it being global state rather than a wire. One per workflow: two calculators both write the same variable, last one to execute wins, so a main plot plus a side experiment means the percentages only make sense for one. It resets on restart: the total lives in memory, so restart mid-run and the counter prints its no-total branch until the calculator runs again - right when you're watching it.
And to be clear on scope: this books the reservation, it doesn't stop the kitchen. It doesn't validate axes, cap the run, or warn you. If it says 992, you're still rendering 992.
Installing it
Same pack, same two routes. ComfyUI Manager: search DemonAlone-nodes-ComfyUI, install, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/DemonAlone/DemonAlone-nodes-ComfyUI
Restart and you're done. requirements.txt has exactly one line, piexif (used by the pack's metadata-aware image and grid nodes); torch, numpy and PIL ship with ComfyUI. Nothing to download, nothing in models/.
Finding it afterwards is the annoying part: display name is the class name, and it sits at utility → text → native. Search "XYZ" rather than browsing.
Context worth having: this is a one-maintainer pack with essentially no community footprint - it barely shows up in the big ComfyUI subreddits, so searching won't answer your questions. The nodes are readable Python, and reading them is how you learn things like the class-variable behaviour above. As with any custom node, it's unreviewed code running with your permissions.
Troubleshooting
Console prints X(1) * Y(1) * Z(1) = 1. One or more axes aren't lists - you wired a single string, and the fallback counts it as one.
Formula prints, progress never shows a total. Nothing downstream reads the stored value: you're missing ImageCounterNode, or it sits in a branch that never runs.
Percentage looks wrong on a big grid. Two calculators, or a second plot in the same graph, overwriting the shared variable.
Completely silent. The node didn't execute, because its output isn't connected to anything.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| x_axis_list | STRING | — | |
| y_axis_list | STRING | — | |
| z_axis_list | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| total_images | INT | — |