OpenClip Writer
Write AI frames back to Flame as a versioned .clip — the safe way
- IMAGE
- MASK
- CLIP_METADATA
- clip_path
The OpenClip Writer is where your processed frames stop being a stack of tensors and become something a Flame artist can grab straight from MediaHub. It writes both the EXR/PNG sequence and the .clip XML manifest that describes it, packaged as versioned OpenClips - v001, v002, … - the same shape Flame itself produces. If the Reader is the pipeline's front door, this is the loading dock.
ComfyUI's default save nodes write a flat folder of PNGs and call it a day, which is fine for solo work. The moment your output has to land in a color-managed, versioned VFX pipeline, you need a package with a manifest, alpha, framerate and metadata - and that's exactly what this writes.
How it works
Feed it an IMAGE batch (if your workflow outputs video rather than frames, extract an image batch first - a Get Video Components node does this), optionally a MASK for alpha, and it renders the sequence through OpenImageIO then writes an OpenClip v8 XML manifest describing it. MASK gets merged in as the alpha channel, so connect it if you want proper RGBA EXR.
The destination is built from a clip_filename pattern using $(path) and $(clip_name) tokens (default $(path)/$(clip_name).clip), which lets you add suffixes like _updated without breaking wired connections. Version handling is Flame-style and deliberately conservative: version_name defaults to next, which scans any existing .clip and picks one past the highest version (v001 for a fresh clip). It will not silently clobber - if the version already exists and overwrite is off, you get a hard "VERSION ALREADY EXISTS" error with three suggested fixes. With overwrite on, it deletes that version's old frames first, so a shorter re-render can't leave stale trailing frames behind. And if you merge into an existing clip with a different resolution, fps or file format, it errors out rather than corrupting the package.
publish drops a copy of the current ComfyUI workflow JSON as a sidecar next to the clip - genuinely useful for tracking which generation produced which version.
The inputs that matter
IMAGE- your frame batch; the only non-negotiable input.clip_path+clip_name- where it goes and what it's called.version_name-nextis right 99% of the time; leave it alone.file_format- EXR for anything that's going into a comp (half-float + PIZ is a solid all-rounder), PNG for previews and quick dailies.overwrite- keep it off. It exists for deliberately re-processing the same version.
The rest are set-and-forget: fps (24), start_frame (1001 - the film-convention first frame), frame_padding (4), and the EXR bit-depth/compression choices if you're picky.
The round-trip pattern
Wire the Reader's outputs straight in - clip_path, clip_name, metadata, fps - and set clip_filename to $(path)/$(clip_name)_updated.clip. Everything stays in lockstep, the version auto-increments, and you never retype a path or framerate. That's the workflow the pack was built for, and it's genuinely painless.
How to install it
ComfyUI Manager (search "ComfyUI_OpenClip") or:
cd ComfyUI/custom_nodes
git clone https://github.com/allklier/ComfyUI_OpenClip.git
Then restart ComfyUI. It needs lxml and openimageio in ComfyUI's Python environment; Manager installs them from requirements.txt automatically. opencolorio is only needed if you also use the Colour Transform node.
Where people get burned
- "VERSION ALREADY EXISTS" - you're re-writing an existing version. Fix: set
version_nametonext, enableoverwrite(if that's intentional), or type a different version. - Format mismatch errors - your render's resolution, fps or file format doesn't match what's already recorded in the
.clipyou're merging into. Check those before blaming the node. - PNG mode with alpha - frame sequences in PNG are three-channel; wire the
MASKand use EXR if you need the alpha to survive.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| IMAGE | IMAGE | — | |
| clip_path | STRING | — | |
| clip_name | STRING | — | |
| clip_filename | STRING | $(path)/$(clip_name).clip | — |
| version_name | STRING | next | — |
| overwrite | BOOLEAN | false | — |
| include_version_in_filename | BOOLEAN | false | — |
| fps | FLOAT | 24.0001–120 | — |
| start_frame | INT | 10010–999999 | — |
| frame_padding | INT | 41–9 | — |
| file_format | COMBO | 2 options: EXR, PNG | |
| exr_bit_depth | COMBO | 2 options: half (16-bit), float (32-bit) | |
| exr_compression | COMBO | 3 options: ZIP, PIZ, DWAB | |
| publish | BOOLEAN | false | — |
| MASKopt | MASK | — | |
| CLIP_METADATAopt | CLIP_METADATA | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| clip_path | STRING | — |