Nodes/Advanced Text Overlay/Advanced Text Overlay - Video
ComfyUI Node

Advanced Text Overlay - Video

Put titles on a video without nuking the audio track

By scofano·Created 10 months ago·Updated 3 months ago· 24
Advanced Text Overlay - Video
    • video_path
    video_path
    filename_prefixTxtOver
    delete_originalfalse
    textthe quick brown fox jumps over the lazy dog
    all_capsfalse
    fontArial
    font_size32
    letter_spacing0.0
    font_alignmentcenter
    fill_color_hex#FFFFFF
    fill_alpha1.00
    padding16
    vertical_alignmentmiddle
    y_shift0
    horizontal_alignmentcenter
    x_shift0
    line_spacing4.0
    stroke_enabletrue
    stroke_color_hex#000000
    stroke_thickness0.20
    stroke_alpha1.00
    bg_enablefalse
    bg_padding8
    bg_radius8
    bg_color_hex#000000
    bg_alpha0.50
    shadow_enablefalse
    shadow_distance3
    shadow_color_hex#000000
    shadow_alpha0.70
    animatefalse
    animation_kindfade_in
    animation_frames32
    animation_easeease_in_out
    animation_opacity_target1.00
    pause_seconds_before_start0

    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 (default TxtOver). 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.

    CategoryAdvanced Text Overlay

    Inputs (36)

    NameTypeDefaultDescription
    video_pathSTRING
    filename_prefixSTRINGTxtOver
    delete_originalBOOLEANfalse
    textSTRINGthe quick brown fox jumps over the lazy dog
    all_capsBOOLEANfalse
    fontCOMBOArial33 options: Arial, Arial Black, Arial Narrow, C059, Comic Sans MS, Courier New, +27
    font_sizeINT321–9999
    letter_spacingFLOAT0.0-10–50
    font_alignmentCOMBOcenter3 options: left, center, right
    fill_color_hexSTRING#FFFFFF
    fill_alphaFLOAT1.000–1
    paddingINT160–1024
    vertical_alignmentCOMBOmiddle3 options: top, middle, bottom
    y_shiftINT0-1024–1024
    horizontal_alignmentCOMBOcenter3 options: left, center, right
    x_shiftINT0-1024–1024
    line_spacingFLOAT4.00–50
    stroke_enableBOOLEANtrue
    stroke_color_hexSTRING#000000
    stroke_thicknessFLOAT0.200–1
    stroke_alphaFLOAT1.000–1
    bg_enableBOOLEANfalse
    bg_paddingINT80–1024
    bg_radiusINT80–512
    bg_color_hexSTRING#000000
    bg_alphaFLOAT0.500–1
    shadow_enableBOOLEANfalse
    shadow_distanceINT3-50–50
    shadow_color_hexSTRING#000000
    shadow_alphaFLOAT0.700–1
    animateBOOLEANfalse
    animation_kindCOMBOfade_in6 options: fade_in, fade_out, move_from_top, move_from_bottom, move_from_left, move_from_right
    animation_framesINT321–1000
    animation_easeCOMBOease_in_out4 options: linear, ease_in, ease_out, ease_in_out
    animation_opacity_targetFLOAT1.000–1
    pause_seconds_before_startINT00–100000

    Outputs (1)

    NameTypeDescription
    video_pathSTRING