Web Apr 2026

JMR Advisory: a portfolio that moves

JS shipped
88 KB gz
JS budget
<200 KB
a11y gates
axe + LH in CI
JMR Advisory: a portfolio that moves

Why a portfolio at all

After eight years in pharmacy benefit management — most recently as Lead, Rebates Data & Reporting at Abarca Health — I founded JMR Advisory to do data automation and web design from Puerto Rico. A portfolio site is the cheapest, highest-leverage artifact in that pivot: it filters inbound work, demonstrates the craft itself, and forces a discipline of editorial restraint that client work rarely gives you.

I wanted the site to be the case study — to render at SOTD-credible level, to ship in a sub-200KB JS budget, and to stay accessible end-to-end. None of that is novel; all of it is hard.

The brief

A self-imposed brief, with non-negotiables:

  • A hero that earns the scroll — but readable underneath. No mystery-meat navigation, no infinite scroll for its own sake.
  • Sub-200KB total JS gzipped. Lighthouse perf gates run on every PR.
  • WCAG-compliant, keyboard-first. axe runs in CI. Reduced-motion is honored at the design-token layer, not as an afterthought.
  • Static-first. Astro 6 with Preact 10 islands only where the page actually needs interaction. The hero is the one exception.

The Loom

The hero is a four-strand weave that breathes — career visualized as data, engineering, design, and business strands intersecting at year markers. It’s an OGL canvas (not three.js — the bundle math doesn’t work with three) running one geometry and two shaders: a thread shader with a sustained breath glow, and an intersection shader that blooms additively at event positions. Scroll progress drives a uUnfurl uniform that animates the strands in from collapsed to woven.

Reduced-motion or no-WebGL falls back to a static SVG version of the same composition with CSS pulse animations — same visual grammar, zero canvas cost.

Measured numbers from the build:

  • JS shipped: 88 KB gz (44% of the 200 KB budget)
  • Static pages: 4 — /, /work/, plus two case-study routes
  • Total bundle deltas this phase: zero new JS islands

What’s still hard

Honest list:

  • The performance budget is ratcheted, not relaxed. CI Lighthouse gates were temporarily set to perf ≥90, LCP ≤3s, TBT ≤250ms when the WebGL hero shipped. Tightening them back toward the original 99-across-the-board is a tracked next milestone, not an open question.
  • The reduced-motion fallback shipped before the audio layer. Placeholder ambient audio is intentionally muted by default; the fallback exists, but the polished version is later in the roadmap.
  • Lenis is scaffolded but initLenis() is never called. ScrollTrigger runs against native scroll for now — fine, just less silky.

These are tradeoffs, not bugs. The site shipped because the calls were made deliberately and the regressions are scoped.

What’s next

Phase 3 (the route you’re reading right now) seeded the editorial layer: career timeline, skills mosaic, project grid, this case study route. Phase 4 adds an in-browser SQL playground over a synthetic PBM dataset — the smallest possible “show, don’t tell” for the analytics-engineering side of the practice. Phases 5–6 are content, polish, and launch.

The site, like the practice, ships in waves.