All Lab Projects
Mayordomo Espejo Portfolio logo

Mayordomo Espejo Portfolio

Personal portfolio built with Next.js 16, Tailwind CSS and Framer Motion

2026Next.js 16React 19TypeScriptTailwind CSSFramer Motionnext-themespnpm

What I Built

  • Next.js 16 App Router with generateStaticParams pre-rendering all project and lab detail pages at build time — zero server-side runtime required in production
  • Custom locale context exposing a t() getter typed against a single translations.ts constant — no external i18n library, locale persisted to localStorage with no flash on load
  • Framer Motion entrance animations defined as reusable variant objects in lib/motion.ts; stagger delays composed per-section without repeating animation configuration
  • Dark / light mode with next-themes: system preference honoured on first render, user override stored in localStorage, colour tokens applied via CSS custom properties
  • Infinite marquee built with CSS @keyframes translateX(-50%) on a doubled item list; animation-play-state: paused on hover, animation disabled entirely under prefers-reduced-motion
  • Responsive layout with Tailwind CSS and centralised design tokens; no custom CSS outside of the marquee keyframes and a handful of global resets

How It Works

  1. 1The root layout wraps the tree in ThemeProvider and LocaleProvider; locale is resolved from localStorage on the client, falling back to the browser language.
  2. 2Project and lab detail pages are statically generated from typed TypeScript data modules — adding a new project is a single data entry with no routing changes needed.
  3. 3Framer motion variants in lib/motion.ts are spread onto motion.div elements; each section adds a stagger delay offset to create a sequenced reveal.
  4. 4The marquee duplicates the items array before rendering so the CSS loop appears seamless regardless of how many cards are in the list.
  5. 5Translations are plain objects keyed by locale; the t() function does a single property lookup and falls back to an empty string for missing keys.