VideoMark Title
Two seconds of black and a copyright line, without leaving ComfyUI
- images
- logo
- logo_mask
- audio
- images
- audio
The bit the overlay node can't do
VideoMark Overlay stamps every frame you hand it, which is the wrong tool for a credit card - those live outside the clip. VideoMark Title renders card frames and splices them onto the front and/or back of an IMAGE batch, then returns the longer batch plus an audio track shifted to match. Head, tail, or both; text, logo, or both; about 2 seconds is the usual.
Why not just do it in an editor? Because that's one more turn of the export-review-reimport loop, and because a card you can re-queue is a card you'll actually update: change the year in the copyright line, hit queue, done. If you generate clips in batches - a Wan run, a side-view sweep, a LoRA comparison - a card that lands on every output beats remembering to add it afterwards.
Pack reputation note, since there isn't one: this is a young, low-profile pack with essentially no discussion in the r/StableDiffusion + r/comfyui + r/civitai corpus - a search for "videomark" across two years returns nothing. The watermark talk that does exist mostly runs the other way, people stripping marks rather than adding them. Judge this one on the code.
How it works
seconds × fps gives the frame count (max(1, round(seconds * fps))). A solid card of that many frames is rendered once - background colour, then text and optional logo laid out as a percentage of frame width - and concatenated before your batch, after it, or both. The card frames come out clean: they don't get the watermark. fade_frames fades the card in from pure black and back out, which on a black background reads as your text and logo fading in.
Connect an audio track and pad_audio inserts matching silence - seconds of it at the head, the tail, or both - so picture and sound still line up after the splice. That's the whole node: numpy and Pillow, no model, no dependencies.
The inputs you'll actually touch
fps- the one field that silently ruins renders. The node converts seconds to frames with it, so it has to match the rate you mux at (H3 commonly outputs 24). Get it wrong and your "2 second" card is 1.6 or 2.5.where-head,tail, orboth, plusseconds.text- multiline, so© 2026 you\nAll rights reservedworks; map it to a year you'll actually update. Optionaltext_inlets an upstream string node (Text Concatenate, String Function) take over the card text, and blank upstream falls back to the widget instead of blanking the card.bg_color(default pure black),use_text/use_logo,logo_scaleandtext_scale(both percentages of frame width; 20–30 suits a Chinese end card),text_colorandtext_stroke_width(leave at 0 on black, give it 2–4 if you lighten the background),fade_frames(8 by default, 0 for a hard cut).pad_audio- leave it on. Plus the optionalaudioinput and the same logo trio the Overlay uses:logo_file, or a wiredlogoIMAGE (the wire wins), withlogo_maskoverriding a PNG's own alpha.
Two outputs: images (the extended batch) and audio (the padded track, empty if you connected nothing).
Wiring it up
… video model → decode to IMAGE ──► VideoMark Title ──images──► video combine / SaveVideo
↑ ↑
audio ─┘───────────────────────┘
Put it after the Overlay, or you'll watermark your own copyright card. And note the node isn't an output node: if nothing downstream consumes images, the graph never executes it. Add a SaveImage or a combine node, or you'll conclude the node is broken.
Install
# ComfyUI Manager: search "comfyui-videomark"
cd ComfyUI/custom_nodes
git clone https://github.com/kaerozhi/comfyui-videomark.git
Or comfy node install comfyui-videomark. Nothing to pip install - this pack adds exactly zero to your Python environment. Restart ComfyUI so the built-in panel loads.
Where people get burned
Audio that drifts by exactly your card length. That's pad_audio off. A 2-second card with an unpadded track puts the whole soundtrack 2 seconds early against picture, and everything downstream is wrong. It's on by default; leave it.
A card holder with no card. use_logo defaults to off, so wiring a logo image changes nothing until you flip it - same trap as the Overlay.
黑体 (simhei) has no © glyph and renders a box where the symbol should be. Use 微软雅黑 / 宋体 / 楷体, or set font_file to an absolute path. If the font dropdown offers only the built-in fallback, font_file is your only option.
A card that looks like a black-to-white wipe. The fade starts from black, not from transparent - fine on purpose with a non-black bg_color, jarring by accident.
A card that's the wrong length after export. Almost always a mux rate that differs from fps, not the node.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| fps | FLOAT | 241–240 | Frame rate, used to convert seconds into a frame count. Must match the final clip's frame rate or the card length will be off (H3 usually outputs 24fps). |
| where | COMBO | head | head = only at the start, tail = only at the end, both = both ends (each gets a full card). |
| seconds | FLOAT | 2.00.1–60 | Card duration in seconds. Around 2s works well for a copyright notice. |
| text | STRING | © 2026 kaero All rights reserved | Card text. Multiple lines supported. |
| use_text | BOOLEAN | true | Turn off to show the logo only. |
| bg_color | STRING | #000000 | Card background colour. Pure black by default. |
| use_logo | BOOLEAN | false | Master switch for drawing the logo. Same sources as Overlay: panel upload, or a linked IMAGE. |
| layout | COMBO | vertical | How logo and text stack when both are present: vertical (logo on top) or horizontal (logo on the left). |
| logo_scale | FLOAT | 30.01–100 | Logo width as a percentage of the frame width. |
| text_scale | FLOAT | 24.01–100 | Text width as a percentage of the frame width. 20~30 reads well for a credit card. |
| text_color | STRING | #FFFFFF | Card text colour. |
| text_stroke_width | INT | 00–24 | Text stroke thickness. Give it 2~4 when the background is not pure black. |
| text_stroke_color | STRING | #000000 | Card text stroke colour. |
| font | COMBO | (built-in fallback font - CJK glyphs render as boxes) | Font. Sorted CJK-first on Windows (Microsoft YaHei / SimHei / SimSun / KaiTi ...). Fonts you drop into ComfyUI's input/fonts folder show up in this list too. Note: SimHei has no glyph for © - it renders as a box. Use Microsoft YaHei / SimSun / KaiTi for text containing ©. |
| font_file | STRING | Font file path relative to ComfyUI's input folder, e.g. fonts/MyFont.otf. When set and the file exists it overrides the font list above. Absolute paths and '..' are rejected. | |
| fade_frames | INT | 80–240 | Fade-in / fade-out length in frames. On a black card this reads as the text/logo fading; 0 = hard cut. |
| pad_audio | BOOLEAN | true | Pad the audio with matching silence so adding a head card does not desync A/V. Keep this on whenever music is connected. |
| logo_file | STRING | Logo file name, relative to ComfyUI's input folder. Clicking 'Upload logo' in the visual panel fills this in; you normally never edit it by hand. You can also type the name of a file already placed in the input folder, e.g. logo/kaero.png. Note: a linked IMAGE on the logo input always wins over this. | |
| text_inopt | STRING | Optional. Feed the text in from another node (any node that builds a string). When connected and non-empty the wired text wins - whatever you typed in the panel is ignored. Disconnected, or an empty string upstream, falls back to the panel text. Typical use: while comparing parameter variants (resolutions / LoRA strengths / seeds), splice this run's parameters into the frame so you can tell at a glance which settings produced it. Note: it takes one plain string - nothing is filled in for you, so build the text you want upstream. | |
| logoopt | IMAGE | Optional. A PNG logo with an alpha channel. Only drawn when use_logo is on. Transparency comes from logo_mask first; falls back to the PNG's own alpha. | |
| logo_maskopt | MASK | Optional. Transparency mask for the logo; falls back to the PNG's own alpha. ComfyUI's Load Image outputs a PNG's transparency as a MASK - just wire it in. | |
| audioopt | AUDIO | Optional. Video audio track. Only when connected does the node pad silence and pass it through. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| audio | AUDIO | — |