How this site was built.
The site you are reading is itself a portfolio piece. Written in collaboration with Claude Code, deployed in days, intentionally over-engineered in the places that matter and intentionally simple everywhere else.
Stack
- Next.js 15 (App Router): static rendering for every page, zero client-side data fetching.
- React 19 + TypeScript, strict mode on.
- Tailwind CSS: design tokens defined in
tailwind.config.ts, customink+accentpalettes. - MDX via
next-mdx-remote: case studies are content files, not React components. Edit a paragraph, redeploy in 30 seconds. - Gray-matter for front-matter (metrics, stack, ordering, featured flag).
- Vercel for hosting and preview deploys.
- Puppeteer for the résumé PDF pipeline (separate repo).
On the MCP server
There are now official marketing-stack MCP servers; HubSpot recently shipped one. I built my own hubspot-mcp before that, to learn the protocol from the ground up and to demonstrate the architecture I would build inside a marketing organization.
The build partner: Claude Code
Claude Code is Anthropic's CLI for Claude: agentic, file-system-aware, runs tools, takes a brief and ships code. I drafted the spec for this site (positioning, sections, content), Claude turned that into a working Next.js app, I reviewed, asked for changes, repeated. The same pattern I use professionally for marketing automation: human owns judgment, model owns mechanics.
The case study MDX system, the résumé HTML to PDF pipeline, the SEO and OG image setup, and the Lighthouse-passing performance tuning were all collaborative: fast iterations, explicit decisions, full version history.
Architecture decisions, briefly
Static everything
Most of the codebase avoids "use client". Pages are server-rendered at build time. The result: first contentful paint under a second on a cold cache, JS bundle close to zero. Hiring managers on a slow mobile connection see content immediately.
Content as front-matter
Case studies live in content/work/*.mdx with structured front-matter for the metrics, stack, and ordering. The home page and the work index both call getAllWork() from lib/work.ts. Add a new case study, push, deploy. It shows up everywhere with no manual wiring. The same pattern I use for client content pipelines at HAZE.
Résumé pipeline as a separate concern
The résumé is generated by a small Node script using Puppeteer. Source of truth is markdown + a typed variants config; HTML/CSS template; PDF output. Two variants (General + Marketing Engineer) ship from one content file. Easy to add a Director variant when the conversation calls for one.
Dark mode, one accent
Technical hiring audiences read dark mode more comfortably, and it avoids the standard agency-portfolio look. One accent color (a desaturated warm cream) used sparingly, applied to the primary CTA and case-study links, keeps the page from looking generic.
What I'd build next
- An MDX component library for inline metric callouts inside case studies.
- Per-case-study OG images generated from front-matter (next/og dynamic OG).
- A small writing section once I have 2–3 essays worth shipping.
Why this page exists
Claiming "I ship with AI tooling" is easy. Demonstrating it is the harder part. If you are hiring for a role where the candidate needs to understand both the marketing and the systems behind it, this page is the evidence. Let’s talk if that is the role.