Skip to main content
Pre-create characters and scenes to cut render latency by ~3x. Assets are stored and reusable across unlimited renders.
Character preprocessing costs 1 credit. Scene creation is free. Rendered video costs 1 credit/second.

Prerequisites

  • A Viggle API key (get one here)
  • A reference image (PNG or JPG)
  • A driving video (MP4)

Workflow

Create a character

Upload a reference image to extract a reusable character embedding. Free — ~5s to process.
import requests, time
API_KEY, BASE = "YOUR_API_KEY", "https://apis.viggle.ai"
headers = {"Authorization": f"Bearer {API_KEY}"}

resp = requests.post(f"{BASE}/api/characters/preprocess", headers=headers,
    files={"image": open("character.png", "rb")},
    data={"name": "My Character"})
character = resp.json()
character_id = character["character_id"]
Poll until ready:
while True:
    status = requests.get(f"{BASE}/api/characters/{character_id}", headers=headers).json()
    if status["status"] == "ready": break
    elif status["status"] == "failed": raise Exception(status.get("error_message"))
    time.sleep(5)

Create a scene

Upload a driving video to extract motion data. Free — ~20s to process.
No driving video? Import a template from viggle.ai instead.
resp = requests.post(f"{BASE}/api/scenes/preprocess", headers=headers,
    files={"video": open("dance.mp4", "rb")},
    data={"name": "Dance Sequence"})
scene = resp.json()
scene_id = scene["scene_id"]
Poll until ready:
while True:
    status = requests.get(f"{BASE}/api/scenes/{scene_id}", headers=headers).json()
    if status["status"] == "ready": break
    elif status["status"] == "failed": raise Exception(status.get("error_message"))
    time.sleep(5)

Render

Combine character + scene to generate video.
job = requests.post(f"{BASE}/api/render", headers=headers, data={
    "character_id": character_id,
    "scene_id": scene_id,
}).json()
print(f"Job: {job['job_id']}")

Poll and download

Poll every 3-5 seconds until complete, then use cdn_url to download the final video.
while True:
    status = requests.get(f"{BASE}/api/render/{job['job_id']}").json()
    if status["status"] == "complete":
        cdn_url = status["cdn_url"]
        break
    elif status["status"] == "failed": raise Exception(status.get("error_message"))
    time.sleep(3)

video = requests.get(cdn_url)
open("output.mp4", "wb").write(video.content)

Reusing assets

job2 = requests.post(f"{BASE}/api/render", headers=headers, data={
    "character_id": character_id,
    "scene_id": another_scene_id,
}).json()
job3 = requests.post(f"{BASE}/api/render", headers=headers, data={
    "character_id": another_character_id,
    "scene_id": scene_id,
}).json()
characters = requests.get(f"{BASE}/api/characters", headers=headers).json()
scenes = requests.get(f"{BASE}/api/scenes", headers=headers).json()

What’s next?

On-Demand Rendering

Render without preprocessing — one API call

Import Templates

Use pre-made templates from viggle.ai

Render Options

Background mode, fast mode, and more