ComfyUI Node
H3 Studio (Image to Video)
MiniMax H3 first/last frame conditioning with an adjustable strength per keyframe, so either frame can guide the motion instead of pinning it.
H3 Studio (Image to Video)
- clip
- vae
- first_frame
- last_frame
- ref_videos
- ref_video_audios
- audio_vae
- ref_images
- ref_masks
- ref_audios
- middle_frames
- v2v_images
- v2v_audio
- positive
- LATENT
- v2v_denoise
◄prompt—►
◄width1344►
◄height768►
◄length124►
◄first_frame_strength1.00►
◄last_frame_strength1.00►
◄first_frame_file►
◄last_frame_file►
◄middle_frame_files►
◄ref_image_files►
◄ref_video_spec►
◄ref_video_files►
◄ref_video_megapixels0.00►
◄ref_audio_files►
◄first_frame_crop►
◄last_frame_crop►
◄middle_frame_crops►
◄ref_image_crops►
◄middle_frame_spec►
◄timed_text►
◄timed_text_modetext only►
◄ref_spec►
◄ref_image_sizematch►
◄ref_megapixels0.00►
◄ref_audio_strength1.00►
◄mask_ref_pixelsfalse►
◄ref_video_crops►
◄v2v_video_file►
◄v2v_start_seconds0.0►
◄v2v_end_seconds0.0►
◄v2v_denoise0.55►
◄v2v_crop►
◄motion_context_file►
◄motion_context_end_seconds0.0►
◄motion_context_frames22►
◄motion_context_audio_frames22►
◄v2v_noise0.00►
◄v2v_noise_declare1.00►
◄motion_context_reuse_latenttrue►
◄motion_context_anchor_brightnesstrue►
◄motion_context_strength0.92►
◄motion_scale1.00►
◄motion_curve►
◄sound_anchors►
Categorymodel/conditioning/minimax
Inputs (57)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | CLIP | — | |
| vae | VAE | — | |
| prompt | STRING | — | |
| width | INT | 134432–16384 | — |
| height | INT | 76832–16384 | — |
| length | INT | 1245–3600 | Frame count at 24 fps, snapped up to the model's 17k+5 grid (124 = ~5s; trained range is ~124-362, longer is untested) |
| first_frame_strength | FLOAT | 1.000–2 | How hard the start frame is enforced. 1.0 matches the stock node (opens exactly on the frame). Lower values dilute the start keyframe toward noise so it reads as a direction rather than a fixed opening -- useful when the first frame is a rough comp or the wrong crop, or to let the model reinterpret the subject. Note the start frame also sets the shot's geometry, so it usually wants a higher value than the end frame. Above 1.0 amplifies the latent and overdrives adherence. No effect unless a first frame is connected or file-picked. |
| last_frame_strength | FLOAT | 1.000–2 | How hard the end frame is enforced. 1.0 matches the stock node (lands on the frame). Lower values dilute the end keyframe toward noise so it reads as a direction rather than a destination -- 0.6-0.8 keeps composition and colour while freeing the motion, 0.3-0.5 is a loose hint, 0.0 ignores it. Above 1.0 amplifies the latent and overdrives adherence. No effect unless a last frame is connected or file-picked. |
| first_frame_file | STRING | Load the first frame straight from the input folder (the timeline UI's picker writes this). Ignored when the first_frame socket is connected -- sockets always win, so Zoom & Pan / graph sources keep working. | |
| last_frame_file | STRING | Load the last frame straight from the input folder. Ignored when the last_frame socket is connected. | |
| middle_frame_files | STRING | Extra middle frames loaded straight from the input folder, one filename per line (the timeline UI's picker writes this). These come AFTER any connected middle_frame_ sockets in the ordering that middle_frame_spec lines pair with. File-based frames can't take ref masks. | |
| ref_image_files | STRING | Extra reference images loaded straight from the input folder, one filename per line. These come AFTER any connected ref_image_ sockets in the ordering ref_spec pairs with. File-based references can't take ref masks (masks pair with socket slots). | |
| ref_video_spec | STRING | OPTIONAL. One strength per reference video, in sockets-then-files order. Empty = 1.0. Applies to the video latent AND its soundtrack together. | |
| ref_video_files | STRING | Reference videos loaded straight from the input/output folder, one filename per line (mp4/webm/mov -- the editor's picker writes this, and 'name [output]' chains from a previous render). Resampled to 24 fps, capped at 15s; an embedded soundtrack is used automatically (needs audio_vae). | |
| ref_video_megapixels | FLOAT | 0.000–4 | Optional area cap for reference video frames, e.g. 0.4. Aspect-preserving (never a squish), down-only, per-axis rounded to the model's 32px grid. 0 = core's 768-short-edge canvas rule. Video reference rows ride through EVERY sampling step multiplied by their duration, so this is the single biggest speed dial in the pack. |
| ref_audio_files | STRING | Reference audio loaded straight from the input folder, one filename per line (wav/mp3/m4a/flac -- the editor's picker and mic recorder write this). These come AFTER any connected ref_audio_ sockets. Needs audio_vae connected, like all reference audio. | |
| first_frame_crop | STRING | Optional framing for the first frame: 'center_x, center_y, zoom' (set by the editor's framing tool). The crop window is locked to the generation's aspect, so what the model sees is exactly what you framed -- no stretch, no blind centre-crop. Empty or '-' = whole image. | |
| last_frame_crop | STRING | Optional framing for the last frame, same format as first_frame_crop. | |
| middle_frame_crops | STRING | Optional framing per middle frame, one line per image in the same sockets-then-files order as middle_frame_spec: 'center_x, center_y, zoom' or '-' for none. Windows are locked to the generation's aspect. | |
| ref_image_crops | STRING | Optional framing per reference image, one line per image in the same order as ref_spec: 'center_x, center_y, zoom' or '-'. Reference windows keep the SOURCE aspect (pure zoom/pan) -- references aren't resized to the canvas, so there is no aspect to match, just content to choose. | |
| middle_frame_spec | STRING | OPTIONAL. Leave empty and connected middle frames are spaced evenly through the clip at strength 0.6 (the positions chosen are printed to the log). To place them yourself, one line per connected middle frame, paired in slot order: position, strength[, description] position is a fraction of the clip (0.5 = halfway) or an absolute frame number if above 1.0. strength works exactly like the first/last dials. description is optional -- it is appended to the prompt as a labelled '<Picture N> at N.Ns: ...' note so the text encoder knows what that frame is meant to show. Example: 0.33, 0.7, boat halfway out of frame 0.66, 0.6, boat near the horizon Either fill in a line for every frame or leave it completely empty -- a partial spec is ambiguous and will error. Lines starting with # are ignored. EXPERIMENTAL: H3 is trained on first/last anchors only. | |
| timed_text | STRING | EXPERIMENTAL. Beats of description pinned to moments in the clip, one per line: position, what happens position is a fraction of the clip (0.5 = halfway) or an absolute frame number above 1.0. No image needed -- this is text, not a keyframe. Example: 0.2, the boat pulls away from the dock 0.8, only wake remains on the water See timed_text_mode for how the timing is delivered. Lines starting with # are ignored. | |
| timed_text_mode | COMBO | text only | How timed_text beats reach the model. 'text only' (default, safe): appended as plain prose, 'At 2.0 seconds: the boat pulls away.' Pure prompting -- the model has seen <N.N seconds> labels in its reference-video training, so this vocabulary is familiar. No patching. 'rope + text': the same prose, but the beat's tokens are ALSO moved onto the video timeline so RoPE places them at that moment. Degrades gracefully to 'text only' if the positional trick does nothing. 'rope only': positions moved, no time words. The purest test of whether the mechanism works -- and the most likely to simply fail. The rope modes are a real distribution violation: text has occupied its own coordinate range in every sample the model ever saw. Try 'text only' first. |
| ref_spec | STRING | OPTIONAL. One strength per connected reference image, in slot order. Leave empty for 1.0 (a firm identity lock). Lower values soften the reference into a suggestion -- 0.7 keeps the likeness while letting the model adapt pose and lighting. Example: 1.0 0.7 Either one line per image or completely empty. | |
| ref_image_size | COMBO | match | Reference image sizing. 'match' scales each reference (down only, keeping aspect) to the generation's pixel area. 'max' uses the reference pipeline's 2048px short edge for best identity fidelity. Reference rows ride through EVERY sampling step, so 'max' can be several times slower. Ignored when ref_megapixels is set. |
| ref_megapixels | FLOAT | 0.000–8 | Optional area cap for reference images, in megapixels -- e.g. 0.4. Overrides ref_image_size when above 0, scaling each reference down (never up) to at most this many pixels, so no external resize nodes are needed. Keyframe inputs never need capping: they are always fitted to the generation canvas anyway (aspect-preserving cover-crop). 0 = off. |
| ref_audio_strength | FLOAT | 1.000–2 | Strength for every connected reference audio. 1.0 is a firm lock on the voice/sound character; lower loosens it. Note H3 leaves audio conditioning completely clean by default (its audio_cond_noise_aug is 1.0, i.e. no noise at all), so this dial is the only way to soften an audio reference. |
| mask_ref_pixels | BOOLEAN | false | What a reference mask applies to. OFF (default): only the condition latent is masked. The text encoder still sees the whole reference photo, so it can describe the background -- conservative, and the usual choice. ON: the excluded area is also greyed out in the image handed to the text encoder, so it describes only the kept region. More consistent, but the encoder sees a hard-edged cutout, which it may read oddly. |
| ref_video_crops | STRING | Optional framing per reference video, one line per video in the same sockets-then-files order as ref_video_spec: 'center_x, center_y, zoom' or '-'. The window keeps the SOURCE aspect (pure zoom/pan into the footage) and applies before sizing, so the MP cap operates on the cropped region. Set by the editor's framing tool -- essential when continuing a clip of a different aspect. | |
| v2v_video_file | STRING | Video-to-video source loaded straight from the input/output folder (the editor's v2v bar writes this; 'name [output]' restyles a previous render). When set (or when v2v_images is connected), the node's LATENT output becomes this footage encoded for partial denoise instead of an empty latent -- sample at denoise 0.3-0.7 to restyle while keeping the motion. The clip length follows the footage; the length widget is ignored. EXPERIMENTAL. | |
| v2v_start_seconds | FLOAT | 0.00–10000 | Restyle only a section of the v2v source: start, in seconds. |
| v2v_end_seconds | FLOAT | 0.00–10000 | Section end in seconds; 0 = to the end of the source. |
| v2v_denoise | FLOAT | 0.550–1 | The v2v restyle amount, as a VALUE THIS NODE EMITS (third output): wire it to H3 Basic Scheduler's denoise input -> SamplerCustom/sigmas, and the editor's v2v bar controls the whole restyle. Has no effect on this node's own outputs otherwise; with a plain KSampler just set its denoise to match. ~0.3 barely touches the footage, 0.4-0.7 restyles keeping motion, 1.0 ignores it. With NO v2v source connected the output is forced to 1.0, since the latent is then an empty one that must denoise in full -- so the same wired graph does normal generation and restyles without rewiring. |
| v2v_crop | STRING | Optional framing for the v2v source: 'center_x, center_y, zoom' (the editor's v2v ⛶ writes this). The window is locked to the width x height widgets' aspect and the footage is resized to exactly that canvas -- so WITH a framing, width/height matter again (reframe landscape footage into a vertical clip, etc.). Without one, the canvas follows the footage and width/height are ignored. | |
| motion_context_file | STRING | Continue WITH MOTION from this video (input/output folder; 'name [output]' chains from a previous render -- the editor's ⏭▶ writes this). Its tail frames are pinned at the head of the new clip ON ITS OWN TIMELINE, so instantaneous motion carries through the join instead of being re-decided from a still, and the tail audio is continued as the same waveform rather than imitated. The pinned frames come back at the start of the render; the editor trims them automatically when the clip joins the reel. When set, first_frame is ignored (the context IS the opening). Technique credit: ComfyUI-H3-Motion-Context. | |
| motion_context_end_seconds | FLOAT | 0.00–10000 | Continue from this moment of the context video, in seconds (0 = its end). The reel's ⏭▶ passes the card's out-trim, so the join lands exactly at the cut. |
| motion_context_frames | INT | 221–39 | How many tail frames to pin. The video VAE only distinguishes runs of 5, 22 and 39 -- anything else snaps DOWN to the nearest. 22 (default) is nearly seamless; 5 is just barely fluid but much cheaper; 39 is untested. Every pinned row rides through all sampling steps, so this is also a speed dial. |
| motion_context_audio_frames | INT | 220–240 | Tail AUDIO to pin, in frames at 24 fps, END-ALIGNED with the pinned video so both finish at the join -- the model continues the actual waveform (same recording) instead of playing a sound-alike. 0 = no audio context. Needs audio_vae when above 0 and the context video has sound. 22 overlays the video window exactly (the tested configuration). |
| v2v_noise | FLOAT | 0.000–1 | Scramble the v2v footage BEFORE sampling: the latent is blended toward noise by this fraction (0 = untouched footage). This is the dial for 'the restyle keeps handing me back the same material'. Raising denoise alone often can't break it: the footage's structure is CORRELATED across frames while the sampler's noise is not, so the model integrates the source back out of the noise. Destroying the structure up front is the one thing it cannot undo. 0.3-0.6 keeps timing and rough motion while freeing content. |
| v2v_noise_declare | FLOAT | 1.000–1 | How much of v2v_noise is DECLARED to the sampler through the v2v_denoise output (the sigma dial). 1.0 (default, safe): the emitted denoise is raised so the schedule starts where the latent actually is -- clean output, and the net effect is like a higher denoise except the source structure is genuinely gone rather than merely diluted. Below 1.0: the sampler is told the latent is cleaner than it really is, so it commits fewer/gentler steps over already-scrambled content -- the furthest you can get from the source, at the cost of grain if you push it (undeclared noise has to land somewhere). Needs the v2v_denoise output wired to H3 Basic Scheduler, and does nothing unless v2v_noise is above 0. |
| motion_context_reuse_latent | BOOLEAN | true | When the clip you're continuing is a render THIS SESSION just made, pin its latent directly instead of decoding the file and re-encoding it. That removes a whole VAE round trip per link -- the loss that compounds and softens a long chain -- and pins the model's own output rather than a lossy copy of it. Falls back to re-encoding automatically, with the reason in the log, whenever the cached latent isn't the right clip, canvas or cut point. Only the tail is held in memory (a few MB). Turn off to force the file path. |
| motion_context_anchor_brightness | BOOLEAN | true | ON by default. Stops a chain's brightness drifting, by correcting the CONDITIONING instead of the finished pixels. The pinned context is what the model matches, so before pinning it the node measures what the previous render actually came out at and nudges the context by the error against the chain's anchor, taken from its first link. Nothing assumes how much a link drifts: 0.5% drift gets a 0.5% correction, 4% gets 4%, and if the model only partly follows the nudge the residue is corrected next link -- it converges instead of accumulating. Measured in PIXELS off the previous render, so it works whether or not the latent cache hit -- and per region, since a sky that drifts while the road doesn't is a case one number cannot express. Costs nothing (an add on a tensor already in memory), never touches finished pixels (so no clipped highlights and no clip paying for the ones before it), and it fixes the render FILES, not just the export. Clamped to +-0.08 so a deliberate lighting change isn't fought; clear the reel to re-anchor. Turn it off to render exactly what the model produces. |
| motion_context_strength | FLOAT | 0.920–1 | How hard the pinned context frames are enforced. 1.0 is ground truth: the model reproduces them exactly. Seamless -- and it also copies any artifact they carry, so blockiness compounds down a chain (measured: a 16px grid climbing to +21% over six links, every link worse than the last). Below 1.0 the pinned rows are read as a reference at that noise level rather than clean content, so the model REGENERATES the region guided by the previous clip instead of duplicating it. Motion, framing and colour carry over; accumulated artifacts don't. 0.92 is the default because it was measured to flatten that grid completely -- the same six-link test ended BELOW its first clip, and a one-off bad frame self-corrected in a single link instead of propagating. Below ~0.7 the join itself starts to drift. Uses the same flow-blend and per-row timestep labelling as the keyframe strength dials. |
| motion_scale | FLOAT | 1.000.1–4 | EXPERIMENTAL. How much motion the clip contains, as a direct dial rather than a hint. Every other motion control describes what should happen. This one rescales the model's CLOCK: the video's RoPE time coordinates carry a fixed amount of time between frames, and widening those gaps tells the model more time passes -- so more has to change. Content, prompt and keyframes are untouched. 1.0 = stock, and the timeline is left byte-for-byte alone. 1.3 packs about a third more movement into the same frames; 0.7 slows the whole clip down. Roughly 0.8-1.3 stays close to what the model was trained on; further out is increasingly a guess. Note the soundtrack is NOT rescaled, so audio drifts against the picture as you move away from 1.0. |
| motion_curve | STRING | OPTIONAL, needs no motion_scale. Vary the speed ACROSS the clip instead of applying one value to all of it -- one line per control point: position, speed position is a fraction of the clip (0.5 = halfway) or an absolute frame number above 1.0. speed is the same dial as motion_scale, at that moment. Between two points the speed ramps linearly; before the first and after the last it is held flat. Example -- settle, then accelerate away: 0.0, 0.6 0.5, 0.8 1.0, 1.8 Speeds multiply with motion_scale, so leave that at 1.0 unless you want to push the whole curve at once. Speeding a section up also pushes everything after it later in the clip's time -- that is what a time axis does. Lines starting with # are ignored. | |
| sound_anchors | STRING | EXPERIMENTAL. Pin a SOUND at a moment of the clip -- one line per anchor: position, file position, strength, file position is a fraction of the clip (0.5 = halfway) or an absolute frame number above 1.0; file is an audio file in the input folder. The sound is anchored AT that frame and runs forward from it, so the model generates the picture that goes with it: a door slam at 2.4s, a phone starting to ring, a line of dialogue landing on a cut. This is not the same as the reel's fx lanes, which mix a sample over the finished video. This one is a CONDITION -- the model hears it while rendering and the picture responds. It also occupies audio rows for its whole length, so keep the files short. strength below 1.0 makes it a hint rather than a fixed event (same flow-blend and per-row labelling as the keyframe strengths). Needs audio_vae, and a ComfyUI new enough to anchor audio at a frame (it is skipped with a warning otherwise). Lines starting with # are ignored. | |
| first_frameopt | IMAGE | — | |
| last_frameopt | IMAGE | — | |
| ref_videosopt | COMFY_AUTOGROW_V3 | — | |
| ref_video_audiosopt | COMFY_AUTOGROW_V3 | — | |
| audio_vaeopt | VAE | The MiniMax H3 audio VAE. Required only when a reference audio is connected. | |
| ref_imagesopt | COMFY_AUTOGROW_V3 | — | |
| ref_masksopt | COMFY_AUTOGROW_V3 | — | |
| ref_audiosopt | COMFY_AUTOGROW_V3 | — | |
| middle_framesopt | COMFY_AUTOGROW_V3 | — | |
| v2v_imagesopt | IMAGE | Video-to-video source frames from the graph (wins over v2v_video_file). The LATENT output becomes this footage encoded for partial denoise. | |
| v2v_audioopt | AUDIO | Soundtrack for the v2v source (wins over a file's embedded audio). Needs audio_vae. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| positive | CONDITIONING | — |
| LATENT | LATENT | — |
| v2v_denoise | FLOAT | The restyle amount -- wire to H3 Basic Scheduler's denoise socket so the editor drives it. Forced to 1.0 when no v2v source is set (an empty latent must denoise in full), so one graph handles both generation and restyling. |