Richness comes from value contrast, type as a large object, composition and rhythm. Flatness is a
hard-fail, not a low score. A lone paper plane with small objects, display type under 180 px,
a TYPE_SCALE under 4, a centered hero, mid-tone fills, too few full-bleed fields, a span over
0.75 s with no gesture (final CTA still over 1.2 s), fewer than 1 gesture onset per second, a
drift and a crossfade each fail the film. So does any decorative effect, with no exception
(the bounded swap blur, master motion blur, ≤ 3 % overshoot and purposeful 3D are not effects). Hard-fails
come first, then 9 scored criteria. PASS = no hard-fail, every scored criterion ≥ 7 and a mean ≥ 8.0.
ffmpeg missing → UNCERTAIN. One pass only.
Motion Review
Agent Workflow (MANDATORY)
- Builder runs
bash .motion/review-pack.sh <video> (template below) and hands the
critic only: video path, .motion/review/, byte budget, expected pix_fmt.
- Critic reads
ffprobe.json first; ffprobe/ffmpeg missing → UNCERTAIN, stop.
Then genre.txt (missing → assumed ad).
- Restate the message in one sentence from the frames — before opening the rubric.
- Hard-fails first (hard-fails.md): confirm or reject each
flags.txt candidate on frames with the critic-safe checks
(review-pack.md). Check every F, M, D, L, X (by genre) and S row.
- Read the look (
look.md, refs.md, board.png in the pack), then score the
9 criteria (rubric.md); map weak scores via
symptom-cause.md.
- Emit the block in verdict-format.md — hard-fails
listed first. Stop.
Overview
| Step |
Input |
Output |
Reference |
| Pack |
video + .motion/brief.md (genre line), look.md, refs/ |
facts, stills, beats, planes, mix, drift, energy, cuts, freezes, flags, copies |
review-pack.md |
| Gate |
pack |
F / M / D / L / X / S list |
hard-fails.md |
| Score |
pack + look copies |
9 scores 1-10 with frame refs |
rubric.md |
| Diagnose |
scores < 7, hard-fails |
symptom → cause → fix rows |
symptom-cause.md |
| Decide |
all of the above |
one verdict block |
verdict-format.md |
Critical Rules
- Intake = the pack — frames, pack text files,
genre.txt and the look copies. Never
the brief's body, beat map, facts, scene code or builder notes; a leak is discarded and
reported as intake_leak: yes.
- Message before rubric — no one-sentence restatement → FAIL.
- Hard-fails decide first — any F, M, D, L, X (ad) or S row → FAIL whatever the mean.
- Flatness and decoration are never scored — F2-F10 and D1-D9 are hard-fails even when
look.md asks for them; floors equal the look.md dials, in px at 1080 wide and OKLCH L.
- Evidence per score — every score and finding cites a timestamp or pack image.
- PASS is strict — no hard-fail, every scored criterion ≥ 7, mean ≥ 8.0; never rounded up.
- One pass, no code — name symptom, cause and fix direction; the builder fixes.
Architecture
.motion/
├── brief.md ← motion-method (only its genre: line reaches the pack)
├── look.md refs/{board.png,refs.md} ← motion-art-direction (locked before scene code)
├── review-pack.sh + review-pack-lib.sh ← review-pack-script.md (builder runs it)
├── out/draft.mp4 | master.mp4
└── review/ (generated, gitignore)
├── ffprobe.json genre.txt facts — read first
├── still-0.0|0.5|1.5|mid|last.png hook window, middle, end card
├── beat-NN.png one still per state between cuts
├── contact.png strip-01..12.png strip.png phone-390.png
├── planes.txt per still: planes, vc, field, mid, cx, bleed (F2 F4 F7 F9 F10)
├── mix.txt drift.txt opacity blends (M1, F1); sub-threshold motion (M2)
├── diff.txt spikes.txt spread.txt energy.txt motion energy, jumps, luma spread
├── cuts.txt segments.txt cut timestamps; state durations (tempo, holds, CTA)
├── stats.txt freeze.txt flags.txt raw metadata; ≥ 0.75 s gesture-free runs; hard-fail candidates
├── gestures.txt gesture onsets + rate per second (F11)
├── look.md refs.md board.png copies the sandboxed critic may read
└── frames.txt image → frame → timestamp
→ See review-pack-script.md for the complete script
Reference Guide
Concepts
| Topic |
Reference |
When to Consult |
| Review pack |
review-pack.md |
Reading the pack; critic sandbox; critic-safe checks (mosaic, halves, psnr, band) |
| Hard-fails |
hard-fails.md |
Every pass, before scoring — the only place IDs are defined |
| Worked example |
hard-fails-example.md |
Calibrating on the rejected flat ad, before and after a cosmetic patch |
| Rubric |
rubric.md |
Scoring — after the restatement; genre rules; audio |
| Symptom → cause |
symptom-cause.md |
Every score < 7 and every hard-fail |
| Verdict format |
verdict-format.md |
Writing the output |
Templates
Best Practices
DO
- Read
ffprobe.json, genre.txt, then flags.txt, before any image
- Judge the hook on
still-0.0, still-0.5, still-1.5; judge each state on its beat-NN
- Cite the dial (
VALUE_CONTRAST, TYPE_SCALE, display 180 px, HOLD) on every F line
- Confirm F2/F9/F10 on a mosaic, F7 on the halves, F6/M2 with
psnr, F3/F8/L2 with band tests
- Keep the findings table between rounds so a repeated row is visible
DON'T
- Pass a white-ground film with small centered blocks because its lightest-to-darkest spread is high: F2 weighs areas
- Credit any gradient background, decorative blur, glow, shadow, grain, glass/chrome, ambient 3D, particle or bouncy overshoot — it is a D fail
- Fail 3D for being 3D: only decorative/ambient 3D, a banned material/effect, or unproven lit determinism is D7
- Accept a film that is readable but under-animated — F6 / F11
- Accept a fade-up, a crossfade or a slow camera push as "motion" — M1 / M2
- Trust a
flags.txt number without the frames, or dismiss a flat film the flags missed
- Soften a verdict on request or run a second pass on the same file