Nodes/was-node-suite-comfyui/Create Morph Image
ComfyUI Node Runs on cloud

Create Morph Image

Crossfade two images into a GIF

By WASasquatch·Created 3 years ago·Updated 2 days ago· 1,839
Create Morph Image
  • image_a
  • image_b
  • image_a_pass
  • image_b_pass
  • filepath_text
  • filename_text
transition_frames30
still_image_delay_ms2500.0
duration_ms0.1
loops0
max_size512
root
filenamemorph
filetype
palette_mode
max_colors256
dithertrue

Give it two images and it spits out an animated GIF (or APNG) that fades from the first into the second. That's the whole pitch, and it's a fun one. Create Morph Image is the quick way to turn a before/after pair into a little looping transition without opening a video editor.

Set expectations first, because the name oversells it slightly: this is a crossfade, not a real morph. It doesn't warp features or track landmarks the way morphing software from the 90s did - it blends the two frames' pixels over a sequence of steps. Feed it two wildly different compositions and you get a ghostly dissolve, not a smooth face-melt. Feed it two images that share a layout - same subject, different style, or two steps of an edit - and it looks genuinely slick.

How it works

The node interpolates between image A and image B across a number of in-between frames, writing each blended frame into an animated file. You control roughly two things: how many frames it generates (more frames = smoother, longer, bigger file) and how long each frame is held (the timing). It assembles those into a GIF or APNG and saves it to your output folder, which makes this an output node - the file lands on disk when the graph runs.

Because it's pixel blending, the two inputs really should be the same dimensions. Mismatched sizes are where the results get ugly.

Inputs and outputs that matter

The two inputs that matter are simply the two IMAGE inputs - the start frame and the end frame. Beyond that you're setting the frame count and the per-frame duration to trade smoothness against file size and speed. The node produces the animation file directly; it's a terminal "save"-style node rather than something you chain deeper into a graph.

If you want to build the transition from more than two stills, its sibling Create Morph Image by Path does the same thing across a whole directory of images, fading through them in sequence. Reach for that when you've got a series rather than a pair.

How to install it

ComfyUI Manager: search was-node-suite-comfyui, install, restart. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui

then install the pack's requirements.txt in your ComfyUI venv (or the python_embeded route on portable) and restart. GIF/APNG writing leans on Pillow, which comes along with the pack's requirements, so there's no separate FFmpeg install needed for this one - that's only the WAS video nodes, which are a different, Windows-oriented story.

Common issues & troubleshooting

The morph is a muddy cross-dissolve, not a clean transition. That's the tool being honest about what it is. It blends pixels; it doesn't warp geometry. To make it look like a real morph, feed it two images that are already aligned - same framing, same subject position - so the blend has something coherent to move through.

The output looks jerky. Too few in-between frames. Bump the frame count up for a smoother fade; the trade is a larger file and a slightly longer run.

The file is enormous. GIF is not an efficient format and frame count multiplies it fast. Keep the resolution modest and the frame count reasonable, or accept that a smooth high-res morph GIF is going to be a chunky file by nature.

Nothing shows up / it errors on save. Check the two inputs are the same size and are actual IMAGE tensors. And remember this is the WAS Node Suite, which has been maintenance-only since late 2023 - if the whole pack throws "Import Failed" after a ComfyUI update, re-run its requirements against the activated venv, that's the usual fix.

CategoryWAS Suite/Animation

Inputs (13)

NameTypeDefaultDescription
image_aIMAGEThe image the animation starts on, and returns to at the end. A batch here becomes one a-to-b pair per frame, all in one animation.
image_bIMAGEThe image the animation fades into. It does not have to match image_a's size: both are letterboxed onto a canvas big enough for the larger of the two. A single image here fades in from every frame of a batched image_a.
transition_framesINT302–60How many blended frames are drawn between the two images. 2 is almost a hard cut, 30 is a smooth fade, and every extra frame adds to the file size.
still_image_delay_msFLOAT2500.00.1–60000How long each of the two images is held before it starts to fade, in milliseconds. 2500 holds it for two and a half seconds.
duration_msFLOAT0.10.1–60000How long each blended frame is shown, in milliseconds. The default 0.1 asks for the shortest frame the format allows, which most players round up to about 10ms; raise it to slow the fade down.
loopsINT00–100How many times the animation plays before it stops. 0 means play forever, which is what most viewers expect from a GIF.
max_sizeINT512128–1280Longest edge of the animation, in pixels. The canvas is otherwise as large as the largest source, so 512 holds a 4000x3000 photograph down to 512x384 and cuts the file and the memory with it. A source already smaller than this is left alone.
rootCOMBOWhich folder the file lands in: ComfyUI's own 'output' or 'temp', or any folder added under paths.allow_write in config.yaml, listed by its own name. filename names the part below it, so '[time(%Y-%m-%d)]/clip' files each day's under a dated folder.
filenameSTRINGmorphName of the file, without an extension, the format below adds one. Tokens are expanded here too, so '[time(%H-%M-%S)]_morph' gives every run its own file instead of overwriting the last one.
filetypeCOMBOWhich format to write. `GIF` plays anywhere but bands gradients at 256 colours; `APNG`, `WEBP` and `WEBP_LOSSLESS` keep full colour and alpha.
palette_modeCOMBOHow the palette is chosen when colours are reduced. `per_frame` fits one per frame, `global` one to the whole animation, so a still area stays put.
max_colorsINT2562–256How many colours the palette holds. 256 is the most a .gif can carry. Lower values shrink the file and give a flatter, posterised look, and below about 64 the choice of palette_mode starts to show. The full-colour formats ignore this at 256 and honour it below that, so it doubles as a posterise control for them.
ditherBOOLEANtrueScatter the rounding error between neighbouring pixels so a gradient stays smooth instead of breaking into bands. Turn it off for flat, poster-like colour, which also compresses smaller.

Outputs (4)

NameTypeDescription
image_a_passIMAGEimage_a exactly as it arrived, so this node can sit mid-chain.
image_b_passIMAGEimage_b exactly as it arrived.
filepath_textSTRINGFull path of the file that was written, extension included.
filename_textSTRINGThe filename widget as it was typed, with no folder and no extension, for feeding a caption or a log.