Blog/developers·24. Sept. 2026·6 Min.·vom eroq-Team
Films-API: Cinema-Projekte von Drehbuch und Storyboard bis Export
Cinema mit Drehbuch per API: v2-Projekte auf /v1/films, wie der Render das Drehbuch liest, neu signierte Medien, Export und Veröffentlichung des Schnitts.
Alles, was der Cinema-Workspace tut, läuft über /v1/films, und das Studio ist ein Client davon wie jeder andere. Dieser Leitfaden richtet sich an Entwickler, die Filme bauen oder automatisieren wollen: das Projektformat, das die Routen als opak behandeln, der Render-Aufruf, der das Drehbuch liest, die Media-Map, die Export-Route und die Obergrenzen. Er setzt voraus, dass du den Leitfaden zum Rendern von Storyboards mit den v1-Grundlagen gelesen hast; hier geht es darum, was v2 hinzufügt.
Das Projekt
Ein Film-Datensatz hat einen title, eine cover_url, eine published_creation_id und ein data-Dokument. data ist das gesamte Projekt: Die Routen prüfen seine Größe (400 KB), normalisieren es beim Lesen und speichern ansonsten, was du schickst. Die v2-Form:
{
"v": 2,
"look": {
"model": "seedance-2-0-mini",
"aspect": "16:9",
"resolution": "720p",
"audio": true,
"seed": 4242,
"filmType": "noir", "era": "1960s", "tempo": "tense",
"cameraType": "35mm film", "lens": "anamorphic", "aperture": "f/1.4",
"palette": "neon noir", "lighting": "practicals",
"chain": true,
"negative": ""
},
"scenes": [
{
"id": "s1", "heading": "EXT. JAZZ CLUB — NIGHT",
"prompt": "A detective in a rain-soaked trench coat waits under a flickering neon sign, slow push-in.",
"shot": "push-in", "seconds": 5, "cast": ["char:9f3…"], "takes": 1,
"dialogue": [{ "id": "l1", "speaker": "char:9f3…", "manner": "whispering", "line": "It's still lit." }],
"options": [{ "libraryId": "cr_…", "contentType": "video/mp4", "seconds": 5 }],
"pick": 0
}
],
"script": [
{ "id": "b1", "type": "h1", "html": "Rooftop night" },
{ "id": "b2", "type": "scene", "sceneId": "s1" },
{ "id": "b3", "type": "p", "html": "Rain machine on for this one." }
],
"edit": { "auto": true, "clips": [], "audio": [], "titles": [], "fadeOut": 0 }
}
Die Dialogzeilen einer Szene liegen in der Szene selbst (dialogue: Sprecher als char:<id> oder freier Name, Sprechweise, Zeile); jeder andere Drehbuchblock ist eine Notiz und erreicht nie eine Engine. Vier Regeln setzt der Normalizer durch, damit du es nicht tun musst: Jede Szene hat genau einen scene-Block im Drehbuch (verwaiste werden verworfen, fehlende angehängt), die Szenen folgen der Reihenfolge des Drehbuchs, dialogue-Blöcke aus einem frühen Entwurf werden in die Szene darüber eingefaltet (einer, der vor der ersten Szene steht, wird zur Notiz), und jede libraryId in options ist eine Creation-ID – Medien werden nie im Projekt gespeichert, sondern nur referenziert. Ein v1-Entwurf (look + scenes mit prompt/shot/seconds/cast/takes) wird beim Lesen in diese Form normalisiert, damit alte Integrationen weiter funktionieren.
Obergrenzen: 24 Szenen, 30 Sekunden pro Szene, 8 Optionen pro Szene, 30 Dialogzeilen pro Szene, 400 Blöcke, 80 Clips, 40 Audioclips, 40 Titel, 4.000 Zeichen pro Prompt oder Block.
Erstellen, lesen, aktualisieren
POST /v1/films
{ "title": "Rooftop night", "data": { … } }
GET /v1/films → cards: scenes, rendered, seconds, aspect, cover, preview
GET /v1/films/{id} → the row + data + media
PATCH /v1/films/{id} → title and/or data (whole document)
DELETE /v1/films/{id} → the draft; renders stay in the library
GET /v1/films/{id} liefert neben dem Projekt eine media-Map: jeden Take, jeden Clip und jeden Sound, auf den das Projekt verweist, mit dem Schlüssel creation:<id> oder upload:<id>, jeweils mit frisch signierter URL, Content-Type, Länge und Thumbnail. Dein Speicher ist privat, deshalb laufen URLs ab; über die Map bekommt ein Client funktionierende Links, ohne für jede Datei einen eigenen Schlüssel zu besitzen. Um einen Teil davon zu erneuern – bevor eine signierte URL abläuft oder wenn eine neue Datei in die Ablage kommt –, liefert POST /v1/films/media mit { "keys": ["creation:…", "upload:…"] } (1 bis 300) dieselbe Form für diese Schlüssel. Unbekannte oder fremde Schlüssel fehlen einfach.
PATCH ersetzt data vollständig. Lesen, ändern, schreiben; es gibt kein partielles Mergen, und ein veralteter Schreibvorgang überschreibt einen neueren, also serialisiere deine Schreibzugriffe.
Rendern
POST /v1/films/{id}/render
{ "store": false }
Ein einziger Aufruf stellt jede Szene mit Prompt in die Warteschlange, als einen asynchronen Video-Job pro Take, auf der Engine des Looks – dieselbe Pipeline wie POST /v1/videos/generations, jeder Job einzeln abgerechnet. Die Antwort ordnet jeder Szenen-ID ihre Job-IDs zu oder den Fehler, der das Einreihen verhindert hat; Szenen schlagen unabhängig voneinander fehl, und ein abgerechneter Fehlschlag wird automatisch erstattet. Poll die Jobs wie jeden anderen Render.
Was die Route in v2 pro Szene zusammensetzt: die Szenenüberschrift, die Handlung und die dialogue-Zeilen (Mina (whispering) says: "…"), wobei die Charakterbögen und Stimmen der Sprecher zu den Referenzen hinzukommen – derselbe Prompt, den auch das Studio sendet. Der Look gilt für jede Szene, einschließlich audio und seed. Die Grenzen der Engine beschneiden Format, Auflösung, Länge und Referenzen vor der Abrechnung; eine Szene, die eine Funktion verlangt, die der Engine fehlt, wird abgelehnt und nicht stillschweigend reduziert.
Wenn ein Take fertig ist, schreib ihn mit seiner libraryId in die options der Szene und setz pick; das Studio erledigt das für dich, eine Integration tut es nach dem Polling. Durchgehende Einstellungen (look.chain) sind ein Verhalten des Clients: Das Studio greift das letzte Frame des vorherigen Takes ab, lädt es hoch und übergibt es als erste Referenz. Über die API schickst du references[0] selbst mit einem POST /v1/videos/generations pro Szene, wenn du die Verkettung willst; die Sammel-Render-Route rendert die Szenen so, wie sie geschrieben sind.
Schnitt und Export
Das edit-Dokument besteht nur aus Daten: Clips, die auf { "kind": "scene", "sceneId" }, creation oder upload verweisen, mit In-/Out-Trims, Übergängen, Lautstärke und Einpassung; Audioclips auf drei Spuren mit Blenden; Titel in vier Stilen; eine Abblende am Ende. Das Studio rendert es im Browser zu einer MP4; die API rendert Schnitte nicht serverseitig.
Die API bewahrt dafür das Ergebnis auf:
POST /v1/films/{id}/export?seconds=42.5&signature=<edit signature>
Content-Type: video/mp4
<raw MP4 bytes>
Der Body ist die Datei selbst, gestreamt. Sie landet als Video-Creation in der Bibliothek – lässt sich also wie jeder Clip abspielen, herunterladen und veröffentlichen – und zählt wie jede Bibliotheksdatei zum Speicher des Workspace. Kostenlos. Die signature ist ein Hash des Schnitts zum Zeitpunkt des Exports; der Film speichert ihn, und eine spätere Änderung am Schnitt macht die gespeicherte Fassung veraltet. Ein erneuter Export ersetzt die vorherige Fassung, wenn diese nie veröffentlicht wurde und nichts im Schnitt sie verwendet.
Das Rate Limit teilt sich die Route mit den Uploads; ein voller Bucket lehnt ab, bevor überhaupt etwas gelesen wird.
Veröffentlichen
POST /v1/films/{id}/cover (multipart file, image ≤ 5 MB, free)
POST /v1/films/{id}/publish
{ "title": "Rooftop night", "segments": ["<the saved cut's URL>"], "durationSeconds": 42 }
Ein Film mit gespeicherter Fassung veröffentlicht diese als einziges Segment; ein Film ohne Fassung veröffentlicht seine ausgewählten Takes der Reihe nach. Jedes Segment muss ein Video in deiner Bibliothek sein. Veröffentlichungen durchlaufen eine Prüfung (review beginnt bei pending auf GET /v1/films/{id}); DELETE /v1/films/{id}/publish nimmt den Film wieder offline und behält das Engagement.
Was die API nicht macht
- Den Schnitt rendern. Der Compositor steckt im Studio; die API speichert das Ergebnis.
- Letzte Frames abgreifen. Verkette, indem du
references[0]pro Szene mitschickst. - Rohe Speicher-URLs ausliefern. Alles ist signiert, über
GET /v1/films/{id}oderPOST /v1/films/media.
Häufige Fragen
Ist das Projektformat dokumentiert?
Die Routen behandeln data als opakes JSON mit Größenlimit und normalisieren es beim Lesen. Die Form oben ist das, was das Studio schreibt; die Felder sind stabil, Ergänzungen sind optional.
Berechnet die Render-Route auch Szenen, die schon Takes haben?
Sie rendert jede Szene mit Prompt, auch solche mit Takes. Um eine einzelne Szene neu zu rendern, ruf POST /v1/videos/generations für diese Szene auf und schreib das Ergebnis in ihre options.
Kann ich eigenes Material in einen Film hochladen?
Lad es mit POST /v1/uploads hoch und verweise im Schnitt darauf als { "kind": "upload", "id": … }. Die Media-Map signiert es wie jeden Take.
Warum ist store eine Option beim Rendern?
store: true speichert jeden Clip zum Tarif des Store (2 Credits pro 10 MB) dauerhaft in deinem Speicher; standardmäßig bleibt es bei der kostenlosen Kopie in der Bibliothek. Die Takes von Cinema liegen so oder so in der Bibliothek.
Alle Felder findest du in der Films-Referenz, den Durchgang für v1 im Storyboard-Leitfaden.
Mach das mit den Modellen hinter diesem Artikel – starte mit 50 Gratis-Credits oder sieh dir alle Engines und ihre Preise an.