ComfyUI Node
Draw ViT Pose (V2)
Render the detected skeleton, face landmarks, iris pupils and gaze arrows onto a clean canvas at the target Wan 2.2 latent resolution. Outputs an IMAGE batch ready to drop into a Wan-Animate sampler.
Draw ViT Pose (V2)
- pose_data
- face_images
- pose_images
- face_video
- face_cfg_scale
- critic_report_json
- worst_aus_csv
- overall_mae
◄width832►
◄height480►
◄retarget_padding16►
◄body_stick_width-1►
◄hand_stick_width-1►
◄draw_headtrue►
◄pose_draw_threshold0.30►
◄draw_iristrue►
◄draw_gazetrue►
◄iris_radius4►
◄gaze_arrow_len30►
◄iris_min_confidence0.05►
◄iris_colorwhite►
◄face_cfg_scale1.0►
◄enforce_512_facetrue►
◄reference_expression_coeffs_json►
◄segment_length77►
◄top_k_aus10►
◄apply_pose_edits_to_facewarp►
CategoryWanAnimatePreprocess_V2
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| pose_data | POSEDATA | From Pose and Face Detection (V2). | |
| width | INT | 83264–2048 | Render canvas width (px). Match the sampler latent size. |
| height | INT | 48064–2048 | Render canvas height (px). Match the sampler latent size. |
| retarget_padding | INT | 160–512 | Padding (px) added around the body bbox when retargeting. Larger = more headroom for big motions. |
| body_stick_width | INT | -1-1–20 | Body skeleton stick width in px. -1 = auto from canvas size. |
| hand_stick_width | INT | -1-1–20 | Hand skeleton stick width in px. -1 = auto. |
| draw_head | BOOLEAN | true | Draw the head/face skeleton (eyes, nose, ears). |
| pose_draw_threshold | FLOAT | 0.300–1 | Per-keypoint score threshold for drawing. |
| draw_irisopt | BOOLEAN | true | Draw iris/pupil markers from MediaPipe iris_data. |
| draw_gazeopt | BOOLEAN | true | Draw gaze direction arrows from iris_data. |
| iris_radiusopt | INT | 41–20 | Pupil circle radius in pixels. |
| gaze_arrow_lenopt | INT | 304–200 | Length of gaze direction arrow in pixels. |
| iris_min_confidenceopt | FLOAT | 0.050–1 | Skip iris frames whose detection confidence is below this. |
| iris_coloropt | COMBO | white | Color of the drawn pupil; magenta gives strongest sampler signal. |
| face_imagesopt | IMAGE | OPTIONAL face crop IMAGE batch (typically the face_images_512 output of PoseAndFaceDetectionV2). When wired, the node validates frame-count parity with the pose batch, optionally force-resizes to 512x512, and forwards it on the 'face_video' output so a single DrawViTPoseV2 can feed the Wan-Animate sampler's pose+face inputs in one place. | |
| face_cfg_scaleopt | FLOAT | 1.01–10 | Passthrough face CFG scale, CONNECTION-ONLY (forceInput) so there is exactly one source of truth: PoseAndFaceDetectionV2.face_cfg_scale. It used to be a second independently-editable widget with the same default, so you could set 2.0 upstream, leave 1.0 here, and get no warning that they had diverged. Unconnected = 1.0 (no-op), which matches the old default. NOTE: Kijai's ComfyUI-WanVideoWrapper has no face-CFG input to wire this into today — for real control over expression adherence use WanVideoAnimateEmbeds.face_strength (spec 2.2's stronger, more direct block-scale lever) instead. |
| enforce_512_faceopt | BOOLEAN | true | If True and 'face_images' is provided at a non-512 size, force-resize each frame to 512x512 (bilinear) before forwarding. Default True so the encoder always sees the trained input shape. |
| reference_expression_coeffs_jsonopt | STRING | Wan-Animate spec 3.1 (closed-loop critic): wire in the 'expression_coeffs_json' output of a PoseAndFaceDetectionV2 run (export_expression_coeffs=True) on the SOURCE driving video. When non-empty, this node measures ARKit-52 blendshapes from ITS OWN pose_data.iris_data (i.e. the GENERATED Wan-Animate output side, since this node is downstream of the generation pass) and reports per-AU + per-segment error against the reference — a numeric fidelity signal instead of eyeballing frames. Leave empty to skip entirely (zero extra cost). | |
| segment_lengthopt | INT | 771–100000 | Frames per segment for the critic's worst-segment breakdown — match WanVideoAnimateEmbeds.frame_window_size (default 77) so segments line up with Wan-Animate's own splice boundaries (spec 2.5/3.5). Only used when reference_expression_coeffs_json is wired. |
| top_k_ausopt | INT | 101–52 | How many worst-tracked AUs the critic reports, worst-first. Only used when reference_expression_coeffs_json is wired. |
| apply_pose_edits_to_faceopt | COMBO | warp | Expression-edit DELIVERY (2026-07-24). When pose_data carries edited face landmarks (WanFaceController3DV2 expression dials / dragged landmarks) AND face_images is wired, 'warp' moves the ACTUAL face-crop pixels from the original landmark positions to the edited ones (same Delaunay piecewise-affine engine as FC3D's preview), so the Wan-Animate face encoder sees the edit. Without this, landmark edits only change the drawn skeleton — the photographic face crop stays neutral and the sampler follows the crop, i.e. your expression edits silently do nothing. No-op when landmarks are unedited (zero cost), so the default stays 'warp'. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| pose_images | IMAGE | Rendered skeleton IMAGE batch. Feed into your Wan 2.2 Animate sampler. |
| face_video | IMAGE | Passthrough face IMAGE batch (512x512 if enforce_512_face). Empty single-frame zero tensor if 'face_images' was not wired. |
| face_cfg_scale | FLOAT | Passthrough face_cfg_scale (Wan-Animate paper Sec. 4.3). 1.0 = CFG off. |
| critic_report_json | STRING | Wan-Animate spec 3.1 closed-loop critic report (JSON): per-AU mean-absolute-error, per-frame error curve, per-segment breakdown worst-first. '{}' when reference_expression_coeffs_json was not wired. |
| worst_aus_csv | STRING | CSV 'name,mae' for the top_k_aus worst-tracked AUs, worst first. Empty string when the critic did not run. |
| overall_mae | FLOAT | Mean of all per-AU MAE values (0.0 = perfect match to the reference). 0.0 when the critic did not run. |