What Lihya is Lihya reads the skin underneath a beard from a single front-facing photo, converts eight YouCam AI signals into named conditions and one score, then renders hair and beard styles on that same face.

One upload. One file_id. Seven Perfect Corp features.

The problem Beard care is decided by packaging. A man whose beard is flaking has four plausible answers in front of him — dandruff shampoo, an exfoliant, a heavier oil, a beard wash — and no way to know which one his skin is asking for. He buys one, it is wrong, and the next purchase is another guess.

The signals that would settle it are already measurable: sebum, hydration, texture, folliculitis, razor irritation. They are simply never measured at the point of purchase. And for most men in the Gulf, the barber is the dermatologist, so an English-only, account-gated beauty app never reaches the counter where the decision is made.

What it does Drop a photo. In about twelve seconds the studio returns eight beard-zone signals, the face shape, and the skin type. A deterministic engine turns those into six named conditions — beard dandruff, folliculitis and bumps, razor irritation, dryness and brittleness, congested pores, dullness — each with its severity, the exact signals behind it, and the next action.

Then the try-on step renders the chosen beard, or one of twenty hairstyles pulled live from the AI Hair Style Virtual Try-On catalogue, on the user's own photo, from the same upload. No second photo, no second billable upload.

The interface is bilingual, right-to-left first-class, and works without an account.

The Beard Index The index is not a model and not an LLM. It is a fixed weighted mean of the normalised signals, where the weights encode what dominates the beard zone: the barrier, the follicles, the sebum.

w=(moisture .22, oiliness .18, acne .18, redness .16, pore .10, texture .10, radiance .06)

The same photo therefore produces the same number twice, and every point of it can be explained to the customer.

How I built it Next.js 15 App Router, React 19 and strict TypeScript. One hand-written stylesheet, inline SVG icons, no component library.

Every Perfect Corp call runs inside a route handler behind import 'server-only', so the API key is unrepresentable in a client bundle. The full asynchronous contract is implemented explicitly: file registration, pre-signed S3 PUT, task creation, polling with backoff, and re-resolution of result URLs before they expire.

A scan is a detached server task with a replayable event buffer; the browser only subscribes over server-sent events. A closed tab therefore cannot orphan a task that still costs units, and a finished run can be reopened at /?run=.

A unit ledger reserves before each call and commits only on success, mirroring YouCam's own billing rule, and answers with a 402 credit_insufficiency instead of a silent failure. Four scan depths are priced up front — LITE 12 units, CORE 22, PRO 36, MAX 56 — and each hair or beard render is 2.

YouCam APIs used AI Skin Analysis V2.0 — /s2s/v2.0/task/skin-analysis AI Face Attributes & Ratio — /s2s/v2.0/task/face-attr-analysis AI Beard Style Generator — /s2s/v2.0/task/beard-style AI Hair Style Virtual Try-On V2.1 — /s2s/v2.1/task/hair-transfer Hair template catalogue — /s2s/v2.1/task/template/hair-transfer AI Fitzpatrick Skin Type, AI Facial Color Tones, AI Skin Simulation — modelled, priced and gated by tier File API — /s2s/v2.0/file, with the pre-signed upload step Screenshot: the studio with the Beard Index at 74 and a real try-on in the gallery.

Challenges YouCam rejects mixed SD and HD actions with InvalidParameters, so the pipeline depth has to be decided early and guarded before the network call — a malformed request should cost zero units, not a round trip.

Response shapes differ per feature and version: flat arrays, sub-regions, or wrapped in results, output and score_info. One tolerant normaliser had to survive all three.

The hair catalogue rejects next_token as a query parameter while the beard catalogue accepts it, so pagination is per-catalogue, not generic.

And the deepest one: scores are not conditions. The first build displayed eight numbers. It was accurate and useless. The product only became real once it owned a vocabulary and could defend every label with the numbers behind it.

What I learned Consumer value lives in the vocabulary layer, not the model layer. The API already knows the skin is dry. The product has to know what dry skin means under a beard, and say it in the customer's language.

Accomplishments Seven YouCam features composed into one pipeline that shares a single upload and one unit ledger. A deterministic index — no LLM, so the reading is reproducible and auditable. A verified live run, with the verbatim payload committed to the repository as evidence. An Arabic interface that is a first-class product, not a translation. What's next Longitudinal tracking — re-scan in fourteen days and show the delta per condition. A retailer view that aggregates de-identified condition distributions for assortment planning, so a brand can see which beard concern its range under-serves. And the remaining hair diagnostics — type, length, frizziness, density — which slot into the existing tier-driven pipeline as new steps rather than new architecture.

Built With

  • ai-beard-style-generator
  • ai-face-attributes
  • ai-facial-color-tones
  • ai-fitzpatrick-skin-type
  • ai-hair-style-virtual-try-on
  • ai-hair-transfer-v2
  • ai-skin-analysis
  • ai-skin-simulation
  • beauty-tech
  • computer-vision
  • css
  • framer-motion
  • grooming
  • next.js
  • node.js
  • perfect-corp
  • playwright
  • react
  • rest-api
  • server-sent-events
  • skincare
  • typescript
  • virtual-try-on
  • youcam-api
Share this project:

Updates

Submission history