FLUX.2 is one model family. Stable Diffusion is another, and the older of the two. SD 1.x and SD 2.x are available as a single all-in-one GGUF. There's no LLM encoder and no VAE to download alongside it.
That single-file layout is the trade. SD 2.1 in this format is much smaller on disk than FLUX.2-klein, so it loads faster on a fresh device and fits in less VRAM. The generation quality is lower than FLUX.2-klein at the same step count, but for short prompts and quick iteration it's the path of least resistance.
Stable Diffusion supports two sampling targets: epsilon (default) and v (the velocity, the change in noise). At high guidance, v is the cleaner choice with fewer artifacts. The modelConfig block setting v would look like so:
const modelId = await loadModel({
modelSrc: SD_V2_1_1B_Q8_0,
modelType: "sdcpp-generation",
modelConfig: { prediction: "v" },
});The generation call is the same diffusion({ modelId, prompt }) as the FLUX.2 lessons:
const result = diffusion({
modelId,
prompt: "a photo of a cat sitting on a windowsill",
});Once the awaited PNG is in hand, write the first one and log the count:
const outputs = await result.outputs;
const first = outputs[0];
if (!first) throw new Error("No image returned from diffusion");
fs.writeFileSync("../../apps/desktop/output/image-gen/cat.png", first);
console.log(`Generated ${outputs.length} image`);SD 2.1 was trained for v-prediction; epsilon would produce a noisier result on this model.
Note: SD 2.1 doesn't support the in-context
init_imagepath that FLUX.2 uses. For img2img with SD, setstrengthinstead. The next chapter covers that.
loadModel with modelType: "sdcpp-generation", modelSrc: SD_V2_1_1B_Q8_0, and modelConfig: { prediction: "v" }.diffusion({ modelId, prompt: "..." }) and await result.outputs.outputs[0] to a PNG file and console.log the image count.$ Run your code to see results
$