mindview-t2i-turbo
A text-to-image model in one file of 1,208 MB that paints a 512 × 512 picture in one, two or four steps, in a web browser, on WebGPU, with no server: try it in this model's Space or on the mindview site, in a desktop browser with WebGPU. On a MacBook Air (M4) in Chrome a picture takes about 4 s in one step, 6 s in two and 15 s in four. It has 4.61 billion weights, and all but 165 million of them are −1, 0 or +1.
It is mindview-t2i with everything added for speed: three side branches trained on this ternary painter, for one, two and four steps, and a 2-step schedule whose first step sketches at a quarter of the size. Each branch is trained to paint like a full-precision teacher: EPFL's 1-step fine-tune of FLUX.2 [klein] 4B for one step, klein with a 2-step LoRA for two, and klein itself for four. It came out of mindview, an art installation that shows these models computing. Most of it is the work of others (see Sources and licenses).
| Mode | Steps | What runs | Time (M4 Air, Chrome) |
|---|---|---|---|
| Instant | 1 | the painter with the 1-step branch, the prompt's own text rows | about 4 s |
| Fast | 2 | a sketch at 256 × 256, then the picture at 512 × 512, with the 2-step branch | about 6 s |
| Best | 4 | the painter with the 4-step branch | about 15 s |
Times are for a first picture on a cool machine, from the prompt to the pixels. The Air has no fan and slows by about a third after minutes of painting.
The same prompts and seed in each mode, as painted in the browser:

