Skip to content

Building this portfolio with Claude Code

Playground / 2026

Like most designers, I was drawn to this field out of a deep desire to create. And in the last few years, AI coding tools have opened up a whole new world of creative opportunities. It feels like an exciting time to be someone with lots of ideas.

When I set out to make this portfolio, I wanted to treat it as a sort of exercise in building a site from scratch. While Claude helped with execution, I asked for the why behind what it was doing so I could actually learn from the experience.

But I also wanted this portfolio to be mine. Every design decision on this site, big or small, ultimately came from me. The writing on this site is my own (unless indicated otherwise, as you’ll see below). While I used AI nearly every step of the way, it still feels like this site is my creation.

As AI continues to evolve and change our ways of working, it’s important that we design, build, and use these tools in a way that keeps human ingenuity in the driver’s seat. AI shouldn’t be used to replace human creativity… but to supercharge it!

View design system

AI-generated content below

Below is a report, written by Claude, explaining the technical work & decisions behind the site.

Why Astro

The site started as plain HTML, which got painful by the fourth case study, so we talked through frameworks. Next.js is the industry default for web apps, but a portfolio isn’t an app, and shipping React to every visitor would be more than this site needs, at least for now.

Claude recommended Astro, a go-to for content sites like blogs and portfolios. It builds static HTML, ships almost no JavaScript, and can still add a React “island” if something ever needs to be interactive.

In practice, no framework code reaches the browser. Each page loads only small, hand-written scripts for what it actually does: the homepage gets one, and case studies add the lightbox.

  • Content collections: each case study is one MDX file, checked against a Zod schema, so a missing title or alt text fails the build instead of shipping a broken page (hero images aside, where alt text is optional).
  • One template: every case study renders through a shared layout and one dynamic route. This report is an MDX file too.
  • Optimized images: responsive WebP at several widths via srcset, plus a full-resolution WebP for the lightbox.

The migration had to look exactly the same afterward, so Claude Code compared every page before and after, on desktop and phone, pixel by pixel.

The design system as code

This site’s design system, galazio: γαλάζιο adj.Greek word for light or sky blue; sometimes translated as azure 💙, grew out of an earlier kit, Azure Arcade, made with Claude Design. We then rebuilt it in code on Tailwind CSS v4. Its tokens live in Tailwind’s @theme block with the defaults cleared, so only design system values exist. --color-ink in code matches color/ink in Figma, and components use semantic roles (action, link) rather than raw colors.

Ann Marie set the naming rule: keep her names where they work, follow industry standards where they apply, and if the two conflict, go with the standard and flag it for her. That’s how we landed on Tailwind’s standard type scale and a 4px spacing grid.

In late October we gave the whole site a shadcn-inspired polish pass: 6px corners, tinted chips, quieter section headings and a frosted case study header.

The design system renders the site’s tokens and components straight from the code. Colors, type sizes, corners and shadows are read out of the theme file at build time, so it can’t drift out of date. The screenshots below come from it.

Design system page: the site’s buttons (solid blue, outline Contact, dark See Work and Read next, a ghost Next) and its chips and section nav

Figma and code, both directions

The Personas case study figures started out built in code, which made them hard to edit. Using the Figma MCP, Claude rebuilt them as Figma frames on the design system’s variables. Ann Marie made her edits by hand on the canvas, and the frames came back to the site as 2x exports. Code to canvas and back again.

The Personas figures laid out as frames on a Figma page

Interaction details

The small things took the most back and forth.

The lightbox uses a native <dialog>, so focus handling and Escape come built in. Each image grows out of its spot on the page and shrinks back into it on close. Pinch, click or +/– zooms; a swipe or the arrow keys move through a set; and the full-size original starts downloading as soon as someone hovers, so it’s usually sharp by the time it opens.

All of it is about 560 lines of plain JavaScript, around 7 KB compressed, with no library behind it, including fixes for a few iOS Safari quirks.

A Procedures Updater screen opened in the full-screen lightbox over the dimmed case study, with a close button and an “Esc to close · +/– to zoom” hint

The contact form runs on a Cloudflare Worker that emails each message to Ann Marie through Cloudflare Email Routing. A hidden honeypot and Cloudflare Turnstile keep bots out, errors show inline and are announced to screen readers, and drafts are saved to sessionStorage, so a reload doesn’t lose a half-written message. For the toast, Claude researched how established libraries animate theirs, and we borrowed react-hot-toast’s easing curve.

The contact page with the 'Message sent' toast and its countdown bar

Accessibility

