Looped Restyler
Upload a starting image and its prompt to generate a looping video from the first to the last frame.
简介
The 'Looped Restyler' workflow in ComfyUI is designed to transform a static image into a dynamic looping video. By utilizing advanced AI models like Nano Banana, Google Gemini, and Wan2.2, this workflow seamlessly transitions from the first frame of an image to the last, creating a continuous loop.
The process begins with loading an initial image and its corresponding prompt, which guides the transformation process. The workflow employs nodes such as LoadImage to import the starting image, and SaveVideo to compile the frames into a video format. The node identified by 3313ce14-acfd-4a9c-9f0c-a1b01147e934 plays a crucial role in generating intermediate frames that ensure a smooth transition between the start and end of the sequence. PreviewImage is used to monitor the progress and make necessary adjustments before finalizing the output.
你需要提供
- 正在读取工作流
在 ComfyUI 中运行。 此工作流无法在本页面运行。你可以在 Comfy Cloud 中打开(已预先加载所需内容),或下载后在自己的 ComfyUI 中使用。
在 Cloud 中试用查看工作流内部
节点图的只读预览。在 Comfy Cloud 中打开或下载后即可编辑节点。
Loading the graph
Open full-size workflow preview需要自定义节点
- 正在读取工作流
通过代码使用此工作流
尽可能根据工作流图和输入自动生成代码,否则显示已保存的示例。运行代码可能产生费用,请先核对凭据和端点。
What you need
- Runs on
- Comfy Cloud
- 密钥
- COMFY_API_KEY
需要付费的 Cloud 方案和额度。
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"4": {
"class_type": "LoadImage",
"inputs": {
"image": "looped_restyler_init.png"
},
"_meta": {
"title": "Load Image"
}
},
"80": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/ComfyUI",
"format": "auto",
"format.codec": "auto",
"video": [
"89:79",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"90": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"89:82",
0
]
},
"_meta": {
"title": "Preview Image"
}
},
"89:27": {
"class_type": "SplitImageWithAlpha",
"inputs": {
"image": [
"89:88",
0
]
},
"_meta": {
"title": "Split Image with Alpha"
}
},
"89:5": {
"class_type": "GeminiImageNode",
"inputs": {
"aspect_ratio": "auto",
"images": [
"89:87",
0
],
"model": "gemini-2.5-flash-image",
"prompt": "A pure illustrated anime image. \n\nThe camera angle is from the back of the character, a back-facing shot.\n\n2D line-art with cel-shaded color fills, expressive outlines, and stylized anime anatomy. Scene is drawn entirely as an illustration. Absolutely no realism, no photo textures, no 3D render qualities — strictly anime illustration style.",
"response_modalities": "IMAGE+TEXT",
"seed": 754210146642470,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana (Google Gemini Image)"
}
},
"89:6": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"89:88",
0
]
},
"_meta": {
"title": "Preview Image"
}
},
"89:73:57": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"89:73:69",
0
],
"text": "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
},
"_meta": {
"title": "CLIP Text Encode (Negative Prompt)"
}
},
"89:73:58": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"89:73:69",
0
],
"text": [
"89:81",
0
]
},
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"89:73:59": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"89:73:60": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"89:73:61": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors",
"model": [
"89:73:60",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"89:73:62": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors",
"model": [
"89:73:59",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"89:73:63": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"89:73:62",
0
],
"shift": 5
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"89:73:64": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"89:73:61",
0
],
"shift": 5
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"89:73:65": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": 24,
"images": [
"89:73:71",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"89:73:66": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "enable",
"cfg": 1,
"end_at_step": 2,
"latent_image": [
"89:73:67",
2
],
"model": [
"89:73:63",
0
],
"negative": [
"89:73:67",
1
],
"noise_seed": 803169991734672,
"positive": [
"89:73:67",
0
],
"return_with_leftover_noise": "enable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 0,
"steps": 4
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"89:73:67": {
"class_type": "WanFirstLastFrameToVideo",
"inputs": {
"batch_size": 1,
"end_image": [
"89:27",
0
],
"height": [
"89:87",
2
],
"length": 81,
"negative": [
"89:73:57",
0
],
"positive": [
"89:73:58",
0
],
"start_image": [
"89:87",
0
],
"vae": [
"89:73:70",
0
],
"width": [
"89:87",
1
]
},
"_meta": {
"title": "WanFirstLastFrameToVideo"
}
},
"89:73:68": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "disable",
"cfg": 1,
"end_at_step": 10000,
"latent_image": [
"89:73:66",
0
],
"model": [
"89:73:64",
0
],
"negative": [
"89:73:67",
1
],
"noise_seed": 0,
"positive": [
"89:73:67",
0
],
"return_with_leftover_noise": "disable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 2,
"steps": 4
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"89:73:69": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"device": "default",
"type": "wan"
},
"_meta": {
"title": "Load CLIP"
}
},
"89:73:70": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "wan_2.1_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"89:73:71": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"89:73:68",
0
],
"vae": [
"89:73:70",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"89:76": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"89:73:65",
0
]
},
"_meta": {
"title": "Get Video Components"
}
},
"89:77": {
"class_type": "ImageBatch",
"inputs": {
"image1": [
"89:76",
0
],
"image2": [
"89:78",
0
]
},
"_meta": {
"title": "Batch Images (DEPRECATED)"
}
},
"89:78": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"89:91:56",
0
]
},
"_meta": {
"title": "Get Video Components"
}
},
"89:79": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": 24,
"images": [
"89:77",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"89:81": {
"class_type": "GeminiNode",
"inputs": {
"images": [
"89:82",
0
],
"model": "gemini-2.5-pro",
"prompt": "I am prompting a video model that understands natural language.\n\nI need a prompt that describes the transitions from image on the left to image on the right.\n\nJust give me the prompt and nothing else.",
"seed": 941151948383059,
"system_prompt": ""
},
"_meta": {
"title": "Google Gemini"
}
},
"89:82": {
"class_type": "ImageStitch",
"inputs": {
"direction": "right",
"image1": [
"89:87",
0
],
"image2": [
"89:88",
0
],
"match_image_size": True,
"spacing_color": "white",
"spacing_width": 0
},
"_meta": {
"title": "Stitch Images"
}
},
"89:83": {
"class_type": "GeminiNode",
"inputs": {
"images": [
"89:82",
0
],
"model": "gemini-2.5-pro",
"prompt": "I am prompting a video model that understands natural language.\n\nI need a prompt that describes the transitions from image on the right to image on the left.\n\nJust give me the prompt and nothing else.",
"seed": 23952267132674,
"system_prompt": ""
},
"_meta": {
"title": "Google Gemini"
}
},
"89:84": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"89:82",
0
]
},
"_meta": {
"title": "Preview Image"
}
},
"89:85": {
"class_type": "ImageScaleToTotalPixels",
"inputs": {
"image": [
"4",
0
],
"megapixels": 1,
"resolution_steps": 1,
"upscale_method": "lanczos"
},
"_meta": {
"title": "Scale Image to Total Pixels"
}
},
"89:87": {
"class_type": "GetImageSizeAndCount",
"inputs": {
"image": [
"89:85",
0
]
},
"_meta": {
"title": "Get Image Size & Count"
}
},
"89:88": {
"class_type": "ImageScaleToTotalPixels",
"inputs": {
"image": [
"89:5",
0
],
"megapixels": 1,
"resolution_steps": 1,
"upscale_method": "lanczos"
},
"_meta": {
"title": "Scale Image to Total Pixels"
}
},
"89:91:29": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"89:91:53",
0
],
"text": "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
},
"_meta": {
"title": "CLIP Text Encode (Negative Prompt)"
}
},
"89:91:33": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"89:91:42",
0
],
"vae": [
"89:91:54",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"89:91:38": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "enable",
"cfg": 1,
"end_at_step": 2,
"latent_image": [
"89:91:40",
2
],
"model": [
"89:91:51",
0
],
"negative": [
"89:91:40",
1
],
"noise_seed": 757394574321365,
"positive": [
"89:91:40",
0
],
"return_with_leftover_noise": "enable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 0,
"steps": 4
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"89:91:40": {
"class_type": "WanFirstLastFrameToVideo",
"inputs": {
"batch_size": 1,
"end_image": [
"89:87",
0
],
"height": [
"89:87",
2
],
"length": 81,
"negative": [
"89:91:29",
0
],
"positive": [
"89:91:41",
0
],
"start_image": [
"89:27",
0
],
"vae": [
"89:91:54",
0
],
"width": [
"89:87",
1
]
},
"_meta": {
"title": "WanFirstLastFrameToVideo"
}
},
"89:91:41": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"89:91:53",
0
],
"text": [
"89:83",
0
]
},
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"89:91:42": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "disable",
"cfg": 1,
"end_at_step": 10000,
"latent_image": [
"89:91:38",
0
],
"model": [
"89:91:52",
0
],
"negative": [
"89:91:40",
1
],
"noise_seed": 0,
"positive": [
"89:91:40",
0
],
"return_with_leftover_noise": "disable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 2,
"steps": 4
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"89:91:47": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"89:91:48": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"89:91:49": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors",
"model": [
"89:91:48",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"89:91:50": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors",
"model": [
"89:91:47",
0
],
"strength_model": 1
},
"_meta": {
"title": "Load LoRA"
}
},
"89:91:51": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"89:91:50",
0
],
"shift": 5
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"89:91:52": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"89:91:49",
0
],
"shift": 5
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"89:91:53": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"device": "default",
"type": "wan"
},
"_meta": {
"title": "Load CLIP"
}
},
"89:91:54": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "wan_2.1_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"89:91:56": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": 24,
"images": [
"89:91:33",
0
]
},
"_meta": {
"title": "Create Video"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)常见问答
High-resolution images with clear focal points tend to produce the best results, as they provide more detail for the AI to work with.
Yes, you can adjust the frame rate in the SaveVideo node to control the speed of the loop.
This workflow focuses on visual output. However, you can add audio using video editing software after exporting the video.
Use the PreviewImage node to check transitions between frames and adjust parameters in the 3313ce14-acfd-4a9c-9f0c-a1b01147e934 node for smoother results.