
Problem
A portfolio has one job: get a visitor from "who is this?" to "I want to talk to them" without making them work for it. The usual failure is a single endless scroll that mixes three unrelated errands — someone hiring a QA engineer, someone hiring a data analyst, and a small business owner pricing a website all land on the same wall of text and have to dig.
The second problem is narrower and more personal: my work splits across two identities — QA/data and web development — and a portfolio that flattens both into "full stack" says nothing.
Approach
Three surfaces, not one page. Work is the projects grid, Services is the paid-work funnel with pricing, and Info is the résumé surface — about, education, skills, experience, contact. The navbar is a three-tab pill, so the visitor picks their errand in one click instead of scrolling to find it.

The dual identity is handled by the grid itself rather than by a persona quiz: a three-way filter (all / web dev / data & qa) with a sliding pill indicator that turns coral for web-dev and violet for data & QA — the same two accents used site-wide, so the color is doing the labeling. The filter reads ?role= from the URL, so a link can drop someone straight into the relevant half of my work.
Architecture
- Next.js 16 App Router — Server Components by default. Client components exist only where they must: the tab bar (pathname), the grid filter (state), the typed hero, the particle canvas, and the magnetic buttons.
- Tailwind CSS v4 with OKLCH tokens — a light-lavender base (
--color-background: oklch(0.92 0.042 292)) with coral and violet brand accents plus mint/amber status colors. Every token is defined once inapp/globals.css; nothing hardcodes a hex. - MDX content layer — each case study is one file in
content/projects/. Frontmatter drives the card, the body drives the page, andmdx-components.tsxmaps every element to design tokens so prose matches the site without a typography plugin. - Particle substrate — a canvas of ~85 drifting nodes that link when within 150px and repel from the cursor, reading its color straight from
--color-violetso the effect can never drift from the palette.
Implementation
The Info surface is where the résumé actually lives, assembled from independent section components rather than one page file — about, education, skills, experience, résumé, contact.

Skills are the part most portfolios get wrong by listing every technology at equal weight. Here each skill carries an honest proficiency level — proficient, familiar, or learning — grouped into QA, Data, Web, and Docs with a counted filter row, so the claim is legible instead of inflated.

Experience is a timeline with expandable entries, framed as a trajectory rather than a job list.

Contact closes the page with the things a recruiter checks before writing: local time, availability, response window, and every channel in one row — no form to fill in.

Challenges
The lavender base fought the accents. Coral at oklch(0.55 0.19 35) looked right and measured 4.31:1 against the background and 4.22:1 against its own tint — both under WCAG AA. Darkening it to 0.50 fixed both without changing the character of the color, and the reasoning stays as a comment next to the token so nobody "brightens it back up" later.
The particle canvas had the opposite problem: readable motion that doesn't compete with the text. It sits behind everything at low alpha, the link lines fade with distance, and the whole loop is skipped when prefers-reduced-motion: reduce is set — decoration that is allowed to disappear entirely.
Outcome
A portfolio with three clear entry points, a project grid that can be linked to by role, and case studies that ship by dropping an MDX file into a folder. Verified with Vitest unit tests and Playwright browser tests, deployed on Vercel.
Lessons Learned
Splitting one scroll into three surfaces was the change that mattered — far more than any animation. Each visitor type now has a page that is entirely theirs, and the site can grow in one direction without crowding the others.
The design-system discipline paid off in an unglamorous way: because every color is a token and every contrast decision is written down next to it, the accessibility fixes were three-line edits rather than a redesign.