Inspiration

Hair usually starts to go around day 18 of chemotherapy. In a survey of 1,478 patients it was the most dreaded side effect (82.6% severe or moderate), and brows (90%) and lashes (88%) follow later. Every cancer charity gives the same advice: choose your wig before your hair goes, and save a lock of hair to match the colour. Every virtual try-on we could find only starts after. Kept starts before.

What it does

  • Likeness: four photos (front, two three-quarter turns, the parting). YouCam's Skin Tone, Face Analyzer, Hair Type, Hair Length, Hair Density and Fitzpatrick APIs measure curl pattern, density, length, brow colour, brow shape and thickness, skin tone and face shape. Every value shows the API and date that produced it.
  • Hair: real wigs from Shopify stores through Shop MCP. Kept reads the hair shade on every listing photo the same way it read yours, ranks them by CIEDE2000 colour distance, texture and length, and tries any of them on your own before photo with YouCam's hairstyle transfer. Checkout is prepared at the store (UCP); you review and pay there.
  • Brows: when brows thin, YouCam's makeup try-on draws them back on today's photo in your measured shape. Then YouCam's Face Analyzer measures the drawing and Kept corrects the colour until it reads as your own shade — the measuring API calibrating the rendering API. Kept also undoes the try-on's whole-face retouch so the brows sit on your real skin tone.
  • Companion: an appearance-only assistant that searches, ranks, renders and prepares checkouts. Medical questions never reach it: a keyword router and a separate fail-closed classifier hand them to a care-team card first, and every reply is checked for medical claims.
  • Wig specialists: a consented, expiring share link (measurements only unless you add a photo), a specialist view, and an MCP server so any assistant can read the same link.
  • Privacy: photos and measurements stay in the browser; YouCam tasks are deleted as soon as their results are read; one tap deletes everything.

How we built it

  • Next.js 16 / React 19 / TypeScript, mobile-first PWA on Vercel; pnpm monorepo with a pure domain core (packages/likeness), a typed YouCam client with a unit ledger (packages/youcam), a Shop MCP client (packages/shop), the gated Companion (packages/agent, AI SDK) and Kept's MCP server (packages/mcp).
  • YouCam APIs: Skin Tone Analysis, Face Attributes & Ratio Analyzer, Hair Type, Hair Length, Hair Density, Fitzpatrick (and its free pre-process face detection, which Kept uses to crop to the face and to locate the hair), Makeup VTO (eyebrows, eyelashes), Hairstyle Transfer, Hat VTO, task deletion and unit balance.
  • Colour maths in CIELAB with CIEDE2000 (tested against the Sharma 2005 reference pairs); closed-loop colour correction in Lab.
  • 184 automated tests; a guardrail evaluation with pre-registered cases, a blind held-out set and a negative control.

Challenges we ran into

  • Skin Tone and Face Analyzer reject head-and-shoulders photos ("face too small"), while hair readings need the whole head. YouCam's free pre-process step finds the face; Kept crops to it for skin and brows and keeps the full frame for hair.
  • YouCam's hair-colour attribute returns one of six families and called both our test personas (chestnut and black hair) "Auburn". Kept reads the exact shade itself from the band of hair above the face YouCam finds, and reads wig listing photos the same way so both sides of the comparison match.
  • The makeup try-on drew brows on a browless face, but they came back ΔE 17.6 lighter than the person's own. Feeding the error back (render → re-measure → correct) brought Anna's brows to the same shade in three rounds. On deep skin it isn't solved yet: Marcus's best round is ΔE 11.4, and we publish that.
  • Hair density needed a photo of the parting with part of the face still visible, so capture became four photos.
  • Keyword routing alone didn't generalise (29/40 on a blind set). A separate scope classifier that fails closed brought it to 40/40.

Accomplishments that we're proud of

  • 40/40 on a blind set of medical, urgent and everyday messages written without access to Kept; the router alone scored 29/40, and a deliberately misconfigured run still let no medical question through.
  • Brows redrawn on a face that has lost them and re-measured by YouCam as the same shade measured before treatment.
  • A wig colour-name audit on live Shopify listings: 24 of 37 sat closer to another colour name's average shade than to their own.

What we learned

A measurement is only useful if you can say where it came from and how far to trust it. Every number in Kept carries its API, date and task id, and the proof page shows the runs that went badly next to the ones that went well.

What's next for Kept

Closing the brow-colour gap on deep skin, a salon inventory import, headwear sizing from the parting photo, and a pilot with an oncology wig specialist.

Proof and links

Built With

  • ai-sdk
  • culori
  • dexie
  • model-context-protocol
  • next.js
  • perfect-corp
  • playwright
  • react
  • remotion
  • sharp
  • shop-mcp
  • shopify
  • tailwindcss
  • typescript
  • ucp
  • vercel
  • vercel-blob
  • vitest
  • youcam-api
  • zod
Share this project:

Updates

Submission history