Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/nodes/create-noise-latents.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ Pipeline Builder → [Create Noise Latents] → Generate Media Latents → Decod
| `seed` | int | random | Reproducibility. |
| `num_inference_steps` | int | `20` | **Only shown for SDXL** — used by SDXL to scale the initial noise. Other pipelines ignore this. |

## Provider / model behavior

| Provider | Behavior |
| --- | --- |
| MiniMax-H3 | This node sets the generated geometry — Generate Media Latents exposes no dimensions of its own. **The defaults do not work:** set `width`/`height` to a MiniMax-H3 canvas (a 768-pixel short edge, e.g. **1344x768** for 16:9, or **960x544** for roughly 2.3x faster steps) and `num_frames` to **108–345**. Both axes must be positive multiples of **32**, the area must not exceed 1032192 pixels, the aspect ratio must sit between 1:4 and 4:1, and `num_frames` is snapped up to the next `17 * n + 5` (124, 141, … 345), which must land between 5 and 15 seconds at the fixed 24 fps. Anything outside that is rejected with an error naming the value and the constraint. The noise latent also carries the audio noise for the jointly generated soundtrack. |

## Tips & pitfalls

- **`width` / `height` must respect VAE divisibility.** Most VAEs require multiples of 8 or 16. Pick standard dimensions (512, 768, 1024, …) to keep shapes valid.
Expand Down
25 changes: 23 additions & 2 deletions docs/nodes/decode_media_latent.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
Category: `ModularDiffusion/Encode\Decode`

## TL;DR
- Output is **dynamic**: `output_image` for image pipelines, `output_video` (+ `fps`) for video pipelines (LTX, LTX2, WAN). It swaps automatically when you connect a `pipeline`.
- Output is **dynamic**: `output_image` for image pipelines, `output_video` (+ `fps`) for video pipelines (LTX, LTX2, WAN, HunyuanVideo 1.5, MiniMax-H3). It swaps automatically when you connect a `pipeline`.
- Almost always the last node in the flow. Connect to a Save Image / Save Video node downstream.
- **MiniMax-H3 videos come out with sound.** The soundtrack is generated jointly with the picture and muxed into the same MP4 here. Connect Generate Media Latents **directly** to this node.

