ブログ/developers·2026年9月24日·2分·執筆:eroqチーム
films APIで扱うCinema:脚本、絵コンテ、レンダリング、書き出し
Cinemaをコードから扱うための解説。/v1/filmsでのv2プロジェクトの構造、脚本を読むレンダリング、メディアの再署名、書き出しルートでのカットの保存と公開。
Cinemaのワークスペースが行う処理はすべて/v1/filmsを経由しており、スタジオもほかと同じく、その一クライアントにすぎません。このガイドは、フィルムを構築・自動化したい開発者向けです。ルートが中身を解釈せずに保持するプロジェクト形式、脚本を読み取るレンダリング呼び出し、メディアマップ、書き出しルート、そして各種上限を扱います。v1の基本については絵コンテのレンダリングガイドを読んでいる前提で、ここではv2で追加された内容を説明します。
プロジェクト
フィルムの行はtitle、cover_url、published_creation_id、そしてdataドキュメントを持ちます。dataはプロジェクト全体です。ルートはサイズ(400 KB)を検証し、読み込み時に正規化しますが、それ以外は送られたものをそのまま保存します。v2の形は次のとおりです。
{
"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 }
}
シーンのセリフはシーン自体に置かれます(dialogue:話者はchar:<id>または自由な名前、話し方、セリフ)。それ以外の脚本ブロックはすべてメモで、エンジンには一切届きません。ノーマライザーが代わりに強制してくれるルールは4つです。各シーンは脚本内にちょうど1つのsceneブロックを持つ(孤立したブロックは削除され、欠けているものは追加される)。シーンは脚本の順に並ぶ。初期の下書きにあるdialogueブロックは直前のシーンに取り込まれる(どのシーンよりも前に書かれたものはメモになる)。そしてoptions内のlibraryIdはすべて作品(creation)のIDである。つまり、メディアがプロジェクトに保存されることはなく、参照されるだけです。v1の下書き(lookと、prompt/shot/seconds/cast/takesを持つscenes)も読み込み時にこの形へ正規化されるので、古い統合もそのまま動き続けます。
上限:シーン24、シーンあたり30秒、シーンあたりの候補8、シーンあたりのセリフ30行、ブロック400、クリップ80、オーディオクリップ40、タイトル40、プロンプトまたはブロックあたり4,000文字。
作成、読み取り、更新
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}は、プロジェクトと並べて media マップを返します。プロジェクトが参照するすべてのテイク、クリップ、サウンドがcreation:<id>またはupload:<id>をキーとして並び、それぞれに新しい署名付きURL、コンテンツタイプ、長さ、サムネイルが付きます。ストレージは非公開なのでURLには有効期限があります。ファイルごとにキーを持たなくても、クライアントが有効なリンクを得られるのはこのマップのおかげです。一部だけを更新したいとき(署名付きURLが切れる前や、新しいファイルがビンに加わったとき)は、{ "keys": ["creation:…", "upload:…"] }(1〜300個)を付けてPOST /v1/films/mediaを呼ぶと、それらのキーについて同じ形で返ってきます。不明なキーや他人のキーは、単に結果に含まれません。
PATCHはdataを丸ごと置き換えます。読み取り、変更、書き込みの順で行ってください。部分的なマージはなく、古い書き込みが新しい書き込みを上書きしてしまうので、書き込みは直列化しましょう。
レンダリング
POST /v1/films/{id}/render
{ "store": false }
1回の呼び出しで、プロンプトを持つすべてのシーンが、ルックで指定したエンジン上で、テイクごとに1つの非同期動画ジョブとしてキューに入ります。パイプラインはPOST /v1/videos/generationsと同じで、それぞれ個別に課金されます。レスポンスは各シーンIDを、そのジョブIDか、キューに入れられなかった原因のエラーに対応づけます。シーンは個別に失敗し、課金済みの失敗は自動で返金されます。ジョブは通常のレンダリングと同じようにポーリングしてください。
v2でルートがシーンごとに組み立てるのは、シーンの柱(スラグライン)、ト書き、そして dialogueのセリフ(Mina (whispering) says: "…")です。話者のキャラクターシートとボイスも参照に加わります。スタジオが送るのと同じプロンプトです。ルックはaudioとseedも含めてすべてのシーンに適用されます。フォーマット、解像度、長さ、参照は、課金前にエンジンの上限に合わせて丸められます。エンジンにない機能を求めるシーンは、黙って機能を落とされるのではなく、拒否されます。
テイクが届いたら、そのlibraryIdとともにシーンのoptionsに書き込み、pickを設定します。スタジオではこれが自動で行われ、統合ではポーリングのあとに行います。連続ショット(look.chain)はクライアント側の挙動です。スタジオは前のテイクの最後のフレームを取得してアップロードし、最初の参照として渡します。APIで連続させたい場合は、シーンごとのPOST /v1/videos/generationsでreferences[0]を自分で送ってください。一括レンダリングのルートは、シーンを書かれたとおりにレンダリングします。
編集と書き出し
editドキュメントは純粋なデータです。{ "kind": "scene", "sceneId" }、creation、uploadを参照するクリップ(イン/アウトのトリム、トランジション、音量、フィット付き)、フェード付きの3トラックのオーディオクリップ、4種類のスタイルのタイトル、そしてフェードアウト。スタジオはこれをブラウザ上でMP4にレンダリングします。APIはサーバー側で編集をレンダリングしません。
APIが行うのは、結果を保存することです。
POST /v1/films/{id}/export?seconds=42.5&signature=<edit signature>
Content-Type: video/mp4
<raw MP4 bytes>
ボディはファイルそのもので、ストリーミングで送ります。書き出したファイルは動画の作品としてライブラリに入るので、ほかのクリップと同じように再生、ダウンロード、公開ができ、ライブラリのほかのファイルと同様にワークスペースのストレージ容量に計上されます。料金は無料です。signatureは書き出し時点の編集のハッシュです。フィルムがこれを記録し、その後に編集を変更すると、保存済みのカットは古いものになります。再書き出しは、以前のカットが一度も公開されておらず、編集内のどこでも使われていない場合に、それを置き換えます。
レート制限はアップロードと共通です。バケットがいっぱいの場合は、何も読み込む前に拒否されます。
公開
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 }
保存済みのカットがあるフィルムは、そのカットを唯一のセグメントとして公開します。カットがないフィルムは、選ばれたテイクを順番に公開します。どのセグメントも、ライブラリ内の動画でなければなりません。公開には審査があります(GET /v1/films/{id}のreviewはpendingから始まります)。DELETE /v1/films/{id}/publishで公開を取り下げられ、エンゲージメントは保持されます。
APIがしないこと
- 編集のレンダリング。コンポジターはスタジオにあり、APIは結果を保存します。
- 最後のフレームの取得。シーンごとに
references[0]を送って連続させます。 - ストレージの生のURLの提供。すべて署名付きで、
GET /v1/films/{id}またはPOST /v1/films/mediaを通じて渡されます。
よくある質問
プロジェクト形式はドキュメント化されていますか?
ルートはdataを、サイズ上限付きの中身を解釈しないJSONとして扱い、読み込み時に正規化します。上に示した形はスタジオが書き込むものです。フィールドは安定しており、追加はオプションです。
レンダリングルートは、すでにテイクがあるシーンにも課金しますか?
プロンプトを持つシーンは、テイクの有無にかかわらずすべてレンダリングされます。1つのシーンだけを再レンダリングするには、そのシーンについてPOST /v1/videos/generationsを呼び出し、結果をそのoptionsに書き込んでください。
自分で撮った映像をフィルムにアップロードできますか?
POST /v1/uploadsでアップロードし、編集から{ "kind": "upload", "id": … }として参照してください。メディアマップは、ほかのテイクと同じように署名付きURLを発行します。
レンダリングでstoreがオプションになっているのはなぜですか?
store: trueにすると、すべてのクリップがStoreの料金(10 MBあたり2クレジット)であなたのストレージに保存されます。デフォルトでは、無料のライブラリのコピーが保持されます。Cinemaのテイクは、どちらの場合もライブラリに残ります。
すべてのフィールドについてはfilmsリファレンスを、v1の手順については絵コンテガイドをご覧ください。
この記事で使ったモデルで作ってみましょう。無料の50クレジットで始めるか、全エンジンと料金をご覧ください。