# How to Use Claude Opus 5.5 with Seedance 2.5 to Make a Short Film

By SeedRouter · Published 2026-09-30 · Updated 2026-09-30

To make a short film with Claude Opus 5.5 and Seedance 2.5, let Opus act as the director and let the other models do the drawing and filming. You give Opus one story idea; it writes a fixed character description, a character sheet prompt and one video prompt per shot. GPT Image 2.5 turns those prompts into a character sheet and start frames. Seedance 2.5 renders each shot, with dialogue and sound, using those images as references. You then join the shots into one file. All three models answer on SeedRouter with the same API key. Every request below follows the SeedRouter API references, checked on September 30, 2026.

## How does the Claude Opus 5.5 and Seedance 2.5 workflow work?

The idea comes from a workflow a creator shared on r/Seedance\_AI in September 2026 ([the original post](https://www.reddit.com/r/Seedance_AI/comments/1wop0ju/)): "I didn't write a single prompt manually. I gave Opus 5.5 one core concept plus a few reference screenshots for the style I wanted." Opus wrote the prompts for the character sheet, start frames, camera moves, dialogue timing and sound; GPT Image 2.5 drew the character sheet and start frame; Seedance 2.5 rendered the shots.

Each model does one job:

| Step      | Model                | Input                                                                | Output                                                                                    |
| --------- | -------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| 1. Plan   | Claude Opus 5.5      | Story idea, optional style images                                    | Character description, sheet prompt, one start-frame prompt and one video prompt per shot |
| 2. Design | GPT Image 2.5        | Sheet prompt, then start-frame prompts with the sheet as a reference | Character sheet and start frames, as image URLs                                           |
| 3. Film   | Seedance 2.5         | Video prompt plus the sheet and start frame as reference images      | One video per shot, with sound                                                            |
| 4. Edit   | ffmpeg or any editor | The shot files                                                       | The finished film                                                                         |

The steps connect through URLs. GPT Image 2.5 returns images hosted on SeedRouter's storage, and Seedance 2.5 takes reference images as public URLs, so the output of step 2 goes straight into step 3 without downloading or uploading anything.

## What do you need before you start?

* **A SeedRouter API key** in your environment:

```bash
export SEEDROUTER_API_KEY="your-key"
```

* **Python 3** with `requests` and the Anthropic SDK: `pip install requests anthropic`.
* **ffmpeg** to join the shots at the end.
* **Credits.** Every call is a paid request. Failed tasks are not charged, and new accounts start with a small free balance.

All the Python snippets below share these two lines:

```python
import os
import requests

HEADERS = {"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"}
```

## Step 1: How do you get Claude Opus 5.5 to plan the shots?

Give Opus a system prompt that explains how Seedance 2.5 reads a prompt, and ask for the plan as JSON so your script can use it. The rules in this system prompt come from ByteDance's Seedance prompt guides, summarized in the [Seedance 2.5 prompt guide](https://seedrouter.ai/blog/seedance-2-5-prompt-guide): subject and action first, one camera move per shot, time ranges for longer shots, reference files named by number.

```python
import json
import anthropic

client = anthropic.Anthropic(
    api_key=os.environ["SEEDROUTER_API_KEY"],
    base_url="https://api.seedrouter.ai",
)

DIRECTOR = """You are the director of a short film made with AI models.
Return only JSON, no other text, in this shape:
{"character": "...", "sheet_prompt": "...",
 "shots": [{"duration": 5, "frame_prompt": "...", "video_prompt": "..."}]}

character: one fixed paragraph describing the main character's face, hair,
build and clothes. Repeat it word for word inside every other prompt.

sheet_prompt: an image prompt for one character reference sheet: a front,
three-quarter, profile and back view, plus four facial expressions, on a plain
light background, with no text other than small panel labels.

shots: 3 to 5 shots, each 4 to 15 seconds.
frame_prompt: an image prompt for the first frame of the shot.
video_prompt: a video prompt for Seedance 2.5. Write it in this order: subject
and action, scene, visual style, camera, audio. Image 1 is the character sheet
and Image 2 is the start frame of the shot; refer to them by those names.
Use one camera move per shot. Say who is holding the camera and how they move.
For shots longer than 5 seconds, split the action into time ranges such as
0-3s. Put dialogue in quotes as: Character's line (emotion): content.
Describe the ambient sound. Do not ask for subtitles or on-screen text.

The character must not look like a real, identifiable person. Use a stylized
look, such as a 3D animated or illustrated character."""

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=16000,
    system=DIRECTOR,
    messages=[{
        "role": "user",
        "content": "A lighthouse keeper finds a lost robot on the rocks during a storm and teaches it to wave at passing ships.",
    }],
)
text = "".join(block.text for block in message.content if block.type == "text")
plan = json.loads(text)
```

A few details matter here:

* **`max_tokens` includes thinking.** Opus 5.5 always uses adaptive thinking, and the [Opus 5.5 API reference](https://seedrouter.ai/docs/claude-opus-5-5) counts thinking tokens against `max_tokens`. Leave room for it, or the JSON can be cut off.
* **Leave out `temperature`, `top_p` and `top_k`, and do not prefill an assistant turn.** Opus 5.5 returns a 400 error for sampling values other than the defaults and for a prefilled reply. To steer how hard it thinks, set `output_config.effort` instead.
* **"Who is holding the camera" is the tip from the original post.** Its author says that telling Opus "my friend is filming from the back seat" made it write micro camera shake, late reframing and autofocus hunting, and that "that single contextual detail is what removes the 'AI look.'"
* **Style references are optional.** Opus reads images, so you can add screenshots of the look you want as `image` blocks with a URL source in the user turn.

If `json.loads` fails, print `text` and ask Opus again. Reading the plan before you render anything is also the cheapest place to fix the story: a change here costs one text request, and a change after rendering costs video.

## Step 2: How do you make the character sheet and start frames with GPT Image 2.5?

Send `plan["sheet_prompt"]` to GPT Image 2.5 first. Then send each shot's `frame_prompt` with the sheet as a reference image, so every start frame shows the same character. Image tasks are submitted to `/v1/images/generations` and read from `/v1/tasks/{id}`:

```python
import time

def image(prompt, size, refs=()):
    body = {"model": "gpt-image-2.5-flare", "prompt": prompt, "size": size, "quality": "high"}
    if refs:
        body["images"] = [{"image_url": url} for url in refs]
    task_id = requests.post(
        "https://api.seedrouter.ai/v1/images/generations",
        headers=HEADERS, json=body, timeout=60,
    ).json()["id"]
    while True:
        task = requests.get(
            f"https://api.seedrouter.ai/v1/tasks/{task_id}", headers=HEADERS, timeout=30,
        ).json()
        if task["status"] == "completed":
            return task["output"]["data"][0]["url"]
        if task["status"] == "failed":
            raise RuntimeError(task["error"]["message"])
        time.sleep(3)

sheet = image(plan["sheet_prompt"], "1536x1024")
frames = [image(shot["frame_prompt"], "1792x1008", [sheet]) for shot in plan["shots"]]
```

Why these settings:

* **`1792x1008` is 16:9.** GPT Image 2.5 takes `size` as `WIDTHxHEIGHT` with both edges a multiple of 16, so a 16:9 frame has to be spelled out; `16:9` is not a valid `size`. Match it to the `ratio` you will ask Seedance for.
* **Flare is enough for most sheets.** Sunburst is the tier for tighter control across edits and is slower; [GPT Image 2.5 Flare vs Sunburst](https://seedrouter.ai/blog/gpt-image-2-5-flare-vs-sunburst) covers when it is worth it.
* **Draft at a lower `quality`.** While you are still changing the character, `low` or `medium` renders faster. Switch to `high` for the images you will film with.

The functions above poll without a deadline to stay short. In your own code, add a time limit and keep the task ID, so an interrupted run can check the same task again instead of paying for a new one.

## Step 3: How do you render each shot with Seedance 2.5?

Send each `video_prompt` to Seedance 2.5 with two reference images: the character sheet as Image 1 and the shot's start frame as Image 2, in that order, because Seedance numbers reference files by the order you attach them. Video tasks use their own endpoint, `/v1/contents/generations/tasks`, and finish with `status: "succeeded"`:

```python
def shot(prompt, refs, duration):
    content = [{"type": "text", "text": prompt}]
    for url in refs:
        content.append({"type": "image_url", "image_url": {"url": url}, "role": "reference_image"})
    task_id = requests.post(
        "https://api.seedrouter.ai/v1/contents/generations/tasks",
        headers=HEADERS,
        json={
            "model": "dreamina-seedance-2-5",
            "content": content,
            "resolution": "480p",
            "ratio": "16:9",
            "duration": duration,
            "generate_audio": True,
        },
        timeout=60,
    ).json()["id"]
    while True:
        task = requests.get(
            f"https://api.seedrouter.ai/v1/contents/generations/tasks/{task_id}",
            headers=HEADERS, timeout=30,
        ).json()
        if task["status"] == "succeeded":
            return task["content"]["video_url"]
        if task["status"] in ("failed", "expired"):
            raise RuntimeError(task["error"]["message"])
        time.sleep(15)

videos = [shot(s["video_prompt"], [sheet, frame], s["duration"]) for s, frame in zip(plan["shots"], frames)]
```

The request choices:

* **Reference images, not a first frame.** Seedance 2.5 can also lock a shot to an exact first frame (`role: "first_frame"`), but the [Seedance 2.5 API reference](https://seedrouter.ai/docs/seedance-2-5) says first-frame modes "cannot be combined with reference items", so you would lose the character sheet. With both as `reference_image`, the prompt tells Seedance that Image 2 is the start frame. The opening follows it closely, but not pixel for pixel.
* **`480p` for drafts.** Render every shot at 480p first, fix the prompts that did not work, then render the keepers at `720p` or `1080p` with the same prompt.
* **`generate_audio: true`** gives you dialogue, ambient sound and effects from the prompt, generated together with the picture.
* **A fixed `ratio`.** Every shot at the same ratio and resolution lets ffmpeg join the files without re-encoding.

A shot can run from 4 to 30 seconds, and a single task can contain several cuts if the prompt gives each cut a time range. The creator's second scene, for example, packed six shots cut on drum hits into 10 seconds.

## How do you keep the same character in every shot?

Consistency comes from repetition, in the prompt and in the references:

* **Repeat the same description.** The `character` paragraph from step 1 goes word for word into every image and video prompt. Two different descriptions of the same person is one of the ways the model drifts or duplicates a character.
* **Send the same sheet to every shot.** The sheet is always Image 1. Seedance 2.5 accepts multi-view sheets; the older Seedance 2.0 can read a multi-angle sheet as several people, and the [prompt guide](https://seedrouter.ai/blog/seedance-2-5-prompt-guide) suggests one face close-up and one full-body image per character for it instead.
* **Refer to the character the same way every time**, for example "the lighthouse keeper from Image 1", and do not rely on a name written inside the picture.
* **Keep one voice across shots.** Seedance 2.5 takes up to 10 audio references (WAV or MP3, 2 to 30 seconds). Attach the same voice clip to each shot and bind it in the text, as in ByteDance's example: "Image 1 depicts the protagonist John and uses the voice timbre from Audio 1."

For two shots that must join without a visible jump, there is a second option: set `"return_last_frame": true` on the first shot, and send the returned `content.last_frame_url` as the next shot's `first_frame`. That locks the join, but that next shot cannot use the character sheet, so use it for continuous action within one scene rather than for every cut.

## Can you use a photo of a real person as the character?

No. Seedance 2.5 does not accept reference images or videos that contain real human faces, and a task with one fails without being charged. [Seedance's real person error](https://seedrouter.ai/blog/seedance-real-person-error) explains ByteDance's rule and the options ByteDance offers on its own platform.

This also affects realistic AI-generated characters. The original post filmed a photorealistic woman, but ByteDance's documentation does not say how its face check treats realistic faces drawn by another model. A stylized character, such as the 3D animated or illustrated look the system prompt above asks for, keeps the workflow clear of that question. If you want a photorealistic look, draft one short shot at 480p first before you plan a whole film around it.

## How do you join the shots into one film?

Download the videos in order, list them in a text file and join them with ffmpeg:

```python
names = []
for index, url in enumerate(videos):
    name = f"shot-{index + 1}.mp4"
    with open(name, "wb") as file:
        file.write(requests.get(url, timeout=300).content)
    names.append(name)
with open("shots.txt", "w") as file:
    file.writelines(f"file '{name}'\n" for name in names)
```

```bash
ffmpeg -f concat -safe 0 -i shots.txt -c copy film.mp4
```

`-c copy` joins the files without re-encoding, which works because every shot has the same resolution, ratio and format. If you mixed settings, drop `-c copy` and let ffmpeg re-encode. The video URLs are hosted on SeedRouter's storage, so download the files you want to keep.

## How much does a Seedance 2.5 short film cost?

Each model bills in its own unit, and current rates are on each model page:

* **Claude Opus 5.5** bills input and output tokens, thinking included. Planning a film is one or a few requests. [Rates](https://seedrouter.ai/models/claude-opus-5-5#pricing).
* **GPT Image 2.5** Flare and Sunburst bill a flat price per delivered image. One sheet plus one frame per shot is four to six images for a short film. [Rates](https://seedrouter.ai/models/gpt-image-2-5#pricing).
* **Seedance 2.5** bills video tokens: output seconds × width × height × 24 ÷ 1024. One second of 16:9 video is 9,607.5 tokens at 480p, 21,600 at 720p and 48,600 at 1080p, and 1080p has its own rate. [Rates](https://seedrouter.ai/models/seedance-2-5#pricing).

Most of the cost is the video. Drafting at 480p uses under half the tokens of 720p, so fixing prompts at 480p and rendering only the final version at a higher resolution is the biggest saving. [Seedance API pricing](https://seedrouter.ai/blog/seedance-api-pricing) works through more examples.

## Frequently asked questions

### Can Claude Opus 5.5 make the video by itself?

No. Opus 5.5 is a text model: it can read images, but it does not generate images or video. In this workflow it writes the prompts, and GPT Image 2.5 and Seedance 2.5 produce the pictures and the footage.

### Can I use Claude Fable 5.1 instead of Opus 5.5?

Yes. Fable 5.1 takes the same Messages request, so change `model` to `claude-fable-5-1`. [Claude Fable 5.1 vs Fable 5 vs Opus 5.5](https://seedrouter.ai/blog/claude-fable-5-1-vs-fable-5-vs-opus-5-5) compares the three.

### How long can a Seedance 2.5 short film be?

One Seedance 2.5 task renders 4 to 30 seconds, or lets the model choose the length with `duration: -1`. A longer film is several shots joined together, so the length has no fixed limit.

### Why does the character change between shots?

Usually because the prompts describe it differently, the sheet is missing from some shots, or the reference files are attached in a different order than the prompt numbers them. Check that every video prompt contains the same character paragraph and that the sheet is always the first image.

### Can I use Seedance 2.0 for this workflow?

Yes, with the same request shape on its own model ID. For character sheets, give Seedance 2.0 separate face and full-body images instead of one multi-view sheet. [Seedance 2.5 vs 2.0](https://seedrouter.ai/blog/seedance-2-5-vs-2-0) lists the other differences.

## Make your first short film

Start with a three-shot story at 480p, check the shots, then render the final cut at a higher resolution. The [Seedance 2.5 page](https://seedrouter.ai/models/seedance-2-5) has current prices and a Playground for testing a single shot, and the full request reference is in the [Seedance 2.5 API docs](https://seedrouter.ai/docs/seedance-2-5), the [GPT Image 2.5 API docs](https://seedrouter.ai/docs/gpt-image-2-5) and the [Claude Opus 5.5 API docs](https://seedrouter.ai/docs/claude-opus-5-5).
