← Home

Colophon

How this site was built.

This portfolio is also a work sample. I designed and built it end to end — no template, no CMS — and everything below is something you can go click. If you're hiring for the engineering, start here.

The stack

Front end

React 18TypeScriptVite 6Tailwind CSSshadcn/uireact-router 6

Rendering

SSR + static prerendercrawlable HTML per routeclient hydration

Tooling

pnpmPlaywright (PDF + visual QA)PyMuPDF + Pillow (report pages)

Deploy

Netlifycontinuous from mainno server, no CMS

A few decisions I'm proud of

Every route is real HTML

The whole site renders on the server at build time (entry-server.tsxscripts/prerender.mjs) and hydrates in the browser. So a deep link to a case study, a report, or a résumé track resolves to static, crawlable HTML — not a blank shell waiting on JavaScript.

The toolkit is a system, not a screenshot

The reports and designs carry an annotation layer — design / data / source bubbles positioned as percentages of the artwork, so they ride the image at any size. One data model (ReportPage, DesignPiece) drives both the on-page markers and the side panel.

One source of truth for the résumé

The résumé, its four role tracks, and every downloadable PDF are generated from a single resume.json. The page renders it as React; a headless-Chromium script prints the same data to Letter PDFs. The page and the download can't drift because they're the same file.

Content lives in typed data, not a database

Projects, reports, designs, teardowns, and posts are typed TypeScript data files. Adding a report is a data object + a folder of page images; adding an annotated design is one src and a few bubbles. The teardown pages are one shared component fed by a section grammar.

Built to be handed real work

There's an upload drop-zone and an annotate-any-design pipeline: drop an image, it becomes an annotated /designs/<id> page; drop a PDF, it renders into the book-style reader. The site is designed to grow by dropping in files, not by rewiring code.