fill-verticallisted
Install: claude install-skill jperrello/C0BALT_CUT
# fill-vertical
Punch-in 9:16 reframe. Fills 1080x1920 on every shot — the "content" look, not the
blurred-letterbox "webinar" look. Runs after `tighten-pace`, before
`chunk-captions`/`burn-subtitles`.
## Usage
```bash
.claude/skills/fill-vertical/fill-vertical.sh <input> <out> \
[target=1080x1920] [face_frac=0.45] [max_zoom=2.0] [scene_thresh=0.4] [samples=5]
```
- **input** — cut/trimmed/tightened clip (any aspect; designed for 16:9).
- **out** — written 1080x1920 mp4, audio stream-copied, duration unchanged, `+faststart`.
## Contract
- **In:** one video file.
- **Out:** one 1080x1920 mp4. Audio copied from input. Duration preserved.
Side artifact `<out>.fillplan.json` records per-shot crop boxes.
- **Idempotent:** if `out` is newer than `input`, exits as a cache hit.
## How it works
1. `ffprobe` for source w/h/fps/duration.
2. Scene-cut detect via ffmpeg `select=gt(scene,thresh)` on a downscaled decode → shot list.
3. Per shot: sample `samples` frames, run MediaPipe **FaceLandmarker** (full lip mesh).
- Link faces across frames by center proximity → tracks.
- **Speaker = track with max mouth-openness variance.** No measurable lip motion →
biggest + most-central face. Single face → trivial.
- Crop box: chosen face ~`face_frac` of frame height, eyeline on the upper third,
centered on the face, clamped to source bounds, capped at `max_zoom`.
- **No face → PERSON tier:** run MediaPipe **Pose** (`pose_landmarker.task`, created
lazily — onl