Notes on what clicked while building each project, kept as a public log.
2026-07-19
The sketchbook's spine, a gradient gutter down the center, had to sit behind everything, including the background paint layer. My first attempt gave it a z-index, thinking 'behind the covers' meant 'above the background, below the art.' That put it above the covers instead. The real fix wasn't a z-index value at all. It was DOM order: making the spine the first child with no z-index, so normal stacking (paint order follows DOM order when nothing's stacked) put it behind everything by default.
Interview-ready: I fixed a persistent z-order bug in a layered canvas UI (paint layer, cover art, decorative spine) by realizing the fix wasn't a z-index tweak but DOM position: putting the element first in paint order instead of trying to out-rank every other layer's stacking value.
2026-07-13
Design By Bulletin runs as three cooperating agents: Editorial, Assignment Scout, and Art Department. The hard problem turned out not to be getting agents to produce content. It's knowing whether what they produced is true. A test suite can confirm the JSON is well-formed and nothing crashed, but it can't tell you a sentence describing a source article is actually about that article. I ended up building a separate review layer, gates that check content-level rules plus a full read-through that fact-checks claims against the original sources, because 'the code works' and 'the agent told the truth' are two completely different guarantees.
Interview-ready: I designed a three-agent editorial pipeline for an autonomous AI magazine and learned that automated tests only prove the output is well-formed, not true. So I added a separate fact-checking review layer that verifies agent claims against their original sources before anything publishes.
2026-07-17
I gave this piece a real route by wrapping the static file in an iframe instead of porting it to React. It's deliberately vanilla HTML, CSS, and JS, so a port would've been the wrong fix for a piece that isn't broken. The wrapper is thin, but iframe content doesn't control the real browser tab. The iframe's own <title> never reaches the outer window, so I had to duplicate that exact title string in the Next.js layout too, or the tab would just show the generic route name instead of the piece's own disguised title.
Interview-ready: I gave a deliberately non-React vanilla HTML/CSS/JS piece a real app route via a thin iframe wrapper instead of porting it, and learned iframe content can't set the real browser tab title. The outer Next.js layout has to duplicate it explicitly.
2026-07-18
For Major Arcana's card art direction, I used Midjourney as a fast way to explore visual language before writing any code, generating dozens of moodboard variations for a single card's palette and composition in the time one hand-sketch would take. It didn't replace the design decision. It collapsed the exploration phase: I could throw out 90% of directions in minutes, and the ones that stuck became the actual reference the Motion (Framer Motion) implementation matched against.
Interview-ready: I used Midjourney as a rapid moodboard and art-direction tool for Major Arcana's card visuals, generating and discarding dozens of directions in the time one hand-sketch would take, before implementing the chosen direction with Motion (Framer Motion). The design judgment stayed mine; the tool just widened the exploration phase.
2026-06-25
The original pen-tool mock tangled "where is the card right now" with "set this SVG transform" in one file. Splitting that into a dependency-free core (owns state only, hands resolved frames to a render callback) plus a themed preset (tarot) meant the same engine could drive SVG, DOM cards, or a test array. Every timeline edit became a pure function, so undo/redo is just an array of snapshots. That separation paid off again later: Swiss Pocket Animator reuses the exact same engine, just restyled, with zero forked logic.
Interview-ready: I extracted a one-off animation mock into a reusable, dependency-free motion engine, separating pure state transitions from the one stateful transport loop, then layered a themed "preset" on top instead of forking the code per use case. That's why the Swiss-design reskin later cost almost nothing.
2026-06-11
CardShine, one of the effects that flips through on the /shaders deck, had a sizing bug where it used relative w-full h-full while every other effect in the same deck used absolute inset-0. That was inconsistent enough that its own padding and margin variables were silently shaving about 32px off its visible size compared to its siblings. The fix wasn't a one-off patch. It was removing the whole prop-based sizing system: CardShine now always fills its parent via absolute inset-0, matching every other effect's contract, so a new effect added to the deck never has to think about sizing at all.
Interview-ready: I found and fixed a sizing inconsistency in a shared card-effect system: one effect used relative sizing with padding while its siblings used absolute inset-0, silently losing about 32px. The fix removed the prop-based sizing API entirely, so every effect in the deck now shares one non-optional fill contract.