PNGTuber Video Mouth Builder
Same extraction as the upload node, but with every knob exposed
- mouthless_video
- mouth_track_json
- mouth_sprite_atlas_json
- bundle_manifest_json
- mouth_closed
- mouth_half
- mouth_open
- mouth_e
- mouth_u
- summary_json
This is the node behind PNGTuber Video Upload to Mouth Bundle - literally. PNGTuberVideoUploadToMouthBundle subclasses this class and calls its pipeline with a fixed set of sensible defaults. Reach for this one when you want the tuning knobs instead: the raw video_path input, the detection strategy, the inpainting geometry, and - the reason it's worth knowing about even if you never touch a slider - the erase_method switch.
The knob that matters most: erase_method
The upload node is hardwired to eigen, which means it needs the local Qwen image-edit stack (model, text encoder, VAE, TextEncodeQwenImageEditPlus) just to erase mouths, and it raises if the stack is missing. Here you can set erase_method to cv2 and get the pure-OpenCV path that runs on requirements.txt alone - the README's "OpenCV TELEA" story is real, it's just behind this switch. That's the difference between "needs several GB of model downloads" and "works on a fresh install." If you want Qwen-quality erasing but a smooth degradation story, eigen falls back to cv2 per-frame... except this node deliberately refuses that fallback, so pick cv2 upfront unless you're sure the stack is installed.
The rest of the controls
- video_path - a path to your video in ComfyUI's input folder (absolute paths work too).
- detection_mode -
anime_first(default) uses the bundled anime cascade, then MediaPipe, then YOLO;mediapipe_first,anime_only, andface_yolo_onlychange the order or pin one detector.face_yolo_fallback(true) lets the pipeline fall back to a YOLO face model if you have one atmodels/ultralytics/bbox/face_yolov8m.pt. - detection_confidence (0.5) - lower it if faces aren't being found; raise it to skip sketchy detections.
- max_frames (0 = all) and frame_stride (1 = every frame) - the classic speed dials for long clips.
- track_quad_scale (1.25), inpaint_scale (1.55), inpaint_radius (5) - how big the tracking quad and the erase mask are relative to the mouth. If the erased patch leaves mouth edges visible, bump
inpaint_scale. - sprite_size (512), preserve_audio (true), plus optional angle_range_degrees / angle_step_degrees (45/15) and occlusion_filter (true).
Outputs are the same ten strings as the upload node: mouthless_video, mouth_track_json, mouth_sprite_atlas_json, bundle_manifest_json, the five sprite paths (mouth_closed/mouth_half/mouth_open/mouth_e/mouth_u), and summary_json. Same bundle schema, so anything that consumes an upload-node bundle consumes this one.
Install and troubleshooting
Same pack install: ComfyUI Manager search for ComfyUI-PromptMaker-PNGTuber, or clone and pip install -r requirements.txt into the Python env ComfyUI uses, then restart. This class also has a compatibility alias registered as PromptMakerPNGTuberVideoMouth, which is the exact same node under an old name - if a workflow references that, it's this.
The practical failure modes are all inherited from the pipeline: a video where the character never opens their mouth gets flagged requiresModelGeneration (then run the generated mouth applier pass), and if the mouth quad drifts on turns, the angle atlas bins exist precisely so the player can pick the nearest-angle sprite rather than stretch one. And if detection flat-out fails on a stylized or heavily occluded face, don't fight the cascade - that's the moment to use a manual bbox, which the eigen-path builders expose as manual_mouth_bbox but this node doesn't. Prefer switching detection_mode first.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| video_path | STRING | input_video.mp4 | — |
| output_dir | STRING | — | |
| asset_id | STRING | pngtuber_video_mouth | — |
| max_frames | INT | 00–20000 | — |
| frame_stride | INT | 11–30 | — |
| detection_confidence | FLOAT | 0.500.1–0.95 | — |
| detection_mode | COMBO | anime_first | 4 options: anime_first, mediapipe_first, anime_only, face_yolo_only |
| face_yolo_fallback | BOOLEAN | true | — |
| track_quad_scale | FLOAT | 1.251–4 | — |
| inpaint_scale | FLOAT | 1.551–4 | — |
| inpaint_radius | INT | 51–31 | — |
| erase_method | COMBO | eigen | 2 options: eigen, cv2 |
| sprite_size | INT | 51264–2048 | — |
| preserve_audio | BOOLEAN | true | — |
| angle_range_degreesopt | INT | 4515–75 | — |
| angle_step_degreesopt | INT | 155–30 | — |
| occlusion_filteropt | BOOLEAN | true | — |
Outputs (10)
| Name | Type | Description |
|---|---|---|
| mouthless_video | STRING | — |
| mouth_track_json | STRING | — |
| mouth_sprite_atlas_json | STRING | — |
| bundle_manifest_json | STRING | — |
| mouth_closed | STRING | — |
| mouth_half | STRING | — |
| mouth_open | STRING | — |
| mouth_e | STRING | — |
| mouth_u | STRING | — |
| summary_json | STRING | — |