Case study
Milk & Henny Media
Work on a personal archive for travel, writing, parties, and the photos I take on digital and film cameras, built so memory can be published and shared without becoming admin.
Tension
The product problem beneath the work.
I travel, write, meet people, and take a lot of photos. After parties and trips, the same problem repeats: people want their photos, large batches are awkward to send, and temporary file-sharing tools become expensive or disposable. Milk & Henny turns that loop into an owned archive with optimized previews, filters, sorting, and HD downloads.
Threads
Three contracts behind the archive surface.
Owned
What I was responsible for, and what it changed.
| Thread | Work | Signal |
|---|---|---|
| Storage model | Separated permanent albums, words content, reusable assets, and private share surfaces across git manifests, KV metadata, and R2 object paths. | The site can hold thoughts and photo archives in one owned place while keeping large media cheap to store and serve. |
| Image pipeline | Built processing for thumbnails, full-size variants, originals, Open Graph images, focal points, rotation handling, filtering, sorting, and face-aware crops. | Large photo sets get fast previews, sensible crops, and HD downloads from Cloudflare R2/CDN instead of expensive one-off sharing tools. |
| Publishing surface | Built the unified words model with markdown bodies in R2, KV metadata, visibility controls, signed share links, and reusable media references. | Writing and photography can live together without sacrificing access control, editorial presentation, or storage clarity. |
Mechanism
The technical layers behind those responsibilities.
| Layer | Detail |
|---|---|
| Album manifests | Permanent galleries use JSON manifests in git with R2-backed media, giving public album pages static speed and low runtime cost. |
| Words storage | Words metadata lives in KV while markdown bodies and media live in R2 under stable paths. |
| Variants | Images produce thumbnail, full, original, and social-preview variants; GIFs, video, audio, documents, and archives follow file-appropriate paths. |
| Focal points | ONNX face detection or Sharp saliency computes crop anchors, with manual overrides for album-level editorial control. |
| Social previews | Album and photo Open Graph images are pre-built as 1200x630 JPGs in R2 to avoid runtime image generation on normal shares. |
| Visibility | Public and unlisted words render through the editorial route; private words resolve through vault links with share-token and optional PIN gates. |
| Reusable media | Word-specific media and shared assets use explicit R2 prefixes so markdown can reference files without duplicating uploads. |
Shape
How media becomes browsable and shareable.
- Content enters through a route that matches its lifecycle: album, word, shared asset, or private entry.
- Photo uploads generate fast previews, HD variants, and social-preview assets before anyone needs them.
- Filtering, sorting, focal points, and crops help people find and recognize the photos they came for.
- Markdown references resolve against explicit R2 media paths and reusable asset paths.
- Visibility rules decide whether the result is public, unlisted, or privately shareable.
Reflection
What the project clarified about owning the archive.
The real product is relief: a place to put the writing, the camera rolls, the party albums, and the people who ask for them later. The storage model matters because it lets the archive feel generous without becoming expensive.