Nodes/ComfyUI_zura_nodes/Zura · Save Guidance Review
ComfyUI Node

Zura · Save Guidance Review

The node that makes you look at the mask before it renders

By ZURAVFX·Created about a month ago·Updated a day ago· 2
Zura · Save Guidance Review
  • clip_details
  • source_frames
  • mask
  • guide_frames
  • guidance_audio
  • performer_mask
  • tracking_coverage
  • shot_id

A five-second Wan or H3 render is minutes to tens of minutes. Finding out at the end that your performer mask clipped the ear off, or that the guidance frames don't line up with the audio, is an expensive way to learn. GenjSaveReview ("Zura · Save Guidance Review") exists to make that mistake annoying instead of costly: it writes the mask, the guidance and a red-tinted preview to disk as one immutable shot, and stamps them with a content-derived ID.

The mechanism

Everything you connect gets validated, then frozen:

  • Every frame count has to match. Source frames, mask, and guide frames must be the same length. Source, mask and guidance must have the same number of frames. is the error, and it's usually a truncated decode rather than a logic bug.
  • The mask gets normalised - nearest-resize to the source raster, then thresholded at 0.5 so it's genuinely binary. Video models care about hard masks more than you'd hope.
  • It refuses an empty mask. The performer mask is empty. Repair it before generation. A too-high detector threshold or an object that isn't in the shot produces exactly this.
  • The shot ID is a hash of the content. shot_ plus the first 16 hex characters of a sha256 over the clip details, every mask frame, every guide frame, the audio samples and the sample rate. Change one pixel of mask and it's a different shot, with a different ID, in a different folder. That's what makes it safe to say "the thing you approved is the thing that gets rendered."

The output folder is output/genj/reviews/<shot_id>/, and it contains source.mp4, mask.mp4, guide.mp4, mask_review.mp4 (the source with the mask tinted orange-red over it - the one you actually eyeball), opening_frame.png, and a review.json manifest listing a sha256 for every file. If you connect the optional performer_mask, it also writes performer_mask.mp4, and that changes the shot ID, deliberately: the genuine performer mask is bound into the identity so it can never be confused with the combined edit mask during text cleanup.

Inputs and outputs

Required: clip_details (GENJ_CLIP, usually from GenjSelectClip), source_frames (IMAGE), mask (MASK - the combined edit mask, i.e. everything the model is allowed to repaint), guide_frames (IMAGE, the pose/performance guide), guidance_audio (AUDIO).

Optional: performer_mask (MASK, the honest performer union before text or props got added to the edit mask) and tracking_coverage (GENJ_TRACK_COVERAGE from ZuraJoinTrackingMasks, which must cover every source frame or you get Tracking coverage must match every source frame.).

The one output is shot_id, a STRING. Wire it into GenjLoadReviewedShot - and note that as an output node it also pushes the mask_review.mp4 and guide.mp4 previews into the ComfyUI UI with the text "Mask ready. Review the full mask and guidance previews in Zura Studio, then choose Use this mask."

Install

ComfyUI Manager → search Zura Nodes → install → restart. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
python -m pip install -r ComfyUI/custom_nodes/ComfyUI_zura_nodes/requirements.txt

This node uses PyAV to write its previews, so av from that requirements file plus ffmpeg/ffprobe on your PATH are non-negotiable - the pack's own error message is Install FFmpeg and add it to PATH, then restart ComfyUI. No model weights are needed for this node; the detector that builds your mask is the part that downloads things.

Where people get burned

  • Re-preparing a shot you already approved. The shot ID is content-addressed, so any change to the mask, the guide or the audio creates a new shot and the old approval no longer applies. If you're using the pack's Studio interface it links the new shot automatically; in a hand-built graph you have to paste the new shot_id into both fields of GenjLoadReviewedShot.
  • Assuming the tinted preview is the mask. It's the source with the mask overlaid at 50%, which is easier to judge than a white-on-black render but not pixel-accurate at the edges.
  • Wiring the combined mask into performer_mask as well. That's the one input where doing the obvious thing quietly breaks the text-removal branch later, because the "genuine performer" union is supposed to exclude the caption rectangles.
CategoryZura/Artist Studio

Inputs (7)

NameTypeDefaultDescription
clip_detailsGENJ_CLIP—
source_framesIMAGE—
maskMASK—
guide_framesIMAGE—
guidance_audioAUDIO—
performer_maskoptMASK—
tracking_coverageoptGENJ_TRACK_COVERAGE—

Outputs (1)

NameTypeDescription
shot_idSTRING—