A sprite plus a motion prompt in, an animated spritesheet and GIF out. Runs asynchronously: submit, get a job id, poll until it lands (typically 60 to 120 seconds).
| Field | Type | Notes |
|---|---|---|
| image_b64 | string, required | The sprite to animate. Max 256x256, min 8x8, aspect ratio between 1:2 and 2:1. Transparent PNG works best |
| prompt | string, required | The motion, e.g. "walking cycle, side view" or "gentle idle bounce". Max 2000 chars |
| frames | int | 2 to 16, default 8. Rounded up to an even number |
Returns 202:
{"job_id": "e17b…", "status": "queued", "cost": 20, "credits_remaining": 346}
Poll every few seconds. Statuses: queued → processing (with progress) → succeeded or failed. A failed job refunds the 20 credits automatically and the response says "refunded": true.
On success:
{
"job_id": "e17b…",
"status": "succeeded",
"sheet_b64": "…", # horizontal spritesheet PNG, transparent
"gif_b64": "…", # animated GIF with transparency
"frame_count": 8,
"frame_w": 96, "frame_h": 96,
"fps": 8,
"id": "f28a…" # history row id (also viewable in the app)
}
import base64, time, requests
KEY = {"Authorization": "Bearer sl_live_YOUR_KEY"}
BASE = "https://spritelab.dev/api/v1"
sprite = base64.b64encode(open("slime_64.png", "rb").read()).decode()
r = requests.post(f"{BASE}/animate", headers=KEY, json={
"image_b64": sprite,
"prompt": "gentle idle bounce with squash and stretch",
"frames": 8,
})
r.raise_for_status()
job_id = r.json()["job_id"]
while True:
time.sleep(4)
j = requests.get(f"{BASE}/jobs/{job_id}", headers=KEY).json()
print(j["status"], j.get("progress", ""))
if j["status"] in ("succeeded", "failed"):
break
if j["status"] == "succeeded":
open("slime_sheet.png", "wb").write(base64.b64decode(j["sheet_b64"]))
open("slime.gif", "wb").write(base64.b64decode(j["gif_b64"]))
else:
print("failed:", j.get("error"), "| refunded:", j.get("refunded"))
frame_w intervals.