Morpheus (Video Sampler) π
Morpheus turns MiniMax H3's 15-second ceiling into a whole video
- shots
- model
- clip
- vae
- audio_vae
- llm_config
- sigmas
- sampler
- noise
- images
- audio
- fps
- last_frame
- report
- prompts
MiniMax H3 is genuinely great at making a clip, but it tops out around 5β15 seconds and ComfyUI ships no extend/continue node for it. So if you want a minute of video, the only real route is to run it a bunch of times and hand each shot's last frame to the next one as its first keyframe. That handoff - plus every seam-adjacent annoyance that makes the naive version come out wrong - is exactly what Morpheus does. It's the "video sampler" for the whole Morpheus storyboard suite, and it's the node you wire the final chain of Morpheus Dream shots into.
What it actually does
You feed it a chain of shots (the output of the last Morpheus Dream in a row), a model, clip and VAE; it samples every shot, passes the last frame forward as the next shot's first keyframe, and hands back one big images batch, one audio track, and an fps float. Four things a hand-wired graph gets wrong are handled here, and they're the reason this node earns its keep:
- The seam frame. A continuing shot's first frame is the previous shot's last frame, so
seam_trim(default 1) drops the duplicate. Raise it to 3β6 and it also swallows the re-acceleration - the model is handed a still frame with position but no velocity, so every shot eases in from rest and the subject visibly speeds up at each seam. Trimming happens at decode time, so cached shots are re-used and tuning it costs nothing. - Loudness.
VAEDecodeAudionormalizes per decode, which steps the level at every seam. Morpheus normalizes once over the whole track and ramps the seams (seam_fade_ms- a fade, deliberately not a crossfade, so audio never drifts against picture). - RAM. 1344Γ768 float32 is ~12 MB per frame - roughly 1.5 GB per 5-second shot. The node manages that so you don't OOM a long chain.
- fps is not a parameter. 24 is baked into the model; it comes back out as a
FLOAT(24.0) that drops straight intoCreate Video, with one monotonic progress bar across the whole run instead of a bar that fills and resets per shot.
The inputs that matter
width/height are one canvas for the whole storyboard. H3's own budget is a 768 short edge with a 768Γ1344 area cap - exceeding it is slow and out of distribution, and the report output will tell you. Height mismatch matters more than most expect: H3 stretches the first frame onto the canvas and doesn't crop, so a wrong aspect ratio distorts every shot.
seed is the base; each shot adds its index and its own seed_offset, so no two shots share noise. shift_video (default 12) is H3's video flow shift, applied automatically unless your model already went through a MiniMax H3 Sigma Shift node. audio defaults to concat - decode, trim to the shot's exact length, ramp seams, normalize once. Without audio_vae wired, the video comes out silent, which is the single most common "why is my Morpheus video mute" answer.
cache: disk stores each shot's sampled latents under user/kinburg-nodes/minimax_shots (~7 MB per shot). Edit shot 5, re-sample 5..N, and shots 1β4 replay instantly. The cache key covers architecture + LoRA patches but not the exact weight file - if you swap to another H3 checkpoint of the same size, bump cache_tag to invalidate. shots_range ("2-4") renders only part of the chain; shots before it are still needed for the handoff frame, but free if cached.
The optional llm_config input is the fancy bit: wire a Local LLM Settings (GGUF) with a Vision Settings (GGUF) mmproj and a vision LLM gets to see the frame each shot really starts on and rework its opening. Per-shot control comes from the refine widget on each Dream node. On 12 GB VRAM with a 26B model, leave llm_keep_loaded off - the LLM is loaded, used and killed around each shot, which is the difference between "runs" and OOM.
Installing it
The node ships in Kinburg/Kinburg-Nodes. Easiest is ComfyUI Manager - search "Kinburg-Nodes" - or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Kinburg/Kinburg-Nodes
then restart ComfyUI. The pack itself has no pip dependencies; the LLM half wants llama-cpp-python (CUDA), which install.py installs automatically when Manager runs it. What you do need to fetch yourself is the H3 model - model, VAE, text encoder - and one thing before that: check the H3 Community License. It excludes the US, EU, UK and South Korea from its applicable territory, so in those regions you're not licensed to run the local weights at all.
Where people get burned
Silent output (missing audio_vae), distorted shots (canvas/keyframe aspect mismatch), and sluggish runs (canvas over H3's budget). The last_frame output is worth remembering too - it's the cover, or the start_frame of a later run if you're building longer than one storyboard.
Inputs (27)
| Name | Type | Default | Description |
|---|---|---|---|
| shots | KINBURG_MORPHEUS_SHOT | The chain out of the last 'Morpheus Dream'. | |
| model | MODEL | The H3 model. 'MiniMax H3 Sigma Shift' is applied here automatically if the model doesn't already carry it. | |
| clip | CLIP | H3's text encoder (it also sees the keyframes). | |
| vae | VAE | The VIDEO vae. | |
| width | INT | 134432β4096 | Canvas width for EVERY shot (they are concatenated, so one canvas for the whole storyboard). Rounded to a multiple of 32. H3's own budget is a 768 short edge with a 768*1344 area cap; going over it is slow and out of distribution, and the report says so. |
| height | INT | 76832β4096 | Canvas height. Match the aspect ratio of your keyframes: H3 STRETCHES the first frame onto the canvas and does not crop it, so a mismatch distorts the whole shot. The report warns when it spots one. |
| steps | INT | 301β1000 | Ignored when a 'sigmas' input is wired. |
| scheduler | COMBO | simple | Ignored when a 'sigmas' input is wired. |
| sampler_name | COMBO | euler | Ignored when a 'sampler' input is wired. |
| seed | INT | 00β18446744073709550000 | Base seed. Each shot samples with seed + shot index + its own seed_offset, so no two shots get the same noise. |
| shift_video | FLOAT | 12.000.01β100 | H3's video flow shift (drives the sigma schedule). Applied here unless the wired model already went through 'MiniMax H3 Sigma Shift'. |
| shift_audio | FLOAT | 3.000.01β100 | β |
| seam_trim | INT | 10β24 | Frames dropped from the HEAD of every shot that starts from a keyframe. 1 (default) removes the duplicate β a continuing shot's first frame is the previous shot's last frame. Higher values also cut the re-acceleration: the model is handed a still frame, which carries position but no velocity, so every shot eases its motion in from rest and the subject appears to speed up again at each seam. 3-6 usually swallows it; each frame costs 1/24 s of that shot. The shot's audio is trimmed by the same amount, so sound stays in sync. Costs nothing to try: trimming is done at decode time, so cached shots are re-used. |
| audio | COMBO | concat | concat = decode each shot's audio, trim it to the shot's exact length, ramp the seams and normalise the whole track once. mute = silent track of the right length (still valid for Create Video). Needs 'audio_vae' wired; without it the track is silent. |
| seam_fade_ms | INT | 400β500 | Fade-out/fade-in ramp on each audio seam, in ms. Kills the click where two independently generated soundtracks meet. Not a crossfade: nothing overlaps, so the audio never shifts against the picture. |
| cache | COMBO | disk | disk = cache each shot's sampled LATENTS under user/kinburg-nodes/minimax_shots (~7 MB per shot). Editing shot 5 then re-samples 5..N and replays 1..4. off = always re-sample. |
| cache_tag | STRING | Free text folded into every cache key. The key covers architecture + LoRA patches, NOT the exact weight file β so if you swap to another H3 checkpoint of the same size, bump this to invalidate. | |
| live_preview | BOOLEAN | true | Stream the in-loop LLM's writing to a 'Kinburg Live Log' node, one labelled block per shot ('refine 2/4 (opening)'). Only does anything when 'llm_config' is wired. |
| llm_keep_loaded | BOOLEAN | false | Leave the LLM in memory between shots instead of shutting its worker down after every call. Faster (no reload per seam) but it holds its VRAM and RAM while H3 samples β on 12 GB with a 26B model that means OOM. Off is the safe default: the LLM is loaded, used and killed around each shot. |
| shots_range | STRING | Render only part of the chain: '' = all, '3' = shot 3, '2-4' = shots 2..4. Shots after the range are skipped entirely; shots before it are still needed for the handoff frame (free if cached). Handy while you design the opening shots. | |
| trims | STRING | Frames dropped from the TAIL of each shot β a comma list, last value repeating, the same shape 'durations' and 'links' take. Blank (default) trims nothing and behaves exactly as before. This is Orpheus' output. H3's shot lengths move in a 0.708 s quantum and bar lines do not, so a cut that has to land on a downbeat is reached by generating the first legal length LONGER than the music needs and dropping the overshoot here. Generate long, cut on the beat. Costs nothing to change: trimming happens at decode, so cached shots replay. The next shot's first frame moves to the cut point with it, and the shot's audio slot shrinks to match, so picture and sound stay together. Note it competes with 'seam_trim' for room β a shot is never trimmed below 5 frames, and the report says when it was clamped. | |
| audio_vaeopt | VAE | The AUDIO vae. Without it the video comes out silent. | |
| llm_configopt | KINBURG_LLM_CONFIG | Optional 'Local LLM Settings (GGUF)' WITH a 'Vision Settings (GGUF)' mmproj. Wire it and the writer gets to see the frame each shot really starts on: just before sampling a shot whose first frame was inherited, the LLM reworks that shot's opening from the actual pixels instead of the forecast it was written against. Per-shot control is the 'refine' widget on 'Morpheus Dream' (the Storyboard node sets it for you). Leave empty and shots are sampled exactly as they arrive. | |
| sigmasopt | SIGMAS | Optional explicit schedule (overrides steps/scheduler). Build it from a model that already has the sigma shift applied, or it won't match. | |
| sampleropt | SAMPLER | Optional explicit sampler (overrides sampler_name). | |
| noiseopt | NOISE | Optional noise source; its seed becomes the base seed, and each shot still gets its own offset. Leave empty to use the 'seed' widget. | |
| lora_triggersopt | STRING | Comma-separated LoRA trigger words, added to EVERY shot's prompt β wire the 'triggers' output of 'Lora Unlim Accumulator' here. They go in just before the prompt's [Negative] section, never after it, and are re-applied after the in-loop writer runs, so neither the storyboard's layout nor an LLM rewrite can lose them. A trigger already present in the text (case-insensitive) is not repeated. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | Every frame of the storyboard, in order. |
| audio | AUDIO | The whole soundtrack, normalised once and seam-ramped. |
| fps | FLOAT | 24.0 β the model's fixed rate, as a FLOAT so it drops straight into 'Create Video'. |
| last_frame | IMAGE | The last frame β the cover, or the start_frame of a later run. |
| report | STRING | Per-shot table: frames, seam trim, seed, write/sample times, cache hits, warnings. |
| prompts | STRING | The prompts that were ACTUALLY sampled, ---separated β after any in-loop rework, so this is the text that made this video. Same format 'prompt_overrides' takes on the Storyboard node. |