# media-src — source masters, local only

Drop raw video/image exports here. Everything in this folder is gitignored except
this README.

**Never put a master in `public/`.** The whole of `public/` is copied verbatim into
`out/` at build time, so a raw export left there ships to production. The site serves
only the encoded copies under `public/media/`.

## Encoding a hero / background video

These are muted, looping, autoplaying clips. They need no audio, no adaptive
streaming, and no player — just a small file the browser caches once and loops
locally. Ship two codecs at two sizes:

| Output | Codec | Who gets it |
|---|---|---|
| `<name>-1080p.webm` | VP9 | most visitors |
| `<name>-720p.webm` | VP9 | small screens, `saveData`, slow `effectiveType` |
| `<name>-1080p.mp4` | H.264 | Safari builds without VP9 |
| `<name>-720p.mp4` | H.264 | same, small screens |

Page scripts pick WebM vs MP4 with `canPlayType('video/webm; codecs="vp9"')` and the
tier by viewport width — see the hero block in `src/site/pages/experiences.html`.

```bash
SRC="media-src/Your Export.mp4"
OUT="public/media/video/your-name"

# VP9 WebM (primary)
ffmpeg -i "$SRC" -an -c:v libvpx-vp9 -crf 39 -b:v 0 -row-mt 1 \
  -deadline good -cpu-used 2 -g 240 -vf "scale=1920:-2:flags=lanczos" "$OUT-1080p.webm"
ffmpeg -i "$SRC" -an -c:v libvpx-vp9 -crf 39 -b:v 0 -row-mt 1 \
  -deadline good -cpu-used 2 -g 240 -vf "scale=1280:-2:flags=lanczos" "$OUT-720p.webm"

# H.264 MP4 (fallback)
ffmpeg -i "$SRC" -an -c:v libx264 -profile:v high -pix_fmt yuv420p -preset slower \
  -crf 27 -movflags +faststart -g 240 -vf "scale=1920:-2:flags=lanczos" "$OUT-1080p.mp4"
ffmpeg -i "$SRC" -an -c:v libx264 -profile:v high -pix_fmt yuv420p -preset slower \
  -crf 29 -movflags +faststart -g 240 -vf "scale=1280:-2:flags=lanczos" "$OUT-720p.mp4"

# poster (covers until the video loads, and stays for prefers-reduced-motion)
ffmpeg -i "$SRC" -vf "select=eq(n\,0),scale=1920:-2" -frames:v 1 -q:v 5 "$OUT-poster.jpg"
```

Notes on those flags:

- `-an` always. Exports routinely carry an AAC track on clips the markup mutes.
- `-movflags +faststart` puts the MP4 index up front so playback starts before the
  file finishes downloading.
- **CRF is not comparable across codecs.** VP9 runs 0–63, x264 runs 0–51. VP9 crf39
  and x264 crf27 were matched by measuring SSIM against the master, not by picking
  similar-looking numbers. If you change one, re-measure rather than guessing:
  ```bash
  ffmpeg -i out.webm -i "$SRC" -lavfi "[0:v]scale=1920:1080[a];[1:v]scale=1920:1080[b];[a][b]ssim" -f null -
  ```

## Checking a clip before you encode it

Two clips have arrived truncated or mis-cut, so verify first:

```bash
ffprobe -v error -count_frames -select_streams v:0 \
  -show_entries stream=nb_read_frames,duration,r_frame_rate -of default=nw=1 "$SRC"

# contact sheet — spots scene cuts and a bad loop seam at a glance
ffmpeg -i "$SRC" -vf "select='not(mod(n,6))',scale=320:-1,tile=6x6" -frames:v 1 sheet.jpg
```

Aim for 7–10s. Much shorter and the loop becomes a visible stutter (a 1.4s clip
cycles ~42×/min). Check the last frame against the first — if they differ wildly the
seam will read as a glitch, unless the clip is a montage whose own cut rhythm hides it.
