Back to Blog
Astro React Tailwind CSS TypeScript Web Development

Building This Website: From Blank Canvas to Production

How I rebuilt my portfolio from a Hugo template into a hand-crafted Astro site with animated SVG diagrams, a custom OKLCH design system, and React islands.

What started as “I should probably have a website” turned into something much bigger. I’d been using a Hugo template for years and fighting it every time I wanted to change anything. At some point I decided to just start fresh and build exactly what I wanted.

This is a look at how it came together — the stack, the design choices, and what I learned along the way.

At a glance

Astro 5 static generation · React 19 islands for interactivity · Tailwind CSS v4 with OKLCH colors · Framer Motion animations · MDX content · Vercel hosting · Built with Windsurf (Cascade) as my AI development environment.


The Starting Point

I had a Hugo site. It worked, technically. But every small change meant digging through someone else’s Go template logic and wondering why things broke. I wanted something where I had full control — the animations, the colors, the way content flows.

The goals were straightforward:

  • Full creative control — every interaction and visual detail, my call
  • Fast by default — static HTML, no framework tax on page load
  • Shows how I think — not just a CV with a dark background
  • Easy to maintain — write in Markdown, push to deploy

Architecture

The idea is simple enough: generate static HTML at build time, only load JavaScript where you actually need it.

architecture
Static Generation
Astro 5
Pre-rendered HTML at build time
Interactive Islands
React 19
Hydrate only what needs JS
Design Tokens
Tailwind v4 + OKLCH
Perceptually uniform palette
Vercel Edge Network
Global CDN · Auto SSL · Deploy on push

Astro’s island architecture is what makes this practical. Pages arrive as plain HTML — no framework runtime, no hydration waterfall. React only shows up for the parts that genuinely need it: the portfolio diagrams, blog tag filtering, the mobile menu.

Everything else is zero-JS static HTML. It’s a good trade-off.


Tech Stack

A
Astro 5
Framework

Content collections with Zod schemas, MDX rendering, automatic sitemap and RSS generation, file-based routing, and ClientRouter for smooth page transitions.

R
React 19
Interactive Islands

Animated SVG diagrams, portfolio hub, blog tag filtering, and mobile navigation. Each hydrated on demand via client:visible to keep the initial bundle small.

T
Tailwind CSS v4
Design System

The new @theme directive with OKLCH colors, custom animation easings, elevation tokens, and a typography scale. All defined as CSS custom properties.

TS
TypeScript
Language

Strict mode everywhere. Every prop, every utility, every component is typed. Biome handles linting and formatting with zero config files to maintain.

Framer MotionMDXLucide IconspnpmBiomeVercel

Design System

I didn’t want the typical dark-mode-with-green-terminal-accents look. I landed on what I call “Slate + Electric Blue” — cool neutral backgrounds with one high-chroma accent. Confident without being loud.

Color Palette

Background
oklch(0.13 0.005 260)
Primary
oklch(0.65 0.20 260)
Accent
oklch(0.70 0.08 290)
Card
oklch(0.17 0.005 260)

The entire palette uses the OKLCH color space. Unlike HSL, it’s perceptually uniform. A lightness of 0.65 looks equally bright at any hue, which means contrast ratios are predictable and the blue accent never clashes with the lavender secondary.

Typography

Aa
Satoshi
Headings and navigation. Geometric, modern, confident
Aa
Plus Jakarta Sans
Body text and UI. Humanist, readable, warm
Aa
JetBrains Mono
Code, tags, and metadata. Technical, precise

The Portfolio: Interactive Expertise Diagrams

The portfolio is probably my favorite part. Instead of listing projects as cards, I built animated SVG diagrams for each expertise area — rendered as React islands with Framer Motion.

01Data Engineering
02Analytics & BI
03Machine Learning
04Web Development
05Automation

Each diagram animates in on scroll with flowing particles on subtle loops. Just enough motion to feel alive without being distracting. Getting the balance right took more iteration than anything else on the site.

See them in action on the portfolio page.


Performance

7
Pages
<3s
Build time
0
Layout shift
100
Lighthouse SEO

What keeps it fast:

  • Static HTML by default — pages render before any JS executes
  • client:visible on below-fold islands — JS only loads when you scroll to it
  • Font preconnect hints — avoids render-blocking font loads
  • Cookieless analytics via Vercel, injected at the edge with zero bundle cost
  • ClientRouter for smooth page transitions after first load

Lessons Learned

Start with the design system, not the pages

Defining the color palette, typography, spacing scale, and animation tokens first meant every component built afterwards was automatically consistent. This was the single highest-leverage decision of the entire project.

Islands architecture changes how you think

Coming from React SPAs, opting in to JavaScript per-component felt counterintuitive. But for a content-heavy site, the performance difference is night and day. Most pages ship zero JS.

One theme, done well

Supporting light and dark themes doubles the design work. For a portfolio that leans into data-visualization aesthetics, dark mode is the natural choice. Committing to one theme and doing it properly was the right call.

AI speeds things up, but taste is still yours

I built this using Windsurf with Cascade as my primary development environment. It’s remarkably effective for scaffolding components and refactoring across files. But the visual refinements (spacing, timing, hierarchy) always came down to manual iteration.


Astro · React · Tailwind · TypeScript · Framer Motion · Vercel