Image Generation: Text-to-Image
Atelico ships several on-device diffusion models for turning a text prompt into a PNG image — no external API, no network round-trip once the weights are cached.
model value | Family | Default steps | Default size | Notes |
|---|---|---|---|---|
pixart-sigma | PixArt-Sigma | 20 | 512×512 | Multi-step DPM-Solver; the steps slider is meaningful |
pixart-alpha | PixArt-Alpha | 1 | 512×512 | Distilled one-step (DMD) generation — fastest |
sana-sprint | Sana | 2 | 1024×1024 | SCM 2-step distilled |
sana-0.6b | Sana 0.6B | 20 | 1024×1024 | Flow matching |
sana-1.6b | Sana 1.6B | 20 | 1024×1024 | Flow matching, higher quality |
anima | Anima DiT | 20 | 512×512 | Supports the distilled rCM few-step sampler |
Prefix with the backend as usual: in-memory::pixart-sigma. Unknown ids return a
clear error listing the supported models.
The flow is the same for every model: a text prompt goes in, a base64-encoded PNG
comes out. Generation takes seconds, so every binding also exposes a
non-blocking async variant (*_async) and a step-by-step streaming variant.
Request fields
The request deserializes into an ImageGenerationRequest. The OpenAI-compatible
top-level fields:
| Field | Type | Default | Description |
|---|---|---|---|
model | string | required | Model id, e.g. in-memory::pixart-sigma |
prompt | string | required | Text description of the image |
n | u8 | 1 | Number of images to generate |
size | string | model-specific | Dimensions as "WxH" (e.g. "512x512", "1024x1024") |
seed | u64 | random | Random seed for reproducible generation |
negative_prompt | string | none | Terms to steer the model away from |
response_format | string | b64_json | b64_json or url |
output_format | string | png | png, jpeg, or webp |
stream | bool | false | If true, emit intermediate denoising steps |
Inference-pipeline knobs live under a nested pipeline_config object:
pipeline_config field | Type | Description |
|---|---|---|
num_inference_steps | u32 | Diffusion steps (higher = better quality, slower) |
guidance_scale | f32 | Classifier-free guidance (higher = more prompt adherence) |
vae_mode | string | "full" (high quality) or "tiny" (fast, softer) |
adapter_weight | f32 | LoRA adapter strength, 0.0–1.0 (if an adapter is loaded) |
use_chi | bool | Sana-only Complex Human Instruction prompt enhancement (default true) |
sampling_mode | string | Anima-only: "base" (default) or "rcm" for the distilled few-step sampler |
nfe | u32 | Anima rCM function evaluations — one of {1, 2, 4} |
LoRA suffixes work here too: in-memory::pixart-sigma::chibi-style loads the
pixart-sigma model with the chibi-style adapter. See
LoRA Adapters.
Response
The response is an ImageGenerationResponse. Each entry in data carries the
generated image as a base64-encoded PNG in b64_json:
{
"created": 1234567890,
"data": [
{"b64_json": "iVBORw0KGgo..."}
],
"output_format": "png",
"size": "512x512"
}
Streaming progress
Pass "stream": true to receive one intermediate ImageGenerationResponse per
denoising step — useful for showing a live preview that sharpens as the image
resolves. The final event carries the completed image. In the native SDKs this is
exposed through the same streaming primitive used elsewhere (Rust StreamHandle,
FFI poll loop, etc.).
SDK usage (in-process)
Rust SDK
use atelico_sdk::{Engine, ImageGenerationRequest};
let engine = Engine::new()?;
let request: ImageGenerationRequest = serde_json::from_value(serde_json::json!({
"model": "in-memory::pixart-sigma",
"prompt": "a cat sitting on a roof at sunset, watercolor",
"size": "512x512",
"seed": 42,
"pipeline_config": { "num_inference_steps": 20 }
}))?;
// Blocking — returns once the image is fully generated.
let response = engine.images().generate_sync(request)?;
let b64 = response.data[0].b64_json.as_deref().unwrap();
let png_bytes = base64::engine::general_purpose::STANDARD.decode(b64)?;
std::fs::write("cat.png", &png_bytes)?;
Generation is seconds-long, so prefer the non-blocking variant in a game loop:
engine.images().generate_async(request) returns a [StreamHandle] you can drive
via poll() (frame integration), next() (async), or next_blocking() (sync).
generate_stream(request).await yields the per-step previews.
Python
import base64, json
from atelico import Engine
engine = Engine()
resp = json.loads(engine.image_generate(json.dumps({
"model": "in-memory::pixart-sigma",
"prompt": "a cat sitting on a roof at sunset, watercolor",
"size": "512x512",
"seed": 42,
"pipeline_config": {"num_inference_steps": 20},
})))
png = base64.b64decode(resp["data"][0]["b64_json"])
open("cat.png", "wb").write(png)
# Non-blocking — returns a JsonResultStream you poll for the final response.
handle = engine.image_generate_async(json.dumps({
"model": "in-memory::pixart-alpha",
"prompt": "a fantasy castle on a cliff",
}))
C / FFI
// Blocking image generation
const char* request =
"{\"model\":\"in-memory::pixart-sigma\","
"\"prompt\":\"a cat sitting on a roof at sunset\","
"\"size\":\"512x512\",\"seed\":42,"
"\"pipeline_config\":{\"num_inference_steps\":20}}";
const char* response_json = NULL;
int rc = atelico_image_generate(engine, request, &response_json);
// response_json: {"created":..,"data":[{"b64_json":"iVBORw0KGgo..."}],
// "output_format":"png","size":"512x512"}
// base64-decode data[0].b64_json to recover the PNG bytes.
For non-blocking generation, atelico_image_generate_async takes the same request
JSON and returns a stream handle; drive it with the shared
atelico_stream_poll / atelico_stream_destroy loop (see the
C FFI getting started guide). The output pointer
is owned by the FFI layer's thread-local return buffer — copy it before the next
API call on the same thread.
Demo
demos/image-gen is a desktop app (also iOS-buildable) that exercises the full
path: pick a model (pixart-sigma, pixart-alpha, or anima), type a prompt,
adjust steps/seed, and view the result. Select the model via the
ATELICO_DEMO_MODEL env var (anima | pixart-sigma | pixart-alpha). It is
the recommended starting point before wiring image generation into a game engine.
See also
- Background Removal — cut out a subject into an RGBA PNG
- LoRA Adapters — style adapters for the diffusion models
- Models — full supported-model catalogue