Skip to main content
Return to Work System.Return('/work')
Next.js Frontend UI/UX Cloudinary Framer Motion

Spilled Palette Studio: Art Gallery at 95+ Lighthouse

Aesthetic-first Next.js 14 portfolio for digital artist Aswathi Bindhu Jawahar — dynamic masonry grids, Cloudinary image optimization, and Framer Motion interactions at 95+ Lighthouse.

$ outcome

Shipped a 95+ Lighthouse gallery the artist updates herself through a single JSON file — no code changes, no developer needed.

Spilled Palette Studio: Art Gallery at 95+ Lighthouse
Date 2026
Status Completed & Operational
Lead Lead Developer & Systems Engineer
95+ Lighthouse score, desktop and mobile
2 Curated collections live at launch
1 JSON catalog file the artist edits — no code changes

$ cat stack.json

  • Next.js 14
  • Tailwind CSS
  • Framer Motion
  • Cloudinary
  • Vercel

$ timeline

2026-05 2026-05

$ session.log

# Representative output from the launch build (May 2026)
$ pnpm build
✓ Compiled successfully
✓ Generating static pages — no errors, all collection routes pre-rendered

$ npx lighthouse https://spilledpalettestudio.com --only-categories=performance --preset=desktop
Performance: 95+ (desktop and mobile)

Overview

Spilled Palette Homepage

Spilled Palette Studio is a digital art portfolio for artist Aswathi Bindhu Jawahar, designed to feel like a quiet luxury physical space. The art is the hero. The technology stays invisible.

I’m a Senior Systems Engineer who took this build to learn modern frontend properly, so I chose Next.js 14, Tailwind CSS, and Framer Motion and held myself to production numbers: 95+ Lighthouse on desktop and mobile, 2 curated collections live at launch, and a single artworks-list.json the artist edits herself. No code changes needed for new work.


1. The Problem

Digital art galleries face a unique set of technical contradictions:

  1. High visual fidelity vs. performance: the artwork files are massive, but the website must load instantly.
  2. Dynamic filtering vs. SEO: users need to filter artwork by category (Botanical, Sanctuary Series) without sacrificing search engine discoverability.
  3. Immersive UX vs. clean design: interactions should feel alive but must not distract from the subtle, minimalist aesthetic of the artwork itself.

2. Architecture

Spilled Palette Studio — Frontend Architecture

Architecture: Visitor → Vercel Edge → Next.js 14 App Router → Tailwind CSS + Framer Motion → Cloudinary CDN

2. Architecture
LayerChoiceWhy
FrameworkNext.js 14 App RouterStatic gallery routes pre-rendered; client islands only for filtering
StylingTailwind CSSCustom quiet-luxury theme: off-whites, soft charcoals, Playfair Display + Inter
MotionFramer MotionMasonry grid transitions and cross-fading category filters
MediaCloudinary CDNFormat negotiation (WebP/AVIF) + responsive srcsets at the edge
HostingVercelCI/CD per push; edge serving for the static shell

3. Implementation

Serving raw, high-resolution artwork files directly would cripple performance, so image engineering was the core build work. Original high-res .tiff and .png files are converted to WebP and AVIF based on client browser capabilities, and responsive srcsets keep mobile users from downloading 4K images.

The design language is intentionally subdued. Using Tailwind CSS, I crafted a custom theme utilizing off-whites (#FDFBF7), soft charcoals (#2C2C2C), and elegant typography pairings (Playfair Display for headings, Inter for body text).

Aesthetic About Page demonstrating the clean typography and soft color palette

Clean, sophisticated layout using Tailwind CSS

Category filtering runs instantly on the client side via Framer Motion, artwork cross-fading in and out of the viewport. No route change, no SEO cost, since every collection also exists as a static route.

Dynamic Category Filtering

Real-time artwork filtering with smooth layout animations

The full Collection grid — 98 original artworks with collection filter pills

The full Collection grid: 98 artworks, seven collections, one filter bar

The build and Lighthouse evidence is the session log above: a clean static build with all collection routes pre-rendered, and 95+ Performance on desktop and mobile measured at launch.


4. Operations

A static gallery is cheap to run. That was the point from the first commit:

  • Hosting: Vercel free tier. Static pages served from the edge, no server to babysit.
  • Media: Cloudinary free tier covers the launch catalog; format negotiation happens at the CDN, so origin bandwidth stays flat as traffic grows.
  • Ownership: the artist adds collections by appending to artworks-list.json. No routing changes, no redeploy knowledge needed beyond a git push triggering CI.
  • Monitoring: Lighthouse CI on the deploy pipeline catches regressions in image weight before they reach production.

5. Results

  • Performance: 95+ Lighthouse across desktop and mobile at launch.
  • Catalog: 2 curated collections live, with an inquiry channel per piece connecting buyers to the artist.
  • Ownership: 1 JSON file (artworks-list.json) stands between the artist and publishing new work. No code changes, no developer needed.

Figures as of May 2026.

The handoff test

The real acceptance test for this build wasn’t the Lighthouse number. It was whether the artist could publish new work without calling me, and the single artworks-list.json catalog passes it: append an entry, push, done. TIFF and PNG originals become WebP/AVIF with responsive srcsets, collection routes pre-render statically in Next.js 14, the Vercel edge serves them at 95+ on desktop and mobile. My judgment call, and one I could be wrong about: I treated performance as a design constraint from day one rather than a polish pass at the end, which meant slower early progress on the visual design the artist actually cared about. She got the gallery she wanted. She just waited longer for the first pretty screenshot than she should have.


What I’d Do Differently

One design regret: client-side filtering state lives entirely in memory, so a shared filtered URL doesn’t reproduce the view. Encoding the active collection in a query param would have made curation shareable for free.

One scope regret: I shipped no blurred-placeholder pipeline. First paint on slow connections shows layout boxes, not art. Cloudinary’s blur-up placeholders would have closed that gap for a few lines of loader config.

“The fastest gallery is the one that ships no JavaScript until the visitor asks for motion.”

Share this case: Share on X Share on LinkedIn Share on Reddit

Continue Reading

Migrating something similar?

I led this deployment end to end — scope, cutover, and guardrails. Tell me what you are running and I will reply with a migration sketch.

↑↓ navigate Tab complete Enter open Esc close View all →