How I built my personal website

Samir Saqer / March 8, 2025

NextJsWeb Development

Look, I'll be honest - building a personal portfolio is one of those things every developer says they'll do "eventually." For me, that eventually finally came, and I'm pretty happy with what I ended up creating.

Why even bother?

I wanted something that was actually me. Not just another clean, minimal portfolio with project cards and a contact form. Don't get me wrong, those are great, but I wanted to build something a bit more playful. Something that would make visitors stick around for more than 30 seconds.

The tech stack

I went with Next.js (App Router) because, well, it just makes sense in 2025. Server components, built-in routing, and the developer experience is honestly pretty smooth. Combined that with:

  • TypeScript - because I like knowing what my props are supposed to be
  • Tailwind CSS - for styling without the stylesheet chaos
  • Framer Motion - for those buttery smooth animations
  • Three.js - for that 3D interactive magic
  • GSAP - for smooth, performant animations
  • React - obviously

Motion design: Making everything feel alive

I'm kind of obsessed with animations. Not the flashy, look-at-me kind, but the subtle ones that make a site feel premium and thoughtful.

Text animations that breathe

Throughout the site, text doesn't just pop in - it flows. I used Framer Motion to create staggered fade-in animations for headings and paragraphs. Each line of text animates in sequence with a slight delay, creating this cascading effect that guides your eye down the page naturally.

TypeScript
// Simple but effective
const textVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { 
    opacity: 1, 
    y: 0,
    transition: { duration: 0.6, ease: "easeOut" }
  }
};

The hero section on the homepage? Those words fade in one by one with a subtle upward motion. It's all about making the entrance feel intentional, not accidental.

Page transitions that connect the experience

Here's something that bugs me about a lot of Next.js sites - you click a link and bam, the new page just appears. No continuity, no flow. I wanted something smoother. Using Framer Motion's AnimatePresence, I created fade and slide transitions between pages. When you navigate, the current page gently fades out while the new page slides in from the right. It creates this seamless flow that keeps you engaged.

Micro-interactions everywhere

The score counter in the system monitor? It doesn't just appear when you start a game - it slides in from the right with a fade. When you hover over project cards, they lift slightly with a shadow transition. Links have a subtle underline animation. Navigation items fade and shift on hover.

These aren't things people consciously notice, but they feel them. That's the goal. The site should feel responsive and alive, like it's reacting to your presence.

The interactive photo: WebGL meets personality

One of my favorite parts of the site is the interactive photo on the homepage. Instead of just dropping in a static image, I wanted something that felt alive and responsive.

I used Three.js to render my photo on a 3D plane with custom GLSL shaders. Here's what makes it special:

It follows your cursor. Move your mouse around, and the image subtly rotates and shifts position, creating this engaging 3D effect. The plane tilts on both X and Y axes based on your cursor position, making it feel like the photo is actually tracking you.

The hover effect is wild. When you hover over the image, a custom shader kicks in that creates this chromatic aberration effect - you know, that RGB split you see in glitch art. The shader also applies a zoom distortion that radiates from your cursor position, using an exponential easing function for that smooth, organic feel.

TypeScript
// The magic happens in the fragment shader
float hoverLevel = exponentialInOut(min(1., (distance(vec2(.5), uv) * uHover) + uHover));
uv *= 1. - zoomLevel * hoverLevel;

It scales dynamically. The entire plane subtly scales based on your vertical mouse position. It's a tiny detail (0.05% scale change), but these micro-interactions add up to make the experience feel polished.

The technical challenge was getting the aspect ratio right across different screen sizes and making sure the image didn't look stretched. I had to calculate the proper UV mapping in the shader to maintain the image proportions while allowing for the distortion effects.

Plus, using GSAP for the animations instead of raw Three.js transforms gave me that buttery smooth 60fps performance with minimal effort. The lerping (linear interpolation) makes every movement feel natural, never jarring.

The fun part: Making it interactive

Here's where I got a bit carried away (in a good way). I built this retro-style system monitor component with a dot matrix display. It shows actual system metrics, but here's the kicker - there's a hidden Konami Code easter egg that unlocks mini-games.

Yeah, you read that right. I put Snake in my portfolio.

The technical challenge was fun: I had to create a custom rendering system that could handle different "scenes" - from displaying CPU metrics to running game logic - all within the same canvas-like component. I built a SceneManager to handle switching between different renderers, and used a circular buffer to efficiently track things like the Konami Code input sequence.

TypeScript
// The backbone of the whole system
const { sceneManager, activeRenderer } = useSceneManager({
  metrics,
  dotMatrixDisplayRef,
  containerRef,
  onScoreChange: setScore,
  onGameEnd: handleGameEnd,
  onGameSelect: handleGameSelect,
});

Things I learned the hard way

Animation performance: My first version of the dot matrix display was... let's say "choppy." Turns out, animating individual DOM elements at 60fps isn't the best idea. I ended up optimizing the render cycle and being smarter about what actually needs to re-render.

Focus management: Making the games keyboard-accessible while also working with the rest of the site's navigation was trickier than expected. I had to properly manage focus states and clean up event listeners to avoid memory leaks.

Shader debugging: Writing GLSL shaders is both fun and frustrating. There's no console.log in shader land, so debugging visual artifacts meant a lot of trial and error with color channels and UV coordinates.

Mobile responsiveness: Those games? They're desktop-only. I could've spent weeks making touch controls work properly, but sometimes you gotta draw a line. The Konami Code hint only shows on larger screens for that reason.

The details matter

I'm a big believer in the small touches. The score counter that slides in when you start a game. The smooth opacity transition when the display initializes. The way the container gets a subtle outline when focused. The photo that reacts to your every move. None of this is strictly necessary, but it makes the experience feel polished.

Even the footer carries intention. I wanted to close the site with something that reflects how I actually think about development:

Progress isn't a goal - it's a constant. Learning is the foundation of every solution, and the most rewarding pursuit I know.

It's not just a nice quote to fill space. It's genuinely how I approach building things. Every project teaches you something new, every bug is a lesson, and that continuous learning loop is what makes this work fulfilling. I wanted visitors to leave with that mindset too.

If you're building your own

My advice: Don't overthink it. Your portfolio doesn't need to be revolutionary. It just needs to be you. Whether that's minimal and clean, or chaotic and game-filled like mine, make something you're excited to show people.

And hey, if you want to hide an easter egg in there, I won't tell anyone.


Credits & Inspiration

Building in public means learning from others who've shared their work. Huge thanks to:

  • Hamed Bahram - His open-source portfolio project was an incredible learning resource and starting point for my own site. Seriously, check out his work.

  • Marijana Pavlinić - The Konami Code easter egg and dot matrix system bar concept came from her incredibly creative portfolio. The moment I saw it, I knew I had to build my own version. Such a brilliant idea!

  • Fontshare - For the Array font that ties the whole design together.

One of the best parts of web development is how much we can learn and build upon each other's ideas. If you're inspired by something, make it your own and share it forward.


Hint: ← → ← → s

Curious? There’s a hidden shortcut if you know the Konami Code..