Skip to content
$ ash_
All work

Lumerrant

→ 20 MB uploads that never pass through the app server

Portfolio site for a Melbourne photography and film studio: full-resolution uploads go straight from the browser to storage, and sharp resizes them before they reach the gallery.

Problem

A Melbourne photography and film studio needed a site it could update itself: full-resolution photos in, a fast gallery out, and enquiries straight to its inbox. The key decision was where the image bytes travel.

My Contribution

I built it solo:

  • Direct browser-to-Blob uploads of JPEG and PNG files up to 20 MB
  • A sharp pipeline that turns each original into a gallery-ready image
  • A photo gallery with a lightbox, and a looping video on the home page
  • A contact form that sends enquiries through Resend

Architecture

The browser gets an upload token from a route handler, limited to JPEG and PNG up to 20 MB, then sends the file straight to private Vercel Blob storage.

A server action then reads the raw file and runs sharp: EXIF auto-rotate, fit inside 2,400px without enlarging, and mozjpeg at quality 82. It stores the result, appends it to the gallery manifest, deletes the raw upload and revalidates the work page.

There's no database. The photo list is a JSON manifest in Blob. Photos stay private and are served through a route with a one-year immutable cache header.

The contact form is a server action that validates name, email and message length, silently drops bots through a honeypot field, and sends through Resend with reply-to set to the sender, so the studio answers straight from its inbox.

Outcomes

Live at lumerrant.com. New work goes from camera file to a resized, compressed gallery image in one upload.

Learnings

Keeping large files off the app server, and the gallery in a manifest instead of a database, kept the moving parts to two services: Blob and Resend.