eratic / docs / 05-media.md
552 words

Photographs, video, and the IPFS question

Two different kinds of file, handled two different ways, for one reason: git is excellent at versioning things you might edit and terrible at storing things you never will.

Photographs — in git

Live beside the entry that uses them:

sites/blog/src/content/photos/2026/harbour.mdx
sites/blog/src/content/photos/2026/images/harbour-01.jpg

referenced as ./images/harbour-01.jpg.

Astro takes it from there: AVIF and WebP at 480/800/1200/1600 px wide, a srcset so a phone downloads a phone-sized file, and all metadata stripped from the output. A 22 kB source becomes a 3 kB file at phone size.

Commit the full-resolution export. A few hundred photographs is a repository of a few hundred megabytes, which is fine for years. If it ever stops being fine, move older sets to the server the same way video works — the components do not care where a file came from.

Before committing, make sure there is no GPS in them. npm run build enforces this and will refuse to proceed. See docs/06-privacy.md.

Video — on the server

Video does not go in git. A single two-minute clip can outweigh every word you will write in a year, and unlike a photo it is never edited in place.

# upload
rsync -av --progress -e "ssh -i ~/.ssh/id_ed25519_eratic" \
  harbour.mp4 harbour.jpg \
  root@178.104.116.235:/opt/web/sites/eratic/media/video/2026/

then reference it by path:

<Video
  src="video/2026/harbour.mp4"
  poster="video/2026/harbour.jpg"
  alt="Boats moving in a harbour at dusk"
  caption="Ten minutes before the light arrived."
/>

Served from media.eratic.ro, same server, no third party. preload="metadata" means a page with five clips downloads five headers, not five videos.

Use ambient for a short silent loop that should behave like a moving photograph — no controls, autoplay, muted.

Encoding

H.264 in MP4 plays everywhere. Sensible defaults:

ffmpeg -i source.mov -vf "scale='min(1600,iw)':-2" \
  -c:v libx264 -crf 23 -preset slow -pix_fmt yuv420p \
  -c:a aac -b:a 128k -movflags +faststart harbour.mp4

ffmpeg -i harbour.mp4 -vframes 1 -q:v 3 harbour.jpg   # poster frame

+faststart matters — without it the browser downloads the whole file before the first frame appears.

/opt/web/sites/eratic/media/ is the only copy of these files. Keep your originals somewhere else too.

IPFS, when ird ships it

The media layer was built with this in mind, so the migration is a configuration change rather than a rewrite.

Every media reference goes through mediaUrl() in packages/core/src/config.ts, which understands three forms:

video/2026/harbour.mp4   → https://media.eratic.ro/video/2026/harbour.mp4
ipfs://bafy…             → {MEDIA.ipfsGateway}/bafy…
https://…                → unchanged

To move to IPFS:

  1. Set the gateway in packages/core/src/config.ts: ts export const MEDIA = { base: 'https://media.eratic.ro', ipfsGateway: 'https://ipfs.eratic.ro/ipfs', };
  2. Pin a file, then change that one reference from video/2026/harbour.mp4 to ipfs://bafy….
  3. Add the gateway origin to media-src and img-src in the CSP in deploy/eratic.caddy, or the browser will block it — which is the CSP doing its job.

Files migrate one at a time. Both forms resolve through the same function, so there is no flag day and no moment where half the site is broken. If a gateway turns out to be slow, change references back.

The one thing to think about before committing to it: a public gateway sees which content-addressed blocks a reader requests, which is a different privacy posture from a server that keeps no logs. Running your own gateway on the same box keeps the current guarantees.

static mirror of HEAD · about · clone: git clone https://git.makefuture.ro/eratic.git