Pure MLX runtime · Apple silicon · No PyTorch
MiniMax‑H3 in pure MLX.
Text to synchronized video and stereo audio on Apple silicon. One packed sequence, one transformer call per step, and nothing from the CUDA stack anywhere in the runtime.
- text—
- cond—
- audio—
- video—
Row counts and both σ grids are computed here with the same rules the runtime uses: 17n+5 frame alignment, f16 spatial and 4× temporal VAE compression, a 1×2×2 patch, 40 Hz stereo audio latents, and the simple schedule shifted by 12.0 for video and 3.0 for audio. The band is drawn to true proportion, with one first-frame keyframe so the conditioning rows are visible. Video rows dominate every real request — that asymmetry is the reason canvas and frame count are the only levers with real leverage on wall clock.
uv tool install --prerelease allow mlx-h3==0.0.1a2
Dependency surface
mlx>=0.32
That is the entire runtime dependency list.
Four obvious dependencies are absent on purpose. Each was left out for a stated reason, not by oversight, and each reason is recorded in pyproject.toml next to the exclusion.
- torch
- The runtime and its validation path are pure MLX. No CUDA, no Triton, no PyTorch execution.
- huggingface_hub
- Ships telemetry. Weights stay local; downloads use the standalone hf CLI.
- safetensors
- Redundant. mx.load() reads safetensors natively.
- tokenizers
- A local byte-level BPE reads tokenizer.json without Hugging Face dependencies.
- av
- Media I/O calls the external ffmpeg and ffprobe executables.
Memory
One large model is resident at a time.
The pipeline is phase-scoped. Each stage loads its weights, materializes its output, releases, and asserts the memory came back before the next stage begins. Peak residency is therefore the largest single phase, not the sum of the checkpoints on disk.
The ghost bar is the DiT as stored, 34.8 GiB. Roughly 13 GiB of that sits in AdaLN branches whose output depends only on timestep and modality, so the runtime materializes the request's exact modulation tables and releases those weights block by block before the first sampling step. Swap activity is a hard failure, never a warning.
Scope
What runs locally, and what does not.
MiniMax released three stages and opened the middle one. This runtime covers exactly that stage. The other two are API-only upstream, and no amount of local work changes that.
- worksText to video and audioT2VA, joint generation from a prompt alone.
- worksFirst / last frame conditioningFL2VA, zero to two keyframe anchors.
- worksOrdered referencesRef2VA, up to 9 images, 3 videos and 3 audio clips. Order is meaningful.
- worksReference-video soundtrackKeep, mute or override a reference video's audio.
- worksSynchronized H.264 / AAC MP4Muxed output, 24 fps video and 32 kHz stereo.
- works8-bit DiT and text encoderMLX affine, group size 32, produced locally.
- upstreamContext-IRThe prompt-expansion stage is API-only. Plain prompts will underperform the official demos without it.
- upstream2K regenerationNot super-resolution — H3 regenerating its own 768p result in context. Withheld for now.
Run it
A CLI, and a directory of weights.
Model files never enter the repository or the published package. Point the runtime at a local checkout of the MiniMax-H3 tokenizer and checkpoints and it will do the rest.
# from PyPI
uv tool install --prerelease allow mlx-h3==0.0.1a2
# or from a checkout
git clone https://github.com/appautomaton/mlx-h3.git
cd mlx-h3 && uv sync
uv run mlx-h3 "$MLX_H3_INPUT_TEXT" \
--width 864 --height 480 \
--frames 56 --steps 20 \
--seed 42 \
--output result.mp4
Before you start
- An Apple silicon Mac with enough unified memory for the canvas and frame count you ask for.
- Python 3.13 or newer, and ffmpeg on PATH.
- A local MiniMax-H3 tokenizer and checkpoints. Nothing is downloaded for you.
- Room under the memory budget, which defaults to 70 GiB. It is a guardrail, not a promise.
Keep prompt text in your shell environment or an untracked file. Use --steps 10 for a fast preview; --steps 20 is the quality baseline. Run mlx-h3 --help for every checkpoint path override.
Specification
Measured, not paraphrased.
Transformer
- Parameters
- 33B dense
- Layers
- 50 + 2 refiner
- Hidden size
- 5376
- Attention
- 56 heads × 128
- FFN
- 14336
- Patch
- 1 × 2 × 2
- Latent channels
- 24 video / 32 audio
- RoPE θ
- 10000.0
Components
- Encoder
- Qwen3-VL-32B
- Read depth
- layers 0–49 of 64
- Visual VAE
- f16t4d24, ViT decoder
- Audio VAE
- 32 kHz stereo → 40 Hz
- Solver
- res_multistep
- Schedule
- simple, 20 steps
- Guidance
- distilled into weights
- Quantization
- MLX affine 8-bit, g32
Output
- Duration
- 4–15 s
- Frame rate
- 24 fps
- Frame count
- aligned to 17n + 5
- Axes
- multiples of 32
- Max area
- 768 × 1344
- Audio
- 32 kHz stereo
- Container
- H.264 / AAC MP4
- Languages
- 11 with stable support
Attention dominates and grows as O(S²) while everything else in a block is linear in S. Canvas times frames is the only lever with real leverage on wall clock. MLX's full-attention kernel already runs near roofline at these shapes.
Elsewhere