Under the Hood

This site is an experiment in delivering HDR photographs as close to the original scene as current technology allows. It's a work in progress — documented here so others can build on what I've figured out so far.


Philosophy

Until recently, no screen could display the full dynamic range a camera sensor captures. The workaround was tone mapping — software that compressed a wide luminance range into the narrow band a display could reproduce. The results were often kitschy: oversaturated skies, glowing halos, the "HDR photography" look that was really just SDR with the contrast cranked up.

True HDR is different. Modern displays can actually produce the luminance range the scene contained. But backwards compatibility is a challenge. Now with JPEG-XL gain maps, a single file carries both an SDR base layer and HDR enhancement data — the browser and display do the rest natively. No tone mapping artifacts. No software interpretation. Just the scene as the camera saw it, on a screen that can finally show it.

This site is built around that idea. Every photograph is mastered in JPEG-XL with full HDR gain maps, and the pipeline is designed to preserve that data end-to-end — no external CDN, no lossy re-encoding. A standard JPEG fallback is generated alongside each image for browsers that don't support JPEG-XL yet — but I'll be the first to admit the SDR versions are a pale shadow of the real thing. That's the whole point: HDR isn't a nice-to-have here, it's the photograph.


Image Pipeline

Each photograph is exported from Lightroom as two files: a JPEG-XL master with an HDR gain map, and a JPEG companion for SDR fallback. Both are processed through the same pipeline to generate responsive derivatives.

JXL →
djxl decode to PNG Sharp resize cjxl re-encode HDR derivatives
JPEG →
Sharp resize SDR derivatives

The JXL path uses libjxl — the reference JPEG-XL codec — to decode the master into a lossless PNG intermediate, which Sharp resizes at each breakpoint, then cjxl re-encodes back to JPEG-XL. HDR metadata survives the entire round-trip. The JPEG path is simpler: Sharp handles the resize directly.

Five derivative sizes are generated per image (400, 800, 1200, 1800, 2400 pixels wide) for both formats. The browser picks the right one via <picture> and srcset — JXL first, JPEG as fallback.


Tech Stack

Framework
Astro — mostly static, with minimal SSR for private content
Hosting
Cloudflare Workers — edge-deployed, incremental uploads via Wrangler
Image codec
libjxl — reference JPEG-XL encoder/decoder
Image processing
Sharp — resize intermediate for derivative generation
Maps
MapLibre GL JS — open-source, self-hosted tiles
Transitions
View Transitions API — native cross-document morphing