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
Deep-dives into the architecture decisions, trade-offs, and lessons behind everything in this project, grouped by area.
Research Explorer
Finding a research topic by measuring the literature: PubMed counts as evidence levels, a curated query layer, and demographic coverage as the gap finder
Learn
Thirteen demos that each rebuilt the same stepper, one useStepPlayer hook, and the overrun the characterisation tests caught
Particle Lab
Two point clouds instead of an object per particle, and why the connection-distance slider is really the performance dial
Explore Toronto
A walkable 3D Toronto built from primitives: a TDD'd pure movement core, an R3F shell around it, a seeded procedural skyline over a real street grid, and exhibits that deep-link back into the site
Gallery Wall
An arranger built pure-core-first: standard frame sizes, an aspect-matching auto-framer with a medium tie-break, a centered shelf-packing layout with overflow detection, and an inches-internal model with a cm toggle at the input edge
Feature Flags
A flag console built engine-first: deterministic FNV-1a bucketing with an avalanche step, sticky and monotonic rollouts, first-match targeting, an explainable evaluation reason, and why the pure core is the whole design
The To-Do List
Soft delete so a mis-click survives, positions assigned server-side so two adds cannot claim the same slot, and an optimistic insert that rolls back the row it added rather than the last one
TCG Pages
API proxy, server/client split, pagination patterns
Calendar
Views, timezone handling, BFF auth pattern
NBA Playoffs Bracket
TDD with MSW, derived state, TBD resolution, submit vs. auto-save design, and leaderboard before results
Fantasy TCG
Minting rarity-tiered trading cards from real ESPN fantasy performances, rarity set relative to the pool
Operator Dashboard
Fleet management with tiered polling, optimistic updates, data freshness, and a globalThis singleton for in-memory state
Work Portfolio
Rebuilding 22 features from 10 old jobs as self-contained demos: reconstruction over emulation, anonymizing client work, the no-new-deps rule, the dual-ticker UX, and shipping it as merge-order-independent PRs
Ketsup
A social app for image and text posts, built and shipped at its own domain
Draft Lab
A Firefox extension living inside the ESPN draft room: pick sync, tier supply, keepers, and live recommendations
AI Agent Patterns
SSE streaming, state machines, tool call UI, approval gates, and streaming markdown — the patterns behind modern agent interfaces
macOS Menu Bar
Turning a desktop clone's dead top-bar labels into a signal-driven macOS menu system — menus derived from window and dock state, real actions, and full keyboard a11y
Craft
A page that reframes the whole site as evidence: ten lead front-end traits, each expandable to the real work that proves it, with a data-integrity test that fails on a dead evidence link
Command Palette
The site-wide ⌘K palette: one globally mounted instance opened from a hotkey or a window event, a registry reused from the hub's FEATURES and THOUGHTS, a hand-rolled fuzzy matcher, and an honest ARIA combobox
Shared Design System
Extracting tokens and components into @paul-portfolio npm packages — CSS custom properties, thin framework wrappers, and token aliasing across React and Angular apps
Framework-Agnostic Charts
Rebuilding recharts and unovis charts as pure SVG from one dependency-free geometry core — Sparkline, BarChart, DonutChart rendering identically in React and Angular, with a token palette and role=img a11y
Design System Showcase
Building a live, in-app gallery for the shared design system: dogfooding the primitives, a data-driven catalog with an integrity test, an interactive props playground, and an axe-checked accessibility contract
Motion Components
TiltCard, GradientBackground, and Spotlight for the shared design system — pointer-driven motion built static-first, with reduced motion as the default and one shared usePrefersReducedMotion hook
Styling Decisions
CSS Modules vs Tailwind v4 and design tokens
Landing Page
Section layout and functionality preview
UI Redesign
Why CSS keyframes gave way to Framer Motion, where Three.js went, and what's actually measurably better
V2 Redesign
URL-based version routing with next/dynamic bundle splitting — Three.js out of the default path, v2 ships a clean slate
V3 Redesign
The whole site as a node graph — a hand-rolled force sim, fit-to-viewport rendering, the drag/hover bugs, and an a11y audit
V4 Redesign
The landing and hub as a slot machine: three dependent reels (category, option, write-up) derived from the same data as the graph, dependent-reel selection, a decelerating spin, and a listbox-based a11y model
V5 Redesign
Retiring the slot machine from the root: a warm editorial palette measured against WCAG before it was written down, eight in-house motion primitives held to a no-opacity-zero-above-the-fold rule, and a landing page briefed against my own defaults
Accessibility
WCAG 2.1 AA compliance — vitest-axe for unit-level scans, systematic primitive audits, and where automated tooling helps vs. where it doesn't
Performance Improvements
Eliminating the dark-mode flash, ISR on static pages, lazy-loading below-fold sections, and caching public API routes
Render Performance
Runtime rendering costs: context instability, resize allocation, backdrop-filter GPU pressure, and unbounded DOM growth
Web Vitals
Real-user metrics, sendBeacon, P75, the collection pipeline, and alerting when a vital goes bad
Bundle Analysis
How the analyzer found Auth0Provider shipping jose to the browser for no reason
Tree Shaking
The three kinds of dead weight, why removing an unused export isn't a bundle win, the judgment calls a depcheck report can't make, and wiring it all into CI as a blocking check
Tree Shaking, Round 2
A second pass from green dead-code checks: tree-shaking the barrels Next doesn't optimize by default for a measured 148KB, then a real LCP fix — moving the entrance reveal off the JS bundle and lazy-loading the operator charts
GraphQL
Why GraphQL, why plain fetch over Apollo
Route Restructure
Why / replaced /protected, the force-static trade-off, and how auth is still enforced
Hybrid Rendering
Giving each Angular route the render mode it needs — the Thoughts pages prerender to static HTML at build time via per-route RenderMode, a SeoService writes the head and JSON-LD on the server, and the interactive shell stays client-rendered
API Hardening
Zod validation, fixed-window rate limiting, and body size limits across every API route
API Backend Overhaul
Rebuilding portfolio_api into a typed, layered TypeScript backend across twelve phases, without breaking a single contract paul-explore depends on
Taking the Database Off the Public Internet
A front-end engineer working through the backend half: a Postgres reachable from anywhere, a TLS rabbit hole worth abandoning, migrations nothing ran, and four minutes of downtime from a rotation whose failure arrives late
Login Redirect
Landing back on the route you logged in from, and turning a denied consent screen from a bare 500 into a toast, both fixed at the Auth0 choke point
React Doctor
Working a static-analysis pass: real fixes, the fix that fought back, false positives, and why severity isn't priority
Project Review
An evidence-backed review of the whole codebase — engineering, system design, architecture overfit, and per-feature UX gains
Refactor Pass
The maintainability roadmap after the review — deduping against existing abstractions, the overfits I avoid, and the order I ship in
Testing
2729+ tests (2670 unit + 59 e2e), Vitest + MSW + Playwright, and the delay() trick for proving optimistic updates fire before the server responds
E2E Testing
Auth0 Universal Login, global setup/teardown, the Google OAuth button hijack, and what broke when we actually ran them
CI E2E Reliability
Auth0 crashing all middleware from a module-level throw, and a search test that needed page.route to stop depending on an external API
Green Checks
Four green checks in the design system that were each measuring something other than what they claimed — the suite nothing ran, the visual gate with no quota, the contrast figure taken under the gloss, and the count that moved when you built
Tiered Testing Strategy
Why you shouldn't run every test on every commit: split by cost — fast unit tests per push, integration on merge, e2e nightly, flaky ones quarantined
CSP & Security
Why 'unsafe-inline' is the right call for Next.js static pages, and what actually prevents XSS
AI Security & Bare Repo Attacks
Prompt injection via CLAUDE.md, hardened least-privilege configs, deny lists, and sandboxed environments for untrusted code
Auditing for Absences
AI-written code passes security tests 56% of the time and fails worst on what is missing. A cross-repo audit, and the seven shapes of absence it actually found
npm to pnpm
Strict dependency resolution, version range surprises, and what a package manager migration actually involves
Bundlers
Which bundler this project runs and why, whether it's the right one, and the real situations where a lead reaches for a different bundler — the deliverable and the dominant constraint pick it, not taste
Deployment
Deployment as five separate jobs, choosing a platform from the app's runtime shape, when to decide, the trade-offs that bite, and the Vercel + Cloudflare setup behind this site
PR Screenshots From an Unattended Agent
Embedding before/after screenshots inline in PR descriptions with only the gh CLI — why user-attachments, gists, and release assets all failed, and why we don't prune the PNGs
TypeScript 7
Why the Go-native compiler is a no for now: the lint stack peer-caps below it, and a 4-second type-check makes the 10x moot
Visual Plans
Why I bracket every change with a visual plan before code and a recap after: structured wireframes over prose, the RED list as the plan, and an honest record of where reality drifted
Crawlers
The five files a site is supposed to serve and this one didn't: what to leave out of robots.txt, why the sitemap carries no lastModified, and the test that stops it going stale