How I Built This Portfolio: A Developer's Journey
How I Built This Portfolio: A Developer's Journey
Building a portfolio is more than just showcasing projects—it's about telling your story. This is mine.
The Vision
I didn't want another generic developer portfolio. I wanted something that would:
- Stand out: Unique design that reflects my personality
- Perform: Blazing fast with modern tech
- Impress: Visually engaging without sacrificing usability
- Scale: Easy to update and maintain
The goal wasn't perfection from day one. It was to create a foundation I could iterate on—a living document of my growth as a developer.
The Tech Stack
After evaluating options, I settled on:
Next.js 14 (App Router)
Why? Server-side rendering for SEO, static generation for speed, and the flexibility to add server components when needed. The App Router's file-based routing made organization intuitive.
TypeScript
Type safety isn't optional for me anymore. Catching bugs at compile time > debugging runtime errors.
Tailwind CSS
Utility-first CSS let me iterate quickly. I'm not a designer, so Tailwind's constraints actually helped guide aesthetic decisions.
Framer Motion
Animations bring life to static pages. Framer Motion's declarative API made complex transitions feel manageable.
MDX for Blog
I wanted content control without building a CMS. MDX gives me the power of React components inside markdown—perfect for technical writing.
Design Philosophy
Dark Mode First
Most developers work in dark mode. Why not build for them first? The neon cyan accent (#00f3ff) against deep black creates that cybersecurity aesthetic I was going for.
Terminal Vibes
Monospace fonts, minimal UI, system-boot loading screens—subtle nods to the command line where I spend most of my day.
Motion with Purpose
Every animation serves a function: guiding attention, providing feedback, or enhancing storytelling. No animation for animation's sake.
The Challenges
1. Build Errors with Framer Motion v11
The newest version of framer-motion broke Next.js 14's production builds with cryptic errors. Solution: Downgrade to v10.16.4 and disable SWC minification. Sometimes, bleeding edge isn't worth the blood.
2. Internationalization (i18n)
Supporting English and Portuguese meant restructuring everything. I built a custom context provider for translations instead of using heavy i18n libraries. Lighter bundle, more control.
3. Blog System Without a CMS
I wanted simplicity. Built a custom MDX parser that reads files from /content/posts, extracts frontmatter, and generates static pages. Zero database, zero overhead.
4. Loading Screen Loop
The loading screen was stuck in an infinite loop because it depended on translation state before language selection. Fixed by removing that dependency and showing it pre-selection.
5. Footer Clickability
Links were unclickable in production. The particle background was overlaying the footer. Solution: Added relative z-10 to the footer component to fix stacking context.
Key Features
- Immersive 3D 404 Page: Animated particles, glitch effects, and terminal aesthetics
- Real Contact Form: Integrated EmailJS for actual email delivery
- Blog Search & Filters: Tag-based categorization with real-time search
- Bilingual Content: Full support for English and Portuguese, including blog posts
- SEO Optimized: Meta tags, Open Graph images, semantic HTML
What I Learned
Start Simple, Iterate Often
I didn't build everything at once. I shipped an MVP, got feedback (from AI assistants, in this case), and iterated. Each feature was a standalone task.
TypeScript Saves Time
Yes, it slows you down initially. But the time saved debugging runtime errors is exponential. Type safety is a gift to your future self.
Performance Matters
Users judge your site in milliseconds. I optimized images, minimized JavaScript, and leveraged Next.js's static generation wherever possible.
Design Systems > Ad-Hoc Styles
Even with Tailwind, consistency matters. I defined color tokens and spacing scales early. It paid off when making global changes.
The Deployment
Deployed on Vercel (Next.js's home turf):
- Automatic previews for every commit
- Edge caching for global performance
- Zero-config SSL
Setting up environment variables for EmailJS was the only manual step.
What's Next
This portfolio isn't done. It's a work in progress. Future ideas:
- Project video demos: Show, don't just tell
- More blog content: Deep dives into security and DevOps
- Interactive playground: Embed live code examples
Final Thoughts
Building this portfolio taught me more than any tutorial could. It forced me to make real decisions, face real bugs, and ship real code.
If you're building yours: start today. It doesn't have to be perfect. It just has to be yours.
Built with ❤️ by Rafael Sanoli. View the source on GitHub.