Skip to content
Thai · Portfolio000
THAI
← Hub / Dev / patine-archive

Patine Archive

YEAR
2026
ROLE
Designer & Developer
STACK
Next.js 16 · React 19 · TypeScript · Tailwind CSS · MDX · anime.js
LIVE
Visit ↗
Patine Archive — hero

Patine is an editorial wiki for youngtimer cars — the ones that gain value as they age, driven as much as they are admired. It borrows the look of specialist car magazines and the rigour of a manufacturer spec sheet, across a collection of fourteen cars of character: the MX-5 NA, S2000, Corvette C5 and many more. Each gets a fourteen-section sheet — from historical context to buyer's guide, by way of limited editions, the current market and preparation levels.

The challenge

Fit rich editorial writing and a repeatable structure into the same architecture — no CMS, no backend, no compromise on visual quality. The answer was to separate the data from the editorial voice. Every car ships as two files: a typed .ts describing versions, specs, colours, prices, hotspots and market stats; an .mdx carrying the history, the call-outs, the buying checklists and the tuning advice. The page itself is purely structural — it composes the two streams side by side.

Stack

  • Framework — Next.js 16.2.6 (App Router, Turbopack, React Server Components by default)
  • Language — TypeScript (strict), React 19.2
  • Styling — Tailwind CSS with a custom bone / ink / accent palette and three type families (Instrument Serif, JetBrains Mono, Inter)
  • Content — MDX (@next/mdx, next-mdx-remote/rsc) with a custom section-splitting loader
  • i18nnext-intl v4 (FR, with the infrastructure kept for later locales)
  • Animation — anime.js through three custom hooks, with prefers-reduced-motion honoured everywhere
  • 3D — Sketchfab embeds plus a custom viewer with clickable captions
  • Deployment — Vercel (static build with ISR, Vercel Analytics)

Architecture highlights

Colour is data, not styling. Each car carries its accent in its TypeScript file (accent: "#1A3F8E" for the STi in World Rally Blue). The page sets that value as a CSS variable on the root <article>, and the whole sheet inherits it — borders, links, animations, count-ups. No prop drilling, no theme provider.

MDX, section by section. A homemade loader splits each .mdx file on {/* SECTION: id */} markers and exposes every section as a pluggable component, slotted at a precise place between the data blocks.

The component map is the design system. The MDX mapping — editorial headings, accented emphasis, <Lede>, <Callout>, <Checklist>, <ModCard> — is, on its own, the narrative design system.

One animation vocabulary. A single easing (easeOutCubic), a shared cadence (60–120 ms stagger, 400–700 ms duration) and three reusable hooks (useScrollReveal, useCountUp, useTilt). Every component speaks the same motion language.

Results

  • 13 car sheets built on one architecture, each with its own visual identity
  • Type-safe end to end — from the registry down to the component
  • Fast — static site, lazy-loaded sections, on-demand Sketchfab viewer, loading skeletons
  • Accessibleprefers-reduced-motion on 100% of animations, WCAG-checked contrast, semantic HTML
  • Migrated Next.js 15 → 16 (Server Components, Turbopack, async APIs, proxy.ts) with no regressions