v0.13.2 · 2026-10-15

Features and abilities

Every feature, how to ask for it on the command line, and how to ask for it from the served HTTP API (tt-model serve). This page is updated as each served feature lands.

01

Feature matrix

FeatureCLI (examples/generate.py)Served (tt-model serve)
Prompt, negative prompt, frames, steps, guidance, seed, temporal alpha--prompt … --temporal-alphasame names, num_inference_steps, num_frames
Style LoRAs (SD 1.x, kohya format), stackable--lora SOURCE[:FILE][@SCALE]lora (a name from the operator's catalog)
LCM fast sampling (4 steps)--lcm-loraautomatic for a catalog variant that includes the LCM-LoRA
Prompt travel (keyframe prompts)--prompt-scheduleprompt_schedule
Live previews while generating--preview-pathpreview, preview_every, GET /v1/videos/preview
Chaining (continuity across runs)--chain-from, --chain-save, --chain-alphachain_save, chain_from, chain_alpha (named chains)
Euler sampler (the CLI's Lightning)--lightningsampler: "euler"
MotionAdapter temporal attention (Phase 3)--motion-adapter, --motion-adapter-alpha, --motion-adapter-skipmotion_adapter, motion_adapter_alpha, motion_adapter_skip (operator enables it)
CPU and simulator modes--mode cpu|simNot served (CLI only)
One chip

The served model runs on one Blackhole chip. Requests are handled one at a time.

02

Style LoRAs

A LoRA is merged into the model's weights on the CPU before they are uploaded to the chip, so the device runs ordinary Stable Diffusion with different numbers in it. The merge takes under a second and nothing is added per frame: 2.3 s per frame warm, with or without a LoRA.

command line
$ python examples/generate.py --prompt "storybook anime illustration, a moonlit crypt" \
    --lora "neonforestmist/sd15-storybook-anime-lora:storybook_anime_lora.safetensors@0.85"

Stack LoRAs by repeating --lora; their deltas add. The file header is read before any model loads, and the run stops with a reason for an SDXL LoRA, a LoHa or LoKr file, a DoRA file, or a file without kohya lora_down / lora_up weights. The header's most common training tags are printed as trigger-word hints.

Checked on the device

scripts/lora_device_check.py compares a LoRA's effect on the chip with the CPU. The effect arrives for every LoRA tried (correlation 0.94 for pixel art, 0.69 for storybook anime at 0.85, 0.86 for the LCM-LoRA). A small effect is partly buried in bfloat16 noise. Details are in docs/LORA.md.

The same crypt prompt with no LoRA, pixel art, storybook anime and both stacked

Crypt, seed 666, top to bottom: no LoRA, pixel art, storybook anime at 0.85, both stacked.

A full clip: the suspension bridge at Iguazu Falls

The contact sheet shows three frames per clip. These are the complete 16-frame clips, a pair for each of two seeds, without a LoRA and with the pixel art LoRA. Prompt: the suspension bridge at iguazu falls, with Pixel Art, in front for the LoRA column. 25 steps, 512×512, guidance 7.5.

The suspension bridge at Iguazu Falls, seed 11, no LoRA
No LoRA, seed 11
The suspension bridge at Iguazu Falls, seed 11, pixel art LoRA
Pixel art, seed 11
The suspension bridge at Iguazu Falls, seed 33, no LoRA
No LoRA, seed 33
The suspension bridge at Iguazu Falls, seed 33, pixel art LoRA
Pixel art, seed 33

The bridge is clear in seed 11 in both columns. Seed 33 drew the falls without a clear bridge, with or without the LoRA. Motion is slight, as with every clip from the default path. Made on 2026-10-14 through the v0.13.1 container image on one chip; each GIF is 2.5–3.9 MB and is the server's output, which was not re-encoded.

03

LCM fast sampling

--lcm-lora merges latent-consistency/lcm-lora-sdv1-5 and samples with the LCM scheduler: 4 steps at guidance 1.5 instead of 25 steps at 7.5. It stacks with style LoRAs.

Run (8 frames, seed 666, one chip)DenoisePer frame
Pixel art, 20 steps, guidance 7.518.6 s2.3 s
Pixel art + LCM, 4 steps, guidance 1.59.2 s1.2 s
Pixel art + LCM, 8 steps11.3 s1.4 s
Served, warm: LCM variant, 4 steps / style variant, 25 steps4.2 s / 21.6 s0.5 s / 2.7 s
Pixel art at 20 steps, pixel art plus LCM at 4 and 8 steps, LCM only at 4 steps
Trade-offs

On the command line the speed-up is about 2x end to end, because VAE decode and the temporal blend do not shrink. Fewer steps also give less cross-frame blending: the first and last frames of a clip differed by 43.9 with LCM against 19.4 with 25 steps, so try 8 steps before using it for a loop. The grid lines in the LCM-only panel come from the prompt asking for "Pixel Art"; a neutral prompt gives a clean image.

04

Serving LoRAs

The operator defines a catalog of named variants in ANIMATEDIFF_LORAS. Each variant is a full model set kept on the chip, so a request picks one at no cost. Variants share one VAE. A request names a variant and never a repo id or a path.

tt-model serve has no option for the catalog. It forwards only HF_TOKEN from the host, so the catalog is part of the package. tt_model_package.yaml ships two serve profiles from one image: full (the default), with the pixel, pixel-fast and lcm catalog and the motion adapter, and plain, with neither.

server
$ tt-model serve episod/tt-animatediff-container-v5.1                    # full
$ tt-model serve episod/tt-animatediff-container-v5.1 --profile plain

A different catalog means a repackage, because the values are part of the published manifest. full downloads the LoRA files and the adapter at startup and keeps three more UNets on the chip.

request
$ curl -s localhost:8000/v1/videos/generations -H 'content-type: application/json' \
    -d '{"prompt": "a moonlit crypt", "lora": "pixel-fast", "num_frames": 8}'
  • GET /v1/models lists the names under loras. An unknown name is a 400 that lists the valid ones.
  • A variant that includes the LCM-LoRA samples with LCM and defaults to 4 steps and guidance 1.5 when the request leaves them out. Values you send are used as sent, up to 50 steps: more is a 400, because the LoRA was distilled on a 50-step schedule.
  • The published LCM-LoRA is recognised by its repo id. Mark a local copy with #lcm after the scale, for example "/data/loras/my-lcm.safetensors@0.8#lcm"; without it the variant samples with PNDM at 25 steps.
  • A bad catalog or incompatible file stops the server at startup, before it reports ready.
  • LoRA files come from the Hugging Face cache or the network at startup, so a container with no network access needs them cached first.
The same prompt and seed served with no LoRA, pixel art and storybook anime
05

Live previews

GET /v1/videos/preview reports the generation in flight: {"step": n, "total": N, "gif_b64": "…"|null, "running": bool, "request_id": str|null}. It never waits on the device, so it answers while a generation runs (about 140 ms measured). The step counter always runs. The 256×256 GIF is rendered only when the request sets "preview": true, because each render costs about 0.4 s: 8 frames at 20 steps took 13.5–13.9 s without previews and 17.8–20.2 s with them. "preview_every": n renders every nth step.

Reading it correctly

step is 1-based and total is the loop's real step count (a 20-step request reports 21). The last frame stays readable after a run ends, until the next request begins, so check running.

06

Chaining

A request can save its final latents under a name ("chain_save": "lh"). A later request that sets "chain_from": "lh" blends them into its starting noise at chain_alpha (default 0.6), so the new prompt inherits the old composition. The names belong to the server: it stores them in its own directory under a hash of the name, keeps the newest 32, and forgets them when it stops. An unknown chain_from is a 400.

A lighthouse source, then a meadow prompt with no chain and chained at 0.3, 0.6 and 0.9
Keep alpha low

At 0.6 and 0.9 the lighthouse's tower and cliff carry into the meadow prompt, and the prompt itself is mostly lost: no flowers or butterflies appear. The library advises 0.2 to 0.55. At 0.3 the effect is small.

07

Sampler

The plain model samples with PNDM. "sampler": "euler" uses an Euler schedule on the same weights (the CLI's --lightning; no distilled weights are involved). 4 frames at 25 steps took 7.7 s with Euler and 7.9 s with PNDM, and the pictures differ. An LCM variant always samples with LCM, so naming a sampler with one is a 400.

08

Motion adapter (Phase 3)

The MotionAdapter's temporal attention can be injected into the UNet blocks. The operator enables it with ANIMATEDIFF_MOTION_ADAPTER=default (or a repo id or path) in the package's serve.env or a serve profile, which loads the adapter at startup; GET /v1/models then reports "motion_adapter": true. Requests set "motion_adapter": true, with motion_adapter_alpha (0 to 1) and motion_adapter_skip (any of down0 down1 down2 mid up0 up1 up2). It works with the Euler sampler, prompt schedules, chaining and style LoRA variants, and not with an LCM variant.

Slow

With up1 and up2 skipped, 2 frames at 6 steps took 5.6 s on one chip. Without skipping it is far slower: about 52 s per frame at 25 steps measured earlier on a four-chip box, so an 8-frame request runs for minutes. Set client timeouts to match.

09

Request reference

POST /v1/videos/generations. The response is {"created": ts, "data": [{"b64_json": "<GIF>"}]}.

FieldDefaultNotes
prompt(required)Non-empty
negative_prompt""
num_frames161–64
num_inference_steps251–100. 4 for an LCM variant when omitted
guidance_scale7.50–20. 1.5 for an LCM variant when omitted
seed42
temporal_alpha0.350–1, cross-frame blend
height, width512Only 512 is accepted: the UNet is compiled at a fixed size
loranoneA catalog name; 400 if unknown
prompt_schedulenoneUp to 16 {"frame": n, "prompt": "…"}; each frame must be below num_frames
samplerpndmpndm or euler; 400 with an LCM variant
chain_save, chain_fromnoneNames (letters, digits, . _ -; up to 64 characters). Unknown chain_from is a 400
chain_alpha0.60–1; 0.2–0.55 keeps the prompt in charge
motion_adapterfalse400 unless the operator set ANIMATEDIFF_MOTION_ADAPTER; 400 with an LCM variant
motion_adapter_alpha, motion_adapter_skip1.0, []Only with motion_adapter: true
previewfalseRender preview GIFs for GET /v1/videos/preview
preview_everylibrary default1–100
request_idnoneYour name for the request (letters, digits, . _ -, up to 64). GET /v1/videos/preview echoes it, so a client sharing the server can ignore previews that belong to another request
response_formatb64_jsonOnly b64_json