WorksBlogResume
WorksBlogResumeContact
GitHub

       in Pondicherry, India

viewsContactPrivacyllm.txt

On this page

Blog

How I designed this portfolio

The references, the rules, the small details, and every library this site runs on.

Gokulakrishnan·Oct 22, 2026·4 min readviews

I rebuilt this site from an empty folder. Here's how I designed it, what I borrowed, and every library it runs on.

Where it started

I had benji.org open the whole time. One narrow column, short first-person lines, no hero, no buzzwords. It reads like a person talking.

For the components I wanted small things that make you stay a second longer: a heatmap that feels native, link previews on hover, a little life in the footer.

The content came from my old portfolio. Same facts, fewer words.

The rules I set first

Before any component, I wrote down a few rules and kept to them.

  • One column, about 580px wide, on every page.
  • Hierarchy comes from colour and weight, not from big type.
  • Every colour and every duration is a token. No one-off values.
  • Every animation has a reduced-motion fallback.
  • Nothing scrolls sideways, on any screen.

Most design decisions after that were easy. I just checked them against the list.

Type

Body text is 14px with a line height of 1.7 and slightly tight tracking (-0.01em).

On Apple devices the site uses San Francisco, the system font, so it feels like apple.com. Everywhere else it falls back to Inter. Dates and code use the system monospace. A serif italic (Newsreader) shows up only for post summaries.

Titles aren't bigger. They're medium weight. That one choice keeps the page calm.

Colour

Light mode is near-white with soft grey text for anything secondary. Dark mode is near-black, not pure black. The GitHub greens come in both versions.

There's almost no accent colour. Blue appears in two places: the verified tick and the highlighter behind "Best Paper Award". Because it's rare, it gets noticed.

Motion

I used transitions.dev as a reference for timing. Its snippets gave me consistent durations and easing, so the modal, the menus and the page slide all feel like one system.

  • Sections fade up in a short stagger when a page opens.
  • Pages slide in a few pixels with a soft blur.
  • The ⌘K menu scales in and closes faster than it opens.
  • Numbers pop in digit by digit.
  • The "Best Paper Award" highlighter draws in from left to right.

The GK logo loops like a GIF: the G spins once, then the K's arm and leg spring out and back. The browser tab icon plays the same loop. Browsers won't animate an SVG favicon, so the site redraws it on a canvas and swaps the tab icon frame by frame. The tab title types itself in too.

The small details

These took the most time and they're my favourite part.

  • Inline logos. Every company or profile in the about text has its logo in front of it. Hover one and you get a preview card: a banner for projects, an avatar for people.
  • A bunny in the footer. It's made of text characters. It sleeps with little z's at night in Pondicherry and blinks during the day.
  • Sound. Opening ⌘K, switching the theme, reacting to a post and copying a link make a soft sound. There's a toggle in the footer if you'd rather not.
  • A paper plane in the blog sidebar that flies to the section you're reading.
  • Emoji reactions on every post, with counts.

Mobile

I tested every page from 280px folding phones up to 1440px desktops.

  • On phones the nav collapses into a menu button and a search icon.
  • The blog sidebar becomes a floating pill at the bottom that shows where you are and opens the full list.
  • Dates move under titles, so long titles get the full width.
  • Every tap target is at least 32px.
  • Hover previews switch off on touch screens, where you can't hover anyway.

The stack

Here's everything the site runs on, grouped by job.

Framework

  • next (16), App Router with Cache Components, so most pages are prebuilt.
  • react (19).
  • typescript.

Styling

  • tailwindcss (v4), with design tokens as CSS variables.
  • tw-animate-css for a few utility animations.
  • next-themes for light, dark and system themes.
  • next/font to load Inter and Newsreader.

Content

  • @next/mdx, @mdx-js/loader and @mdx-js/react, so each post is an MDX file.
  • rehype-slug and github-slugger to give headings stable IDs for the sidebar.

Components

  • shadcn to set up the project and pull in components.
  • rare-ui's rail-toc (the paper-plane sidebar) and emoji-reaction (post reactions), installed through shadcn.
  • A blog grid with category filters, adapted to fit this column.
  • cmdk for the ⌘K command menu.

Motion and sound

  • motion (Framer Motion) for the reactions, the sidebar and the blog grid.
  • transitions.dev for CSS transitions and timing tokens.
  • cuelume for the interface sounds. They're generated in the browser, so there are no audio files.

Icons and logos

  • lucide-react for interface icons.
  • simple-icons for the tech stack logos and the IEEE wordmark.
  • react-apple-emojis for the reaction emoji.
  • Hand-drawn SVGs for the GK monogram, the footer bunny and the single-colour company marks.

Data

  • @upstash/redis for reaction counts, page views and contact messages.
  • Umami for cookieless analytics and the per-page view counts.
  • The public GitHub contributions API for the heatmap.
  • The contact form can also email messages through Resend, if a key is set.

What I'd tell you

Pick one reference and study why it works. Mine was a site with great writing, and I added the details I'd always wanted.

Write your rules down before you design. They save you from a hundred small arguments with yourself.

And spend time on the small stuff. Nobody remembers the grid. They remember the bunny.

Thanks for reading.

If this one landed, leave a reaction. One per person, and you can change it anytime.

Leave a reaction
← PreviousHow I design websites using AI