critique.md
# Critique from a contact sheet
`qc.py` measures what can be measured: contrast, text size, overflow, held stills, loudness. It can't
say whether the video is any good. For that, look at it the way a juror looks at a page: every scene
at once, at rest, and judge only what's in the pictures.
```bash
uv run tools/contact_sheet.py out/video.mp4 # one settled frame per scene -> out/video.sheet.png
uv run tools/contact_sheet.py out/video.mp4 --keep-frames # also each frame on its own, to look closer
```
## The passes
Make each pass on its own.
1. **One second.** Glance at the sheet and look away. What did you see? One answer (a colour story, a
number, a shape). "Lots of charts" means nothing leads.
2. **The acts.** Can you see where the story turns from the colours alone? Count the field changes and
compare them with the acts in `design.md`. A change without a turn, or a turn without a change, is a
finding.
3. **Lightness.** Squint. Each neighbouring pair should differ clearly in lightness. Two neighbours of
the same lightness flicker at the cut.
4. **The accent.** Point at the brand colour in each frame. It should be on one thing, the thing being
said. Three places, or a chart with two hues, means the accent stopped meaning "here".
5. **Off-palette colours.** Any colour you didn't choose: a tint of the ground, a muddy mix, a default
blue. Usually unhighlighted bars or a semi-transparent fill.
6. **Edges.** Do all titles start at the same x? Count the distinct left edges across the sheet.
7. **Type.** Count the sizes (five is the ceiling). Any title on three lines, any orphan word, any
label under 28px at 1080p?
8. **One dominant thing.** In each frame, is there one thing to look at? A frame of equal small parts
has no hierarchy.
9. **Sameness.** One word per scene's layout (statement, line chart, bars, figure + bar, ...). The same
word three times in a row is the template showing; vary the composition, not the colour.
10. **Ground.** If the fields carry a pattern, is it the subject's own shape (`SKILL.md`, "A ground from the
subject") and quiet enough that the type reads first? Does anything on it sit under a line of type? A
pattern that could belong to any video is decoration: flat is better.
11. **Tells.** Rows of identical tiles, gradients, glows, shadows at rest, eyebrow labels above titles,
monospace labels, 01/02/03 numbering.
12. **Phone.** At the size of a phone (shrink the sheet to a third), can every title and figure still be
read? Can the chart's point be seen without its labels?
13. **Substance.** Does each frame carry what its narration claims, with the number visible? An empty
frame waiting for the narration is a hole, not a rest.
## The score
Four criteria, 1-10, weighted: **design 40%** (composition, type, colour), **clarity 30%** (can the
point of each scene be read in the time it's on screen, on a phone), **idea 20%** (is there a visual
idea specific to this subject, carried through), **content 10%** (are the words and numbers specific
and true).
`overall = 0.4·design + 0.3·clarity + 0.2·idea + 0.1·content`
Real award-level work lands around 7.5-8. If your first score for your own render is 9, score it again
as someone who didn't make it.
**Caps** (they override the arithmetic):
- A title or statement on three lines, a row of identical tiles, a gradient or glow, a shadow at rest,
or an eyebrow label in any frame: overall at most **6.5**.
- Colour that changes without a narrative turn (a field per scene): design at most **6.5**.
- Text under 28px at 1080p that the viewer needs, or any `qc.py --layout` contrast warning on it:
clarity at most **6**.
- A `qc.py --render` still stretch nobody chose: clarity at most **7**.
- A number on screen or in the narration that the data doesn't support: content at most **4**, and fix
it before anything else.
## Writing it down
```
ROUND n — <video>, <date>
Seen in one second: …
Acts vs fields: …
Layout words: intro=… / cards=… / …
Scores: design _ · clarity _ · idea _ · content _ → overall _._ (caps: …)
Top three problems, most visible first, each with the frame it shows in and the fix:
1. …
2. …
3. …
```
Fix in this order: anything untrue, then the acts and colour, then hierarchy, then type, then detail.
Render, make a new sheet, look again. Three rounds at most; stop when a round finds nothing above
detail level.
Adapted for video from taste-skill's `references/critique.md` (MIT, see `sources.md`).
handoff.md
# design.md: the handoff
`design.md` sits in the project root. Whatever gave the direction (a design skill, a brand guide, the
user in conversation) is written down here in one shape, so the build, the critique and the next
session all read the same decisions. Changing source means rewriting this file, not the code.
Keep it short: a page. The values in it are what the scenes use; a scene that needs a colour or a size
that isn't here is a sign the file is missing a decision.
## Format
```markdown
# Design: <project>
Source: <design source and what it dealt, e.g. "taste-skill, direction colour-chapters, palette
orange-sky-lime (seed 1125998202), palette redrawn for brand"; or "ours: brand + bone + black">
Brand: <brands/<name>>
## Acts
| Act | Scenes | Says | Field |
| --- | --- | --- | --- |
| 1 Who | intro | <one line> | identity |
| 2 The work | cards, outcomes, notes, escalations | <one line> | record |
| 3 Getting better | better, models, cost | <one line> | lab |
| 4 Close | close | <one line> | identity |
## Fields
| Field | Ground | Ink | Data accent | Other data | Secondary ink |
| --- | --- | --- | --- | --- | --- |
| identity | #ea580c | #111111 | ink | — | ink 80% |
| record | #f4f1ea | #111111 | #ea580c | #d9d4c7 | ink 75% |
| lab | #161615 | #f4f1ea | #ea580c | #3b3a37 | ink 75% |
## Type
Family: <Inter>, weights <800 / 400>
Steps (1080p): display <220> · figure <112> · title <72> · label <36> · note <28>
Display tracking <-0.04em>, leading <0.95>
## Ground
<flat> or <the subject's shape, e.g. "week grid: 7 columns and hour rows, ink 16%, type scenes only; meetings
land as outlined event cards in the hook and empty on the question">
## Layout
Title edge: x = <120>
<anything else decided once: margins, where sources go>
## Rules turned off
- <rule> — <why, in one line> (or "none")
```
## How a source maps onto it
A design skill made for pages deals things a video doesn't have (a hero, a nav, buttons) and things it
does (a palette, a type system, an idea). Take the second kind and map it:
| A page skill deals | design.md gets |
| --- | --- |
| ground, ink, accent | the main field's ground and ink; the accent becomes the **data accent** |
| section fields / chapter colours | one field **per act** (not per scene); keep two or three, ordered by lightness |
| type system (face, weights, sizes) | family and weights as dealt; sizes mapped onto the five video steps |
| the idea ("X becomes Y") | the acts' "Says" column and the intro's composition |
| hero, sections, nav, buttons, scroll scenes | nothing: video has scenes, `motion-craft.md` handles motion |
| imagery rules | keep: real pictures and the product's own UI beat drawings and stock |
When the source's palette fights the brand or the subject, keep its **proportions** (one ground, one
ink, one accent) and take the colours from the brand, and say so under Source.
## Worked example: Lugh's work (2026-11)
The first version used one colour per scene (orange, sky, lime, black, in turn). The critique found the
colours meant nothing (sky held both "the work" and "testing models"), orange and sky flickered at the
cut, and 45% ink over each ground made olive and steel-blue bars. Rewritten by act:
- Acts: who Lugh is (intro) · the work (cards, outcomes, notes, escalations) · how it got better (the
model switch, testing models, cost) · close. The notes and escalations scenes moved ahead of "how it
got better" so the second act stays together.
- Fields: identity = Digital Samba orange, record = bone, lab = near-black: mid, light, dark, so every
act change is a clear cut, and there are three in two minutes.
- Data accent: orange on bone and black; ink on orange. Other bars one neutral step per field.
- Type: five steps; the close broken by hand onto two lines; the intro's four tiles became one track.
palettes.md
# Act palettes
Palettes that hold up on video, written as fields with their roles. Each is two or three fields
ordered by lightness, so an act change is always a clear cut. Use them as starting points; a brand's
own colour usually replaces the accent, or one field.
Roles, as in `design.md`: **ground**, **ink** (text and plain data), **accent** (the one narrated
thing), **other** (unhighlighted data: one neutral step, never a tint of the ground).
## Brand + bone + black (light, mid, dark)
The default when a brand has one strong colour. The brand colour is the identity field (open and
close); bone carries the record (the long middle, where charts read best); near-black is the
surprise act (a turn, an experiment, the cost). Used for Lugh's work, 2026-11, with Digital Samba
orange.
| Field | Ground | Ink | Accent | Other |
| --- | --- | --- | --- | --- |
| identity | brand (e.g. `#ea580c`) | `#111111` | ink | — |
| record | `#f4f1ea` | `#111111` | brand | `#d9d4c7` |
| lab | `#161615` | `#f4f1ea` | brand | `#3b3a37` |
Check the brand's lightness: a very light brand colour (yellow, mint) sits too close to bone; swap
bone for white or a pale grey a full step away.
## Brand blue + cool grey + navy (a brand with a dark second colour)
When the brand has a mid colour and a dark one, use both and skip bone: the mid colour opens and closes, a
pale cool grey carries the product or the record, and the dark colour is the turn. Used with Digital Samba's
own colours (product blue, wordmark navy and coral) for a product launch, 2026-11.
| Field | Ground | Ink | Accent | Other |
| --- | --- | --- | --- | --- |
| identity | brand blue (`#3771e0`) | `#ffffff` | ink | — |
| record | `#eef2f8` | navy (`#323e66`) | brand blue | `#c9d3e6` |
| lab | navy (`#323e66`) | `#ffffff` | second accent (coral `#f06859`) | `#4a5684` |
White on a mid blue only just passes AA at body sizes; keep text on the identity field at title size and up.
## Graphite, one accent (one field)
For a short piece or a single act: no field changes at all, everything carried by one accent.
| Field | Ground | Ink | Accent | Other |
| --- | --- | --- | --- | --- |
| graphite | `#18191b` | `#eff0f1` | brand | `#5f6268` |
From taste's `graphite-safety-orange`.
## Paper, one accent (one field, projector-friendly)
For rooms with light in them: townhalls, a projector at the back.
| Field | Ground | Ink | Accent | Other |
| --- | --- | --- | --- | --- |
| paper | `#ffffff` | `#111111` | brand, one step darker if it's light | `#c8ccd1` |
From taste's `white-signal-red`, with the brand as the accent.
## Loud two-act (bold, campaign pieces)
When the brief is "bright and poppy": two saturated fields of different lightness, plus black type.
Keep it to two; a third saturated field is where it starts to look like a different colour per scene.
| Field | Ground | Ink | Accent | Other |
| --- | --- | --- | --- | --- |
| loud | `#ff8126` | `#111111` | `#111111` | `#ffffff` |
| calm | `#c5f53d` | `#111111` | `#111111` | `#ffffff` |
From taste's `orange-sky-lime` (its sky blue left out: it has the same lightness as the orange).
On a saturated ground the data is two-tone: the narrated bar in ink, the rest solid white. Never ink
at partial opacity over the colour; that is what made the muddy olive and steel-blue bars.
Palettes marked "taste" are from taste-skill's library (https://github.com/Leonxlnx/taste-skill,
Copyright (c) 2026 Leonxlnx, MIT License), adapted into video roles.
SKILL.md
---
name: video-design
description: Visual design for videos - colour by act, type scale, chart and layout rules for 16:9 and 9:16 scenes, a design.md handoff that any design skill can fill, and a contact-sheet critique of the render. Use when designing or refining how a video looks (title cards, data scenes, slides, a whole video's palette), when a scene looks generic or busy, when choosing colours for a video, or when /design or /scene-review asks for visual work. Works on its own with a brand, or takes direction from a design source such as taste-skill, Anthropic's frontend-design, or the user's own design skill.
---
# Video design
A web design skill knows pages: scrolling, hover states, a nav bar. A video has none of that. It has
scenes the viewer can't pause on, a narration that sets the pace, a phone in someone's hand or a
projector at the back of a room. This skill is the toolkit's video layer: it takes a design direction
from wherever it comes from and turns it into scenes, then checks the render the way a juror would.
## Three layers
```
design source (optional, the user's choice) → design.md (the handoff) → video-design (this skill) → qc.py + critique
taste-skill, frontend-design, a team's own palette, type, acts, fields per act, one data layout, contrast,
design skill, a brand guide rules on/off accent, type steps, motion stills, contact sheet
```
- **The design source** gives the direction: a palette, a typeface, an idea. Any skill that can do that
works, and none is required: with ours (the default), this skill writes `design.md` itself from an act
palette and the brand. Plug in your own design skill, or use ours. The project
records its choice in `project.json` (`design.source`). See `sources.md`.
- **`design.md`** lives in the project. It is the contract: what the source decided, mapped onto the
video's acts, plus any house rule turned off and why. A different source means a different
`design.md`, not different code. See `handoff.md`.
- **This skill** applies it with the rules below, which hold whatever the source says, because they
come from how video is watched rather than from taste.
## Rules for video
**Colour follows the story.**
- Two or three fields at most, and a field changes only when the narrative does (a new act, not a new
scene). A colour that changes every scene means nothing; one that changes at the turn tells the
viewer something turned. Write the acts down first (`handoff.md`), then give each act its field.
- Neighbouring fields differ in **lightness**, not only hue: light, mid, dark. Two fields of the same
lightness (orange and sky blue) flicker at the cut, and even ffmpeg's cut detector can't see the
change.
- Fields meet with a hard cut. Content can fade out and in; the ground does not cross-fade.
- **One data accent.** The brand colour goes on the thing the narration is talking about (the bar it
names, the line, the number) and nowhere else. Everything else is ink or one neutral step. Never a
tint of the ground (45% black over lime renders as olive, a colour nobody chose).
- Text on a coloured field is the field's ink at full strength, or at 70-80% for secondary lines if it
still passes contrast. Grey text on colour reads as dirt.
**Type.**
- Five sizes per video, decided once. At 1080p: display 200-260, figure 112-132, title 64-72,
label 32-36, note 28. The phone floor is 28px at 1080p (`qc.py --layout` checks 2.6% of the short side).
- One family, two weights at most. Tracking -0.03 to -0.05em on display sizes, leading 0.9-1.0.
- A title or statement is two lines at most, broken by hand at the phrase (`<br />`), never left to
wrap. Count it: ~32 characters a line at display size on 1920px. An orphan word on a third line is
the most visible tell there is.
- Numbers in tabular figures, so a counting number doesn't jitter.
**Layout.**
- One left edge for every title in the video (the same x in every scene); charts and figures may run
wider, but headings never move.
- One dominant thing per scene: the chart, the figure, or the statement. A big number and a chart can
share a scene only when the number is what the chart adds up to.
- No row of identical tiles (four black boxes for four steps). Use one shape with stops on it, a
sentence, or a sequence that reveals on the narration.
- No gradients, glows, drop shadows on things at rest, glass panels or decorative shapes. A flat field,
the product itself, a real picture, or a ground drawn from the subject (below).
- Footnotes and sources: one line, at the note size, at the bottom left. A scene that needs three
lines of notes needs a sentence of narration instead.
**A ground from the subject.** A flat field is the default and often right. When it reads dull, don't decorate
it: draw the subject's own structure on it. Ask what shape the thing already has: a calendar has a week grid, a
song a beat grid or staff, code a line-number gutter, a map its contours, a chat its message column, a
spreadsheet its cells. That shape, and nothing invented, becomes the ground.
- Hairlines in the field's ink at 10-16% (a little less on dark fields). It should read on a phone and
disappear behind the type; if a viewer notices the lines before the words, halve them.
- One motif for the whole video, the same on every type scene. Scenes with the product or a chart get no
ground: they are already the picture.
- Things on the ground use the subject's own vocabulary (a calendar's event cards, a chat's bubbles), as
outlines in the ink, and land on the words that name them (`cue()`). They sit above and below the type,
never under its lines.
- It can carry a turn: fill it while the narration lists, empty it on the question. That's the difference
between texture and an idea.
- Record it in `design.md` under "Ground". Never noise, stock imagery, blobs or a generated background; those
are the decoration this replaces.
**Charts** (`lib/components/DataChart.tsx`).
- Flat area fill at 15% or less (`area="flat"`), square columns (`radius={0}`), no legend on a single
series, 3-7 gridlines or none.
- The accent lands on the narrated bar or line on its word (`highlightAt` / `growAt` from `cue()`); a
second group, if any, in ink or white, never a second hue.
- Every number on screen comes from the data file, and every number the narration says is checked
against it at build time (see `examples/data-chart-stars` and the `check()` pattern).
**Transitions.** An act change is a hard cut, or `wipe()` from `@remotion/transitions` when a moving edge helps;
never a cross-fade between fields. When one scene shows the same thing again in a new way (the same chart in
another design, a screen after the fix), turn it in place with `PageTurns` (`lib/components`), each turn on the
word that names the new page. Effect transitions (`lib/transitions`: glitch, light leak, zoom blur) are a brand
choice, not a default; record one under "Rules turned off" in `design.md`.
**Motion** belongs to `.claude/skills/remotion/motion-craft.md`: timing in frames, read time, and the
defaults that look generated. Each change on screen lands on the word that names it (`cue()`), so a
held scene always has a next action, which is what `qc.py --render`'s still-stretch check looks for.
## Workflow
1. **Acts.** Write the video's acts (two to four) and which scenes each holds. This is the most
important design decision and it is made in words.
2. **Direction.** Use the project's design source if `project.json` names one; otherwise offer the
installed ones (`sources.md`), or use ours: an act palette from `palettes.md` with the brand.
3. **`design.md`.** Fill it from the source's direction (`handoff.md`): a field per act, ink, the one
accent, the five type steps, the ground (flat, or the subject's own shape), rules turned off with a reason.
4. **Build** the scenes to it.
5. **Check.** `uv run tools/qc.py --project <p> --layout` and `--render out/video.mp4`.
6. **Look.** `uv run tools/contact_sheet.py out/video.mp4` tiles one settled frame per scene. Critique
it with `critique.md`, fix the top three, render, look again. Three rounds at most.
## Files
| File | Read it when |
| --- | --- |
| `handoff.md` | Writing or reading `design.md`: the format, and a worked example. |
| `sources.md` | Choosing a design source, plugging in another, or listing one for others. |
| `critique.md` | Reviewing a render from its contact sheet: the passes, the score, the caps. |
| `palettes.md` | Act palettes that already work on video, mapped to roles, with their sources. |
Parts of these rules (colour fields as chapters, lightness between neighbours, one accent, two-line
headlines, five sizes, the critique's score and caps) are adapted for video from
[taste-skill](https://github.com/Leonxlnx/taste-skill) by Leonxlnx (MIT). See `sources.md`.
sources.md
# Design sources
**Plug in your own design skill, or use ours.** A design source is any skill, guide or person that decides
how something should look: the palette, the type, the idea. The toolkit depends on none of them. Its own
source, **ours**, is `video-design` itself (the act palettes in `palettes.md` with the project's brand), and
any installed design skill can take its place, because everything goes through the handoff (`design.md`).
## Choosing one for a project
1. If `project.json` has `design.source`, use it.
2. Otherwise offer, in this order:
- **ours** (the toolkit's own, nothing to install);
- each source in the registry's `designSources` that is installed in this session, the recommended one
marked. A plugin skill shows up with its plugin's prefix, so match the registry's `skill` with or without
it (`frontend-design` is installed as `example-skills:frontend-design` from Anthropic's plugin);
- "another design skill": the user names one.
Don't offer every skill whose description mentions design or brand. That sweeps in skills that aren't design
sources, such as a brand-guidelines skill that applies another company's colours.
3. Record the choice in `project.json`:
```json
{ "design": { "source": "taste-skill", "file": "design.md" } }
```
`source` is the registry key for a listed source (`ours`, `taste-skill`, `frontend-design`), so every session
saves the same value for the same choice; for an unlisted skill it is the skill's name as invoked (e.g.
`acme:house-style`). `"source": "ours"` means the toolkit's own: `video-design` picks an act palette from
`palettes.md` and fills it with `brands/<name>/`.
Whatever the source, its output goes into `design.md` (`handoff.md`) before anything is built, and the
rules in `SKILL.md` still apply on top. When a source contradicts one (a gradient, a glow, a third
field colour), the video rule wins unless the brand requires it; write the exception under "Rules
turned off".
## Known sources
These are listed in the registry (`_internal/toolkit-registry.json`, `designSources`).
| Source | What it's good for | Install |
| --- | --- | --- |
| **taste-skill** (recommended plug-in) | Dealt directions and palettes from 247 studied sites, measured house rules, a juror's critique with caps. Its colour chapters, one-accent rule and critique translate well to video. MIT. | `/plugin marketplace add Leonxlnx/taste-skill` then `/plugin install taste-skill@taste-skill` ([repo](https://github.com/Leonxlnx/taste-skill)) |
| **frontend-design** (Anthropic) | General visual direction for interfaces: a bold aesthetic stance, type pairing. Written for web pages, so expect to turn down its effects (gradient meshes, glows) for video. | Anthropic's skills repo: [anthropics/skills](https://github.com/anthropics/skills) |
| **Ours** (the toolkit's own, the default) | `video-design`'s act palettes and rules, filled with `brands/<name>/brand.json`. | Nothing to install |
| **Your own** | A team design system, an agency's house style, a skill you wrote. | See below |
"Recommended" means it's the one we currently find gives the best results on video, not that the
toolkit needs it. It changes when something better turns up.
## Bringing your own
Any skill works if it can tell `video-design` five things, which is what `design.md` asks for: the
grounds (one per act, two or three), the ink on each, the one accent, the type family and weights, and
the rules it wants off. It doesn't need to know about Remotion, frames or narration.
To list a design source for other users, open an issue with:
- a link and a one-line description;
- its licence (it must allow use in videos people publish);
- the `design.md` it produced for `examples/data-chart-stars`, and that example's contact sheet
rendered with it (`uv run tools/contact_sheet.py out/data-chart-stars.mp4`), so sources can be
compared on the same video.
Listed sources go in the README's "Design sources" table and the registry. They are not copied into
the toolkit; users install them from their own repos.
## Credit
Parts of `video-design` are adapted from taste-skill (https://github.com/Leonxlnx/taste-skill),
Copyright (c) 2026 Leonxlnx, MIT License: the colour-fields-as-chapters idea, lightness between
neighbouring fields, the one-accent rule, the two-line headline and five-size limits, and the critique's
weighted score and caps. The palettes in `palettes.md` marked "taste" are from its library. The rest is
the toolkit's own, from making these videos.