🪴Sapling

Colophon

tended 1 month ago

#architecture#meta

Why This Page Exists

Most portfolios show what was built. This page explains why each technical decision was made — and what was traded away. Every choice here is a deliberate constraint, not a default.

This site is a digital garden — an interconnected knowledge graph, not a static portfolio. The architecture reflects that philosophy: everything is linked, everything grows, and every page knows what references it.

Architectural Decisions

Next.js 16 + Static Export

Why

React is my primary professional competency — using it for my personal site is a direct portfolio signal. Static export means zero server cost, zero cold starts, and a site that survives even if I stop paying for infrastructure.

Trade-off

No server-side features (API routes, ISR, middleware). Every dynamic data source needs a creative workaround — build-time scripts or client-side fetches.

GitHub Pages over Vercel

Why

Free, no vendor lock-in, and the deploy pipeline is a simple GitHub Actions workflow I fully control. The site is pure static HTML/CSS/JS — it doesn't need edge functions or serverless infrastructure.

Trade-off

No preview deployments per PR, no built-in analytics, no automatic cache invalidation.

Tailwind CSS v4

Why

Utility-first CSS eliminates the naming problem and keeps styles co-located with markup. v4's CSS-native configuration removes the need for a JS config file entirely.

Trade-off

Long class strings in JSX. Mitigated by extracting repeated patterns into components rather than @apply directives.

Framer Motion v12

Why

The animation API maps directly to React's mental model — animate on mount, exit on unmount, layout animations via layoutId. The page transition system uses template.tsx + motion.div for fade-in on navigation.

Trade-off

Bundle size (~30KB gzipped). Acceptable for a portfolio site where polish is the point.

react-force-graph-2d

Why

Canvas-based graph rendering handles the knowledge graph's 26+ nodes smoothly. The library supports custom node painting, which lets me color-code by type and scale by connection count.

Trade-off

Requires ssr: false dynamic import (Canvas doesn't exist during SSR). The graph is client-rendered, not part of the static HTML.

Cron-based Data Pipelines

Why

Spotify, Flickr, and Steam data require API keys or OAuth. Instead of a server, GitHub Actions crons run fetch scripts every 30min–6h and commit JSON files to the repo. The site reads from raw.githubusercontent.com — no redeploy needed.

Trade-off

Data staleness up to the cron interval. Git history accumulates data commits. Both are acceptable trade-offs.

MDX over plain Markdown

Why

MDX lets me embed React components inside blog posts — interactive code blocks, LinkedTerm hover cards, custom callouts. This is essential for a site that treats content as an interconnected graph, not isolated pages.

Trade-off

Slightly more complex build pipeline (next-mdx-remote + gray-matter). Worth it for the authoring flexibility.

View Transitions API for Theme Toggle

Why

The circular reveal effect when switching dark/light mode is pure CSS — no JavaScript animation library needed. It creates a memorable micro-interaction that visitors notice and remember.

Trade-off

Not supported in all browsers (Firefox partial). Falls back gracefully to an instant theme switch.

Full Stack

The complete technology surface documented in one place — see /uses for the development environment.

Framework

Next.js 16 (App Router)

Styling

Tailwind CSS v4

Animation

Framer Motion v12

Graph

react-force-graph-2d

Content

MDX + gray-matter

Tooltips

Radix UI Hover Card

Icons

Lucide React

Hosting

GitHub Pages

Analytics

Umami Cloud

CI/CD

GitHub Actions