API DOCS OPEN APP
← API OVERVIEW

UI Kits

A UI mockup or a description in, a complete game UI kit out: matching panels, frames, buttons with their states, bars, slots and icons, each sliced, named and given 9-slice borders, packaged with a Godot theme and a Unity package. Runs asynchronously, typically 45 to 90 seconds.

Early access: UI kits are available to Dragonlord accounts. Other keys get 403 not_entitled and are not charged.

POST /ui-kit

POST /api/v1/ui-kit concept 2 CR + 5 CR per sheet (Mythic 6 + 10)

Send either a mockup or a description. A mockup skips the concept step and its charge, and is the most faithful way to get the kit you have in mind (a screenshot, a paintover, or a mockup from another image tool all work).

FieldTypeNotes
image_b64stringUI mockup or screenshot to rebuild as a kit. Skips the concept charge
promptstringThe screen to design, e.g. "inventory for a cozy farming game". Required without a mockup (or send style)
stylestringThe look, e.g. "warm walnut wood frames, cream parchment panels, moss green accents". Defaults to the prompt
screenstringmain menu, HUD, pause, settings, inventory, dialogue, shop, quest log, character select, map, game over or custom
gamestringOne line about your game. Without it, concepts drift toward generic fantasy
specificstringExtra direction; it wins over everything else
scopestringOnly build part of the screen, e.g. "only the buttons"
qualitystringepic (default) or mythic (richer materials)
max_sheetsint1 to 3, default 2. The cost cap: busy screens split across sheets so every piece stays large. You are charged only for sheets that are planned and succeed
statesboolAdd hover, pressed and disabled for every button, tab and slot. Default false (only what the mockup shows)
pixelboolConvert the whole kit to pixel art with one shared palette. Default false (HD)
pixel_sizeint2 to 12, default 3. Source pixels per art pixel when pixel is on; smaller keeps more detail
coloursint8 to 64, default 24. Kit palette size when pixel is on
namestringKit name, shown in the app

The worst case (concept plus max_sheets sheets) is reserved upfront. Sheets the plan doesn't need, sheets that fail, and failed jobs are refunded to the credits that paid. Returns 202:

{"kit_id": "9f56…", "status": "queued", "credits_reserved": 12, "credits_remaining": 488}

GET /ui-kit/{kit_id}

GET /api/v1/ui-kit/{kit_id} FREE

Poll every 5 seconds. Statuses: queued → running (with stage: concept, planning, sheets, slicing, pixel, naming) → succeeded or failed. A job interrupted by a restart on our side fails and refunds on your next poll.

On success:

{
  "kit_id": "9f56…",
  "status": "succeeded",
  "name": "Seed Shop",
  "pixel": false,
  "sheets": 2,
  "credits_charged": 12, "refunded": 0,
  "pieces": [
    {"name": "buy_button_hover", "family": "buy_button", "kind": "button", "state": "hover",
     "sheet": 0, "x": 412, "y": 610, "width": 238, "height": 74,
     "nine_slice": false, "borders": {"l": 22, "t": 18, "r": 22, "b": 18}, "middle": "stretch"},
    …
  ],
  "download_url": "https://spritelab.dev/api/v1/ui-kit/9f56…/download"
}

GET /ui-kit/{kit_id}/download

GET /api/v1/ui-kit/{kit_id}/download FREE

The same zip the app exports: png/ (every piece at the export scale) and png_native/ (1x), a packed atlas with TexturePacker-style JSON carrying the 9-slice borders, a Godot 4 StyleBoxTexture per 9-slice piece plus a Theme, a Unity .unitypackage with sprite borders set, and the concept as a layout reference. Send the same Authorization header.

Full example

import base64, time, requests

KEY = {"Authorization": "Bearer sl_live_YOUR_KEY"}
BASE = "https://spritelab.dev/api/v1"

mockup = base64.b64encode(open("shop_mockup.png", "rb").read()).decode()
r = requests.post(f"{BASE}/ui-kit", headers=KEY, json={
    "image_b64": mockup,
    "screen": "shop",
    "game": "cozy farming sim",
    "max_sheets": 2,
})
r.raise_for_status()
kit_id = r.json()["kit_id"]

while True:
    time.sleep(5)
    k = requests.get(f"{BASE}/ui-kit/{kit_id}", headers=KEY).json()
    print(k["status"], k.get("stage", ""))
    if k["status"] in ("succeeded", "failed"):
        break

if k["status"] == "succeeded":
    for p in k["pieces"]:
        print(p["name"], p["kind"], p["state"], "9-slice" if p["nine_slice"] else "fixed")
    open("ui_kit.zip", "wb").write(requests.get(k["download_url"], headers=KEY).content)
else:
    print("failed:", k.get("error"), "| refunded:", k.get("refunded"))

Notes