About this site
This site was built with an AI coding assistant. It seems better to say so here than to leave it to be guessed at.
What I did, and what I didn’t
I've taken a programming course and I can write basic code. I didn't hand-write this site, and I don't think hand-writing it was the useful part.
What I did was decide what it had to do. I wrote the requirements, chose the stack, picked the visual direction, and set the rules the build enforces. Every project write-up, number and figure on the site is mine. Claude Code wrote the code from that.
The part that took judgement was reading what came back and rejecting what was wrong. A project description that credited me with machining I'd only submitted a work order for. An explanation of my own design that I hadn't given and didn't agree with. Several paragraphs that read as selling rather than saying. A skills matrix that rated me higher than I'd rate myself.
Being able to scope a technical problem, direct the work, and tell when the output is wrong is a different skill from writing it line by line. It's the one I actually used, and I expect it's the one I'll use more of.
What the build refuses to publish
Most of the rules I set are enforced rather than remembered. These fail the build, which means the mistake never reaches a page — including when I am the one making it.
- A project page without a written statement of what I personally did fails the build. There is no way to publish a vague one.
- A skill claimed at proficient or better with no project or job linked to it fails the build. That rule is why the skills page is shorter than it could be.
- Image alt text has to describe the engineering content. A filename, or fewer than three words, fails the build.
- A link to a section that's been switched off fails the build, checked against the exported HTML rather than the source.
- Colour contrast below 4.5:1 fails the automated review, so the palette can't drift into something unreadable. A hover colour that had been under the floor since the first version was caught this way.
- A photograph gets a warm grade; a drawing, an FEA plot or a chart never does. Grading a colour scale would make it report the wrong values, so that rule is enforced in a browser test, not left to review.
Tools used
16 of them, across 5 parts of the job. What each one does here, rather than what it is in general.
How it was built
- Claude Code
- Anthropic's coding agent, run from a terminal. It wrote the code, and I specified, reviewed and corrected it.
- Git and GitHub
- Version control. Every change is a commit with the reasoning behind it written down.
- VS Code
- Where the editing happens.
The site
- Next.js 15
next - React framework, App Router. Exports the whole site as static files, so there is no server to go down and no vendor to be locked into.
- React 19
react - The component model. Most of the site ships no JavaScript at all — only the theme control, the figure lightbox, the project filters and the map need it.
- TypeScript
typescript - Strict mode, including the setting that makes array access admit it might be empty. Types are checked in CI before anything deploys.
- Tailwind CSS 4
tailwindcss - The theme layer. Design tokens compile to CSS variable references, so switching light and dark repaints without rebuilding anything.
- MDX
next-mdx-remote - Project write-ups are Markdown with frontmatter, so they can be edited from a phone through GitHub's web editor.
The parts that check my work
- Zod
zod - Validates every content file against a schema at build time. Most of the rules above are Zod rules — the build refuses the mistake rather than warning about it.
- Playwright
@playwright/test - Runs the site in a real browser at desktop and phone width and checks the things a build can't prove: keyboard operation, focus handling, no sideways scrolling, and that no figure is filtered when it shouldn't be.
- Lighthouse CI
@lhci/cli - Scores performance, accessibility, best practices and SEO on every push. Accessibility has to be 100 or the check fails.
- GitHub Actions
- Runs all of the above on every push. A red check is the signal to revert, and the live site keeps serving the last good build in the meantime.
Built once, at build time
- d3-geo and TopoJSON
d3-geo - The travel map is projected from Natural Earth coastline data into flat SVG when the site is built, so the page loads no mapping library and makes no network request. Around 56 KB of geometry, no runtime dependency.
- sharp
sharp - Resizes and converts images to WebP inside a size budget, because static export means there is no image server to do it on demand.
Where it lives
- Vercel
- Hosting, free tier. Because the output is plain static files it could move to another host in about an hour.
- GoDaddy DNS
- annabel.buelter.app is a subdomain of a domain my dad owns, pointed here with a CNAME record.
There are no trackers, no analytics and no cookie banner on this site, and nothing on any page loads from a third party. The typefaces are served from this domain rather than from Google.
The repository is private, but I'm happy to walk through any part of it.