Annotate
Composition boxes, grids, and broadcast-safe padding — without leaving the graph
- video
- video
Somewhere between "I need a box on screen" and "let me open a compositor" there's a gap that this node lives in. Annotate draws a box, a grid, a filled border, or a scrolling image onto your footage and hands you back the composited video - no keyframes, no extra software, no render round-trip. It's the ComfyTV equivalent of slapping a safe-area guide or a lower-third rectangle onto a frame, and it's one of those stages you don't think about until you need it, then it saves your afternoon.
You'll use it for the classic boring-but-necessary jobs: drawing a rule-of-thirds or safe-area grid while you frame a shot, boxing the region of a video you're about to inpaint or key, filling the borders when your source aspect ratio doesn't match your output (that broadcast-style black-bar problem), or panning/scrolling an oversized image across a smaller canvas. Each of those is a different mode on the same node.
How it works
The mode combo picks which FFmpeg filter the node drives, and the code confirms it: box runs drawbox, grid runs drawgrid, fillborders runs fillborders, and scroll runs scroll. The x/y/w/h inputs are fractions of the frame, not pixels - x=0.25, y=0.25, w=0.5, h=0.5 centers a half-size box. color takes a hex string (default #4ADE80, a very on-brand green), thickness is the stroke in pixels, and opacity is 0–1. For fillborders, border_mode picks how the padded edge is filled - mirror, reflect, wrap, smear, fade, or fixed color - and border_px sets the border size. For scroll, scroll_h and scroll_v are horizontal/vertical speed in -1..1 and at least one must be non-zero (the node errors otherwise, which is its way of telling you to actually scroll).
The inputs marked "Internal" - force_run_token, project_id, parent_output_id - are frontend plumbing that the ComfyTV canvas manages. Don't touch them. The optional video input takes a COMFYTV_VIDEO and the node is itself an output node, so the composited result is also video. The tooltips on x/y/w/h are gone from the brief, but the min/max of 0..1 tells you everything: everything here is relative.
Installing ComfyTV
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Full backend restart (quit the app, not just refresh the browser) and it shows up under ComfyTV → VideoFX. ComfyUI Manager finds it as "ComfyTV". No extra Python deps, no models - the heavy lifting is FFmpeg filters via PyAV, which ComfyUI already ships.
The README's install trap: on macOS / ComfyUI Desktop / multi-install machines, cd ComfyUI/custom_nodes may hit the wrong instance. Find the running instance's path in the startup log, clone by absolute path into that instance's custom_nodes (quotes needed for spaces/parentheses), verify ComfyTV/__init__.py is top-level, and fully restart.
Common issues
- "border size is zero" -
border_pxis 0. Give it a real value. - "scroll speed is zero" - both
scroll_handscroll_vare 0. The scroll mode needs motion. - Box is in the wrong place. Remember x/y/w/h are fractions of the frame (0–1), not pixels. The default places a half-size box at the top-left quarter.
- Grid too fine or too coarse.
wandhare the cell size in grid mode, so a 0.5×0.5 grid is four cells.
It's not a headline feature, but it's the kind of node that makes ComfyTV feel like a workbench instead of a toy. One box, one grid, done.
Inputs (16)
| 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. |
| mode | COMBO | box | 4 options: box, grid, fillborders, scroll |
| x | FLOAT | 0.250–1 | — |
| y | FLOAT | 0.250–1 | — |
| w | FLOAT | 0.500–1 | — |
| h | FLOAT | 0.500–1 | — |
| color | STRING | #4ADE80 | — |
| thickness | INT | 31–40 | — |
| opacity | FLOAT | 1.000–1 | — |
| border_mode | COMBO | mirror | 6 options: smear, mirror, fixed, reflect, wrap, fade |
| border_px | INT | 320–512 | — |
| scroll_h | FLOAT | 0.00-1–1 | — |
| scroll_v | FLOAT | 0.00-1–1 | — |
| videoopt | COMFYTV_VIDEO | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| video | COMFYTV_VIDEO | — |