Nodes/Pulse Studio/Pulse Slate · MiniMax H3
ComfyUI Node

Pulse Slate · MiniMax H3

The MiniMax H3 director node that stops you typing tag numbers

By Addis-Pulse-Studio·Created about a month ago·Updated 16 days ago· 2
Pulse Slate · MiniMax H3
  • model
  • clip
  • vae
  • audio_vae
  • model_fl2va
  • ref_video
  • ref_video_audio
  • ref_music
  • refs.ref_image_1
  • refs.ref_image_2
  • refs.ref_image_3
  • refs.ref_image_4
  • refs.ref_image_5
  • refs.ref_image_6
  • refs.ref_image_7
  • refs.ref_image_8
  • shots.shot_1
  • shots.shot_2
  • shots.shot_3
  • shots.shot_4
  • shots.shot_5
  • shots.shot_6
  • shots.shot_7
  • shots.shot_8
  • shots.shot_9
  • shots.shot_10
  • shots.shot_11
  • shots.shot_12
  • shots.shot_13
  • shots.shot_14
  • shots.shot_15
  • shots.shot_16
  • shots.shot_17
  • shots.shot_18
  • shots.shot_19
  • shots.shot_20
  • shots.shot_21
  • shots.shot_22
  • shots.shot_23
  • shots.shot_24
  • voices.voice_1
  • voices.voice_2
  • voices.voice_3
  • timeline
  • positive
  • latent
  • combined_audio
  • images
  • compiled_prompt
schema_version3.0.0
timeline_data{"schema": 2, "assets": [], "cast": []}
global_promptstyle: identity: soundscape: music:
shot_prompt[Shot 1] [Shot 2] At 00:05.000,
duration_seconds10.0
aspect_ratio16:9 landscape
width1344
height768
steps20
sampler_nameres_multistep
schedulersimple
cfg1.0
seed0
partition_strategybalanced
window_seconds15.0
resize_methodcrop
carry_modeimage
carry_audiotrue
carry_audio_seconds4.0
ref_image_sizematch
shift_video12.00
shift_audio3.00
audio_ref_ceiling3
continuitynone

The whole point is that you never type <Picture 3> again

MiniMax H3 is the 33B omni-modal video model that ComfyUI got day-zero support for, and it's genuinely good - native stereo audio, joint generation, the works. But its reference tags are a trap. <Picture N>, <Audio j> and friends are ordinals assigned by socket position in ComfyUI's source. Insert one image at the top of your reference bin and every <Picture N> after it silently shifts by one. The render still succeeds - it just describes the wrong pictures, with no error anywhere. A reference video's soundtrack even renumbers every standalone <Audio> in your prompt before you know what happened.

Pulse Slate is the compiler node from the Pulse Studio pack that kills that whole failure class. You write @Mimi or {{mimi}} instead of a number; the node computes every ordinal from live bin order at compile time, and hand-typed tags are reported as an error rather than silently trusted. It's the difference between a tool that fights you and one that checks your work.

What it actually does: compile, don't render

Pulse Slate takes your prompts, an asset bin and (optionally) a chain of PulseShot nodes, and turns them into a PULSE_TIMELINE. It does not sample. There are two paths depending on length:

  • ≤ 15 s (one window) - it hands back positive and latent, and your own graph does sampler → decode → mux. This is PulseSlate_Single.json, the short path.
  • > 15 s (many windows) - positive and latent are blocked; you take the timeline output to a PulseRender node, which does the window loop, disk cache and stitching.

That blocking is a fix, not a bug: pre-3.0.0 builds handed the last window's latent back, and a still-wired sampler quietly re-rendered that one window as the whole film - a 7-second file where there should have been fifteen, no error anywhere.

The inputs that matter

