// Project
This Site
HTML · CSS · Node.js · Claude AI
HTML / CSS / JSNode.jsClaude AIFormspreeNetlify

This Website —
Built Collaboratively
with AI

A personal site covering portfolio, blog, resume, and an AI chat assistant — designed, built, iterated, and deployed entirely through conversation with Claude.

6
HTML pages
0
npm dependencies
2
Deployed proxies
AI
Powered chat

Why build it this way

Every developer eventually needs a personal site. The usual options are a WordPress theme you never quite get right, a Squarespace template that looks like everyone else's, or a weekend project that stalls at a half-finished React app. I wanted something different: a site that genuinely reflects how I work, built using the same collaborative AI-assisted process I've been applying to larger projects.

Structure and design

The site is plain HTML, CSS, and JavaScript — no framework, no build step, no bundler. A single shared styles.css carries the design system across all pages. The site is structured into six separate files: index.html as the homepage, projects.html for the portfolio, blog.html as the listing page, individual blog post pages, and dedicated project write-up pages. Internal links connect everything without any routing library.

The design went through two full iterations. The first was a warm cream-and-bark palette. The second — what you're reading now — is a dark navy, green, and teal technical aesthetic inspired by Shift5.io, built entirely through feedback in conversation with Claude.

The contact form and Formspree

A contact form that doesn't send anything is worse than no contact form. The solution was Formspree, integrated using their Vanilla JS Ajax library. The Ajax approach means the page doesn't reload on submission, field-level validation errors appear inline, the submit button disables during the request, and a success message appears after a successful send. Submissions land directly in my inbox. No backend required, no credentials to manage.

The AI chat assistant

The floating AI chat assistant is where the site stops being a static brochure and becomes something interactive. The architecture has two parts. The frontend is a self-contained chat panel — a floating button that opens a conversation interface, maintains message history, handles the thinking state, and degrades gracefully if the proxy isn't reachable. The backend is a small Node.js proxy deployed to Render, written with zero npm dependencies using only Node 22 built-ins.

The proxy holds the Anthropic API key in an environment variable set through Render's dashboard — it never appears in the browser or in the GitHub repository. The system prompt, baked into the proxy and never exposed to the client, contains my complete professional profile. Claude uses this to answer questions accurately and stay on topic, redirecting anything outside its knowledge to the contact form.

Deployment and the real obstacles

Deploying the proxy involved working through friction that doesn't appear in tutorials. An SSH key mismatch with GitHub's host key required clearing the old entry from known_hosts. Setting up SSH access from scratch — generating a key pair, adding the public key to GitHub, verifying the connection — was a full process. A trailing slash in the proxy URL caused a double-slash in the API endpoint path that produced 404 errors until spotted. The site itself moved from AWS S3 to Netlify for free HTTPS on the custom domain, which required working through DNS propagation, nameserver configuration, and Formspree CORS settings along the way.

What building with AI actually means

Every file on this site was produced through conversation with Claude. That's worth being precise about. It means I described what I wanted, gave feedback on what I saw, made decisions about trade-offs, provided my actual data, and directed the work at every step. Claude wrote the code. I reviewed it, deployed it, and iterated based on what I experienced in production.

The process surfaced decisions I might have deferred working alone. Should the blog be a section on the homepage or its own page? How should the proxy handle the API key? What should the AI assistant know, and what should it decline? Each was a real conversation, not a click through a wizard. The resulting site reflects those decisions in its structure — and that's what I care about, regardless of how the code got written.

← Back to projects