Protoface Veo 3.1 · Image to Video
Give a still a camera and a soundtrack
- video
- files
- run id
Stills into shots
Image-to-video is where most real work happens. You already have a frame you like - out of Nano Banana, out of your own local pipeline, out of a photo - and you want motion that respects it. Text-to-video is a lottery; image-to-video is direction.
This is Google's version, on Veo 3.1: one image in, a clip out, with synchronized audio generated in the same pass. It's an Image to Video task node from Protoface, the beta pack that wires hosted APIs into ComfyUI as native nodes. No weights, paid per generation, billed to your Protoface account rather than Comfy credits.
Where it earns its keep: a hero shot for a product, a character beat that has to match a frame from your local model, anything where the client's note is "make this photo move" and the deadline is today. Where it doesn't: iterating on motion ideas. That's a Wan or LTX draft session, because 20 paid takes to find the right camera move is an expensive way to learn.
How it works
The pack generates this node from the provider's public schema and runs everything through one shared adapter: validate the payload, upload the image to Protoface's asset store (content-hashed, so a rerun reuses the upload), journal the request, submit, poll with progress, download, cast to native VIDEO.
The image input is a media input with modes - native Image mode for wiring a ComfyUI IMAGE, and a References mode that takes a Protoface asset ID or a reused result asset from an earlier remote job. That's the neat trick in this pack: chain remote generations without re-uploading a thing.
generation_id is the request identity, not a seed. Keep it fixed and requeue and you get your recorded job back.
The inputs that matter
image is the first frame, and it sets almost everything: composition, aspect, look. It's also why aspect_ratio here defaults to 16:9 - if you feed it a vertical still, set the ratio deliberately or you'll get a letterboxed compromise.
prompt describes the motion, not the picture. "Slow push in, she turns to camera, wind moves the hair, distant traffic" is the shape of a good prompt. Describing the scene again mostly wastes it.
last_image is the optional end frame. Set both ends and the model interpolates between them - the most controllable mode on the node, and the one people underuse. It's media-style, so leaving it Default means the field isn't sent at all.
duration (default 8) is a combo, not a slider. resolution defaults to 1080p. generate_audio defaults on - turn it off only if you're laying your own track underneath, and note it doesn't reduce the price.
negative_prompt and seed are media-style controls: Default omits, Set supplies, Null where supported sends an explicit null. Blank text is not the same as omitted here, which the pack calls out explicitly.
Outputs
video is a native VIDEO list - connect a preview/save node and ComfyUI maps over it. files is every original downloaded asset as PROTOFACE_FILE, and run id is a plain string you feed to Protoface Resume Run if the job finishes after your session dies. For video, assume it might: these runs are slow enough that the poll can outlast an open tab.
Install
Manager → search Protoface → install protoface-nodes → restart → reload the browser. Or from inside your ComfyUI directory:
git clone --branch v0.1.0 --depth 1 https://github.com/protoface-ai/protoface-comfyui.git custom_nodes/protoface
python -m pip install -r custom_nodes/protoface/requirements.txt
ComfyUI 0.41.0+ and Python 3.10+. Install with ComfyUI's interpreter (python_embeded/python.exe for Windows portable). av (PyAV) is what makes native video connections work, so if sockets behave oddly that's your first suspect. Then click Protoface in the lower-right and paste a key.
Where people get burned
Feeding a 4:3 photo and expecting 16:9 motion. It'll adapt, badly. Crop or pad the frame first, or set the aspect ratio and accept the crop.
Rerolling without incrementing. Same generation_id, same inputs, same returned job. That's the feature; increment to spend.
Killing a run you think is stuck. The default job timeout is two hours and the poll interval is two seconds, so a quiet progress bar isn't a dead job. If you do interrupt, know that cancellation is best effort and doesn't guarantee a refund.
A missing node after a restart. Usually the pack, not the model: verify custom_nodes/protoface/__init__.py exists, no duplicate installs, and that the extension imported cleanly in the startup log.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt | STRING | The positive prompt for the generation. | |
| image | COMBO | A public URL, a data URI, or an asset id. | |
| resolution | COMBO | 1080p | Video resolution. |
| duration | COMBO | 8 | The duration of the generated media in seconds. |
| aspect_ratio | COMBO | 16:9 | The aspect ratio of the generated media. |
| generate_audio | BOOLEAN | true | Whether to generate audio. |
| last_image | COMBO | A public URL, a data URI, or an asset id. | |
| negative_prompt | COMBO | The negative prompt for the generation. | |
| seed | COMBO | The random seed to use for the generation. | |
| generation_id | INT | 00–9007199254740991 | Keep fixed to reuse/resume this paid job. Increment for a fresh paid generation; independent of the model seed. |
| request_scope | STRING | Automatically assigned per node. Headless clients must supply a stable unique workflow/node ID. This is not a secret. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| video | VIDEO | — |
| files | PROTOFACE_FILE | — |
| run id | STRING | — |