Zura · Prepare H3 Viewport Frames
Turn a grey blockout into something H3 will render from
- 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_framesasvalid_length(count)- the5 + 17 × ceil((n − 5) / 17)grid H3 wants - and passesreal_framesas 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.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| video | VIDEO | — |
Outputs (9)
| Name | Type | Description |
|---|---|---|
| reference_frames | IMAGE | — |
| width | INT | — |
| height | INT | — |
| padded_frames | INT | — |
| real_frames | INT | — |
| crop_x | INT | — |
| crop_y | INT | — |
| crop_width | INT | — |
| crop_height | INT | — |