Why I Built It From Scratch
Honestly, I could have used Framer or a template and had something live in a weekend. But that felt like it was missing the point.
I've been spending a lot of time at work exploring AI coding tools and thinking about how designers can be more genuinely involved in the front-end: not just handing over specs, but actually understanding the environment their work lands in. Building this portfolio was a way to put that into practice. To stop thinking about it and actually do it.
There were two things I wanted to get out of this.
Design control. Templates, even good ones, have opinions baked into them. Their spacing system, their component structure, their assumptions about what a portfolio should look like. I wanted a site that reflected how I think about design. Clean, minimal, editorial. And I wanted to make decisions about every detail without working around someone else's choices.
Development fundamentals. Understanding how a codebase is structured, how components work, how deployment actually happens: these things make you a better collaborator with engineering. You can't appreciate those conversations from the outside. When you've spent time in the weeds yourself, you start to understand what decisions are genuinely hard and which ones you've been overthinking in design reviews.
You can't appreciate engineering conversations from the outside. You have to spend time in the weeds yourself.
So I built it properly. From scratch.
Before Writing Any Code
One thing I was deliberate about: I didn't touch the codebase until I'd thought through the architecture properly. This is where Claude.ai came in, not as a code generator at this stage, but as a thinking partner.
I spent time mapping out the full site structure first. How many pages, what each one was for, what the URL structure should look like, how case studies would be stored and retrieved. I also worked through the CMS question: whether to use a headless CMS, a full platform, or just MDX files in the repo. Each option has real trade-offs and choosing the wrong one early would have created maintenance problems later.
By the time I started building, I had a clear picture of the folder structure, the component hierarchy, and how content would flow through the site. That upfront planning is invisible in the final product, but it's what made the build feel relatively straightforward rather than chaotic. There was one moment early on where I nearly went down the route of a Notion-powered CMS. The planning conversation talked me out of it. Saved me from rebuilding the content layer weeks later.
The lesson I'd take from this: the thinking you do before the first line of code is the most valuable part. It's the same principle as UX research: front-loading the hard questions saves you from expensive mistakes later.
Stack decided before build started · Architecture planned in conversation · Content structure mapped before first component
The Stack
Next.js 15 was the obvious choice for the framework. It's what Vercel (my hosting platform) is built around, and the App Router gives you file-based routing out of the box. Pages live in folders, which maps naturally to how I think about site structure. It also handles static generation, which matters for performance: every page is pre-built at deploy time rather than generated fresh on each visit.
For styling I used Tailwind CSS v4. The utility-first approach works particularly well when you're working with AI-generated code: the classes are explicit and readable, so you can see exactly what a component is doing without digging into a separate stylesheet.
The hosting setup is straightforward. The repo lives on GitHub. Every push triggers an automatic rebuild on Vercel. No manual deploys, no configuration. The whole thing costs nothing to run.
Next.js 15 · Tailwind CSS v4 · MDX content · Framer Motion · Deployed on Vercel · £0/month
The AI Workflow
This is the part I'd most want other designers to understand, because it's not what I expected going in.
I used two AI tools in a deliberate split, and keeping that split clear was what made the workflow actually function.
Claude.ai: The Thinking Layer
Before any code was written, I used Claude.ai to plan the architecture, evaluate options, and make decisions. When I wasn't sure whether to use MDX or a headless CMS, I didn't just Google it. I worked through the trade-offs in a conversation, explained my constraints (solo project, zero budget, long-term maintainability), and got a reasoned recommendation I could evaluate myself.
This continued throughout the build. When something wasn't working the way I expected, I'd describe the problem here first, not to get code, but to understand what was actually going on. That understanding then shaped how I wrote prompts for the code layer.
The other thing it was useful for: writing precise prompts to hand off to Claude Code. A vague prompt produces vague code. Being able to articulate exactly what a component should do, what it shouldn't do, and what the surrounding file context looks like: that's a skill in itself, and one that sits very naturally with UX thinking.
Claude Code in VS Code: The Implementation Layer
Claude Code is a VS Code extension that generates, reviews, and applies code directly to your files. It's where the actual implementation happened.
The workflow for each feature looked like this:
- Define what needs building and why (Claude.ai)
- Write a precise prompt with component name, behaviour, constraints, and file context (Claude.ai)
- Run the prompt in Claude Code, review the output before applying
- Test visually at
localhost:3000: not just "does it run" but "does it actually look right" - Commit to GitHub and let Vercel deploy automatically

The key habit I built early: never apply generated code without reading it first. Not because it's usually wrong; it usually isn't. But if you don't understand what's in your codebase, you can't debug it when something breaks. And things do break.
What It Actually Feels Like to Review AI Code as a Designer
When I first started, I was approving code I didn't fully understand because it looked plausible. That worked fine until it didn't, and when something broke, I had no idea where to start. I couldn't tell if the problem was in the component, the layout, the data fetching, or somewhere else.
The shift that helped was slowing down and asking Claude Code to explain what each section was doing before applying it. Not every line, just the overall structure. Once I had a mental model of how the pieces fit together, the review got faster and I could actually catch things that were subtly off.
Designers are well-equipped for this. We're used to asking why something looks right. Applying that same instinct to code is the same skill in a different medium.
Key Decisions
MDX over a headless CMS
The appeal of something like Notion as a CMS is obvious: familiar interface, no code to touch when updating content. But for a portfolio at this scale it added complexity without meaningful benefit. I'd need to manage API keys, handle rate limits, and deal with network latency at build time.
MDX keeps everything in the same repo as the code. It builds statically at deploy time. And it gives me full control over how every piece of content renders. My writing and code are versioned together in Git: if something breaks, I can trace exactly when and why.
The trade-off is honest: editing MDX means opening a file in VS Code. That's fine for me. If I were building this for someone else to maintain, I'd make a different call.
Defining the design direction from reference portfolios
Before writing any CSS, I spent time studying portfolios I admired: Matt Ström-Awn and Toan To. The temptation with reference gathering is to copy what you like visually. What I tried to do instead was extract the principles behind what made them work.
The consistent pattern across all of them: restraint. Strong typography, generous whitespace, almost no decorative elements. The design system recedes so the work can come forward. That became the brief for this site: monochrome palette, two fonts maximum, spacing that errs on the side of too much rather than too little.
Those principles then became specific system decisions: DM Serif Display for headings, Inter for body, an off-white background rather than pure white, CSS variables for every colour token so dark mode could be added later without touching individual components.
Separating UX work from AI and passion projects
The work index page splits into two distinct sections. UX case studies are process-heavy: research, design decisions, iteration, measurable impact. Passion projects like this one are outcomes-first: here's what I built, here's what I learned. Merging them would make both weaker.
The split also signals something to the right kind of reader: that I have range beyond traditional UX practice, and that I'm actively curious about the technical side of the work.
What I Took Away From This
The site is live and in its final polish phase. A custom domain is the next upgrade: a proper domain matters when you're actively sharing it professionally.
But the more interesting outcome isn't the site itself. It's what the process changed about how I work day to day.
A few weeks after finishing the core build, I was in a sprint review where an engineer pushed back on a proposed interaction and said it would require a full component refactor that wasn't scoped. Six months ago I'd have taken that at face value. Instead I asked a few specific questions about the component structure and we found a simpler implementation path that worked for both sides. That conversation lasted ten minutes. It used to take a week of back and forth.
The portfolio is the proof. The shift in how I work is the outcome that actually matters.

