Media pipeline

The site uses three deliberately separate media lanes. The distinction is about ownership and rebuildability, not aesthetics.

1. Authored article images

New images uploaded through Writer are source files and live in Git:

assets/uploads/articles/YYYY/MM/article-slug/

Example:

assets/uploads/articles/2026/09/ban-oblique-kicks/
  cover.webp
  rampage-kick.webp

These are the authored originals for that article. Existing legacy files under assets/uploads/ keep their current URLs and are not moved.

2. Generated image derivatives

Responsive variants are machine output:

assets/generated/posts/

Legacy source images continue using the existing flat generated filenames so their public URLs do not change.

For the Stage 2 article hierarchy, new responsive output mirrors article ownership:

source
assets/uploads/articles/2026/09/ban-oblique-kicks/cover.webp

generated
assets/generated/posts/2026/09/ban-oblique-kicks/
  cover-480.webp
  cover-720.webp
  cover-768.webp
  cover-960.webp
  cover-1600.webp

The mapping is generated by scripts/media-paths.mjs and consumed by scripts/optimize-post-images.mjs.

_data/responsive_images.yml remains the lookup table used by Jekyll. Templates should continue asking the manifest for the preferred generated URL rather than constructing derivative paths themselves.

Generated variants are rebuildable outputs. Source images are not.

3. Article video

Writer-uploaded video never belongs in the repository.

The Writer stages video temporarily through the Netlify backend and publishes it as a GitHub Release asset under a monthly release:

writer-media-YYYY-MM

The article stores the resulting Release URL. Temporary upload chunks are deleted after publishing.

Direct external video URLs may still be embedded when appropriate, but the Writer no longer presents assets/uploads/ as a video-storage option.

Enforcement

npm run check:media

The media check verifies:

This check runs as part of Site Quality.