Portfolio Site
This site, rebuilt from flat HTML to Next.js with an AI chatbot, MDX content pipeline, and streaming Anthropic integration. 95+ Lighthouse score.
You're using this site right now. Try the chatbot in the corner. The animated circuit board behind this text runs entirely off the main thread.
My previous portfolio was a flat HTML/CSS/JS single-page site. Functional, but it contradicted my resume: I claimed Next.js and TypeScript expertise while the site itself used neither. The rebuild eliminates that incongruence. Content pipeline, streaming AI chatbot, the whole thing statically generated and tuned for performance.
What It Does
Static content pipeline. Landing, work case studies, and blog posts live as MDX files in the repo. New writing is a commit, not a CMS round trip.
Ask John chatbot. A streaming assistant that answers questions about my experience in my voice, powered by Claude Sonnet 4. Wrapped in seven cost-protection layers so a runaway prompt cannot drain the API budget.
Dual palette design. Navy and mint in dark mode, warmer tones in light, a custom Syne / DM Sans / JetBrains Mono type stack, a numbered sidebar nav, and an editorial case-study layout. The theme switch is driven end-to-end by CSS custom properties.
Considered motion. Staggered hero reveal, scroll-triggered section entrances, a spring-physics chat panel, hover interactions. All gated behind useReducedMotion so anyone with motion sensitivity gets a still site.
Technical Approach
Next.js 15 App Router with TypeScript strict. Server Components where possible, client components only where interactivity demands them, all content pages statically generated via generateStaticParams. Tailwind CSS v4 with design tokens for the dual palette, utility classes throughout, no @apply. MDX runs on next-mdx-remote and gray-matter, with a custom .prose-custom class handling long-form content styling. Framer Motion animates, reduced-motion checked throughout.
The chatbot was the interesting puzzle. It runs on the Edge runtime for low cold-start latency, streams via a native ReadableStream (no Vercel AI SDK dependency), and is wrapped in seven layers of cost and abuse protection:
- Sliding-window rate limiting via Upstash Redis (10 requests per IP per hour)
- Input and output token caps
- Conversation length limits
- Honeypot field
- Timing-based bot detection
- Input sanitization
- Origin checking
Conversations log non-blocking to Neon Postgres so the write never slows the stream. Keeping all of that coordinated without adding noticeable latency was the real work.
Homepage scores 95+ on Lighthouse. next/font/google for zero-FOUT font loading, dynamic import for the chat panel so it is not in the first-paint bundle, static generation everywhere, and Next.js Image optimization inside MDX.
Credits
The visual and structural DNA of this site comes from Brittany Chiang's v4 portfolio. The navy palette, the Syne / DM Sans / JetBrains Mono type stack, the numbered sidebar, and the hero layout all descend directly from her work. Her source is on GitHub, and her only ask is a link back. Consider this that link, and then some: go look at her portfolio, it is the reason this one exists. Case-study structure takes a cue from Terry Godier.
Three files worth reading
If you want to jump straight to the interesting code, here are the three files that demonstrate the most:
app/api/chat/route.ts— the streaming chatbot route, with all seven cost-protection layers wired inworkers/circuit-worker.ts— generation, rendering, and animation of the PCB background, all off the main thread via OffscreenCanvaslib/chatbot-prompt.ts— the system prompt itself, the single most important piece of writing on this site