Most developer portfolios take a weekend. Mine took stubbornness.
Not because the tech was hard — it's a Next.js site, not a distributed system — but because I kept asking "what if it was better?" at every step. What started as a basic layout turned into something I genuinely enjoy looking at, and more importantly, something that taught me a lot about building for real users.
Here's how it went.
Starting With the Right Question
I didn't start with a framework or a color palette. I started with a question: what should someone feel when they land on my site?
Not "what should they read" — that's content. Not "what should they click" — that's UX. What should they feel?
I wanted the answer to be: "this person builds things with care." Everything else followed from that.
The Design Wasn't Designed Once
The first version was a dark mode site with bronze accents. It looked like every other developer portfolio on the internet. Moody, "professional," forgettable. I scrapped it.
The second version used a warm cream palette with vibrant orange accents. Better — it had personality. But the colors were wrong. Too muted. I went through four different cream tones before landing on #FEF0CE — a soft, warm base that's easy on the eyes for extended reading.
The lesson: good design isn't getting it right the first time. It's being honest about what isn't working and iterating until it is.
The Sun Decides Your Theme
Here's one of my favorite technical decisions. The site has a light and dark mode, but you don't toggle it — the sun does.
On page load, the browser asks for your location. Using a solar position algorithm, the site calculates the exact sunrise and sunset times at your coordinates for today's date. If it's daytime where you are, you see the light theme. If it's night, dark theme. Someone in New York at 2pm sees cream and orange. Someone in Mumbai at the same moment sees deep navy and warm amber.
There's a manual toggle if you prefer one over the other, but the default is the sky outside your window.
Building this meant implementing a real solar calculator — declination angles, hour angles, zenith corrections. It's maybe 40 lines of math that I'm unreasonably proud of.
Animations That Respect Your Time
I went through three iterations of the animation system:
Version 1: Animations play once, never again. Boring on revisit.
Version 2: Animations replay every time you scroll past. Fun the first time, infuriating by the fifth.
Version 3 (final): Animations scale with your scroll speed. Scroll slowly and deliberately? You get the full cinematic experience — word-by-word reveals, section headers sweeping from the bottom, blur-to-sharp transitions. Scrolling fast to get to the contact section? Everything appears in milliseconds. Scrolling back up? No animations at all, content is just there.
The system tracks scroll velocity as a continuous multiplier (not a binary fast/slow toggle) and feeds it into every animation component. The result is something that feels responsive to intent, not just input.
Small Things That Took Unreasonable Effort
The three dots on the project cards aren't decorative. Red advances to the next project. Green opens the GitHub repo (if one exists — it dims to 50% opacity when there's no link). Yellow... well, you should click it and find out.
The profile photo opens into a modal when tapped, but you can't long-press to save it. Four layers of prevention — preventDefault on context menu, pointer-events none on the image, webkit-touch-callout none, and draggable false. Overkill? Maybe. But it was a puzzle I enjoyed solving.
The scroll progress bar at the top is 3 pixels tall. I spent more time on those 3 pixels than I'd like to admit.
The Contact Form Problem
I needed a contact form that works without a database. Formspree handles the submissions, but I added two anti-spam layers on top:
- A honeypot field — an invisible input that bots fill out but humans never see. If it has a value, the form pretends to submit but doesn't.
- A localStorage counter — after two messages, the form locks. If someone clears their storage and sends more, they're a real person making a genuine effort to reach me, which isn't a problem I need to solve.
What I'd Do Differently
I built this as a single-file client component. All 700+ lines in one page.jsx. For a portfolio, this is fine — it's one page with one purpose. But if I were to add more interactivity (and I might), I'd split it into proper components from the start.
I also wish I'd built mobile-first instead of desktop-first. Retrofitting responsive design onto a desktop layout works, but starting with mobile constraints and expanding outward produces cleaner code.
The Stack
For anyone curious:
- Next.js 14 with App Router
- Vercel for deployment
- Satoshi for headings, Aileron for body, JetBrains Mono for code
- Formspree for the contact form
- Zero CSS frameworks, component libraries, or animation libraries
Everything is hand-rolled. Not because libraries are bad, but because a portfolio should demonstrate that you can build things, not that you can install things.
If you made it this far, thanks for reading. If you're building your own portfolio, my advice is simple: don't settle for the first version that "works." Push it until it feels like yours.
And if you want to talk about anything I built here — or anything you're building — reach out. I'd love to hear about it.