Personal portfolio
Sole developer.
A portfolio rendered as the thing it describes: a connected service topology.
Most of my work is message routing between services, so this portfolio is built as a node graph. That choice is not decorative: the edges in the SEL clusters are real runtime message paths between services I worked on, not "these two share a technology." Solid animated edges mean messages actually move along them. Faint static edges mean shared tooling. The distinction is the point.
Next.js App Router with Three.js through React Three Fiber. The canvas lives in the root layout rather than in a page, so it persists across route changes and the camera flight from the landing page into the graph is continuous rather than a page transition. Layout positions are computed once at build from a seeded generator, so the constellation is identical on every load.
There is one world and one camera. The graph sits at the origin at life size on every route and never moves; `/`, `/work/[slug]` and `/nebula` are three places the camera stands, solved per frame from the same rules that used to solve a scale factor. Getting there meant proving the two are equivalent — a group scaled by s and a life-size graph at the matching distance project identically — so the rebuild could be gated on zero changed pixels rather than on an opinion. Zustand carries state across the boundary between React DOM and the R3F scene, camera-controls owns the pointer, and Motion handles everything that is not the camera.
Every project exists as a real, crawlable, keyboard-navigable page at /work/[slug], rendered from the same content object the 3D node displays. The graph is a second way through the same material, never the only one. With WebGL unavailable the site is completely usable.
Built with Claude Code.
Next.js, React, TypeScript, Three.js, Tailwind CSS