---
title: Make a brand ad film from a brief, with generated shots and your real product
description: Turn a brief into a 30 or 60 second brand spot or commercial. Generated mood shots, your real product on screen, one color look, music and voice.
---
Make a brand ad film, a 30 or 60 second spot or commercial, from a written brief. Your agent generates the mood shots, cuts in real footage or photos of your product, puts one color look over all of it, and adds music and a voice. You end up with an MP4 and a timeline you can still change shot by shot.

This is ordinary ad work for a real product. The agent makes the film. You decide where it runs, and you upload it to the ad platform yourself. The agent never publishes an ad or sends an email.

Use invideo for this when you want generated shots and real product footage on one timeline, with the brief, the brand rules and every take kept in the same project.

## Quickest path

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

```text
Make a 30 second brand film for Brewly cold brew from this brief: <brief>.
Use the real product shots in ./product. Generate the mood shots around
them, never the product itself. One warm look across every shot, an
instrumental track, a calm female voice for the last line. Price every
generation first and show me frames before you export.
```

Replace `<brief>` with your brief, pasted as text. In a chat app, you drag the product shots and the logo into the project. In a terminal, the agent uploads them from the folder you name.

## What you need

The agent needs the brief and the real product.

- The brief: the audience, the one message, the tone, the length (30 or 60 seconds) and the shape (16:9 for YouTube and TV, 9:16 for Reels and TikTok).
- Real footage or photos of the product. The product on screen is always the real one.
- The brand kit: colors as hex codes, fonts as TTF or OTF files, the logo.
- The last line or the tagline, word for word.
- A LUT as a `.cube` file if your brand has one. This is optional.

## Steps

The agent plans first, generates second, and edits on a branch.

<Steps>
<Step title="Write the brief and the brand kit">
The agent makes a brief with `new_brief` and adds a `shot-list` note with `edit`. It writes the brand kit to `context/brands/brewly.md` with `write`: colors, fonts, logo and rules like "never show the can on its side". It sees the brief URL and the entry URL.
</Step>
<Step title="Bring in the real product">
The agent uploads the product shots, logo, fonts and LUT with `start_upload` and `add_media`. It sees one sequence URL per file, and a bin id for each font.
</Step>
<Step title="Generate the mood shots">
The agent runs `find_models` with the job in words, picks one, and reads its inputs with `get_model`. For a shot from words alone, a good pick is `seedance_2_5.frames`. For a shot that must match a look, a good pick is `seedance_2_5.r2v` with `reference_images`. Your agent can search for others with `find_models`. It calls `generate` with `dry_run: true` and the real inputs, and tells you the price. Then it calls `generate` with `max_credits` set to that price and an `idempotency_key`. It sees a thread URL and, when each take lands, a sequence URL. It reads that URL with `read` and never calls `generate` again to check.
</Step>
<Step title="Make the music and the voice">
The agent runs `find_models` for an instrumental track and for a voice, and reads each pick with `get_model`. Good picks are `elevenlabs_music_v2_5_instrumental` for the music, and `elevenlabs_text_to_speech.elevenlabs_tts_v4` with a `voice_id` from `elevenlabs_text_to_speech_voices` for the last line. For each, it calls `generate` with `dry_run: true`, tells you the price, and runs with `max_credits` and an `idempotency_key`. It sees a sequence URL for each and reads it with `read`.
</Step>
<Step title="Cut the film">
The agent makes the timeline with `new_timeline` and branches with `timeline_history`. It places shots with `place_media`, the real product shots on the beats where the product shows, the music on `A2` and the voice on `A1`. It adds the `ducker` audio effect to `A2` and the logo and tagline with `add_text`. A new timeline ducks under `A1` by default. It sees a new `state_token` after each call.
</Step>
<Step title="Give every shot one look">
The agent applies the LUT to each clip with `apply_lut`, or adds a grade with `edit_grade` and sets it with `set_grade_parameter`. It copies the look to the other clips with `paste_attributes`. It sees the grades in `get_timeline`.
</Step>
<Step title="Check that the shots match, then export">
The agent calls `capture` at one frame per shot and compares them by eye: color, light, and the product's label. It runs `check_timeline`. Then it runs `export`. It sees an export card with status `completed`.
</Step>
</Steps>

The terminal version:

```bash
invideo agent register <project-url> --name <name>
export INVIDEO_AS=<name>
invideo context new-brief <project-url> --name "Brewly 30s" \
  --description "30 second brand film, warm, morning ritual"
invideo context write <project-url>/context/brands/brewly.md \
  --markdown @brewly.md
invideo asset upload <project-url> ./product/*.mp4 ./brand/*
invideo gen models <project-url> --query "cinematic mood shot from words"
invideo gen model <project-url> --model seedance_2_5.frames
invideo gen run <page-url> --model seedance_2_5.frames --dry-run \
  -i prompt="slow dawn light over a kitchen counter" -i aspect_ratio=16:9
invideo gen run <page-url> --model seedance_2_5.frames \
  --max-credits <price> --idempotency-key brewly-dawn-1 \
  -i prompt="slow dawn light over a kitchen counter" -i aspect_ratio=16:9
invideo status <thread-url> --wait
invideo edit new <project-url> --name "Brewly 30s"
invideo edit show <edit-url> --json
invideo branch new <edit-url> --name cut-1 --token <state_token>
invideo edit show <branch-url> --json
invideo edit change <branch-url> --timeline T1 --token <state_token> \
  --operations @look.json
invideo edit capture <branch-url> --at 1,5,9,13,17,21,25,29 --out ./frames
invideo edit check <branch-url>
invideo edit export <branch-url> --format video --quality 1080 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out
```