Every animation on the site has a reduced-motion fallback: the homepage gradient and typing intro, the scroll reveals, carousels, videos and the lightbox all hold still for anyone who’s asked their device for less motion.

Images open in the lightbox from the keyboard too (Enter or Space), and focus goes back to the image when it closes. And since the build checks for alt text, every image that carries meaning has a description.

ARIA follows its own first rule: native HTML first (<dialog>, <details>, <button>), and ARIA only where HTML can’t say it. That means aria-label on icon-only buttons like the carousel arrows, live regions so the toast, error banner and character count get read out, aria-describedby and aria-invalid to tie each contact field to its error, and aria-hidden on purely decorative icons so screen readers skip them.

galazio: γαλάζιο adj.Greek word for light or sky blue; sometimes translated as azure 💙 Design System

Tokens and components used on this site, rendered live from the code.

Buttons

PrimaryContactSee WorkRead nextNext

Hover them: the envelope and arrows slide in, the glow edge lights up.

Chips and nav

FigmaFreddie MacOngoing
OverviewIdeaSchemaLibrary

Cards

At a glance
Role
UX designer, 1 of 2
Team
Tiger Team, internal AI product team
Timeline
4-5 months, 2026
Status // Ongoing; V3 in progress after two pilots (10, then 30 users)

Alerts

Work in progress

This is an ongoing initiative. More updates to come!

Key Question: How can we make our personas AI-native?

This was going to be harder than we thought

AI-generated content below

You’ve reached the end of my case studies.

Confidentiality Note

This was proprietary internal work at a financial institution. Every screen below is a faithful recreation rebuilt from memory and notes, and all names, loans and data shown are fictional and non-confidential.

Forms

Please enter a valid email, like you@example.com.

Your message didn’t send

Please try again in a moment.

Toast

Message sentThanks! I’ll get back to you as soon as I can.

Type

Hero title · Archivo semibold · 30
Personas Context Library
Section heading · Archivo semibold · 16 · ink-soft
Schema design with the team
Body · Archivo regular · 14 / 155%
Every persona now has a file in the library.
Small · Archivo regular · 12 · ink-faint
Graphic is for illustrative purposes only.
Caps · Archivo all small caps · 7%
Work in progress
Serif · Newsreader regular · 48
welcome!
Logo · Epilogue regular · lowercase
Mono · JetBrains Mono · 12
role: Underwriting analyst
Aaxs · 12px
Aasm · 14px
Aabase · 16px
Aalg · 18px
Aaxl · 20px
Aa2xl · 24px
Aa3xl · 30px
Aa4xl · 36px
Aa5xl · 48px
Aa6xl · 60px
Aa7xl · 72px

Shape and elevation

radius-sm 4px
radius-md 6px
buttons and form fields
radius-lg 8px
alerts, cards, toast, code blocks
radius-xl 12px
cards (shadcn's Card radius)
shadow-ghost
shadow-ghost-bright
shadow-xs
outline buttons, form fields
shadow-sm

Color

blue
#1e86ee
Info
blue-deep
#0b6bd6
Buttons, links
blue-deeper
#0854a9
Hover, text on pale blue
blue-pale
#dee9f6
Ongoing status, case study tags
green
#16b37e
Glow button edge
green-deep
#08815a
Success, done
green-deeper
#06674a
Text on pale green
green-pale
#d9ede3
Done status
mist
#8fa5c4
Tag borders
mist-pale
#dfe6f0
Soft fills
periwinkle
#b9bee7
Chip borders, skill hover
periwinkle-pale
#e8eafd
Chips, icon tiles
bone
#fcfdfe
Form fields, popovers
blue-bright
#4770eb
Focus ring, small accents (✦, icons)
purple-deep
#6b3fbf
Playground "Learning" status
lime
#e3ff54
Highlights
rust
#cb4c21
Warnings and errors
red
#d0353b
Problem cards
ink
#191b1d
Headings and body text
ink-soft
#44484d
Secondary text
ink-faint
#6b7076
Labels, captions, meta
rule
#dcdfe4
Borders and dividers
paper
#ffffff
Page background, cards

Semantic roles

bgpaper
bg-altblue-pale
bg-brightbone
bg-inverseink
fg-1ink
fg-2ink-soft
fg-3ink-faint
fg-inversepaper
actionblue-deep
action-hoverblue-deeper
action-fgbone
linkblue-deep
link-hoverblue-deep
inputcolor-mix(in srgb, ink-faint 75%, paper)
focusblue-bright
focus-ringfocus
successgreen-deep
warningrust
infoblue