Advanced Text Overlay - Video
Put titles on a video without nuking the audio track
- video_path
Most text-overlay nodes in ComfyUI are image-only, which leaves you with a nasty choice when you want a title or subtitle burned into a clip: render the video to a batch of frames, overlay each one, reassemble, and pray the audio doesn't get orphaned. Advanced Text Overlay - Video is the same renderer as the pack's image node, but pointed at a file path instead of an IMAGE tensor, and it writes a finished MP4 - audio re-muxed back in - to ComfyUI's output folder.
You give it video_path (a plain string path to a video file on disk), and it reads the file frame by frame with imageio, applies the identical text engine, and writes a new MP4. The interesting bit is at the end: after rendering it shells out to ffmpeg and does a stream copy (-c copy -map 0:v:0 -map 1:a:0) to splice the original audio track into the new file. That's a zero-re-encode merge, so audio quality isn't touched.
The inputs that matter
Everything from the image node is here - text, font, font_size, fill_color_hex, stroke_*, bg_*, shadow_*, alignment, and the full animation_* set - plus three video-specific ones at the top:
video_path- full path to the input file. Not an Upload node; you type or wire in a path string.filename_prefix- the output name becomes{prefix}_{original_name}.mp4(defaultTxtOver). It auto-increments so it never overwrites an existing file.delete_original- if you flip this on, the source video is deleted after processing. Probably leave it off until you've confirmed the output looks right.
One deliberate difference from the image node: the pause input here is pause_seconds_before_start, not pause_frames_before_start. It's converted to frames using the source video's FPS, so "2" really means two seconds. Same animation system otherwise - fade or slide in over animation_frames, then hold the final pose for the rest of the clip. The output is a single video_path string (the node is an output node, so it shows up in the UI's outputs panel).
Installing it
Identical to the rest of the pack:
cd ComfyUI/custom_nodes
git clone https://github.com/scofano/ComfyUI-Advanced-TextOverlay
pip install -r requirements.txt
Restart, and it's under Advanced Text Overlay in the node list. No model files, no huge dependencies - numpy, torch, Pillow, imageio, tqdm, fonttools.
Where people get burned
The one real external dependency is ffmpeg itself, and it's not in the pip requirements - the code just shells out to the ffmpeg binary. If it's missing from your PATH, the overlay still renders fine, but you get a silent video and a console message saying the mux failed. Most ComfyUI installs have ffmpeg around already (imageio-ffmpeg bundles one), but if you're on a bare container, apt install ffmpeg or the equivalent is the fix.
Other things to know: this re-encodes every frame, so a long clip takes real time - the progress bar is your friend. And the writer is told to use macro_block_size=1 so frames aren't silently resized to multiples of 16, which keeps your overlay exactly where you laid it out. If your output looks slightly different in size from the source, check whether something upstream gave you an odd resolution in the first place. And again: delete_original deletes your source file. It's a convenience flag, not a requirement.
Inputs (36)
| Name | Type | Default | Description |
|---|---|---|---|
| video_path | STRING | — | |
| filename_prefix | STRING | TxtOver | — |
| delete_original | BOOLEAN | false | — |
| text | STRING | the quick brown fox jumps over the lazy dog | — |
| all_caps | BOOLEAN | false | — |
| font | COMBO | Arial | 33 options: Arial, Arial Black, Arial Narrow, C059, Comic Sans MS, Courier New, +27 |
| font_size | INT | 321–9999 | — |
| letter_spacing | FLOAT | 0.0-10–50 | — |
| font_alignment | COMBO | center | 3 options: left, center, right |
| fill_color_hex | STRING | #FFFFFF | — |
| fill_alpha | FLOAT | 1.000–1 | — |
| padding | INT | 160–1024 | — |
| vertical_alignment | COMBO | middle | 3 options: top, middle, bottom |
| y_shift | INT | 0-1024–1024 | — |
| horizontal_alignment | COMBO | center | 3 options: left, center, right |
| x_shift | INT | 0-1024–1024 | — |
| line_spacing | FLOAT | 4.00–50 | — |
| stroke_enable | BOOLEAN | true | — |
| stroke_color_hex | STRING | #000000 | — |
| stroke_thickness | FLOAT | 0.200–1 | — |
| stroke_alpha | FLOAT | 1.000–1 | — |
| bg_enable | BOOLEAN | false | — |
| bg_padding | INT | 80–1024 | — |
| bg_radius | INT | 80–512 | — |
| bg_color_hex | STRING | #000000 | — |
| bg_alpha | FLOAT | 0.500–1 | — |
| shadow_enable | BOOLEAN | false | — |
| shadow_distance | INT | 3-50–50 | — |
| shadow_color_hex | STRING | #000000 | — |
| shadow_alpha | FLOAT | 0.700–1 | — |
| animate | BOOLEAN | false | — |
| animation_kind | COMBO | fade_in | 6 options: fade_in, fade_out, move_from_top, move_from_bottom, move_from_left, move_from_right |
| animation_frames | INT | 321–1000 | — |
| animation_ease | COMBO | ease_in_out | 4 options: linear, ease_in, ease_out, ease_in_out |
| animation_opacity_target | FLOAT | 1.000–1 | — |
| pause_seconds_before_start | INT | 00–100000 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| video_path | STRING | — |