ZZX_PaintsUndoSequence
Turn a finished image into a fake drawing timelapse
- image
- frames
- prompt
You know the trick: an AI image shows up in a thread with a video attached and everyone assumes the artist drew it. Paints-UNDO is the model that makes that video, and it runs the process backwards - from the finished picture toward the blank page. ZZX_PaintsUndoSequence is the node that gets you the whole run in one go: your image in, a batch of keyframes out, feed it to a video save node and you have a drawing-timelapse of something that was never drawn.
It's a wrapper around lllyasviel's single-frame Paints-UNDO model, and worth being clear about what it isn't: it doesn't recover your actual layer history, and it doesn't do the motion interpolation the upstream research demo used. You get keyframes. Smooth playback is your problem - or your video node's, with a bit of frame duplication.
The mechanism, briefly
At each operation value the model re-renders your image conditioned on the encoded latent of the original plus a scalar "how far back" code. operations is that list - ascending, comma separated, default 400,600,800,900,950,999. 0 is the original, 999 is nearly the earliest strokes. It's a position in a learned drawing trajectory, not a step count.
The seed is reused for every keyframe deliberately, mimicking upstream's same_noise_in_batch: same initial noise across the sequence keeps frames from flickering into unrelated variations. Models shuffle on and off the GPU one stage at a time (VAE encode, CLIP encode, UNet per frame, VAE decode), the VAE stays float32 to avoid the fp16 overflow that spits out black frames, and everything lands back on CPU when it's done. Sequences of eight frames ran in the 27–38 second range on a 32 GB Ada card in the author's own testing - this is not a heavy node by 2026 video-model standards.
Prompt handling is the nice part. Leave prompt empty and the node runs the original WD14 MOAT tagger on your image to produce the caption itself. It's the recommended default in the README, and it's usually better than hand-typing tags, because the model was trained against that tagger's output style.
The inputs that matter
image must be a single RGB image - a batch raises an error rather than quietly dropping frames. operations is the one field to experiment with first: more values means more frames and more compute; a tight cluster near 900–999 gives you the last, sketchiest stretch, which is the most convincing part of the effect. resolution is the longest side, default 640, resized to multiples of 64 without cropping - bump it and both time and VRAM go up.
sampling_steps (default 50, examples use 30) and cfg (default 3.0) are the sampling knobs. include_original prepends your source; include_blank appends a white frame. That white frame is synthesised, not predicted - a clean ending for a timelapse, nothing more. negative_prompt defaults to the usual lowres, bad anatomy, ... string and rarely needs touching.
Outputs: frames, an IMAGE batch of shape [N, H, W, 3], float32, 0–1 - wire it to Save Image for a contact sheet or to a video-combine node at a low fps; and prompt, the caption that was used, auto-tagged or typed.
Install
Manager: search ZZX (Comfy Registry: ComfyUI-ZZX). Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/ZZXYWQ/ComfyUI-ZZXYWQ
python -m pip install -r ComfyUI-ZZXYWQ/requirements.txt
Windows portable:
python_embeded\python.exe -m pip install -r ComfyUI\custom_nodes\ComfyUI-ZZXYWQ\requirements.txt
First run downloads lllyasviel/paints_undo_single_frame and the WD14 tagger into ComfyUI/models/paints_undo (override with PAINTS_UNDO_MODEL_DIR). Several GB, needs network once, offline afterwards. Restart ComfyUI after updating the pack - a running server keeps the old Python code.
Where it goes wrong
The one you'll actually hit is a half-downloaded model directory. no file named model.safetensors means the single_frame subfolders are incomplete; if that folder exists, the node trusts it and ignores everything else. Verify the unet, text_encoder and vae weight files are there, not just configs.
Second: the node unloads all other models in ComfyUI before inference. If Paints-Undo sits mid-graph, your checkpoint is gone when it finishes and has to reload.
Third, and the one that matters creatively: this thing simulates drawing, and simulates badly in places. Colour and stroke changes depend heavily on the input - flat illustrations and clean renders work much better than busy photos. It won't always remove detail monotonically; some frames redraw things that were already gone. Adjust operations and seed and accept that it's a plausible sketch, not a forensic one.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| prompt | STRING | — | |
| operations | STRING | 400,600,800,900,950,999 | — |
| seed | INT | 123450–18446744073709550000 | — |
| sampling_steps | INT | 501–100 | — |
| cfg | FLOAT | 3.001–20 | — |
| resolution | INT | 640256–1024 | — |
| include_original | BOOLEAN | true | — |
| include_blank | BOOLEAN | true | — |
| negative_prompt | STRING | lowres, bad anatomy, bad hands, cropped, worst quality | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| frames | IMAGE | — |
| prompt | STRING | — |