Magic Hour: Lip Sync
Magic Hour: Lip Sync
- video
- audio
- video
- video_path
- credits_charged
Two inputs, video and audio, and the face in the video speaks the audio. It's the dubbing tool: you have footage of a person talking and a track that isn't what they said, and you want the mouth to agree with the track.
The local picture, honestly
This is one of the few jobs where local is genuinely good. The KB's audio doc ranks the open options: InfiniteTalk is the fast talking-head default and by far the most-discussed in the corpus, supporting unlimited-length video-to-video dubbing; LongCat Avatar does smoother results slower; Wan S2V has a poor local reputation. ComfyUI's ecosystem has real depth here.
So the honest case for paying is: you don't have the GPU, or you don't want another node pack's dependency stack, or you need a result in two minutes rather than an afternoon of setup. The honest case for local is: free iterations, no upload of footage of a person's face, and you can run a hundred variants of a five-second clip while you're thinking about it.
How it works
Your video is written to a temp MP4 and your audio to a temp 16-bit WAV. Both are uploaded, the remote model retimes the mouth region to the phonemes, and the result comes back into ComfyUI/output/magic_hour/ as an MP4 wrapped in a VIDEO.
The 60-second thing. The pack caps the audio length it considers at 60 seconds, and the sync window is the minimum of the video's length and that capped audio length. So if your clip is 30 seconds and your audio is five minutes, you get a 30-second window; if your clip is two minutes and your audio is twenty seconds, you get twenty. Leave end_seconds at 0 and it resolves to that minimum automatically, which is the right behaviour and also exactly why people are surprised when a long track produces a short result.
If end_seconds can't be resolved - no clip length available and you left it at zero - the node raises a clear error and tells you to set it. Video duration detection isn't always available across ComfyUI versions, so on older builds you'll set both ends manually more often than you'd expect.
generation_mode
Three choices: standard, lite, pro. standard is the default and the sensible starting point. lite is the cheap-and-fast tier - worth using while you're working out the window and the framing, because you're going to throw those runs away anyway. pro is the one you switch to for a final render where the mouth shapes have to hold up under scrutiny.
My advice: do every iteration at lite, then exactly one run at pro with settings you've already validated. Same pattern as 640px in the Image Editor - the expensive pass should never be the one that discovers a problem.
Inputs and outputs
Required: video (the face to drive), audio (the speech to match), generation_mode, start_seconds, end_seconds.
Best results: the subject facing camera, mouth clearly visible, decent light. Profile shots, hands over the face and heavy beards are all harder, and a face that's 40 pixels wide in a wide shot gives the model nothing.
Outputs: video (the synced clip as a real VIDEO), video_path (STRING, the saved file), credits_charged (INT).
Install
cd ComfyUI/custom_nodes
git clone https://github.com/magichourhq/comfyui-magic-hour
pip install -r comfyui-magic-hour/requirements.txt
Restart ComfyUI, then look under Magic Hour. The only requirement is magic-hour>=0.87.1, and you need a ComfyUI new enough to have the VIDEO type - otherwise the node raises an error pointing you at the video_path output, which still works. ComfyUI Manager users can search "Magic Hour".
export MAGIC_HOUR_API_KEY=your_key_here
before starting ComfyUI, or a bare key in comfyui-magic-hour/api_key.txt. Keys aren't widgets on purpose: widget values are stored in the workflow and shared with it.
What breaks
Audio longer than the clip. Expected behaviour, and the most common confusion. The node syncs a window; it doesn't extend your video to fit your song.
Two clips of different lengths. The window is the shorter of the two. Trim upstream so you're not guessing.
Mouth-only artifacts. Teeth, tongue, hard consonants at the edge of the frame - lip sync always shows its seams there. Check a frame-by-frame pass on the hardest two seconds before you commit to a full render.
Queue blocked for minutes. Same as every video node here. It waits synchronously.
Content filters. Your footage and audio go to a hosted service with moderation. A refusal comes back as an error, and there is no local workaround inside this node.
The workflow that actually makes sense: generate the voice locally (Chatterbox or Kokoro), sync a single hero shot here at lite to validate, then decide whether the local InfiniteTalk route is worth setting up for the volume you need.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| video | VIDEO | — | |
| audio | AUDIO | — | |
| generation_mode | COMBO | standard | 3 options: standard, lite, pro |
| start_seconds | FLOAT | 0.00–3600 | — |
| end_seconds | FLOAT | 0.00–3600 | 0 = to the end of the clip |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| video | VIDEO | — |
| video_path | STRING | — |
| credits_charged | INT | — |