## Typical workflow position
```text
Expand Down Expand Up @@ -35,7 +36,27 @@ Generate Media Latents → [Decode Media Latent] → Save Image / Save Video

| Name | Type | Default | Notes |
| --- | --- | --- | --- |
| `fps` | int (1–120) | `25` | Output frame rate. **Only shown for video pipelines.** |
| `fps` | int (1–120) | model's native rate | Output frame rate. **Only shown for video pipelines.** Defaults to the rate the selected model generates at (LTX 25, MiniMax-H3 24, WAN 16, HunyuanVideo 1.5 15), so leaving it alone plays back at the correct speed. |

## Provider / model behavior

| Provider | Behavior |
| --- | --- |
| Image pipelines | `output_image` as an `ImageArtifact`. |
| LTX, LTX2, WAN, HunyuanVideo 1.5 | `output_video` as a silent MP4 at `fps`. |
| MiniMax-H3 | `output_video` as an MP4 **with an audio track**. Video and audio are generated jointly by one denoising loop, and are muxed together here. `fps` defaults to the model's fixed **24** — changing it desynchronises the soundtrack, since the audio is muxed at its own true sample rate. |

### MiniMax-H3: keep the edge direct

MiniMax-H3's audio latent travels in the latent's *metadata*, not in its tensor. Only a direct
`Generate Media Latents → Decode Media Latent` edge preserves it:

- **Empty Latents, Save/Load Latent Tensor** drop the audio metadata. Decoding still works and
produces a silent video, with a warning in the logs.
- **Add / Subtract / Multiply Latents, Latents Composite Mask, Latent Upsampler** are worse: they
change the video latent but carry the *old* audio latent through unchanged. This node detects that
mismatch and **fails with an error** rather than muxing a soundtrack that no longer matches the
picture.

## Tips & pitfalls

Expand Down
6 changes: 6 additions & 0 deletions docs/nodes/encode_media_latent.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ Load Image → [Encode Media Latent] → Generate Media Latents → Decode Media
| --- | --- | --- |
| `latent_tensor` | `LatentArtifact` | Encoded latent in the pipeline's canonical latent space. |

## Provider / model behavior

| Provider | Behavior |
| --- | --- |
| MiniMax-H3 | **Not supported.** MiniMax-H3 has no general VAE-encode path — its only encoder is keyframe-specific and produces conditioning rows rather than a reusable latent. This node raises an error. For keyframe conditioning, connect a [Media Gen Conditioning](media_gen_conditioning.md) node to `conditioning_images` on [Generate Media Latents](generate_media_latents.md) instead. |

## Tips & pitfalls

- **The input slot adapts to the connected pipeline.** Image pipelines (Flux, SD3, etc.) show an `image` input; video pipelines (LTX, LTX2, WAN, etc.) show `input_video` instead. Switching pipeline types replaces the slot — rewire the input after switching.
Expand Down
1 change: 1 addition & 0 deletions docs/nodes/generate_media_latents.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The exact list depends on the connected pipeline. Common parameters:

- **ControlNet:** when `pipeline` is a `ControlNetDiffusionPipelineArtifact`, the `controlnet_parameters` input is added automatically.
- **Inpainting:** when `input_latent` is an `InpaintMaskArtifact` (from [Encode Masked Media Latent](encode_masked_media_latent.md)), the node automatically routes through the inpaint pipeline class and uses the artifact's `strength`.
- **MiniMax-H3:** generates the video **and its soundtrack** in one denoising loop. Only `prompt` and `conditioning_images` are exposed — there is no `guidance_scale` and no `negative_prompt` (the checkpoint is guidance-distilled, so guidance is baked into the weights and every step runs a single forward pass), and no dimensions (they come from the input latent, so set them on [Create Noise Latents](create-noise-latents.md)). Keyframes are optional: leave `conditioning_images` unconnected for text-only generation, or connect a [Media Gen Conditioning](media_gen_conditioning.md) node for a first and/or last frame. The output latent carries the audio in its metadata, so wire this node **directly** to [Decode Media Latent](decode_media_latent.md). Partial denoise must chain from another MiniMax-H3 generate — a `start_step` above 0 on a latent with no audio is rejected, since the soundtrack would restart from noise mid-schedule. `return_fully_denoised` is not supported. Inpainting, ControlNet, image-to-video and video-to-video are unavailable.

## Tips & pitfalls

Expand Down
8 changes: 7 additions & 1 deletion docs/nodes/pipeline_builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Category: `ModularDiffusion/Pipeline`

| Name | Type | Notes |
| --- | --- | --- |
| `provider` | choice | `Flux`, `Flux2`, `Stable Diffusion`, `Stable Diffusion 3`, `Qwen`, `Z-Image`, `HunyuanVideo 1.5`, `LTX`, `LTX2`, `WAN`. Changing this swaps every parameter below. |
| `provider` | choice | `Flux`, `Flux2`, `Stable Diffusion`, `Stable Diffusion 3`, `Qwen`, `Z-Image`, `HunyuanVideo 1.5`, `LTX`, `LTX2`, `MiniMax-H3`, `WAN`. Changing this swaps every parameter below. |
| `pipeline_type` | choice | Per-provider pipeline class (e.g. `FluxPipeline`, `WanImageToVideoPipeline`). Determines what the pipeline can do. |
| `<model repo>` | HF repo picker | Hugging Face repo ID. Diffusers-format only — single-file `.safetensors` checkpoints are not loaded directly. |

Expand All @@ -55,6 +55,12 @@ Category: `ModularDiffusion/Pipeline`

Enable only what you need — each option trades speed for memory.

### Provider / model behavior

| Provider | Behavior |
| --- | --- |
| MiniMax-H3 | The **Memory optimization** knobs above are ignored. MiniMax-H3 is a Modular Diffusers pipeline whose transformer (61.7 GB in bfloat16) and Qwen3-VL conditioner (62.1 GB) cannot be placed by the post-load optimizer, so the builder loads it in bfloat16 and registers the components for automatic CPU offload instead. Expect a single 80 GB accelerator plus ample host RAM. LoRAs are not supported. |

## Tips & pitfalls

- **Pipeline cache after restart.** The cache lives in process memory only; the node re-resolves automatically on the next run.
Expand Down
2 changes: 1 addition & 1 deletion griptape-nodes-library.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"beautifulsoup4>=4.13.4",
"controlnet-aux>=0.0.9",
"static-ffmpeg>=2.8",
"diffusers==0.39.0",
"diffusers @ git+https://github.com/huggingface/diffusers.git@abc5e9bf71fd38f53cd471bc3acaa84bc5ecbfdc",
"imageio[ffmpeg]>=2.37.2",
"ninja>=1.13.0",
"numpy>=2.2.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ def __init__(self, pipe: DiffusionPipeline):
self._pipe = pipe
self._modular_pipe: ModularPipeline | None = None

# Soundtrack published by ``decode_latent`` for models that generate audio jointly with the
# video, read by the VAE Decode node in the same call so it can be muxed into the output
# file. ``decode_latent`` owns these: it must set them on every call, clearing them when the
# decode produced no audio. Drivers for silent models leave them ``None``.
self.last_audio: torch.Tensor | None = None
self.last_sampling_rate: int | None = None

@property
def pipe(self) -> DiffusionPipeline:
return self._pipe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
)
from modular_diffusion_nodes_library.latent_pipeline_drivers.ltx import LTXLatentPipelineDriver
from modular_diffusion_nodes_library.latent_pipeline_drivers.ltx2 import LTX2PipelineDriver
from modular_diffusion_nodes_library.latent_pipeline_drivers.minimax_h3 import MiniMaxH3LatentPipelineDriver
from modular_diffusion_nodes_library.latent_pipeline_drivers.qwen import QwenLatentPipelineDriver
from modular_diffusion_nodes_library.latent_pipeline_drivers.qwen_edit import QwenEditLatentPipelineDriver
from modular_diffusion_nodes_library.latent_pipeline_drivers.stable_diffusion_3 import (
Expand All @@ -40,6 +41,7 @@
"Flux2Pipeline": Flux2LatentPipelineDriver,
"Flux2KleinPipeline": Flux2KleinLatentPipelineDriver,
"LTX2Pipeline": LTX2PipelineDriver,
"MiniMaxH3ModularPipeline": MiniMaxH3LatentPipelineDriver,
"QwenImagePipeline": QwenLatentPipelineDriver,
"QwenImageEditPipeline": QwenEditLatentPipelineDriver,
"StableDiffusion3Pipeline": StableDiffusion3LatentPipelineDriver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@

class LTX2PipelineDriver(LatentPipelineDriver):
produces_video: ClassVar[bool] = True
# frame_rate defaults to 24.0 in LTX2Pipeline.__call__ and its EXAMPLE_DOC_STRING.
video_fps: ClassVar[int] = 24

_HDR_LORA_ADAPTER_TOKEN: ClassVar[str] = "ic-lora-hdr"
_IC_LORA_REFERENCE_KEY: ClassVar[str] = "ltx2_ic_lora_reference"
Expand Down
Loading
Loading