The problem
Everything I make ended up somewhere different. Code on GitHub, recipes in Notion, half-finished experiments on a branch nobody merged, and notes in whichever app I had open. None of it was lost exactly, but finding any particular thing meant remembering where I had put it.
The previous version of this site didn’t help, because it was a portfolio. It showed a few finished things to people who might hire me, and had nowhere to put the unfinished ones. So the unfinished ones stayed scattered.
The approach
If it isn’t labeled, I’ll lose it, so the site works like the boxes at home. Three ideas shaped it:
How it’s built
Next.js App Router, with a hard split: everything under app/ is a route, a layout or an API handler, and everything else lives in src/. External APIs are only ever called from the server, so no key ever reaches the browser.
The live widgets all follow the same shape. A server component wraps a client component that runs a React Query fetch against an internal route, and that route calls a function in src/apiManagement. The card that finally renders is presentational and takes loading and error states as props, which makes it easy to look at in isolation.
The sky is the one piece of genuine state. It picks one of six phases from the visitor’s own clock, and paints a gradient, drifting clouds, and — after dark — stars and the Big Dipper. The cloud layout comes from a seeded generator so the server and the browser lay out identical skies.
What I’d change
I seeded the cloud generator to keep hydration stable, then shuffled the cloud bands with sort(() => random() - 0.5). Sort calls its comparator a different number of times in Node than in Chrome, so the two drained the generator differently and every single page load threw a hydration mismatch. A seeded generator only buys you determinism if every draw from it is fixed in count and order — a Fisher-Yates shuffle, not a random comparator.
The other thing: I built the design system and the home page before deciding where the writing and curriculum content would actually live. That was the right call for the look, but it means a few boxes on the shelf currently say "coming next" rather than opening.
