Back to Projects

Building a Dual-Personality Portfolio

Architecture & best practices for creating a unified portfolio that presents both professional expertise and personal identity

Next.js 15React 19Tailwind CSS 4

The Vision

Most developer portfolios fall into one of two categories: sterile professional pages that list skills and projects, or personal blogs that bury technical competence under lifestyle content. I wanted neither. Instead, I set out to build a single application that presents two distinct experiences—a professional portfolio and a personal space—unified under one roof.

The goal was simplicity. Visitors should immediately find what they're looking for without wading through walls of text. A recruiter lands on the professional side and sees skills, experience, and projects. Someone curious about the human behind the code explores adventures, photography, and personal interests. Same application, different journeys.

Architecture Philosophy: One App, Two Identities

The foundation of this portfolio rests on a single architectural decision: route groups.

Next.js App Router enables organizing routes into logical groups without affecting the URL structure. This means the professional portfolio lives at the root path while personal content lives under its own path—yet both share core infrastructure like layouts, components, and utilities.

Why this pattern works:

  • Shared codebase, distinct experiences: Common components adapt based on context
  • Independent layouts: Each section maintains its own visual identity
  • Clean URL structure: No awkward nested paths cluttering navigation

Theming System: CSS Custom Properties by Choice

The portfolio supports three distinct visual modes: professional light, professional dark, and an adventure theme for personal content. Rather than reaching for a CSS-in-JS library or Tailwind's built-in dark mode, I implemented theming through CSS custom properties.

Why this approach? Control.

CSS custom properties allow runtime theme switching without JavaScript re-renders. When a user toggles between light and dark mode, only CSS values change—no component tree updates, no React context consumers re-rendering unnecessarily. This translates to instant, flicker-free theme transitions.

--professional-primary: #3B82F6;
--adventure-primary: #0E7490;

For engineers building similar systems, the key insight is: let CSS do what CSS does best. Reserve JavaScript for state management and logic, not runtime style calculations.

Navigation: Intersection Observer Over Scroll Events

Single-page portfolio sections often highlight the current section in navigation as users scroll. The naive approach—attaching scroll event listeners—creates performance problems. Scroll events fire rapidly, potentially dozens of times per second.

This portfolio uses the Intersection Observer API instead. Rather than constantly calculating scroll position, observers watch for when sections enter or exit the viewport. Navigation updates only when visibility actually changes.

Implementation refinements:

  • Threshold tuning: Observers trigger based on section visibility
  • Root margin configuration: Accounts for fixed headers
  • Scroll-to-section with offset: Calculates header height automatically

Gallery Design: Intentional Layout, Optimized Delivery

The personal section features a photo gallery that required careful attention to both visual design and performance.

Layout Strategy

The gallery uses a CSS multi-column layout that creates a Pinterest-style masonry effect. Unlike CSS Grid (which excels at defined row/column structures), multi-column layout naturally flows content into available vertical space.

Image Optimization

  • Format selection: Modern formats with fallbacks
  • Compression tuning: Balance between size and quality
  • Responsive sizing: Different resolutions per viewport
  • Lazy loading: Images load as users scroll

Typography: Local Fonts, Full Control

Web fonts typically load from external CDNs like Google Fonts. This portfolio hosts fonts locally using IBM Plex Sans, a variable font that provides multiple weights from a single file.

Local hosting advantages:

  • No external dependencies: Site loads even if third-party services are unavailable
  • Privacy: No requests to external tracking servers
  • Performance control: Font loading strategy entirely under control

Deployment: Docker on Google Cloud Run

Deployment follows containerization principles using Docker, hosted on Google Cloud Run. This choice reflects both technical preferences and practical constraints:

  • Docker familiarity: Consistent environments from development to production
  • Cloud Run simplicity: Serverless container hosting scales automatically
  • Cost efficiency: Free tier handles portfolio traffic

Key Takeaways for Your Portfolio

Building this portfolio reinforced several principles worth adopting:

Simplicity serves users

Every architectural decision should ask: does this help visitors find what they need? Clever implementations that obscure content fail the fundamental purpose.

Separation enables flexibility

Route groups, semantic CSS properties, and component composition all share a common theme: separate concerns so they can evolve independently.

Performance is a feature

Image optimization, efficient theming, and smart navigation aren't premature optimization—they're baseline expectations for modern web experiences.

Technology choices should be intentional

Using Next.js 15 and Tailwind CSS 4 wasn't about chasing trends; it was about building with tools that represent current best practices.

Let the platform do the work

CSS for styling, Intersection Observer for visibility detection, Next.js for routing and image optimization. Fighting platform capabilities wastes effort; leveraging them multiplies impact.

What's Next

This portfolio continues evolving. Planned improvements include enhanced accessibility auditing, expanded project case studies, and refinements based on real-world usage patterns. The architecture supports these additions without requiring fundamental restructuring—a testament to thoughtful initial design.

For engineers building their own portfolios: start with clarity about what you want to communicate, then choose architecture that serves that vision. Technical sophistication should amplify your message, not obscure it.