Image Comparer
A Before/After Slider You Can Just Drop Into the Wire
- image_a
- image_b
- IMAGE
There's a moment in every refining workflow - you added a detail pass, or moved a LoRA weight, or swapped the upscaler - where you can't tell whether the new result is better or just different. Two Preview Image nodes won't answer that. A split slider dragged back and forth over the same pixels will. That's DA_ImageComparer, and its best trick is that it isn't a dead end: it passes your image straight through, so you slot it into the graph instead of hanging it off a branch.
How it works
The pack's premise (straight from its README) is that the UI lives in JavaScript so previews update without a page reload. The Python side of this node is thin: it runs your two inputs through the core PreviewImage node's save_images() with the prefixes comp_a. and comp_b., then hands the frontend a list of pairs of /view?... URLs. The JavaScript in the pack's web/ folder builds a DOM widget inside the node - image B full-size underneath, image A clipped to a percentage width with a thin white seam, and a transparent range input stretched over the whole area. Drag anywhere in the preview and the seam follows.
Two consequences matter. It's an output node, so it runs on every queue - which is why the comparison area is blank until you actually Run. And the pixels come off disk from ComfyUI/temp/, the scratch directory a stock Preview Image writes to (see image-io-metadata.md). Nothing here is a save.
The inputs and the output
Both inputs are optional, and both are IMAGE:
image_a- the "before" layer, the one the slider clips.image_b- the "after" layer, drawn full-size underneath.
The single output is an IMAGE, and it's pure passthrough: whatever you fed image_a comes out untouched (or image_b, if that's the only one wired). That's the point. Drop the node between your decode and your Save Image, wire both sides, and the graph behaves exactly as it did before - no reroute node, no duplicated decode. The obvious uses are base decode vs. upscaled, pre-detail vs. post-detail, two checkpoints, two seeds.
Wire only one input and it compares that image against itself - pointless-sounding, but a fine way to page through a batch. With neither input connected it returns a 1×1 black tensor instead of erroring, so don't leave a Save Image downstream of it while you're muting branches to bisect a problem.
Batches pair by index and the longer batch wins. When one side runs out of frames, that half falls back to the other side's frame at the same index, so both halves just look identical instead of one going empty. No error, only a quieter comparison. Once there's more than one pair, small < > buttons show up at the bottom of the preview so you can step through without re-running.
Installing it
Search ComfyUI Manager for the pack title, DemonAlone-JS_Addon-ComfyUI, or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/DemonAlone/DemonAlone-JS_Addon-ComfyUI
Restart ComfyUI. There's no requirements.txt and the pyproject.toml declares no dependencies, so nothing to pip install; the JavaScript under web/ loads automatically via the pack's WEB_DIRECTORY. If the node appears but the comparison area stays empty, hard-refresh the browser tab before filing bugs.
You get the whole pack either way - Video Maker V2, Load Video, controllers, Resolution Selector, Any Switch and friends. It's a one-person hobby pack (the README openly thanks Gemini/Qwen/DeepSeek for help) that complements, but doesn't require, the author's larger DemonAlone-nodes-ComfyUI package.
Where people get tripped up
Two nodes named "Image Comparer". Type that into the node search and you get this one plus rgthree's, which is the famous one - it's what made compare sliders standard kit (rgthree-comfy panel). Check the pack name, or the category (MyCustomExtension/Image here versus rgthree's rgthree), before wiring up the wrong one and wondering where the passthrough output went.
You can't grab the node body. The slider is a transparent input covering the entire widget with an ew-resize cursor. That's deliberate - drag anywhere to move the seam - but you'll have to move the node by its title bar. Resize handles work normally.
Keep it roughly square. Both images are letterboxed to fit, so a wide, short node gives you two thin strips you can't judge. The A image is also scaled to the container's width so the halves stay registered, and the node re-syncs that on resize - if the seam looks offset, resize the node.
Halves go blank mid-session. The preview points at files in ComfyUI/temp/. If anything clears that folder while ComfyUI is running, the images break until the next run writes new ones - the same reason a long tweaking session leaves a little pile of comp_a_* / comp_b_* files behind. That's the preview mechanism, not a leak.
Custom DOM widgets and the frontend. This node's whole value is a DOM widget, which is the class of thing the Nodes 2.0 frontend rewrite churned for third-party packs (see comfyui-ecosystem.md). If the comparison area renders blank or half-styled while your stock previews are fine, toggle back to the legacy canvas and re-check before assuming the node is broken.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image_aopt | IMAGE | — | |
| image_bopt | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |