# Color Grade

> Color-grade a video — apply a cinematic look / LUT, or generate and compare candidate looks for the user to pick. Use whenever footage looks flat/muted/cold and needs grading, you want a named reusable look (warm, teal-orange, punchy, neutral), or you have a .cube LUT to apply. Covers applying .cube/HALD LUTs via ffmpeg, baking a look from a color-filter chain, and the "render a few looks, let me choose" workflow.

- Skill: `agamm/color-grade` (Agent Skill)
- Install (CLI): `npx skillmds@latest add agamm/color-grade`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agamm/color-grade/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: agamm (https://skillmd.com/u/agamm)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/agamm/color-grade

---


# Color grade (LUTs via ffmpeg)

Grade through **LUT files** rather than re-deriving filter params each time. Two LUT formats,
both native to ffmpeg, no extra deps:
- **`.cube`** — a 3D LUT (what colorists ship). Applied with `lut3d`.
- **`.png` HALD-CLUT** — a look baked from a filter chain (below). Applied with `haldclut`.

The `grade` command auto-detects by extension.

```bash
# Apply a look
uv run video-agent grade apply in.mp4 --lut luts/teal_orange.cube -o out.mp4
uv run video-agent grade apply in.mp4 --lut luts/warm.png        -o out.mp4   # HALD
```

## "Make a few looks and let me choose"

The best grading UX: render the SAME frame through several candidate looks into one labelled
contact sheet, show it, let the user pick — then apply the winner to the whole video.

```bash
uv run video-agent grade preview in.mp4 --at 45.0 \
    --lut none --lut luts/warm.png --lut luts/teal_orange.cube --lut luts/punchy.png \
    -o looks.png
# read looks.png → user picks → grade apply with that one
```
`none` = the ungraded original (always include it for reference). Pick a frame (`--at`) with
skin tones + a bright and a dark area so the grade's effect is visible.

## Bake a look into a reusable LUT

Author a look as a **color-filter chain**, then bake it into a HALD LUT once so it's reusable
and fast to apply:

```bash
uv run video-agent grade gen-lut \
    --eq "curves=r='0/0 .5/.55 1/1':b='0/.03 1/.97',colorbalance=rs=.05:bs=-.05" \
    -o luts/warm.png
```
This runs an identity HALD-CLUT through the chain → a `.png` LUT. **Use available filters
only** — this ffmpeg is LGPL, so **no `eq`** (and no `drawtext`). Grade with: `curves` (the
workhorse — per-channel tone curves), `colorbalance` (shadows/mids/highlights RGB),
`colorchannelmixer` (channel mixing / saturation), `lut1d`. Quick starting points:
- **warm**: `colorbalance=rs=.04:rm=.03:bs=-.04:bm=-.03`
- **teal-orange**: `colorbalance=rh=.06:bs=.08` + lift shadows blue, push highlights warm
- **punchy**: `curves=all='0/0 .25/.18 .75/.82 1/1'` (S-curve contrast) + light saturation via `colorchannelmixer`
- **desaturate/filmic**: `colorchannelmixer` toward grey, or `curves` to lift blacks

## Where grading sits in a pipeline

- Grade **at the final encode**, after cuts/reframe, before captions/overlays (so burned text
  keeps its intended color). In an `edl-edit` job, set `"grade": "luts/x.png"` in the EDL and
  it's applied to the whole cut in the same pass.
- Grading helps most on **flat/log/prosumer footage**; typical Rec.709 screen-recordings and
  webcams need only a gentle lift. Don't over-grade — a subtle look beats a heavy filter.

## Gotchas

- **`.cube` vs HALD**: external colorist LUTs are usually `.cube` (→`lut3d`); looks you bake
  here are `.png` HALD (→`haldclut`). The command handles both; just keep the extension honest.
- **HALD level**: `gen-lut` defaults to level 8 (a 64³ grid) — plenty for smooth grades;
  raising it makes a bigger file, rarely needed.
- **Grade once, reuse**: commit your `luts/*.png` (or `.cube`) so the look is plain-text/
  data and re-applies identically across clips and re-renders.

