keys+Wasserman Slate AI Studio, powered by TensorFold, built with integrated Fish Audio Drama 3 (Mac + DGX Spark)
**An AI film studio on your own machine: plan a film the way a crew does in the Wasserman Slate AI Studio, and render it here. Pictures from Qwen-Image-2.1-Turbo or FLUX3-K (Black Forest Labs' FLUX 3 Image Klein), MiniMax H3 / FastH3 video with sound and Fish Audio Drama 3 voices, on TensorFold: Apple-silicon Macs (Metal) and the NVIDIA DGX Spark (CUDA).**
Banner art made with this studio's own Qwen-Image-2.1 step (1664x928, seed 25); the lettering was set afterwards.
Named at the request of the TensorFold project: this is an app built on TensorFold, not a TensorFold product.
Name, credits, colours and voice for anything public: the brand guide.
Big credit: Sam Wasserman (wassermanproductions.com)
Sam Wasserman shaped the production side of this studio: the AI film workflow and the ideas behind it. Slate, his prompt studio for AI filmmaking, is the workflow inside the Wasserman Slate AI Studio tab. The Wasserman Sharp Spec, the QA gate that follows it, and the 80s Horror LoRA that opens the Keys and Wasserman LoRA Hub are his too. The Motion Previs tab's analysis is a Python port of his Motion Previs Studio. The aim we share is the best AI film studio there is, and this pack is where his planning tools meet a render engine. See CREDITS.md.
Thank you to everyone this stands on: the Qwen team at Alibaba (Qwen-Image-2.1, Qwen3-VL), the MiniMax team (MiniMax H3), Ash Hart and the TensorFold contributors, antirez (h3.c), RobZombAI (H3MLX), mrbizarro (minimax-h3-mlx / Phosphene), Filip Strand and the mflux contributors, Viggle (the image turbo adapter up to 2.2), speach1sdef178 (the 2x video decoder), LightX2V (the video Turbo adapter), NVIDIA Research (Sol-Engine, Sol-Attn, Sol-H3), FastVideo (FastH3), and Apple's MLX team and every MLX contributor, Fish Audio (Drama 3, text to speech), the MiniMax team again (MiniMax-Music3, the Music tab's songs), Black Forest Labs (FLUX 3 Image Klein) and felix-ab (flux3-mlx). This pack is their work, ported, pinned and measured. See CREDITS.md. Built with Qwen. Built with Fish Audio.
2.9.0 · Apple-silicon Macs (measured on a Mac Studio M5 Ultra 256 GB) and the NVIDIA DGX Spark · TensorFold 0.6.5 + two families, and TensorFold 1.0's native Zig runtime for FastH3 on Metal and on CUDA: Qwen 2.1 Turbo, Qwen 2.1 Full, FLUX3-K Fast and FLUX3-K Full (text to image, and Edit a picture) · MiniMax H3 (video with sound) · Fish Audio Drama 3 (Voice) · MiniMax-Music3 (Music: songs with sung vocals) · int8 kernels on the M5 tensor units and on the GB10's tensor cores · a 2x video decoder for 2K finals on the Mac
New in 2.9.0
- Music: MiniMax Music 3 (MiniMax-Music3). A new Music tab beside Voice makes a whole song with sung vocals
[Intro], [Verse], [Pre-Chorus], [Chorus], [Bridge], [Instrumental],
[Outro] ...) on lines of their own; the tab has a button for each and says when a tag looks wrong.
- Style is a caption: genre, tempo, key, mood, vocals, instruments. A helper writes one from those six boxes.
- Use as soundtrack: a song can be laid under a long video, the Editor's export or any clip of the Library. It
sits under the clip's own sound, is lowered up to 12 dB while someone speaks, and no peak passes -1 dBFS.
- Mac: TensorFold's MLX port (music3-mlx, pinned at 71c7c1f8), installed by bash oneshot-setup.sh --music
into its own environment, with the 22 GB of weights. DGX Spark: ComfyUI's own MiniMax Music 3 nodes,
bash oneshot-setup-spark.sh --music.
- Measured through the app, one 60 s song on each machine (the same pop lyrics and style, seed 7, 30 steps; one run
each):
| 60 s song | Mac Studio M5 Ultra (MLX) | DGX Spark (ComfyUI, CUDA) | |---|---|---| | Whole job, song made | 75.8 s (59.99 s of song), files in the page cache | 289.0 s (59.99 s of song), ComfyUI started and the files read from an empty page cache | | Words and melody (autoregressive model) | 37.8 s | 176.3 s | | Sound (DiT, 30 steps) | 34.6 s | 96.3 s | | Decoder | 2.0 s | 4.1 s | | Model load | 0.9 s (first song) | inside the stages above (ComfyUI loads as it goes); about 12 s more than with the files cached | | Peak memory | 27.6 GB (MLX's own peak); the machine's in use rose 32.9 GB | 29.3 GB taken from the machine (MemTotal - MemAvailable, 5.1 GB before) | | Whisper on the take | 96 % of the words sung (128 of 134); the song reached 43 % of the lyrics at 60 s | 1 %: on this take Whisper heard only "We'll be right back" twice. A second take through the app (hip-hop lyrics, seed 11, 273.2 s): 98 % (166 of 169), all the lyrics reached |
- Honest limits. A song is not played while it is made (no streaming yet). Whisper's count on sung words is rough, and one Spark take in three was barely heard by it (above). Lengths measured: on the Spark 30, 60, 120 and 300 s asked (one run each; the 300 s one ended itself at 189.8 s, so no song over 120 s was made to its full length there); on the Mac songs of 10, 30 and 60 s. Other lengths are untested, and so is anything but the default settings. On the Spark the autoregressive stage runs in ComfyUI's Python loop at about 9 frames a second, so a song takes about 4.4 times its length there against 1.25 on the Mac.
- Upgrade with
git pull, thenbash oneshot-setup.sh --upgrade --music(on either machine) to add the Music tab's
- Licence: MiniMax-Music3 Community License. Commercial use is allowed, but a commercial product must show
New in 2.8.0 and 2.8.1
- 2.8.1: Qwen 2.1 Full. The picker now offers Qwen-Image-2.1 in two versions, as it does FLUX3-K: **Qwen 2.1
oneshot-setup.sh --image-edit).
- Mac: the Mac's generator gained --cfg for it.
- DGX Spark: it runs ComfyUI's 40-step CFG-4 workflow.
- Times on an M5 Ultra at 1344x768: Turbo 12 s, Full 47 s, both peaking at 15.3 GiB. Full run without guidance
took 24 s and was barely better than Turbo, so guidance stays on.
- A shootout of all four picture models, Mac against DGX Spark, with 128 pictures, says which to use for what:
▶ Watch the 60 s demo: the Studio on one Mac Studio M5 Ultra, recorded live on 2026-10-16. It shows the app at work, two clips with sound, and the times and memory measured during those renders.
- Pick the picture model. Wherever the Studio makes a picture you can choose Qwen 2.1 Turbo (the quickest),
bash oneshot-setup.sh --flux3 (41 GB); first accept the FLUX Kommunity License on Hugging Face.
- How each prompt is handled: BFL's prompt upsampler writes a full scene caption from your prompt first.
- On a DGX Spark: FLUX3-K runs on ComfyUI's own FLUX 3 nodes, with ComfyUI moving to 5a665890.
- On a Mac: it runs on flux3-mlx in an environment of its own.
- Edit a picture with FLUX3-K. It also takes up to nine further reference pictures, for example a person from one
- Better text and whole figures. On the same prompts and seeds, FLUX3-K:
- New carrier image.
ghcr.io/drowzeys/keys-tensorfold-studio:2.8.0now holds the DGX Spark's LoRA engine
h3-cuda-lora 1f7ecc75), so a Spark install no longer builds it from source.
- Upgrade with
git pull, thenbash oneshot-setup.sh --upgrade. Add--flux3for the FLUX3-K weights.
*The poster prompt, two seeds. Left: Qwen 2.1 Turbo, on the Mac. Middle and right: FLUX3-K Full ("Base") and FLUX3-K Fast ("Distilled"), here run through diffusers on a Spark, so the times are diffusers' (91 s and 15.5 s). In the Studio, through ComfyUI, they take 57.5 s and 10.5 s.*
Picture times, 1344x768, model loaded, bf16:
| | DGX Spark | Mac Studio M5 Ultra | |---|---|---| | Qwen 2.1 Turbo, 8 steps | 9.5 s | 9.7 s | | Qwen 2.1 Full, 40 steps at CFG 4 (2.8.1) | | 47 s (whole run, model load included) | | FLUX3-K Fast, 16 steps | 10.3 to 10.7 s | 14.9 s | | FLUX3-K Full, 50 steps | 57.5 s | 53.6 s | | FLUX3-K prompt upsampler, once per prompt | about 18 s | 5 s | | Edit a picture: Qwen / FLUX3-K Fast / FLUX3-K Full | 24 / 37 / 139 s | 10 / 37 / 240 s | | Two-picture edit: Qwen / Fast / Full | 23 / 44 / 188 s | 13 / 42 / 427 s |
FLUX3-K Full is slow for edits on a Mac, so Fast is the FLUX3-K to use there.
A whole clip, text to picture to 5 s of video with sound, measured through the app. On the Mac these are the demo renders; on the Spark, the 2.8.0 tests.
| | Picture | Video (FastH3, 8 passes) | Total | Peak memory of the render | |---|---|---|---|---| | Mac, 864x480, FLUX3-K Fast | 11 s | 70 s (5.93 s a pass) | 81 s | 29.0 GB | | Mac, 1344x768, Qwen 2.1 Turbo | 11 s | 201 s (20.1 s a pass) | 212 s | 33.0 GB | | DGX Spark, 864x480, FLUX3-K Fast | about 32 s (upsampler included) | 70 to 96 s | 102 to 128 s | | | DGX Spark, 864x480, FLUX3-K Full | 53 s | 96 s | 149 s | |
Peak memory is the render process's macOS footprint, GPU memory included, sampled every second. The peak comes at the handover from the picture model. FastH3 itself holds 23 GB at 864x480 and 27 GB at 1344x768.
!Memory of the render process during the two demo renders on the M5 Ultra
The Studio's TensorFold work, submitted upstream. At the TensorFold project's invitation, the engines behind this Studio are open as pull requests to ashhart/TensorFold. Each lists what was tested and what was not:
| Pull request | What | |---|---| | #949 #950 #959 #960 #961 | MiniMax H3 / FastH3 on Metal in bf16 (10.2 s a pass against 27.9 s for MLX bf16), from an image, any step count, re-voicing, Ref2VA | | #947 #958 #946 | MiniMax H3 / FastH3 on CUDA, one GPU or one pass split over several DGX Sparks (3 Sparks: 3.0 s a pass in int8, 5.0 s in bf16), and the runtime hook it uses | | #939 #956 | Fish Audio Drama 3 on CUDA (34 frames/s) and on Metal (84 frames/s, first audio 0.15 s, 9.5 GB) | | #948 | Qwen-Image 2.1 on Metal (0.74 s a step, 43 dB PSNR against mflux) | | #941 to #944 | This Studio: Slate, Motion Previs, FLUX3-K and Voice |
These are proposals: this repository's install still pins the engines on the drowzeys/TensorFold fork.
Which picture model to use: the evidence
The test: a shootout on 2026-10-16 with Studio 2.8.1, run on a Mac Studio M5 Ultra and one DGX Spark.
- Pictures: 8 prompts × 2 seeds × 4 models × 2 machines = 128 pictures at 1344x768, 0 failed jobs.
- Judging: by eye, from the full-size pictures.
- Full report: every grid, the raw numbers and the method are in
Speed and memory, per picture with the model loaded (median):
| Model | Mac M5 Ultra | DGX Spark | Peak memory (Mac / Spark) | |---|---|---|---| | Qwen 2.1 Turbo, 8 steps | 4.7 s | 8.6 s | 33 / 31 GB | | Qwen 2.1 Full, 40 steps at CFG 4 | 43.3 s | 80.1 s | 33 / 30 GB | | FLUX3-K Fast, 16 steps | 9.8 s | 10.5 s | 38 / 37 GB | | FLUX3-K Full, 50 steps | 59.9 s | 58.7 s | 40 / 37 GB | | FLUX3-K prompt upsampler, once per prompt | 5.2 s | 12.5 s | |
- Qwen: runs about 2x faster a step on the M5 Ultra.
- FLUX3-K: runs at the same speed on both machines.
| Prompt | Winner | The evidence | |---|---|---| | Poster with title and tagline | Qwen 2.1 Full | Most coherent scene. All 32 posters, every model, spelled both lines exactly | | Photoreal portrait | Qwen 2.1 Full | Real skin and the whole face. FLUX3-K cropped off the mouth in 8 of 8 | | Character turnaround | Qwen 2.1 Full, narrowly | Gear consistent across views. FLUX3-K wins for a labelled line-art sheet | | Crowded night market | FLUX3-K Full | Lanterns, steam, mostly real words on signs. Qwen drew pseudo-script | | "Red cube on a blue sphere, left of a green pyramid" | FLUX3-K Fast | Right in 8 of 8; Qwen 2 of 8 | | Food photography | FLUX3-K Fast | More professional styling. No model reliably drew the three pancakes asked for | | Watercolor | FLUX3-K Full | Truest washes and paper texture | | Hands at a piano | FLUX3-K Full | Five fingers on each hand in 8 of 8. Qwen drew a third hand 3 times |
*The spatial prompt. Every FLUX3-K picture (right two columns) has the pyramid on the right, as asked. Six of the eight Qwen pictures put it on the left.*
Conclusion: which to pick
- Drafts and scouts: use Qwen 2.1 Turbo. It is the quickest, and its quality is visibly below the other three.
- The everyday default: use FLUX3-K Fast. It is right on layout and good on hands and crowded scenes, at about
- Faces, portraits, posters and character sheets: use Qwen 2.1 Full. It is twice as fast on a Mac.
- Final frames of complex scenes, illustration and hands: use FLUX3-K Full.
- Machine: for Qwen, the Mac when you have the choice. For FLUX3-K, the machine does not matter.
Speed: the first version on each machine, and 2.3
One run each unless a range is given; 5 second clips are 124 frames. Mac: Mac Studio M5 Ultra, 256 GB. Spark: one NVIDIA DGX Spark (GB10), models already loaded.
| 5 second clip, 864x480 | Mac, first version (1.0, 2026-10-04) | Mac, 2.3 | DGX Spark, first build (ComfyUI's own blocks, bf16) | DGX Spark, 2.3 | |---|---|---|---|---| | What makes the video | MiniMax H3 + Turbo adapter on MLX, 3 passes | FastH3, 8 passes, TensorFold's Zig + Metal engine | FastH3, 8 passes, ComfyUI | FastH3, 8 passes, TensorFold's CUDA engine in int8 | | Image, then video from it | 74 s (103 s with the sound made again, the later default) | 79 s (image 6 s, video 73 s) | 155 s | 115 s (measured before the faster decoder below, which takes about 10 s more off) | | Text straight to video | not offered | 66 s | 118 to 121 s | 73 s | | One denoising pass | 9.5 s | 5.3 s | 10.5 s | 7.1 s | | Video decode | not timed apart | 13 s | 26 s | 14 s |
| Other sizes and lengths | Mac, first version | Mac, 2.3 | DGX Spark, first build | DGX Spark, 2.3 | |---|---|---|---|---| | 864x480, 4 passes, text to video | | 43 s | 71 s | 45 s (from the pass time) | | 1280x720, 5 s, text to video | | 199 to 217 s | not measured | 183 s | | 1344x768, 5 s, text to video | | 175 s | 289 s | about 195 s | | 1344x768, 8 s, image then video | 364 s (709 s with the later default) | not re-measured | | | | 1280x720, 10 s (243 frames), text to video | | 378 s | not measured | 444 s | | One 15 s part of a chained 864x480 clip | | about 249 s | not measured | about 304 s | | One image, 1344x768 | 9.2 s (Viggle adapter, 6 steps) | 8.9 s (Qwen-Image-2.1-Turbo, 8 steps; peak 15 GiB against 28) | 18 to 21 s with the model load | 9.5 s |
- The Mac's first version and 2.3 use different video models, so the 74 s and 79 s rows are not the same work: the
- On the Spark the model is the same in both columns. The gain is the engine (10.5 s a pass to 7.1 s) and the 8-bit
- Both engines are TensorFold H3 families on the TensorFold 1.0.4 base, from one commit of one branch. 1.0.3 and 1.0.4
Which Mac runs what
Every row is Studio 2.3. "Default" means images (Qwen-Image-2.1-Turbo) and FastH3 video with sound, the web app and the one-click app. Only the M5 Ultra with 256 GB has actually run it; every other row follows from memory measured on that machine and is marked untested.
| Chip | Memory | What runs | Install command | Video engine it uses | Peak memory | Status |
|---|---|---|---|---|---|---|
| M5 family | 64 GB | Default | bash oneshot-setup.sh --app | FastH3, native Zig engine | 32 GiB | Untested |
| M5 family | 96 GB | Default | bash oneshot-setup.sh --app | FastH3, native Zig engine | 32 GiB | Untested |
| M5 family | 128 GB | Default, and MiniMax H3 Turbo if wanted | bash oneshot-setup.sh --turbo --app | FastH3 native; Turbo on the MLX engine with int8 kernels | 32 GiB; 103 GiB for Turbo | Untested |
| M5 family | 256 GB or more | Everything | bash oneshot-setup.sh --turbo --app | The same | The same | Tested (M5 Ultra, 256 GB) |
| M1 to M4 | 64 GB | Default, slowly | bash oneshot-setup.sh --app (add Q8_ONLY=1 in front to save 65 GB of disk) | FastH3, MLX engine, 8-bit weights | 37 GiB at 480p, 40 GiB at 720p | Untested; emulated on the M5 |
| M1 to M4 | 96 GB | Default, slowly | bash oneshot-setup.sh --app | FastH3, MLX engine, 8-bit weights | 37 to 40 GiB | Untested; emulated on the M5 |
| M1 to M4 | 128 GB | Default, slowly. Turbo installs but is not recommended | bash oneshot-setup.sh --app | FastH3, MLX engine, 8-bit weights | 37 to 40 GiB | Untested; Turbo's memory without the int8 kernels is not measured |
| M1 to M4 | 256 GB or more | Default, slowly; Turbo should fit | bash oneshot-setup.sh --turbo --app | FastH3 MLX 8-bit; Turbo on the MLX engine in bfloat16 | 37 to 40 GiB; Turbo not measured | Untested |
| Any | 48 GB | Images only | bash oneshot-setup.sh --image-only | none | 28 GiB | Untested below 256 GB |
How to configure it:
- Nothing to set on a normal install. The setup reads the chip and the memory and picks the engine: the native
- Disk: 175 GB for the default on an M5; 212 GB on an M1 to M4 (147 GB with
Q8_ONLY=1); 64 GB more with
--turbo; 33 GB for --image-only.
- Speed on an M1 to M4: the 8-bit path took 31 s a pass at 864x480 on the M5 Ultra's GPU, against 5.3 s for
STEPS=4 bash scripts/fast.sh "a prompt" out.mp4, or the 4 passes card in the app).
- Overrides:
FASTH3_Q8=0runs an M1 to M4 with the uncompressed weights (64 GiB peak: a 96 GB Mac or larger;
FASTH3_ENGINE=mlx forces the MLX engine on an M5. ENGINE=h3 asks for Turbo where it is installed.
| Studio version | Smallest Mac for video | |---|---| | 2.0 and earlier | 128 GB (M5 for the fast path) | | 2.1 | 64 GB on an M5; 96 GB on an M1 to M4 | | 2.2 to 2.5 | 64 GB on any Apple silicon |
On a DGX Spark the setup asks for 100 GB of memory for video (a Spark has 128 GB; about 70 GB was in use during a clip). No NVIDIA machine with 64 GB has been tried.
Measured memory for each kind of job is under Minimum requirements.
DGX Spark (CUDA) build
The same Studio (web app, scripts, one-shot install) also runs on an NVIDIA DGX Spark (GB10, 128 GB unified
memory, CUDA 13). FastH3's transformer runs there on TensorFold's H3 family for CUDA: the Mac engine's design
(int8 projections, tile-routed int8 attention with FastH3's own sparse selection) on the GB10's tensor cores, written
in Zig over the CUDA driver. ComfyUI, pinned, hosts the rest: the text encoder, the sampler, the decoders and
Qwen-Image-2.1. The header of the web app says which build you are in: a green DGX SPARK · NVIDIA GB10 · H3-CUDA
badge, or a purple MAC · APPLE SILICON MX · H3-METAL.
Thank you to Ash Hart for TensorFold, FastVideo (Hao AI Lab) for FastH3 and its ComfyUI release, MiniMax for H3, the Qwen team for Qwen-Image-2.1-Turbo, and the ComfyUI team for the runtime this build stands on.
git clone https://github.com/drowzeys/keys-Wasserman-Slate-AI-Studio-powered-by-TensorFold-built-with-integrated-Fish-Audio-Drama3.git && cd keys-Wasserman-Slate-AI-Studio-powered-by-TensorFold-built-with-integrated-Fish-Audio-Drama3
sudo apt install -y git ffmpeg
bash oneshot-setup.sh # the same command as on a Mac: on Linux it runs oneshot-setup-spark.sh
# 99 GB of models, the engine build, a test image and a 5 second test clip
bash scripts/app.sh # http://127.0.0.1:7870
ffmpeg is part of the install, and the installer stops without it. A Spark that was set up some other way (a copy of another Spark's folders, say) may lack it: the app then starts, says so in its log and in the page's header, and refuses the jobs that need it when they are queued. The 720p preset is not one of them any more: it generates 1280x736 and crops to 1280x720, and the crop is now made inside the ComfyUI workflow, before the clip is encoded (one encode instead of two); in 2.6.5 it was an ffmpeg pass after the render, and a Spark without ffmpeg lost the finished clip there. Without ffmpeg a clip also keeps ComfyUI's own sound track instead of the limited 256 kb/s one, and the render says so.
Upgrade from 2.5 or 2.6 (DGX Spark)
cd keys-Wasserman-Slate-AI-Studio-powered-by-TensorFold-built-with-integrated-Fish-Audio-Drama3 && git pull
bash oneshot-setup.sh --upgrade # on Linux: oneshot-setup-spark.sh --upgrade
--upgrade moves an existing install to the version of the clone: the environment's packages, ComfyUI at its pinned
commit, the engine (rebuilt only when its pinned commit changed) and the Motion Previs environment, which it adds
when it is missing. It fetches no weights (a model that is not on disk is named and left out; an image-only
install stays image-only), does not touch ~/TensorFoldStudio (clips, projects, LoRAs, settings), prints the version
before and after, and ends with --verify. Running it a second time changes nothing. Restart the app afterwards
(bash scripts/app.sh) so it serves the new pages. Run it when no clip is rendering.
The installer takes the prebuilt engine from the carrier image when Docker is there, and otherwise builds it from
source (spark/build-engine.sh: it fetches Zig 0.17.0 and the engine's source,
drowzeys/TensorFold h3-1.0.4, and needs the CUDA toolkit's
nvcc, 12.9 or newer). Without it the Studio still works on ComfyUI's own blocks, slower.
Measured on one DGX Spark (2026-10-09, one run each; 124 frames, text to video, models already loaded):
| Size | Passes | TensorFold engine (int8) | A pass | ComfyUI's own blocks (bf16) | A pass | |---|---|---|---|---|---| | 864x480 | 8 | 73 s | 7.1 s | 118 to 121 s | 10.5 s | | 864x480 | 4 | 45 s (from the pass time) | | 71 s | | | 864x480 | 20 | 158 s (from the pass time) | | 244 s (from the pass time) | | | 1280x720 (rendered 1280x736) | 8 | 183 s | 18 s | not measured | | | 1344x768 | 8 | about 195 s | 20.5 s | 289 s | 29.4 s |
The engine's column includes ComfyUI's 8-bit video decoder, the default here: it decodes 124 frames of 864x480 in
14 s where the fp16 one takes 26 s (29 s against 42 s at 1344x768), and the picture matches the fp16 decode to 42 to
44 dB. SPARK_VAE=minimax_h3_video_vae_fp16.safetensors selects the fp16 decoder if you download it.
| Also | Time | |---|---| | A clip from an image, 864x480, 8 passes | 85 s | | First clip after a start, 864x480, 8 passes | about 115 s (ComfyUI's blocks: 144 to 156 s) | | Qwen-Image-2.1-Turbo image, 1344x768 | 9.5 s (20 s with the model load) | | Three scout images, 864x480 | 23 s |
Lowest free system memory seen with the engine was 49 GB of 121 (35 GB on ComfyUI's blocks): the transformer is held
in int8, 21 GB instead of 42. The first use converts the checkpoint on the GPU (about 90 s) and saves the int8 copy
beside it (….safetensors.tf-int8, 21 GB of disk); later starts read that in a few seconds.
How close the engine is: on the same input with dense attention, the stream after all 50 blocks has cosine 0.998 against ComfyUI's bf16 blocks. With sparse attention the same seed gives the same scene as ComfyUI's sparse path, and a repeat of a seed gives a bit-identical clip.
What is different from the Mac build:
- Slower than an M5 Ultra, about 1.35x a pass at 480p (7.2 s against 5.3 s).
- FastH3 only. No MiniMax H3 Turbo, and no 2x decoder, so the sizes are 864x480, 1280x720 and 1344x768.
- Sparse attention at every size (FastH3 was trained with it: a video tile keeps the best 20% of video tiles).
SPARK_SPARSITY=0 renders with dense attention, slower.
- Clips from an image want the app's prompt. The web app writes MiniMax H3's first-frame lead line and structured
FIRST_FRAME gave a jump cut in a test (on ComfyUI's own sparse path too).
SPARK_ENGINE=comfyrenders on ComfyUI's own blocks in bf16 (dense attention under about 720p, its block-sparse
- Why int8. The GB10's tensor cores run int8 products at 245 TOPS and bf16 ones at 122 (measured on registers).
- ComfyUI keeps running with the models loaded after a render (
bash spark/comfy.sh stopfrees the memory). It runs
More than one DGX Spark: the Sparks setting
A job can use more than one DGX Spark. Sparks, a number from 1 to 8, is how many machines a job may use, the one
the app runs on counted as one. It is at the top of the Queue on every tab, in the last step of Create, on the
Production board and in a Slate shot; through the API it is "sparks": 5 beside kind and params. The app shows
how many Sparks are there and able and uses that many: choose 8 with five machines and it says 5 of 8 available
and uses five.
- Several clips (jobs in the queue, a Production board's segments, a Slate scene's shots) render one clip per
- One clip renders on one Spark. So do a long video (a chain of clips), pictures, edits and Library actions, on
- The Sparks tab is the list of the other Sparks: add one by the address you would type after
ssh, and
- Safe by construction. A worker's app listens only on its own
127.0.0.1; this app reaches it through an ssh
Measured through the app's own API on 2026-10-13, eight 56-frame 864x480 FastH3 clips, models loaded, one run each:
| Sparks | 1 | 2 | 3 | 4 | 5 | |---|---|---|---|---|---| | Wall time, 8 clips | 263 s | 130 s | 98 s | 69 s | 65 s | | Against one Spark | 1.00x | 2.03x | 2.70x | 3.81x | 4.05x |
Five were barely better than four for eight clips (two rounds of clips either way); the fifth pays from ten clips. Six to eight are not measured: five machines exist here. One clip split across Sparks is measured outside the app (1.40x, 1.73x and 1.77x on two, three and four) and is not built in. The whole of it, with what is not built: docs/multi-spark.md.
The memory guard (DGX Spark)
On a Spark the GPU and the system share one pool of memory. On 2026-10-13 one clip with a LoRA at 1376x768 took a
worker Spark down: the app accepted it, and the server's check (once a second, against 4 GB) did not act. The guard
in spark/memory_guard.py replaces that check, in three layers that every way of starting a render goes through
(the app, scripts/video.sh, spark_generate.py, a worker's copy of this folder):
- Before a clip is queued, and again before anything is loaded, its peak is estimated from measured peaks. A
- While the server runs, the guard reads the machine's memory twenty times a second. It stops the server when
SPARK_MEMORY_FLOOR_MB), or is falling so
fast that it would be under a third of the floor within a second, or when the kernel reports work stalled on
memory. The job fails with that reason. It also gives the model files' page cache back when little memory is
free (SPARK_MEMORY_FREE_MB, 8.3 GB): the GPU driver takes its memory from what is free, not from what is
available.
- The server is marked as the first process the kernel ends if memory runs out all the same.
The estimate is a straight line through those points for each route plus 6 GB (no point is more than 1.7 GB from its line; most are one run). Three things it does not know, said plainly:
- A clip with a LoRA is refused above the largest one measured on its route. Since 2.7.1 a LoRA on FastH3 is
--engine comfy) it stays refused above 1280x736 at 124 frames (35.0K rows), whatever the line
says. By that line the clip that took the Spark down needs 77 GB and leaves 41, and that is what the machine showed
for a minute before it was lost, so its end is not explained by how much memory the clip takes and the size is not
offered there. Its logs were never read; what is known is in the next paragraph.
- Reference clips (Ref2VA), MiniMax H3's own transformer and a Spark without the engine were not measured here; they
- Pictures, edits and Library actions are not estimated: the running guard covers them.
NVRM ... NV_ERR_NO_MEMORY) at 2 GB free and 54 GB available. With the guard beside the server the same renders
kept 8 GB or more free, took the same time (146 s against 145 s), and the driver logged nothing. Proof of the two
refusals, without a machine near its limit: the app and scripts/video.sh both refuse the lost clip before anything
loads, and a server started with SPARK_MEMORY_FLOOR_MB=70000 was stopped during a small clip's load at 69.8 GB
available (lowest point 69.77 GB while memory fell at 28 GB a second; gone in 0.5 s, the job failed with the reason).
python3 spark/memory_guard.py check --width 1376 --height 768 --frames 124 --lora prints a verdict.
Longer clips on the engine: 10 seconds at 1280x720 (243 frames) took 444 s, a pass 43.7 s, against 378 s on an M5 Ultra for the same prompt; a 30 second chained clip at 864x480 (two 15 second parts) took 611 s.
Not tested: clips longer than 15 seconds in one piece, chains longer than 30 seconds, a download of the models from nothing (the files were already on the test machine), any GPU other than the GB10, and two Sparks working on one clip.
What changed
2.8.1 (2026-10-16): Qwen 2.1 Full. The picture-model choice adds Qwen-Image-2.1's 40-step base model as
Qwen 2.1 Full, beside Qwen 2.1 Turbo, as FLUX3-K has Fast and Full.
- Guidance: it runs with true classifier-free guidance at 4 and an empty negative prompt, as Qwen's own pipeline
does: ComfyUI's CFG-4 workflow on a DGX Spark, and qwen_image_generate.py --cfg 4 on a Mac. The Mac's
generator had no guidance before.
- Where it is offered: where the base weights are installed (--image-edit).
- Measured on an M5 Ultra at 1344x768: Turbo 12 s, Full 47 s, both peaking at 15.3 GiB. Full without guidance
took 24 s and looked barely better than Turbo.
- Docs: the README opens with what is new, the 2.8.0 demo and a new banner.
2.8.0 (2026-10-15): pick the picture model: Qwen 2.1 Turbo, FLUX3-K Fast or FLUX3-K Full. Black Forest Labs'
FLUX 3 Image Klein ("FLUX3-K") joins Qwen-Image-2.1-Turbo wherever the Studio makes a picture from a prompt: *Image
only*, the scouts a clip starts from, and a last frame. FLUX3-K Fast is the distilled checkpoint (16 steps),
FLUX3-K Full the base one (50 steps at CFG 3.5); both get a full scene caption from BFL's prompt upsampler first.
On a DGX Spark they run on ComfyUI's own FLUX 3 nodes (ComfyUI moves to 5a665890, v0.41.0 and later), upsampler
included, so the render stays under the memory guard; on a Mac on flux3-mlx (Apache-2.0, a port of BFL's reference
code) in an environment of its own. oneshot-setup.sh --flux3 installs them (41 GB; the Hugging Face repos are gated:
accept the FLUX Kommunity License first). Measured at 1344x768 with the model loaded, bf16: Qwen Turbo 9.7 s on an
M5 Ultra; FLUX3-K Fast 10.3 to 10.7 s on a Spark (ComfyUI; diffusers took 15.5 s for the same picture) and 14.9 s on
an M5 Ultra; FLUX3-K Full 57.5 s on a Spark and 53.6 s on an M5 Ultra; the upsampler, once per prompt, about 18 s on
a Spark and 5 s on an M5 Ultra. Against Qwen on the same six prompts and two seeds, FLUX3-K spelled a poster's title and tagline
right where Qwen wrote "SOME ONE IS STOLL LISTENNING", drew whole figures for character sheets where Qwen cut them at
the waist, and kept two characters recognisable in a two-reference shot; Fast looked as good as Full. The same seed
draws a different picture on the two machines (the runtimes draw their noise differently). Edit a picture offers
the same choice: FLUX3-K takes the picture, and up to nine more beside it, as reference latents (BFL's edit layout:
every picture on the prompt and on the negative, the result at the first picture's size), and the upsampler sees the
pictures before it writes the caption of the result (its i2i system prompt). Image LoRAs, the camera ring and the
40-step base model stay Qwen's. Measured with the job's own scripts, seed 7, 1344x768, upsampler included: an edit
took 24 s with Qwen, 37 s with FLUX3-K Fast and 139 s with Full on a DGX Spark, 10, 37 and 240 s on an M5 Ultra; two
pictures (a person from one put in the place of another) 23, 44 and 188 s on a Spark, 13, 42 and 427 s on the Mac.
The reference rows lengthen every step, so Full is slow for edits on a Mac (about four times its text-to-image
time): Fast is the FLUX3-K for edits. FLUX3-K follows "switch the neon off" where Qwen left the signs lit on the
Spark. FLUX 3 Image Klein is under the FLUX Kommunity License: non-commercial use, and commercial use of the
outputs only for Qualifying Users (under US$5M revenue). The carrier image moves to
ghcr.io/drowzeys/keys-tensorfold-studio:2.8.0: the same Mac payload, and the DGX Spark's prebuilt engine is now the
LoRA build of 2.7.1 (h3-cuda-lora1f7ecc75), so a Spark install takes it instead of building it from source.
2.7.8 (2026-10-15): no dropped lines on the Spark, a cloned voice at once on the Mac. On a DGX Spark the app
now gives every take the Mac engine's end-of-text check (app/wordcheck.py, its rules copied from TensorFold's
drama3-mlx): Whisper hears the take, and when words are missing (under 85 % heard, three in a row, or the ending)
the take is made again with another seed, not played, twice at most, the best kept and the first one's check kept
beside it. The two-speaker example on seeds 1 to 8 through the head app: before, seed 2 lost its last line (15 of
20 words) and the other seven were whole; after, all eight whole, seed 2 drawn again once (42.7 s for the take
against 18 to 25 s for the others). On the Mac a voice to clone left without its words is heard by the engine's own
Whisper on the GPU (TensorFold drama3-mlx 8f3d4b33), not by the app's on the CPU first: the first sound of a
cloned take reaches the page 0.56 to 0.63 s after the request, against 10.6 to 10.8 s in 2.7.7.
Built with Fish Audio.
2.7.7 (2026-10-15): Voice answers at once on the Mac, and dialogue keeps its lines. The Mac's Drama 3 now runs
as a persistent server, like the Spark's (TensorFolddrama3-mlx92c09a8e,--serve): the first take loads it
(5.2 s, about 50 GB with its word check), later takes start at once, and it is unloaded after five idle minutes and
before any video or picture job, holding the studio's GPU lock while loaded. **Once loaded, a take's first sound
reaches the page 0.23 to 0.30 s after it is asked for** (5.4 s on the first take, 2.7.6's every take). A two-speaker
line is now sent a turn a line on both machines (on one line Drama 3 dropped later turns; Fish's own prompt format),
and the tab's example is written so: on the M5 Ultra the two-speaker example came back whole on seeds 1 to 4, three
of them while playing and one made again without playing. The Mac engine also redraws a part whose last word is
missing. Measured through the Mac app: a 46 s read in 16.8 s, a Slate cast line in 1.5 s, every take's words all
heard. Built with Fish Audio.
2.7.6 (2026-10-15): the Mac's Voice tab catches up with the Spark's. On a Mac a take now **plays while it is
made** (the engine's--stream, through the same/api/voice/takes/{id}/liveas on a Spark) and the engine
checks its own words as it goes (TensorFold drama3-mlx 4a8a982f: Whisper on MLX after each part, a runaway tail
cut, a part with missing words drawn again, and a stop rule on the model's own end signal). The check's word count
is the take's score, so the take is no longer transcribed a second time, and the tab shows it part by part, with
the time to the first sound. A part cannot be drawn again once it has been heard: a take that comes out short while
playing is made once more without playing (Play while it is made off does that from the start). Measured on the
M5 Ultra through the app: 8 s of speech in 8.7 s from the click, the first sound 5.3 s after it (start-up and the
3.7 s load, then 0.22 s), a 46 s read in 21.9 s. Both engines are now public on
drowzeys/TensorFold (drama3-mlxfor the Mac,drama3-cudafor the
Spark), andoneshot-setup.sh --voiceinstalls the Mac one (scripts/setup-voice.sh); on a Spark it checks the
hand-built engine and prints the steps. Built with Fish Audio.
2.7.5 (2026-10-15): Voice on the DGX Spark. The Voice tab now works on a DGX Spark as on the Mac, through
TensorFold's native CUDA port of Fish Audio Drama 3 (drama3-generate, Zig + CUDA, no Python at run time; nothing is
sent to Fish Audio). The engine is a persistent server: the first take loads it (about 18 s, 41.6 GB at the peak),
later takes start at once, and it is unloaded, its memory given back, after five idle minutes and at once before any
video or picture job of the queue starts, so it never stands beside MiniMax H3. It holds the studio's GPU lock for as
long as it is loaded and stands under its own memory guard. A take plays while it is made (the first sound
about 0.3 s after the take starts on a loaded engine). Long text goes in parts and keeps one voice. Measured on a
GB10 through the app: 28 to 31 frames a second (a take made in 0.7 to 0.8 times its length), Whisper 92 to 100 %
on a plain line, a cloned voice, two speakers, a Slate cast voice and a 56 s read. See
Voice on a DGX Spark. Built with Fish Audio.
2.7.4 (2026-10-15): Voice, with Fish Audio Drama 3. A new Voice tab speaks text with Fish Audio Drama 3 on
the Mac itself, through TensorFold's MLX port (nothing is sent to Fish Audio): up to 16 speakers in one take
(<|speaker:0|>...<|speaker:15|>),[directions]for the delivery ([whispering],[sighs], or a description of
the voice), and a voice cloned from a clip, with a consent box that must be ticked. Each take runs in the render
queue, one at a time and never beside a video (Drama 3 peaks at about 50 GB), under the studio's GPU lock; Whisper
then checks its words. Use as Ref2VA voice reference puts a take into the create wizard as reference audio
(; a take over 15 s is cut to its first 15). In Slate's Sound tab a voice sheet has Cast voice: its
sample line spoken in the voice the sheet describes, kept on the sheet, and sent as that speaker's reference audio in
shots that open on cast stills. On a DGX Spark the tab is there and says the CUDA port is not available yet. Measured
on the M5 Ultra: 63 frames a second (about 2.9 times real time), 3 to 4.5 s of engine time for a 7 to 11 s line, 16 to
18 s a take through the app with the word check. See Voice (Fish Audio Drama 3).
Built with Fish Audio.
2.7.3 (2026-10-15): the new name. The studio is now *Wasserman Slate AI Studio, powered by TensorFold, built
with integrated Fish Audio Drama 3*, and the repository moved to
drowzeys/keys-Wasserman-Slate-AI-Studio-powered-by-TensorFold-built-with-integrated-Fish-Audio-Drama3 (the old
address redirects). Fish Audio Drama 3, a 35B text-to-speech model with up to 16 voices per scene, voice cloning and
direction tags, is being ported to run locally on TensorFold: natively on CUDA for the DGX Spark and on MLX for the
Mac. The voice step is not in this release yet; it arrives when both ports pass their parity checks against
Fish's reference. No Fish Audio cloud API is used, and the pack ships no Drama 3 weights.
2.7.2 (2026-10-14): typing a custom size. The Width and Height boxes of a custom resolution, and the box of
a custom number of passes, took one digit at a time: every key redrew the form and the box under the cursor with it.
The value still changes with every key; the form is redrawn once the box is finished (Enter, Tab or a click elsewhere).
The seed was checked at the same time, on both machines: two seeds give two different clips on a Mac (Zig engine), on a
DGX Spark (TensorFold int8 engine) and on a Spark with a LoRA merged into that engine. The Create tab, each Production
segment and each Slate shot keep a seed of their own, and the Sharp Spec sets every segment or shot to 42.
2.7.1 (2026-10-14): a LoRA on a DGX Spark renders on TensorFold's int8 engine again.
- LoRA clips are merged into the engine (TensorFoldH3Blocks): the node takes the LoRA's patches for the block
projections off ComfyUI, merges them into the bfloat16 weights as ComfyUI does, and the engine quantizes them
(tf_h3_set_weight, engine1f7ecc75). The memory and the speed are the engine's own: 1376x768 at 124 frames
took 62.3 GB against 62.2 without a LoRA, and 864x480 at 124 frames 114 s against 140 s on ComfyUI's blocks.
- The memory guard takes LoRA clips up to 1376x768 at 243 frames, measured from below on a worker Spark (a route
of its own, int8-lora); the Sharp Spec size and 1344x768 take a LoRA again. A Spark whose engine is older
renders a LoRA on ComfyUI's bfloat16 blocks with the old limit (1280x736, 124 frames), and the app says which.
- Same seed, the engine's LoRA clip and ComfyUI's bfloat16 one show the same shot (LoRAs in the hub section).
Reference clips (Ref2VA), MiniMax H3's own transformer (--base h3) and the Turbo path keep ComfyUI's blocks.
2.7.0 (2026-10-13): the Sparks setting, one to eight DGX Sparks for a job.
- A Sparks tab: add a worker DGX Spark by the address you would give ssh, check it, update its Studio code and
start its app, stop it. Each row shows its version, memory guard, memory and disk, and what it renders.
- A Sparks chooser, 1 to 8, at the top of the Queue, in Create, on the Production board and on a Slate shot
(sparks: N in the API). The app uses as many as are up and able to do the job and says so ("5 of 8 available").
- Several clips go one per Spark, in parallel, and land in the head's Library and project as if rendered there,
with seed, settings and Spark on each take. One clip stays on one Spark; a long video stays on the head (each
piece opens on the last frame of the one before); a clip with a LoRA or reference pictures goes only to a worker
that has them and whose memory guard accepts it.
- Measured, the same eight clips (56 frames, 864x480, FastH3 8 passes) through the app: 263.2 s on one Spark,
129.8 s on two (2.03x), 97.5 s on three (2.70x), 69.0 s on four (3.81x), 65.0 s on five (4.05x). Five is little
better than four for eight clips: they go in two rounds either way.
... (README truncated for length)