arkennemasis Video Assemble (clips + music + subs)
Concat, level speech, duck the music, burn the subs
- videos
- caption_style
- final_path
- video
Scene List fans a plan out so one chain renders every scene; Video Assemble is the node that brings it all back together. It declares INPUT_IS_LIST, so ComfyUI hands it the whole collection of finished clips in a single call, in order, however many there are. Then it does the four jobs that turn loose clips into a film: concatenate, level each clip's speech, trim and duck a music bed under it, and burn subtitles timed from the same scene plan that generated the video.
The problem it fixes before the first frame
Two things would wreck a naive "just join the clips" approach, and both are handled locally here. First, video models mix speech very quietly - measured around -20 to -27 dB on H3 output against roughly -16 LUFS for normal web video. Without levelling, the finished cut sounds nearly mute. normalize_speech (default on) levels each clip to EBU R128 -16 LUFS. Second, the music bed has to sit under the dialogue: music_volume defaults to 0.18, low enough not to fight the speech the clips already carry.
The inputs
Required: videos (wire the scene chain's video output - the loop delivers every scene to this one socket), output_dir (wire from Run Folder; relative paths resolve inside ComfyUI's output directory), and filename (default final).
Optional, and they carry most of the actual features:
scenes_json- the same plan that made the clips. ItsvoiceTextfields become the subtitles, timed from each clip's real duration, so cue N starts exactly where clips 1..N-1 ended. That's deliberately better than transcribing the finished audio and hoping the words line up.music_path- absolute path to a music file; blank = no bed. Trimmed to the video length automatically.burn_subtitles(default on) andcaption_style- wire a Caption Style node here for fonts and one of five subtitle styles (classic, karaoke, highlight, underline, word-by-word). Leave it unconnected for plain white captions;subtitle_size(default 0 = scale to about 4% of frame height) only applies then.crf- x264 quality, default 18, "visually lossless."
Outputs: final_path (the mp4) and video.
Two implementation details that tell you this was debugged for real
Subtitle timing runs a silencedetect pass on each clip to find where the narration actually stops - a dubbed shot is a fixed slot with a silent tail, so the audio stream's duration no longer says anything about the speech, and captions spread across the whole slot would drift seconds behind the voice. And the whole thing runs through ffmpeg (found on PATH or via imageio-ffmpeg), so the find_ffmpeg failure mode is the one to know about: if nothing's on PATH and imageio-ffmpeg isn't installed, assemble fails at startup.
Install
ArkVideoAssemble is one of the 61 nodes in the comfyui-arkennemasis pack, in arkennemasis/Video:
cd ComfyUI/custom_nodes
git clone https://github.com/Hishamahmer/comfyui-arkennemasis
pip install -r comfyui-arkennemasis/requirements.txt # then restart ComfyUI
Or ComfyUI Manager → Install via Git URL with the repo URL. It needs ffmpeg available and no API key. This is the node that makes the whole loop worth building: one canvas, N scenes, one film out - 5 scenes or 50, same wiring.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| videos | VIDEO | Wire the scene chain's video output here. The loop delivers every scene to this one socket, in order. | |
| output_dir | STRING | Where to write final.mp4. Relative paths resolve inside ComfyUI's output directory. Wire from Run Folder. | |
| filename | STRING | final | — |
| scenes_jsonopt | STRING | The same plan that made the clips. Its voiceText fields become the subtitles, timed from each clip's real duration. | |
| music_pathopt | STRING | Absolute path to a music file. Blank = no bed. Trimmed to the video length automatically. | |
| music_volumeopt | FLOAT | 0.180–1 | 0.18 sits under spoken dialogue. The clips carry their own speech, so this must stay low. |
| normalize_speechopt | BOOLEAN | true | Level each clip to EBU R128 -16 LUFS. Without it the finished cut sounds nearly mute. |
| burn_subtitlesopt | BOOLEAN | true | — |
| caption_styleopt | ARK_CAPTION_STYLE | Wire a Caption Style node here to choose the font and one of the five subtitle styles. Leave it unconnected for plain white captions at subtitle_size. | |
| word_timingsopt | STRING | Measured word timings from ArkWordTimings. Supplied, the moving caption styles mark the REAL word and the cue boundaries come from the audio too. Left unwired, both fall back to an estimate that drifts. | |
| subtitle_sizeopt | INT | 00–200 | 0 = scale to the video (about 4% of frame height), which is what you want when one workflow renders previews and finals at different sizes. Only used when caption_style is NOT connected — the style node carries its own size. |
| crfopt | INT | 180–51 | x264 quality; lower is better. 18 is visually lossless. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| final_path | STRING | — |
| video | VIDEO | — |