THE BUILD SYSTEM — CASE STUDY
How this site was built — brief to deployed, one hand
Designed in Paper, engineered with Claude Code and custom MCP tooling — ≈16,000 lines of hand-reviewed TSX and CSS, zero templates.
OVERVIEW
Designed on canvas.
Engineered in conversation.
Every page of matt-kenney.com is drawn in Paper first, then built
in conversation with Claude Code running in Conductor — and verified
against the canvas before it ships.
THE PROBLEM
“AI-built” earns the doubt it gets.
Generated sites tend to fail the same three ways — and a hiring manager has seen all of them.
- Template physicsGeneration gravitates to the layouts it has seen most — the result reads assembled, not designed.
- Unreviewed outputCode nobody read is code nobody owns — the first bug becomes an archaeology project.
- No way to verifyIf the design lives in the same tool that built it, nothing independent says the build is right.
THE OPERATOR MODEL
Design first. Review everything. Verify against the drawing.
The AI raises the ceiling; the discipline holds the floor.
- The canvas is the contractPages exist in Paper before they exist in code — the build is diffed against the drawing, not a memory of it.
- Conversation, then reviewClaude Code proposes; the hand reads, prunes, and decides. Every line that ships was seen.
- Verification is built inPixel-diff against the boards, headless probes for every interaction, and guards written before features.
THE ARTIFACTS
LENS 01 — CREATIVE TECHNOLOGIST
An agent pipeline
with editorial rules.
Case studies are synthesized from raw client material by agents — under rules that forbid invention, and limits that keep copy from breaking layout.
Ground rule: copy is drawn from your materials (verbatim where they're authoritative). No invented metrics or claims — if a fact isn't in the sources, Claude asks rather than fabricates.
Briefs, transcripts, and testimonials go into a folder; an agent drafts the study; the rules keep it honest.
/** Soft character limits per editable field — guidance so * copy doesn't clip in the layout (the accordion especially: * panels are `overflow: clip` … `peak.playLabel` is * `white-space: nowrap`; many tile/meta fields are * width-bounded). */
Every editable field carries a character budget derived from its container — agent-written copy fits by contract, not by luck.
THE ARTIFACTS
LENS 02 — DESIGN TECHNOLOGIST
The handoff is a document,
not a vibe.
2,861 lines of board→build specs translate the canvas into buildable fact — values decoded from the design file, never eyeballed. The discipline is tool-agnostic: the same handoff works from any canvas.
All values are taken from the decoded JSX exports (artboard.pretty.jsx.txt in each dossier), not eyeballed from screenshots. … The four artboards are four states of ONE page, not four pages. Diffing the decoded JSX confirms it: the entire shell … is byte-identical across all four boards except for exactly two things.
599 lines for one template — geometry, tokens, and interaction ground truth, written so a builder (human or agent) can't drift.
--ground: #090b0b; --ink: #ffffff; --hairline: #2e2e2e; --ink-muted: #9c9094; --red: #ff003c; --red-glow: rgba(255, 16, 70, 0.55); --font-display: 'Season', 'Niveau Grotesk', …; --font-mono: 'Mono45 Headline', ui-monospace, …; --maxw: 1500px; --pad-x: 40px; --rail-h: 48px;
Thirty custom properties carry ground, ink, type, and rhythm through every deck — change one, and every page follows.
THE ARTIFACTS
LENS 03 — DESIGN ENGINEER
The parts you'd
review first.
The one write surface has a written threat model — and the hand reviewing the AI's output learned the old way. The pre-AI baseline is in the repo.
multipart/form-data and text/plain bodies are CORS-safelisted, so a cross-origin POST fires no preflight and the write lands server-side … - prod builds → 404: no write surface ships. - Sec-Fetch-Site must be `same-origin`: blocks drive-by CSRF. - Host must be loopback: blocks DNS-rebinding, where a rebound attacker page is same-origin to itself but reaches us with a foreign Host. - Custom header must be present: forces a preflight on any cross-origin attempt, which these routes never satisfy.
The inline CMS writes to disk in dev, so it defends like it ships: four layers, each against a named attack.
function navigateTo(pageId, projectKey) {
document.querySelectorAll('.page')
.forEach(p => p.classList.remove('active'));
const target = document.getElementById('page-' + pageId);
if (target) target.classList.add('active');1,883 lines of vanilla HTML, CSS, and JS — no framework, no build step. The judgment predates the acceleration; AI raised the ceiling, not the floor.
THE INSTRUMENTATION
PORTFOLIO AS PROOF
It measures itself.
First-touch attribution, engaged time, and meaningful clicks — cookieless, and swappable at the sink. Every link this portfolio travels on carries UTMs; the site reports which one did the work.
const landing: Record<string, string> = {
source: utm.utm_source || refHost || "direct",
medium: utm.utm_medium || (refHost ? "referral" : "direct"),
landing_path: window.location.pathname,
};
if (utm.utm_campaign) landing.campaign = utm.utm_campaign;
sessionStorage.setItem("mk_landing", JSON.stringify(landing));
track("landing", landing);A LinkedIn arrival, a résumé-PDF arrival, and a tailored application link all report as themselves — once per session, no cookies.
/** One import for every custom analytics event in the app.
* Wrapped so that analytics being disabled or blocked can
* never throw into the UI, and so the sink (currently Vercel
* Web Analytics) can be swapped for PostHog/Clarity later
* without touching any caller. */
export function track(event: string, props?: Props) {
try {
vercelTrack(event, props);
} catch { /* analytics unavailable — never break the page */ }
}Engaged seconds count only while the tab is visible; clicks classify by delegation — project opens, résumé, outbound, email — with no per-component wiring.
DECISIONS & TRADE-OFFS
What was chosen —
and what wasn't.
- The canvas is the contract.Nothing is built that wasn't drawn, and every build is diffed against the drawing. Slower to start; impossible to drift.
- Conversation is a build tool, not a shortcut.The agent proposes, the hand disposes. The speed comes from iteration, not from looking away.
- No templates, on purpose.A portfolio assembled from a kit proves taste in kits. This one had to prove the pipeline.
RETROSPECTIVE
What I'd do
differently.
- Publish the tooling.The specs, guards, and MCP servers deserve a public repo — reading about code isn't reading code.
- Instrument from day one.The attribution layer on the previous page shipped months after launch — it runs on every page now, but the first waves of visits went unmeasured.
- Write the spec before the excitement.The pages built from 599-line specs shipped clean. The pages built from enthusiasm got rebuilt.
GET IN TOUCH
You just read
the product demo.Let’s talk.
Open for creative technologist / design engineer / senior graphic design roles
Matthew Kenney
Designer at Podcast Monkey, USA.