Paint Strokes
Clone, blur, or paint directly on your video, over a chosen time window
- video
- reveal_video
- video
Paint Strokes is ComfyTV's answer to the eternal cleanup question: "there's a thing in my footage I want gone, and it's there for three seconds." You draw brush strokes on the node's video preview, and on Run they apply to the clip over a time window - so you can paint over that microphone shadow, soften a blemish, or smear a logo, without leaving the graph and without keyframing a mask.
The strokes have three modes, which is what separates this from a one-brush paint node:
- clone - paint in pixels offset from elsewhere in the frame. This is the "cover that object with the wall behind it" workhorse. A second optional input,
reveal_video, supplies the source pixels for reveal-style painting - think replacing a sign with a clean take. - blur - soften an area over time. For sensor dust, motion-blur patches, or just taking the edge off something you can't remove.
- color - paint a flat color, for simple covers or roto-ish fixes.
Each stroke carries its own radius and hardness, and the strokes input is JSON ([{mode, points, radius, hardness, ...}]) - but you won't type that; you draw on the card and the node serializes it.
The inputs that matter
video(optional) - the clip to paint on.reveal_video(optional) - the alternate source for clone/reveal strokes.strokes- the serialized stroke list, written by the on-node paint canvas.t_start/t_end- the time window the strokes act on. This is the important mental model: strokes aren't frame-locked, they're windowed. Set the window, paint, and the same stroke persists across the whole range.
One output: video (COMFYTV_VIDEO), the retouched clip. In the pack's roto/tracking family it sits next to Roto Mask, Motion Track, and Mask Propagate - if you're doing a cleanup that needs a mask rather than a brush, Roto Mask is the sibling you want; Paint Strokes is the one where you just... paint.
Install
Pack-wide:
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Restart ComfyUI - on Desktop/macOS clone into the running instance's custom_nodes by absolute path, confirm __init__.py is top-level, and restart the backend rather than just the browser tab. ComfyUI Manager finds it as "ComfyTV". No extra Python dependencies.
The realistic gripes: clone brushes are only as good as the source region you steal from, so pick an offset with similar lighting; and heavily painted regions can shimmer if the stroke radius is too small against moving footage. Start wide and soft, preview, and tighten. And remember the pack rule - the video output is a project snapshot, so native ComfyUI nodes downstream need a Bridge.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| force_run_token | INT | 00–2147483647 | Internal — bumped on Run to invalidate ComfyUI's input cache. |
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| strokes | STRING | JSON [{mode, points:[{x,y,p}], radius, hardness, dx, dy, sigma, color, life_start, life_end}] | |
| t_start | FLOAT | 0.000–3600 | — |
| t_end | FLOAT | -1.00-1–3600 | — |
| videoopt | COMFYTV_VIDEO | — | |
| reveal_videoopt | COMFYTV_VIDEO | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| video | COMFYTV_VIDEO | — |