Nodes/ComfyUI_zura_nodes/Zura · Prepare H3 Viewport Frames
ComfyUI Node

Zura · Prepare H3 Viewport Frames

Turn a grey blockout into something H3 will render from

By ZURAVFX·Created about a month ago·Updated a day ago· 2
Zura · Prepare H3 Viewport Frames
  • video
  • reference_frames
  • width
  • height
  • padded_frames
  • real_frames
  • crop_x
  • crop_y
  • crop_width
  • crop_height

The "viewport to final" route is one of the more interesting ideas in Zura Studio: block out a scene in 3D, render the grey mesh as a clip, and let a video model dress it into something photoreal. GenjH3ViewportFrameData ("Zura · Prepare H3 Viewport Frames") is the node that makes a blockout clip acceptable to H3 - and, more importantly, tells the graph how to get the original camera framing back afterwards.

It's the viewport sibling of GenjH3FramePad, with two real differences: there's no mask, because the whole scene is being regenerated from a reference video rather than a region of a real shot; and it returns a crop window instead of a performer mask.

How it works

It takes video - the prepared viewport clip, already trimmed by GenjSelectClip - and:

  • Validates. 24 fps (Prepare the viewport clip at 24 fps before using H3.), 5–120 frames (Local H3 viewport renders currently support 0.21–5 seconds per take. Select a five-second section of the train scene.), and a finite, 4-dimensional frame tensor.
  • Pads to a 32-multiple with a replicated border, not a crop. Both dimensions go up to ceil(size / 32) × 32, and the new pixels come from edge replication. The comment in the source is explicit about why: 16:9 sizes like 1280×720 get a tiny border rather than being cropped or stretched, so the camera geometry in your blockout is preserved exactly.
  • Computes padded_frames as valid_length(count) - the 5 + 17 × ceil((n − 5) / 17) grid H3 wants - and passes real_frames as the count you actually asked for.
  • Returns the padding offsets so the pipeline can undo them.

Inputs and outputs

One input: video (VIDEO). Nine outputs:

| Output | What it's for | | --- | --- | | reference_frames (IMAGE) | the padded viewport frames, as H3's video reference | | width, height (INT) | the padded raster - used to scale the opening still and the depth guide to match | | padded_frames, real_frames (INT) | generation length and the trim-back length | | crop_x, crop_y (INT) | where the real image sits inside the padded frame | | crop_width, crop_height (INT) | the original unpadded dimensions |

The pack wires width/height into ImageScale on the opening image so the still matches the generation canvas, and feeds the crop values to an ImageCrop after decoding. Here's the nice part about using the original dimensions rather than the padded ones: both 1920×1080 and 1280×720 are already multiples of 32 in the useful sense, so for typical 16:9 sources the crop is a no-op and the padded border is only a few pixels wide. On an odd source size, the crop is what stops you shipping a film with an edge-replicated stripe down one side.

Install

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

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

Pure tensor work - no ffmpeg call, no model. The models the viewport route needs are the H3 stack (minimax_h3_ref2va_pruned_int8_convrot.safetensors and friends from INSTALL_STUDIO.md) plus whatever produced your blockout.

Practical notes

A blockout is a reference, not a control. In the pack's own validation notes, the viewport integration tests all returned exactly 120 frames at 24 fps - the plumbing works - but "a structurally valid graph does not guarantee visual identity". If your mesh has a character-shaped blob on a train seat, H3 will invent a person there, and it will be its person. The pack's stated position is that these runs are integration tests until an artist accepts the specific output, which is a refreshingly honest way to put it.

Don't feed it the source clip. This node is for the viewport branch. If you're replacing a performer in a real shot, you want GenjH3FramePad plus a mask; the viewport route has no mask input because it has no notion of "keep this part untouched".

Give it five seconds or less, at 24 fps, from GenjSelectClip. Everything else in the pack follows from those two constraints.

CategoryZura/Artist Studio

Inputs (1)

NameTypeDefaultDescription
videoVIDEO—

Outputs (9)

NameTypeDescription
reference_framesIMAGE—
widthINT—
heightINT—
padded_framesINT—
real_framesINT—
crop_xINT—
crop_yINT—
crop_widthINT—
crop_heightINT—