---
title: Color grade log footage and match shots
description: Your log footage converted to normal color, graded with a LUT and color controls, and matched shot to shot on a timeline you can keep changing.
---
You get log footage turned into normal-looking video, also called color correction and color grading. Your agent tells invideo which camera profile the clips were shot in, applies your LUT, sets exposure, white balance and curves per clip, and matches the shots so a scene looks like one place and one time.

Use invideo for this when you want the grade on the same timeline as the cut: every grade stays editable, your agent can change one control on many clips in one call, and you see each change live in the browser.

## Quickest path

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

```text
These clips in ./scene-12 are Sony S-Log3, S-Gamut3.Cine. Set the color
profile, apply my LUT ./looks/teal-warm.cube at a light strength, then match
every shot to the wide shot. Show me frames side by side before and after.
Work on a branch.
```

In a chat app, you drag the clips and the .cube file into the project. In a terminal, you name the folders and the agent uploads them.

## What you need

Tell the agent the camera and its log profile. A wrong profile makes every later step wrong.

- **The footage.** The original camera files, in log.
- **The camera and profile.** For example Sony S-Log3 with S-Gamut3.Cine, or Panasonic V-Log.
- **A LUT, if you have one.** A .cube or PNG file: the camera maker's conversion LUT, or a creative look.
- **The hero shot.** The shot the others should match, usually the wide.
- **The look in words.** "Warm skin, cool shadows, low contrast" is enough.
- **The delivery.** SDR for the web, or HDR for a platform that takes it.

## Steps

The agent grades on a branch and shows you frames after each step.

<Steps>
<Step title="Bring in the footage and the LUT">
The agent sets up in three calls.

1. It makes a timeline with `new_timeline`.
2. It creates a branch with `timeline_history` and `action: "create_branch"`.
3. It adds the clips and the .cube file with `add_media` on the branch URL.

Expected result: a media bin id for each clip and for the LUT.
</Step>
<Step title="Set the color profile of each clip">
The agent sends `set_media_color_profile` for each log file in the bin, with the `profile` that matches the camera, like `slog3_sgamut3cine` or `vlog_vgamut`. Then it sets the timeline to `rec709` with `set_timeline_working_space`, or to `rec2020` for an HDR grade. Expected result: clips that look normal, not flat and gray.
</Step>
<Step title="Apply the LUT">
The agent places the clips, then sends `apply_lut` on each clip with the LUT's bin id and a `strength` between 0 and 1. Expected result: a new `state_token`, and the look on every clip.
</Step>
<Step title="Correct each shot">
The agent adds a grade with `edit_grade` kind `add` where a clip needs its own fix. In a second call, with the grade id from `get_timeline`, it sets `exposure`, `temperature`, `tint`, `contrast` and `saturation` with `set_grade_parameter`, and shapes the contrast with `set_grade_curve` on the `master` curve. For a face in shadow or a hot sky, it adds a mask with `edit_grade_mask` and a `circle`, `rectangle` or `gradient` shape. In a second call, with the mask id from `get_timeline`, it places the mask with `set_grade_mask_parameter` (`center`, `size`, `feather`). Expected result: each shot correct on its own, and any mask changes the grade only inside it.
</Step>
<Step title="Match the shots">
The agent runs `capture` at a time in the hero shot and a time in each other shot, and compares them side by side by eye. It looks at skin, a white or gray object, and the shadows. It nudges `temperature`, `tint` and `exposure` on the shot that is off, and captures again. Expected result: shots that cut together without a jump in color.
</Step>
<Step title="Add a shared look">
For one look over the whole scene, the agent adds an adjustment clip with `add_adjustment` above the top video track, then adds a grade on it with `edit_grade`. A change to that grade changes every shot below it. Expected result: one place to change the look of the scene.
</Step>
<Step title="Check, then export">
The agent runs `check_timeline` and `capture` at every cut, and looks for clipped highlights and crushed blacks. Then it runs `export` with `format` video. Expected result: an export card with status `completed`, a 1080p MP4.
</Step>
</Steps>

The same job from a terminal:

```bash
invideo edit new <project-url> --name "Scene 12 grade" --fps 24
invideo asset upload <edit-url> ./scene-12/*.mp4 ./looks/teal-warm.cube
invideo edit show <edit-url> --json
invideo branch new <edit-url> --name grade-v1 --token <state_token>
invideo edit show <branch-url> --json
invideo edit catalog <edit-url> --ops set_media_color_profile,apply_lut
invideo edit change <branch-url> --timeline T1 --token <state_token> \
  --operations @grade.json
invideo edit capture <branch-url> --at 2,9,15,22 --out ./frames
invideo edit check <branch-url>
invideo edit export <branch-url> --format video --quality 1080 --json
```

Where the values come from: `<project-url>` from `invideo project new`, and `<edit-url>` from `invideo edit new`. `<state_token>` comes from `invideo edit show` on the URL the next command runs on: `<edit-url>` for `branch new`, then `<branch-url>`, read fresh after each change, because the main token is stale on the branch. `<branch-url>` is the `branch_url` that `branch new` returns. The file in `--operations @grade.json` is a bare list of ops, like the `operations` list below.

The key MCP calls set the profile, the working space and the LUT, then one correction. Each fence is a full MCP `edit_timeline` call. The ids `m1`, `m9` and `c3` come from `get_timeline`, and so does `<state_token>` on the MCP path.

```json
{
  "url": "<branch-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "set_media_color_profile", "asset": "m1",
      "profile": "slog3_sgamut3cine" },
    { "op": "set_timeline_working_space", "timeline": "T1",
      "working_space": "rec709" },
    { "op": "apply_lut", "clip": "c3", "lut": "m9", "strength": 0.7 }
  ]
}
```

The agent reads the grade id, `<grade-id>`, and a fresh token with `get_timeline` after `apply_lut` makes the grade, then sends the corrections in the next call.

```json
{
  "url": "<branch-url>",
  "timeline_id": "T1",
  "expected_state_token": "<state_token>",
  "operations": [
    { "op": "set_grade_parameter", "clip": "c3", "grade": "<grade-id>",
      "parameter": "temperature", "value": 0.1 },
    { "op": "set_grade_curve", "clip": "c3", "grade": "<grade-id>",
      "which": "master",
      "points": [[0, 0.04], [0.25, 0.22], [0.75, 0.8], [1, 0.97]] }
  ]
}
```

### HDR delivery

`export` makes a 1080p SDR MP4. For an HDR file, the agent grades in `rec2020`, exports at 1080p, then runs the export through an HDR model with `generate`: `topaz_hyperion_2_5_sdr_hdr` gives HDR10, HLG or ProRes, and `ltx_video_hdr_upscale` gives ProRes, HLG or DNxHR. Both take the export card's URL as their `video` input, with no download. They charge per second of the source video. The agent follows the generation pattern.

1. It runs `find_models` with the job in words, picks one, and reads its `output_format` and `resolution` choices with `get_model`. A good pick is `topaz_hyperion_2_5_sdr_hdr`. Your agent can search for others with `find_models`.
2. It calls `generate` with `dry_run: true` and the real inputs, and tells you the price.
3. 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 gets a thread URL and, when the result lands, a sequence URL. It reads that URL with `read` and never calls `generate` again to check.

```bash
invideo gen models <project-url> --query "SDR to HDR conversion"
invideo gen model <project-url> --model topaz_hyperion_2_5_sdr_hdr
invideo gen run <page-url> --model topaz_hyperion_2_5_sdr_hdr --dry-run \
  -i video=<card-url> -i output_format=hdr10_hevc_mp4
invideo gen run <page-url> --model topaz_hyperion_2_5_sdr_hdr \
  --max-credits <price> --idempotency-key scene12-hdr \
  -i video=<card-url> -i output_format=hdr10_hevc_mp4
```

Where the values come from: `<project-url>` from `invideo project new`. `<card-url>` is `.sequences[0]` of the export answer. `<page-url>` comes from `invideo notebook show <project-url>`. `<price>` is the price the dry run returns, its `estimated_credits`.

## 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.

- **Free:** the color profile, the LUT, every grade, mask and curve, `capture`, and the export.
- **Costs credits:** only the HDR conversion with `topaz_hyperion_2_5_sdr_hdr` or `ltx_video_hdr_upscale`, priced per second of video.

A scene grade takes the agent a few minutes. Matching shots with you takes longer, because you judge the frames. See [Credits and what they cost](/account/credits) for prices.

## If something goes wrong

Most problems come from the wrong profile or a LUT stacked on a grade.

| 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 footage looks flat and gray | The color profile is not set. Send `set_media_color_profile` with the camera's profile. |
| The footage looks too dark and too saturated | The LUT converts log, and the profile also converts it. Use one of them, not both. |
| The camera's profile is not in the `set_media_color_profile` list | Skip the profile. Use the camera maker's conversion LUT with `apply_lut` instead. |
| `apply_lut` is refused | The clip has more than one grade. Remove one with `edit_grade` kind `remove`, then apply the LUT. |
| The LUT is too strong | Lower `strength` on `apply_lut`, or `lut_strength` with `set_grade_parameter`. |
| A mask is in the wrong place | Move it with `set_grade_mask_parameter` and `center`, then `capture` again. |
| `edit_timeline` refused with an old token | Someone edited first. Read with `get_timeline`, then rebuild the ops. |
| CLI exit 3 | The edit changed since your read. Run `invideo edit show` and rebuild. |
| Avoid: matching shots by numbers alone | Instead: `capture` both shots and compare them by eye. Skin and neutrals tell you more than a value. |
| Avoid: grading main | Instead: grade on a branch, so you can compare looks. |

## Prompts to try

Each prompt is a real variation of the job.

```text
These are Panasonic V-Log clips. Set the profile, then give me a warm,
soft look and a cool, high-contrast look, each on its own branch.
```

```text
The close-up at 00:42 is warmer than the wide at 00:30. Match it to the
wide and show me both frames before and after.
```

```text
Darken the sky in every exterior shot with a gradient mask, keep the faces
as they are, and add a light vignette over the whole film.
```

## When to use something else

Your agent sees captured frames, not scopes like a waveform or a vectorscope, so it matches by eye. For a grade that must hit exact broadcast levels, finish in DaVinci Resolve: export with `format` set to `davinci` and grade there.

`set_media_color_profile` covers the profiles in its list. For other log profiles, like ARRI LogC or Canon Log, use the camera maker's conversion LUT with `apply_lut`.

## Related

- [How should I choose a LUT for my footage?](/guides/how-should-i-choose-a-lut-for-my-footage-in-invideo-editor)
- [What to adjust when a LUT looks too strong](/guides/what-should-i-adjust-when-a-lut-makes-my-shot-look-too-strong)
- [Export to Premiere Pro, DaVinci Resolve or Final Cut Pro](/how-to/export-to-premiere-resolve-final-cut)
- [Generate a missing shot or extend a clip inside your edit](/how-to/film/generate-a-missing-shot)
- [Check your video before you say it is done](/how-to/check-your-video)