Where the values come from:

- `<project-url>` is your project's URL, or what `invideo project new` returns. `<edit-url>` comes from `invideo edit new`.
- `<name>` is the name you choose for the agent in `invideo agent register`.
- `<page-url>` is a notebook page; `invideo notebook show <project-url>` lists them.
- `<price>` is the dry run's `.estimated_credits`. `<thread-url>` is the `url` the paid run returns.
- `<state_token>` comes from `invideo edit show <edit-url>`. `<branch-url>` is the `.branch_url` that `invideo branch new` returns. On the branch, `<state_token>` is the one from `invideo edit show <branch-url>`; the main token is stale there.
- `<card-url>` is `.sequences[0]` of what the export returns. `invideo status` waits and does not download; `invideo notebook show` saves the file as `./out/export.mp4`.

The file `./look.json` holds a bare list of operations: one look on every clip, and the ducker on the music. On the MCP path, the same list goes in the `operations` field of `edit_timeline`. A new timeline has `A1` (Voice) and `A2` (Music), and ducks under `A1` by default. `m4` is the LUT in the bin, and the clip ids come from `get_timeline`.

```json
[
  { "op": "apply_lut", "clip": "c3", "lut": "m4", "strength": 0.8 },
  { "op": "paste_attributes", "from": "c3", "to": ["c4", "c5", "c6"],
    "attributes": ["effects"] },
  { "op": "add_audio_effect", "target": "A2", "target_kind": "track",
    "effect": "ducker" }
]
```

For a 4K delivery, export at 1080p first. Then run `media` `video.upscale` on the export with a model from its list, like `byteplus_vod_upscale`, or `generate` with `topaz_starlight_fast_3` and `resolution` set to `4k`. Both take a dry run first and `max_credits` on the paid run. Upscales charge for each second of the source.

## 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 generated shot, the music, the voice, paid stock, and an upscale.
- Free: the brief, the brand kit, uploads, every edit, the grade, `capture` and `export`.

Video generation is the big cost, and it grows with length and resolution. Generate short takes at a lower resolution to pick a direction, then make the final takes. A first cut takes about an hour. See [Credits](/account/credits) for prices.

## If something goes wrong

Most problems are shots that do not match, or a product that looks wrong.

| 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. |
| 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. |
| A generated shot shows a fake product | Cut it. Generate the scene around the product, then cut to the real product shot. |
| The shots do not look like one film | Use one LUT or one grade, copied with `paste_attributes`. Pass a frame from the hero shot as a reference image. |
| `generate` refused for `max_credits` | The price is above the cap. Run `dry_run`, tell the person, and ask before raising it. |
| `apply_lut` refused | The clip has more than one grade. Remove one with `edit_grade` kind `remove`. |
| The music drowns the voice | The ducker follows `A1` by default. If the voice is on another track, point it there with `set_sidechain_source`. Raise `reduction` with `set_audio_effect_parameter`, using the ducker's id from `get_timeline`. |
| CLI exit 3 on the branch | The token is from main. Run `invideo edit show <branch-url>` and use its `state_token`. |
| Avoid: generating the product | Instead: keep the real product as a clip. A generated label or shape misleads buyers. |
| Avoid: saying done after the last edit | Instead: `capture` one frame per shot and compare them. |

## Prompts to try

Each prompt is a real variation of this job.

```text
Make the 60 second version of the Brewly film from the same brief. Reuse
the approved shots, add two new mood shots, and keep the same look.
```

```text
Cut a 15 second version and a 6 second bumper from the approved 30 second
film. One branch each.
```

```text
The client wants 4K. Export the final branch at 1080p, price an upscale to
4K, and wait for my OK.
```

## When to use something else

invideo does not shoot your product. For a hero product shot with real light and motion, book a product photographer or a studio, then bring the footage in. Music from a model or from stock covers most ads. For a jingle or a known song, license it from the rights holder. For TV delivery specs, ask your broadcaster or a post house for the final check.

## Related

- [Make a launch video from your product URL and screenshots](/how-to/marketing/launch-video)
- [Turn a product photo into a video without redrawing the product](/how-to/marketing/product-photo-to-video)
- [Make a stock-footage commercial for your business, in short and long cuts](/how-to/marketing/stock-footage-commercial)
- [Resize one master ad for every placement, with safe zones](/how-to/marketing/every-placement-from-one-master)
- [Label AI content so your ad runs on TikTok, Meta and Google](/how-to/marketing/ai-disclosure-for-ads)
- [Color grade log footage](/how-to/film/color-grade-log-footage)