---
title: Make storyboards and previs before the shoot
description: Storyboard frames for every shot, an animatic timed on a timeline, previs clips from the boards, and a greybox render dressed into a lookable shot.
---
You get a storyboard for every shot, also called boards or a shot board, laid out on a timeline as an animatic with notes on lens, move and dialogue. Then your agent turns key boards into short previs clips, and turns your own greybox blocking render into a dressed shot, so everyone on the shoot sees the film first.

Use invideo for this when you want the boards, the animatic and the previs in one project: each board is a clip you can retime, swap or redraw, and the timeline runs at your shoot's frame rate from the start.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it this prompt.

```text
Here is my shot list for scene 3 in ./shotlist.md. Make a storyboard
frame for each shot with cinematic_cameras, using the lens and focal
length I list. Lay them on a 24 fps timeline as an animatic with a note
on each board. Then make previs clips of shots 3 and 7. Price it first.
```

In a chat app, you paste the shot list into the chat. In a terminal, you name the file and the agent reads it.

## What you need

A shot list with framing and lens is enough. A script helps the agent time the animatic.

- **The shot list.** Shot number, framing, lens, camera move, action and dialogue.
- **The look.** Sketch boards, or photo-like frames that show light and lens.
- **References.** Photos of the location, the cast or the props, if you have them.
- **The shoot's frame rate and shape.** For example 24 fps and 2.39:1, or 25 fps and 16:9.
- **A greybox render, for the recipe.** A simple blocking render from Blender, Unreal or another 3D tool.

## Steps

The agent works on a branch and shows you each board as it lands.

<Steps>
<Step title="Draw the boards">
The agent follows the generation pattern for the boards.

1. It runs `find_models` with the job in words, picks an image model, and reads its inputs with `get_model`. A good pick is `cinematic_cameras`, which takes a lens, a focal length and an aperture, so each board looks like the lens you list. Your agent can search for others with `find_models`, such as `flux_2_lora.ballpoint_pen_sketch` for sketch boards, or `nanobanana_pro` and `gpt_image_26` for boards from reference images.
2. It calls `generate` with `dry_run: true` on one board, and tells you the price.
3. For a price of 1 credit or more it waits for your yes. Then it runs each board with `max_credits` set to that price and its own `idempotency_key`, reads each sequence URL with `read`, and names each board with `rename`, like "Shot 3 · 35mm push in".

Expected result: an image sequence URL per shot.
</Step>
<Step title="Lay out the animatic">
The agent makes a timeline with `new_timeline` at the shoot's frame rate, or sets it with `set_timeline_settings`. It places each board on `V1` with `insert_media` in shot order and sets its length to the shot's time with `trim_clip`. For a camera move on a still board, it adds the `dynamic_zoom` effect with `add_effect`, then sets its start and end framing with `set_effect_parameter` in a second call. Expected result: an animatic that runs as long as the scene.
</Step>
<Step title="Add notes to each board">
The agent adds a text clip on the board with `add_text`: the shot number, the lens, the move and the line of dialogue. It adds a marker per shot with `add_marker`. Expected result: notes you can read in every frame of the animatic.
</Step>
<Step title="Make previs clips from key boards">
For a shot that needs motion, the agent runs `find_models` for video from a first frame and reads its pick with `get_model`. A good pick is `seedance_2_5.frames`, with the board as its first frame. Your agent can search for others with `find_models`. It calls `generate` with `dry_run: true` and tells you the price. For a price of 1 credit or more it waits for your yes. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`. It reads the sequence URL with `read`, and swaps the clip in with `place_media` mode `replace`. Expected result: a moving shot where the board was.
</Step>
<Step title="Dress a greybox render">
You give the agent your blocking render, and it brings it in with `add_media`. It runs `find_models` for a model that restyles a video and keeps its motion, and reads its pick with `get_model`. A good pick is `luma_ray_32.edit`, which restyles a video from a prompt. Your agent can search for others with `find_models`. It calls `generate` with `dry_run: true` and tells you the price. For a price of 1 credit or more it waits for your yes. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`, and reads the sequence URL with `read`. Expected result: the same blocking and camera move, with real-looking light, set and cast.
</Step>
<Step title="Check, then export at the shoot's frame rate">
The agent runs `capture` at each board and `check_timeline`. Then it runs `export` with `format` video and the `fps` of the shoot. For printed boards, it exports one still per shot with `mode` image and `still_at`. Expected result: an export card with status `completed`.
</Step>
</Steps>

The same job from a terminal:

```bash
invideo edit new <project-url> --name "Scene 3 animatic" --fps 24
invideo gen models <project-url> --query "storyboard frame with a real lens"
invideo gen model <project-url> --model cinematic_cameras
invideo gen run <page-url> --model cinematic_cameras --dry-run \
  -i prompt="Rain on a bus window, a woman looks out" \
  -i focal_length=35mm -i lens="Cine Prime" -i aspect_ratio=16:9
invideo gen run <page-url> --model cinematic_cameras \
  --max-credits <price> --idempotency-key board-03 \
  -i prompt="Rain on a bus window, a woman looks out" \
  -i focal_length=35mm -i lens="Cine Prime" -i aspect_ratio=16:9
invideo status <thread-url> --wait
invideo notebook show <thread-url>
invideo asset upload <edit-url> ./greybox/shot-07.mp4
invideo gen models <project-url> --query "restyle a video, keep its motion"
invideo gen model <project-url> --model luma_ray_32.edit
invideo gen run <page-url> --model luma_ray_32.edit --dry-run \
  -i video=<greybox-url> -i prompt="Night street, wet asphalt, neon"
invideo gen run <page-url> --model luma_ray_32.edit \
  --max-credits <price> --idempotency-key greybox-07 \
  -i video=<greybox-url> -i prompt="Night street, wet asphalt, neon"
invideo edit change <edit-url> --timeline T1 --token <state_token> \
  --operations @animatic.json
invideo edit capture <edit-url> --at 0,4,8,12 --out ./frames
invideo edit export <edit-url> --format video --fps 24
invideo edit export <edit-url> --format video --mode image --still-at 4
```

Where the values come from: `<project-url>` from `invideo project new`, and `<edit-url>` from `invideo edit new`. `<page-url>` comes from `invideo notebook show <project-url>`. `<price>` is the price each dry run returns, its `estimated_credits`. A dry run returns a price and no URL, so `<thread-url>` is the `url` the paid run returns. `<greybox-url>` is the `url` that `invideo asset upload` returns. `<state_token>` comes from `invideo edit show <edit-url>`. The file in `--operations @animatic.json` is a bare list of ops, like the `operations` list below.

The key MCP call lays a board with its note and marker. This fence is the full MCP `edit_timeline` call. `start_f` and `end_f` are frames at the timeline's frame rate. `<edit-url>` is the timeline's URL from `new_timeline`, `<state_token>` comes from `get_timeline`, and `<board-1-url>` is the sequence URL of the first board.

```json
{
  "url": "<edit-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "insert_media", "asset": "<board-1-url>", "track": "V1",
      "at_f": 0, "ripple": true },
    { "op": "add_text", "track": "V3", "start_f": 0, "end_f": 96,
      "text": "1 · WS · 24mm · static · She waits at the stop" },
    { "op": "add_marker", "at_f": 0, "name": "Shot 1" }
  ]
}
```

## Cost and time

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything.

- **Costs credits:** each board from an image model, each previs clip from a video model, and each greybox dressed with `luma_ray_32.edit` or `id_v2v.restyle`.
- **Free:** the animatic, the notes and markers, the frame rate, `capture`, the stills and the video export.

Boards for a scene take a few minutes each. A previs clip takes a few minutes more. See [Credits and what they cost](/account/credits) for prices.

## If something goes wrong

Most problems come from boards that disagree on the look, or a greybox the model cannot read.

| Symptom | Fix |
| --- | --- |
| `get_model` or `generate` refuses the model as not found | Models retire. Run `find_models` with the job in words, use the best match, and tell the person which model you used. |
| The boards look like different films | Pass the same reference images to every board, and keep the same style words in every prompt. |
| A board has the wrong lens | Set `focal_length` and `lens` on `cinematic_cameras` instead of naming the lens in the prompt. |
| The dressed greybox loses the camera move | Use an adhere preset in `strength` on `luma_ray_32.edit`, which keeps more of the source. Or restyle the render's first frame with `nanobanana_pro`, then run `id_v2v.restyle`, which keeps the source's motion. Price each with `dry_run` first. |
| The previs clip runs at a different frame rate | Export with `fps` set to the shoot's rate. The timeline's rate sets the cuts. |
| Exit code 6, or `status` is `held` | A safety review, not a refusal. Wait, then run `invideo status <url> --wait` again. Do not resend. If it ends `failed`, change the input the review flagged. |
| CLI exit 5 | A limit on credits or quota. Check the balance. |
| Avoid: generating every board in one go without a price | Instead: run `dry_run` on one board, tell the person the price per board, then run the rest. |
| Avoid: calling `generate` again to check on a board | Instead: `read` the thread URL or call `status`. |

## Prompts to try

Each prompt is a real variation of the job.

```text
Make pen-sketch boards for the whole shot list with
flux_2_lora.ballpoint_pen_sketch. Time the animatic to my scratch voice
track in ./scratch.wav.
```

```text
Here is my Blender greybox of the car chase. Dress it as a night city
with luma_ray_32.edit and keep every camera move. Show me frames side by
side with the greybox.
```

```text
Export one still per board for the shooting script, then a 25 fps video
of the animatic for the people on set.
```

## When to use something else

invideo does not build 3D sets or block cameras in 3D. Make the greybox in a 3D tool such as Blender, Unreal Engine or Cascadeur, then bring the render in for the recipe above.

For a printed storyboard book with panels and arrows, lay out the exported stills in a layout tool like Storyboarder or InDesign.

## Related

- [Make an AI short film with a character that stays the same](/how-to/film/short-film-consistent-character)
- [Generate a missing shot or extend a clip inside your edit](/how-to/film/generate-a-missing-shot)
- [Make a sizzle reel or proof-of-concept to raise money](/how-to/film/sizzle-reel-for-financing)
- [Get started with AI filmmaking](/guides/get-started-with-ai-filmmaking)
- [Know the cost before you spend](/how-to/cost-before-you-spend)