This site uses one functional cookie to keep feature rollouts consistent for you. Nothing is set until you choose. See the privacy notice.
Dev notes
The Learn pages are interactive walkthroughs of the things I keep having to explain properly — binary search, sliding window, two pointers, hash maps, recursion and backtracking, dynamic programming, trees and graphs, stacks and queues, memoization, debounce and throttle, event delegation, async patterns, and the newest one on AI agent patterns. The interesting engineering isn't any single demo. It's that thirteen of them each grew their own copy of the same stepper, and what went wrong when I finally pulled that apart.
Every demo needs the same thing: a list of steps, a current index, play and pause, forward and back, reset, and keyboard control. I built that inline the first time because one page doesn't need an abstraction. By the time there were a dozen, the shape had been retyped a dozen times, and each copy had drifted — different key handling, different behaviour at the end of the list, different ideas about what pause meant when you were already at the last step.
That is the version of duplication I actually care about. Not the typing, which is cheap, but the fact that thirteen copies means thirteen slightly different answers to the same question, and no one place to fix any of them. It became one useStepPlayer hook.
Before consolidating I wrote tests for the stepper behaviour, which is the order I'd insist on for anything that already ships: characterise what it does, then change how it does it. Those tests immediately caught an overrun — the player could step one past the end of the list.
The fix is the part worth keeping. The autoplay timer was deciding whether to stop inside the state updater, checking the index it was about to set. That reads fine and is wrong: an updater has to be a pure function of previous state, and using it to decide whether to cancel a timer is a side effect hiding in a place React is allowed to call twice. The stepper now stops from the callback, where the decision belongs, and the updater only computes the next index.
Learn is thirteen near-identical routes, which makes it the cheapest place in the app to prove a cross-cutting change and the most expensive place to get one wrong. Several passes landed here first:
AmbientBackground primitive and then PageShell, which collapsed the per-page background boilerplate onto one component.motion to m migration, which only pays off when every route does it, since one straggler pulls the full bundle back in.buildArticleMetadata so the head tags come from one helper rather than being hand-rolled per page.Update — August 10, 2026
This page existed for months with no write-up, which I only noticed when I audited which features had one. Two others were in the same state, and the work-portfolio write-up turned out to exist while nothing linked to it.
Writing it up surfaced the thing I would actually tell someone: the hook extraction was not the valuable part. Writing the characterisation tests first was. They found a real off-by-one that had been shipping, and they are the reason I could change thirteen pages at once and believe the result.