Skip to content
shotsbybrookss

Colophon

I designed and built this site myself. The code is public on GitHub.

Numbers

Photos published
178
Image derivatives
1768
Bytes saved by pipeline
3.68 GB
Build time
5.1 s
Pages prerendered
18
Lighthouse performance
92
Lighthouse accessibility
100
Lighthouse best practices
100
Lighthouse SEO
100

Last measured 2026-10-15

Stack

Next.js 16 + TypeScript
Every page prerendered
Tailwind CSS 4
Styling
Three.js + React Three Fiber
The globe
Lenis
Smooth scrolling
sharp + exifr
Image encoding and EXIF, plus a Fuji maker-note parser
Vercel Blob
Image hosting
Vitest + GitHub Actions
Tests and CI

Image pipeline

  1. 01

    Originals

    content/collections/*/photos (git-ignored)

  2. 02

    Read EXIF

    exifr + Fuji maker-note parser

  3. 03

    Derivatives

    sharp: AVIF + WebP at 5 widths, max 2560px

  4. 04

    Placeholder

    thumbhash + dominant colour

  5. 05

    Privacy

    metadata stripped, GPS rounded to city

  6. 06

    Upload

    Vercel Blob, immutable cache

  7. 07

    Manifest

    content/manifest.json (committed)

  8. 08

    Static build

    Next.js prerenders every page

npm run ingest

Code

Reads the film simulation from Fujifilm's maker note.src/lib/exif/fuji.ts
/** Returns the film simulation recorded in a Fuji maker note, or null if unknown. */
export function parseFilmSim(note: Uint8Array | undefined | null): FilmSim | null {
  if (!note) return null;
  const tags = readFujiTags(note);

  const saturation = tags.get(TAG_SATURATION);
  if (saturation !== undefined) {
    const mono = monochromeFromSaturation(saturation);
    if (mono) return mono;
  }

  const mode = tags.get(TAG_FILM_MODE);
  if (mode !== undefined) return FILM_MODES[mode] ?? null;

  // Colour shots with no FilmMode tag were taken on the default, Provia.
  return saturation !== undefined ? "Provia" : null;
}
Finds the rotation that turns any city to face the camera.src/components/globe/geo3d.ts
/**
 * The globe rotation (Euler XYZ) that puts a lat/lng dead centre, north up.
 * First spin around Y to bring the point onto the YZ plane, then tilt
 * around X by the latitude to bring it level with the camera.
 */
export function rotationToFace(lat: number, lng: number): { x: number; y: number }
Draws each travel arc with a single uniform.src/components/globe/shaders.ts
export const arcFragment = /* glsl */ `
  uniform vec3 uColor;
  uniform float uDraw;
  uniform float uOpacity;
  uniform float uBase;
  varying float vT;
  void main() {
    float drawn = step(vT, uDraw);
    float head = smoothstep(uDraw - 0.12, uDraw, vT) * drawn * step(uDraw, 0.999);
    float alpha = mix(uBase, 0.9 + head * 0.1, drawn);
    gl_FragColor = vec4(uColor + head * 0.5, alpha * uOpacity);
  }
`;

Credits

Inter Tight
Rasmus Andersson, SIL Open Font License
Geist, Geist Mono
Vercel, SIL Open Font License
Land data
Natural Earth (public domain) via world-atlas
Libraries
Next.js, React, three.js, React Three Fiber, GSAP, Lenis, sharp, exifr, thumbhash, Shiki, Tailwind CSS