Best is the most faithful to the prompt: its lettering is clean and its faces whole. Fast has the most detail but sometimes repeats things (the sign above says OPEN twice). Instant is a little softer.
What is in the file
| Part | What it does | Weights | Stored |
|---|---|---|---|
| reader | Ternary Bonsai 1.7B with its tokenizer, cut to its first 9 of 28 layers. It reads the prompt. | 764 M, ternary | 158.4 MB |
| cond | One linear map from the reader's states at layers 3, 6 and 9 to the painter's text stream (6,144 → 3,072), trained for this model. | 18.9 M, f16 | 35.3 MB |
| painter | The diffusion transformer of Bonsai Image 4B, which is FLUX.2 [klein] 4B with ternary weights. | 3,682 M, ternary | 761.3 MB |
| decoder | TAEF2, which turns the latent into pixels. | 1.3 M, f16 | 2.5 MB |
| 1-step branch | A side branch of rank 32 on each of the painter's 100 ternary matrices, trained on this painter to paint like epfl-vita/flux2-klein-1step-rdm (see One step). | 48.0 M, f16 | 82.7 MB |
| 2-step branch | A side branch of rank 32 on the same matrices, trained on this painter to paint like klein with radames/FLUX.2-klein-Sana-Sprint in two steps (see Two and four steps). | 48.0 M, f16 | 82.6 MB |
| 4-step branch | The same again, trained to paint like klein in four steps. | 48.0 M, f16 | 82.6 MB |
| schedules | Noise levels and the painter's modulation for 1, 2, 3 and 4 steps, and for 1 step with the 1-step branch; the branches' trained offsets are in the modulation for 1, 2 and 4 steps. | 2.1 MB |
The decoder also carries two colour probes (390 numbers) that show its 128 × 128 and 256 × 256 stages as pictures, for mindview's visuals; painting does not use them. That is about 2.1 bits per weight on average, all parts included. The reader, the map and the way they are joined are described on the mindview-t2i card; they are the same here.
One step
EPFL's RDM distils FLUX.2 [klein] 4B to a single step with a full fine-tune. Its change to klein carries over to the ternary transformer of Bonsai Image 4B without retraining, in two parts:
- The 100 big matrices changed by 0.17% on average. As a side branch, y = W x + B (A x), each change's best rank-4 approximation (an SVD) paints like the whole change, although rank 4 holds only about 30% of the change's energy.
- The time embedder and the modulation layers changed by 0.1 to 0.6%. The painter's modulation depends only on the step,
so it is precomputed with RDM's weights at σ = 1 (schedule
1r), and this part costs nothing at run time.
Carried over like that, it painted in 1 step but softly, with defects: a cat's face doubled, a fox as a ball of fur. RDM itself, on the full-precision klein, paints sharply from the same conditioning, so the gap is the ternary weights. The branch in this file is trained to close it:
- Teacher: RDM on klein, 1 step. Student: the ternary painter with a rank-32 branch on its 100 matrices, started from RDM's change, and offsets on the 1-step modulation. Both get the conditioning the browser gives (the reader's layers 3, 6 and 9 through the map), for 2,000 prompts, one noise each.
- Loss: LPIPS (VGG) between the two pictures, decoded by TAEF2 as the browser decodes them, plus a little mean squared error on the latents. Mean squared error alone makes it worse: it lowers the error by blurring, where the student cannot match the teacher's detail.
- 3,000 steps of 4 on one H100, about 25 minutes. On 12 prompts never trained on, the LPIPS distance to the teacher went from 0.454 to 0.381.
A second run, at rank 64 with three noises per prompt, did a little better by that measure but painted the same, so the file keeps rank 32. RDM also changed the image and text embedders and the output layer, by 0.08 to 0.3%; leaving those out changes nothing visible, so the file does not carry them.
Two steps, the first at a quarter of the size
The 2-step schedule goes from σ = 1 to 0.885 to 0: after the first step the picture is still 88% noise, so the first step only has to place things. Here it runs at 256 × 256 (256 patches instead of 1,024) and reads only the first 128 of the prompt's 256 text rows. The reader is causal, so those rows are exactly what a 128-row encoding would give. Its guess of the clean picture is upsampled to 512 × 512 in the latent space (bilinear, per channel), noised back to σ = 0.885 with fresh noise, and the second step paints at full size.
That takes about a third less time than two full steps, and on the test prompts the pictures are as good or better.
Two and four steps
The 2-step LoRA was trained on the full-precision klein and carried over to the ternary painter with some loss, and four steps of the ternary painter alone are close to klein but not the same. Both now have a branch trained on this painter, the way the 1-step branch is:
- Teachers: for two steps, klein with the Sana Sprint LoRA merged in, run exactly as Fast runs (the first step at 256 × 256 on the first 128 text rows, its guess enlarged and noised back to σ = 0.885, the second step at full size); for four steps, klein itself. Students: the ternary painter with a rank-32 branch on its 100 matrices and offsets on each step's modulation. The 2-step branch starts from the LoRA's best rank-8 approximation, the 4-step branch from nothing. At every step the student starts from the teacher's own noisy picture and learns the teacher's guess.
- Loss: as for one step, LPIPS between the guesses decoded by TAEF2, plus a little mean squared error.
- 2,000 prompts, 3,000 steps of 4 each on one H100, about 20 minutes each. On the 12 held-out prompts the LPIPS distance to the teacher went from 0.496 to 0.419 for two steps, and from 0.448 to 0.370 for four.
In the pictures, four steps gained the most: lettering that came out as "OPENI" now reads "OPEN", and a helmet that cut through a cat's face now sits around it. Two steps gained detail.
Running it
The file is read by the mindview browser runtime (WebGPU and WGSL, no server):
src/lib/runtime/packed.ts reads the file,
bonsai-llm.ts runs the reader and
painter.ts the rest
(setSteps('1r'), setSteps(2) with setNoise(…, low) and upsampleLatent, setSteps(4); each turns on its branch). The page at
neovand.github.io/mindview/paint loads it from this repository with range
requests, so it is never all in memory at once, and the browser keeps what it downloaded.
It is a GGUF file (v3), but its architecture is its own (mindview-t2i) and four of its tensor types are new, so
llama.cpp and other GGUF tools cannot run it as it is. The format is described on the
mindview-t2i card. The branches are stored as
<branch>.<matrix>.a and <branch>.<matrix>.bt, with the branch rdm for one step, lora for two and best for
four; mindview.rdm, mindview.lora and mindview.best give their ranks and sources.
Limits
- It paints only 512 × 512: the modulation is precomputed for these schedules.
- The map from the reader imitates the stock encoder closely but not exactly (cosine 0.959). It follows a prompt less well than Bonsai Image 4B with its own encoder, and it has had little testing beyond short English prompts.
- Instant is a little softer than Fast and Best, and Fast sometimes repeats things.
- It keeps the limits and biases of FLUX.2 [klein] and Bonsai Image. There is no safety filter.
Reproducing it
From the mindview repository, with the source models in static/models and
the Hugging Face cache:
python research/scripts/adapter_layers.py final 3 6 9 # the map (see mindview-t2i)
python research/scripts/rdm_delta.py # RDM minus klein: rank-256 SVDs of the 100 matrices
python research/scripts/distill_1step.py prepare # the map and the branch's start, for the training
modal run research/cloud/distill_modal.py --step upload # then --step fetch, targets, train, pull (one H100)
python research/scripts/distill_1step.py export 32 # the trained 1-step branch
RDM_STUDENT=research/data/distill/student_r32.pt python research/scripts/export_painter_schedules.py
# two and four steps (scripts/distill_steps.py), each with --mode fast and --mode best:
modal run research/cloud/distill_modal.py --script steps --step targets --mode fast --n 2000
modal run research/cloud/distill_modal.py --script steps --step train --mode fast --steps 3000 --rank 32 --lr 1e-4
modal run research/cloud/distill_modal.py --step pull --only fast_
python research/scripts/distill_steps.py export fast 32 # fast_trained_r32.safetensors, fast_offsets.pt
python research/scripts/pack_model.py --fused research/data/adapter/fused_final_layers_3_6_9.pt --float \
--lora research/data/distill/fast_trained_r32.safetensors --lora-rank 32 \
--fast-offsets research/data/distill/fast_offsets.pt \
--best research/data/distill/best_trained_r32.safetensors --best-rank 32 \
--best-offsets research/data/distill/best_offsets.pt \
--rdm research/data/distill/rdm_trained_r32.safetensors --rdm-rank 32
distill_1step.py and distill_steps.py also run on a Mac (MPS), about a hundred times slower. rdm_test.py, rdm_rank.py, progressive.py and
progressive_rows.py hold the experiments behind the other choices above.
Sources and licenses
- Ternary Bonsai 1.7B by PrismML, Apache 2.0. Layers
0–8 and the tokenizer of
Ternary-Bonsai-1.7B-Q2_0.gguf, with every ternary weight exact. - Bonsai Image 4B by PrismML, Apache 2.0. It is FLUX.2 [klein] 4B by Black Forest Labs, Apache 2.0, with its weights made ternary. The transformer is repacked with every ternary weight exact. Its context embedder is folded into the map.
- TAEF2 by Ollin Boer Bohan (madebyollin/taef2), MIT license. It is repacked unchanged.
- The 2-step branch starts from the LoRA by radames (radames/FLUX.2-klein-Sana-Sprint, Apache 2.0, distilled from FLUX.2 [klein] 4B): its best rank-8 approximation, widened to rank 32 and trained for mindview on the ternary painter, with klein and that LoRA as the teacher. It is released under Apache 2.0.
- The 4-step branch was trained for mindview on the ternary painter, with FLUX.2 [klein] 4B as the teacher. It is released under Apache 2.0.
- The 1-step branch comes from RDM by EPFL VITA (epfl-vita/flux2-klein-1step-rdm, Apache 2.0; paper, code): started from its change to FLUX.2 [klein] 4B's matrices and its time and modulation weights, then trained for mindview on the ternary painter with RDM as the teacher. It is released under Apache 2.0.
- The map was fitted for mindview on the models above and on the outputs of Qwen3-4B (Apache 2.0). It is released under Apache 2.0.