Remember that performance monitoring system I built? The one I was so proud of? Well, it turns out that was just a band-aid on a much bigger problem. Let me tell you about how my portfolio's past caught up with me.
The Origin Story
When I first built this portfolio, I had just learned web development. The only framework I knew was Angular—and an old version at that. I had no concept of maintainability, code quality, or best practices. The result? One massive HTML file, one enormous SCSS file, and one absolutely monstrous TypeScript file containing my entire website.
But here's the thing: it worked. And when something works, you keep building on it. Over the years, I kept adding features: the WebGL galaxy background, particle effects, decrypt animations, and Magic Bento hover effects. Each addition made the codebase more tangled, but the site kept looking better and better.
The Breaking Point
The performance monitor was my attempt to fix everything without addressing the root cause. It was like putting a turbocharger on a car with a cracked engine block. Sure, it helped—but the foundation was crumbling.
The real problems were deeper:
- No code splitting—users loaded everything at once
- No lazy loading—below-fold content blocked initial render
- Outdated Angular patterns with no modern optimization techniques
- An unmaintainable structure where any change risked breaking everything
- No server rendering, resulting in poor SEO and a slow initial paint
The Decision
I knew what I needed: a complete rewrite. Not a refactor. Not an upgrade. A full, ground-up rebuild using modern best practices. The choice of framework was easy: Next.js 15 with React 19, server components, the App Router, and built-in optimizations.
The Migration Journey
- Component architecture. Instead of one monolithic file, I broke everything into focused components. Each section became its own module with clear responsibilities.
- Server Components. Static content renders on the server and only interactive parts hydrate. The Hero shell renders on the server; the decrypt animation hydrates on the client.
- Dynamic imports. Below-fold sections are lazy loaded with
next/dynamic. Users see the hero immediately while the rest loads in the background. - Porting the WebGL. The GLSL shaders translated directly, but the React lifecycle required careful handling of context creation, cleanup, and resizing.
- Asset optimization. PNGs became WebP assets and images moved to
next/imagefor automatic optimization and smaller payloads.
The Results
The new portfolio is everything the old one couldn't be:
- Maintainable: a clean, focused component structure
- Fast: server-rendered, lazy-loaded, and optimized
- Modern: built on Next.js and React
- SEO-ready: server rendering, metadata, and a sitemap
- Smooth: compositor-friendly animation and delegated events
And the best part? That performance monitor I was so proud of? I removed it entirely. When your foundation is solid, you don't need band-aids.
Sometimes the right answer isn't to fix what's broken—it's to build something better.