The node face carries two multiline boxes plus an asset panel - nothing hidden behind a gear.

  • global_prompt - art style, lighting, camera rules, identity locks, score. Optional line labels: style: identity: retention: soundscape: music:; unlabelled text counts as style.
  • shot_prompt - one shot per line, each starting with [Shot N] or a [MM:SS.mmm] timecode. Shots without a timecode spread evenly between the ones that have them. Quoted "text" becomes dialogue.
  • The asset bin - drag images, video or audio straight onto the node body, no loader nodes. Each drop gets a short alias you rename inline. A description promotes a reference from a bare citation to a <Subject N> definition (that's what identity consistency is built on); retention is written verbatim into the prompt's retention section.

Beyond those: aspect_ratio (presets fitted to H3's 1,032,192 px budget - 16:9 is 1344×768), window_seconds (each H3 call, capped at ~15.08s), partition_strategy (balanced / fill / shot_aligned), and continuity - last_frame_carry and keyframe_pairs pin real frames, which is the fl2va checkpoint's job, so they need model_fl2va wired and fail at compile time without it.

cfg stays at 1.0 - seriously

H3's reference pipeline has no negative conditioning; it runs BasicGuider, a single-conditioning path. cfg = 1.0 is the native default. Above 1.0 it switches to CFGGuider with an empty negative - offered because people asked, not because it's good. Leave it.

Install and the model haul

cd ComfyUI/custom_nodes
git clone https://github.com/Addis-Pulse-Studio/comfyui-pulse-studio

Restart ComfyUI. There's nothing to pip install - zero dependencies, just torch, numpy, Pillow and av that a working ComfyUI already has. You can also find it in ComfyUI Manager by searching "comfyui-pulse-studio". Two real requirements:

  1. ComfyUI 0.30.0+, carrying comfy_extras/nodes_minimax_h3.py and comfy/ldm/minimax/. Older builds simply don't have H3 to direct.
  2. The weights, not redistributed here. From Comfy-Org/MiniMax-H3: the ref2va DiT (~20 GB) and the fl2va DiT (~20 GB, only if you use anchored continuity) into models/diffusion_models/minimax/, the qwen3vl text encoder (~15 GB) into models/text_encoders/minimax/, and the video + audio VAEs into models/vae/minimax/.

Two gotchas before you commit 40 GB of disk. On Linux and macOS the five loader widgets load red because the example graphs were authored on Windows with backslash paths - click each and re-pick the file. And the weights carry the MiniMax H3 Community License, which excludes the US, EU, UK and South Korea from its applicable territory - if you're in one of those, running the local weights isn't licensed, even though the hosted Hailuo API is.

Where people get burned

  • Pre-2.0.0 workflows won't load. Widget order changed once, deliberately; those files are refused by name rather than guessed at. Rebuild from example_workflows/PulseSlate_LongForm.json. There is no migration and won't be one.
  • The speed patches are wired upstream, not by this pack. The documented chain is UNETLoader → SpectrumApplyMiniMaxH3 (history_storage: system_ram) → PatchSageAttentionKJ → Sol-Attn → PulseSlate. The node inspects what it's handed and warns - on the node face and console - when it finds no attention or offload patch, but it never blocks and never patches for you. And system_ram isn't a speed setting: on a 32 GB card it's what makes a full-length window fit at all; set Spectrum to vram and expect an OOM.
  • Run dry_run first. A wrong reference binding renders successfully and gives you a well-formed film of the wrong person; the per-shot ordinal map in the report is how you catch it before spending GPU hours.
CategoryAddisPulse/H3

Inputs (67)

NameTypeDefaultDescription
modelMODELThe ref2va (Reference) checkpoint. Read here only to detect the upstream patch chain and warn about it; this node no longer samples. Anchors and references are different checkpoints; wire the fl2va one into model_fl2va.
clipCLIP
vaeVAE
audio_vaeVAERequired on both branches -- H3 always builds a joint audio+video latent, even when no reference audio is encoded.
schema_versionSTRING3.0.0Which widget layout this node was saved with. Written by the node, read at load time to restore values by name. Do not edit.
timeline_dataSTRING{"schema": 2, "assets": [], "cast": []}The Asset Bin's storage: assets and cast, as JSON. Managed by the panel and never written to by the execute path.
global_promptSTRINGstyle: identity: soundscape: music: Art style, lighting, camera rules, character identity locks and score. Compiles into subject_definitions and retention_analysis. Optional labels at the start of a line: style: / identity: / retention: / soundscape: / music:. Unlabelled text is treated as style. Reference assets by name (@Mimi) or id ({{mimi}}) -- never by number. Ordinals are assigned from bin order at compile time.
shot_promptSTRING[Shot 1] [Shot 2] At 00:05.000, Timecoded shots, one per line. Begin each with [Shot N] or a [MM:SS.mmm] timecode. IGNORED whenever any PulseShot node is connected -- the two are never merged. See spec §5. Quoted "text" becomes dialogue. @Name references the Asset Bin.
duration_secondsFLOAT10.00.2–600Total length of the finished video. Snapped up to the 17k+5 frame grid, and split into windows if longer than window_seconds. Ignored when PulseShot nodes are connected -- their durations define the length.
aspect_ratioCOMBO16:9 landscapePreset canvases fitted into H3's 1,032,192px budget. Choose 'custom' to use the width and height widgets instead.
widthINT134432–4096Used only when aspect_ratio is 'custom'.
heightINT76832–4096Used only when aspect_ratio is 'custom'.
stepsINT201–100
sampler_nameCOMBOres_multistep6 options: res_multistep, euler, euler_ancestral, dpmpp_2m, dpmpp_2m_sde, ddim
schedulerCOMBOsimple6 options: simple, normal, beta, sgm_uniform, karras, exponential
cfgFLOAT1.01–201.0 uses BasicGuider, which is H3's own native path -- its reference pipeline has no negative conditioning anywhere. Above 1.0 switches to CFGGuider with an empty negative prompt. Leave at 1.0 unless you are deliberately experimenting.
seedINT00–18446744073709550000The base seed. Each window's actual seed is derived from this and from the set of shots in that window, so inserting a shot does not reroll the windows that did not change.
partition_strategyCOMBObalancedHow a long timeline is split. 'balanced' spreads it into near-equal windows, avoiding a short trailing window below H3's 124-frame trained floor. 'fill' packs full windows and merges any short tail backwards. 'shot_aligned' puts window seams on shot boundaries wherever the 17k+5 grid allows it, so fewer shots are compiled into two windows -- it reports which cuts it could not reach, and it gives up window_seconds to do it.
window_secondsFLOAT15.05.2–15.1Length of each individual H3 call. The trained ceiling is ~15.08s (362 frames) and the floor is ~5.17s (124 frames).
resize_methodCOMBOcropHow a reference image whose aspect does not match the canvas is fitted. 'pad' letterboxes, which makes the bars themselves reference content.
carry_modeCOMBOimageWhat the previous window contributes to the next as a REFERENCE on the ref2va branch. Distinct from `continuity`, which chooses whether a frame is pinned as a keyframe.
carry_audioBOOLEANtrueFeed the previous window's audio tail forward. Without it each window invents its own score and the seam is audible.
carry_audio_secondsFLOAT4.00.5–15
ref_image_sizeCOMBOmatch'match' scales references to the render's pixel area (faster). 'max' uses a 2048px short edge for stronger identity, but reference tokens ride every sampling step, so it is several times slower.
shift_videoFLOAT12.000.01–100
shift_audioFLOAT3.000.01–100
audio_ref_ceilingINT33–9How many standalone audio references the bin may hold. 3 is what MiniMax documents and what ComfyUI's ref_audios socket declares. Above 3 goes past both. Raise it to test, not to set and forget.
continuityCOMBOnoneHow windows join. 'none' samples each independently. 'last_frame_carry' pins the previous window's final frame as the next one's first frame. 'keyframe_pairs' pins each shot's start and end frames. The last two need model_fl2va and fail at compile time without it -- they do not fall back silently.
model_fl2vaoptMODELThe First/Last-Frame checkpoint. Required by the 'last_frame_carry' and 'keyframe_pairs' continuity modes. Loading both checkpoints is ~42GB.
ref_videooptIMAGEA reference video as frames, from an upstream loader.
ref_video_audiooptAUDIOSoundtrack of ref_video. Claims an <Audio N> ordinal ahead of every standalone audio reference.
ref_musicoptAUDIONon-diegetic score. Always the last audio ordinal.
refs.ref_image_1optIMAGEGlobal reference image 1, visible to every shot.
refs.ref_image_2optIMAGEGlobal reference image 2, visible to every shot.
refs.ref_image_3optIMAGEGlobal reference image 3, visible to every shot.
refs.ref_image_4optIMAGEGlobal reference image 4, visible to every shot.
refs.ref_image_5optIMAGEGlobal reference image 5, visible to every shot.
refs.ref_image_6optIMAGEGlobal reference image 6, visible to every shot.
refs.ref_image_7optIMAGEGlobal reference image 7, visible to every shot.
refs.ref_image_8optIMAGEGlobal reference image 8, visible to every shot.
shots.shot_1optPULSE_SHOTShot 1. Connecting any shot socket makes the shot text box inactive.
shots.shot_2optPULSE_SHOTShot 2. Connecting any shot socket makes the shot text box inactive.
shots.shot_3optPULSE_SHOTShot 3. Connecting any shot socket makes the shot text box inactive.
shots.shot_4optPULSE_SHOTShot 4. Connecting any shot socket makes the shot text box inactive.
shots.shot_5optPULSE_SHOTShot 5. Connecting any shot socket makes the shot text box inactive.
shots.shot_6optPULSE_SHOTShot 6. Connecting any shot socket makes the shot text box inactive.
shots.shot_7optPULSE_SHOTShot 7. Connecting any shot socket makes the shot text box inactive.
shots.shot_8optPULSE_SHOTShot 8. Connecting any shot socket makes the shot text box inactive.
shots.shot_9optPULSE_SHOTShot 9. Connecting any shot socket makes the shot text box inactive.
shots.shot_10optPULSE_SHOTShot 10. Connecting any shot socket makes the shot text box inactive.
shots.shot_11optPULSE_SHOTShot 11. Connecting any shot socket makes the shot text box inactive.
shots.shot_12optPULSE_SHOTShot 12. Connecting any shot socket makes the shot text box inactive.
shots.shot_13optPULSE_SHOTShot 13. Connecting any shot socket makes the shot text box inactive.
shots.shot_14optPULSE_SHOTShot 14. Connecting any shot socket makes the shot text box inactive.
shots.shot_15optPULSE_SHOTShot 15. Connecting any shot socket makes the shot text box inactive.
shots.shot_16optPULSE_SHOTShot 16. Connecting any shot socket makes the shot text box inactive.
shots.shot_17optPULSE_SHOTShot 17. Connecting any shot socket makes the shot text box inactive.
shots.shot_18optPULSE_SHOTShot 18. Connecting any shot socket makes the shot text box inactive.
shots.shot_19optPULSE_SHOTShot 19. Connecting any shot socket makes the shot text box inactive.
shots.shot_20optPULSE_SHOTShot 20. Connecting any shot socket makes the shot text box inactive.
shots.shot_21optPULSE_SHOTShot 21. Connecting any shot socket makes the shot text box inactive.
shots.shot_22optPULSE_SHOTShot 22. Connecting any shot socket makes the shot text box inactive.
shots.shot_23optPULSE_SHOTShot 23. Connecting any shot socket makes the shot text box inactive.
shots.shot_24optPULSE_SHOTShot 24. Connecting any shot socket makes the shot text box inactive.
voices.voice_1optPULSE_VOICEGlobal voice 1, visible to every window -- one wire instead of one per shot. Numbered ahead of ref_music, which is always the last audio ordinal.
voices.voice_2optPULSE_VOICEGlobal voice 2, visible to every window -- one wire instead of one per shot. Numbered ahead of ref_music, which is always the last audio ordinal.
voices.voice_3optPULSE_VOICEGlobal voice 3, visible to every window -- one wire instead of one per shot. Numbered ahead of ref_music, which is always the last audio ordinal.

Outputs (6)

NameTypeDescription
timelinePULSE_TIMELINE
positiveCONDITIONING
latentLATENT
combined_audioAUDIO
imagesIMAGE
compiled_promptSTRING