Nodes/ComfyUI-H3Studio/H3 Studio (Image to Video)
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.

By shootthesound·Created 13 days ago·Updated 5 days ago· 20
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)

NameTypeDefaultDescription
clipCLIP
vaeVAE
promptSTRING
widthINT134432–16384
heightINT76832–16384
lengthINT1245–3600Frame 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_strengthFLOAT1.000–2How 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_strengthFLOAT1.000–2How 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_fileSTRINGLoad 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_fileSTRINGLoad the last frame straight from the input folder. Ignored when the last_frame socket is connected.
middle_frame_filesSTRINGExtra 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_filesSTRINGExtra 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_specSTRINGOPTIONAL. One strength per reference video, in sockets-then-files order. Empty = 1.0. Applies to the video latent AND its soundtrack together.
ref_video_filesSTRINGReference 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_megapixelsFLOAT0.000–4Optional 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_filesSTRINGReference 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_cropSTRINGOptional 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_cropSTRINGOptional framing for the last frame, same format as first_frame_crop.
middle_frame_cropsSTRINGOptional 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_cropsSTRINGOptional 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_specSTRINGOPTIONAL. 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_textSTRINGEXPERIMENTAL. 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_modeCOMBOtext onlyHow 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_specSTRINGOPTIONAL. 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_sizeCOMBOmatchReference 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_megapixelsFLOAT0.000–8Optional 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_strengthFLOAT1.000–2Strength 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_pixelsBOOLEANfalseWhat 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_cropsSTRINGOptional 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_fileSTRINGVideo-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_secondsFLOAT0.00–10000Restyle only a section of the v2v source: start, in seconds.
v2v_end_secondsFLOAT0.00–10000Section end in seconds; 0 = to the end of the source.
v2v_denoiseFLOAT0.550–1The 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_cropSTRINGOptional 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_fileSTRINGContinue 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_secondsFLOAT0.00–10000Continue 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_framesINT221–39How 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_framesINT220–240Tail 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_noiseFLOAT0.000–1Scramble 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_declareFLOAT1.000–1How 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_latentBOOLEANtrueWhen 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_brightnessBOOLEANtrueON 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_strengthFLOAT0.920–1How 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_scaleFLOAT1.000.1–4EXPERIMENTAL. 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_curveSTRINGOPTIONAL, 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_anchorsSTRINGEXPERIMENTAL. 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_frameoptIMAGE
last_frameoptIMAGE
ref_videosoptCOMFY_AUTOGROW_V3
ref_video_audiosoptCOMFY_AUTOGROW_V3
audio_vaeoptVAEThe MiniMax H3 audio VAE. Required only when a reference audio is connected.
ref_imagesoptCOMFY_AUTOGROW_V3
ref_masksoptCOMFY_AUTOGROW_V3
ref_audiosoptCOMFY_AUTOGROW_V3
middle_framesoptCOMFY_AUTOGROW_V3
v2v_imagesoptIMAGEVideo-to-video source frames from the graph (wins over v2v_video_file). The LATENT output becomes this footage encoded for partial denoise.
v2v_audiooptAUDIOSoundtrack for the v2v source (wins over a file's embedded audio). Needs audio_vae.

Outputs (3)

NameTypeDescription
positiveCONDITIONING
LATENTLATENT
v2v_denoiseFLOATThe 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.