Hair loss is one of those things people research obsessively but rarely act on, mostly because the first real step — a clinical consultation — feels like a big, expensive commitment just to find out "how bad is it, actually?" We set out to remove that barrier entirely: open the site, take a few guided photos with a phone or webcam, and get a clinical-style read in under a minute. No sign-up required, no waiting room. The product that resulted lets a visitor capture a short set of face and scalp photos, runs them through a multimodal AI vision pipeline, and returns a Norwood-scale classification, a dermatological ("trichoscopy") read of the scalp itself, an estimated graft count and cost range for a hypothetical transplant, and a ranked list of nearby clinics — all wrapped in a tabbed report that can be saved, downloaded as a PDF, or shared with a link.

This is the part that had to feel closer to a face-ID unlock than a photo booth. A live face-mesh model tracks the user's head in real time, checks it against an on-screen oval guide, confirms the pose actually matches the requested angle (front, left, right, top), and waits for two full seconds of stillness before firing the shutter automatically — no button press needed for face shots. Close-up scalp photos flip that logic: the system specifically waits until no face is detected and hands control to a manual capture button instead.
The capture flow runs a live face-landmark model over every frame and checks three signals before firing: the detected face sits inside the on-screen guide across a sampled grid of points; the head's rotation actually matches the requested angle, computed from the relative eye-to-nose distances; and the frame has been stable — movement under a small threshold — for two full continuous seconds, which is what actually eliminates motion blur rather than just timing.
Once the photo set is complete, the pipeline chains a face-landmark pass, several AI classification calls, and a set of clinical calculations — work whose total duration genuinely varies. Rather than a bar that either freezes or lies about being done, progress is modeled honestly: real, fast pre-flight steps complete quickly and visibly, then the bar advances on an estimate that's only ever allowed to move forward and deliberately stalls short of 100% until the real response actually lands.
A bar driven only by real milestones sits frozen for long stretches; a naively faked one can visibly reverse or claim completion before the network call returns. Modeling it as two phases — fast real pre-flight steps, then an estimate-driven phase that never reverses and never claims 100% early — means the bar never looks broken and never lies.

The centerpiece of the product. A stage classification with a confidence score sits front and center, backed by a four-stat summary (graft count, golden-ratio deviation, symmetry score, session/recovery estimate), a cost comparison across treatment geographies, and a set of AI-generated suggestions personalized against the user's stage and intake questionnaire answers.
For users who provide an actual scalp close-up, a second, deeper AI pass produces a genuinely clinical-style trichoscopy report: hair density and diameter-variation measurements, follicular and vascular pattern findings, scalp-surface observations, and a primary diagnostic impression with a confidence score and differential diagnoses. This tab is gated behind a free account, both because it's the most sensitive data the product produces and as a natural conversion point.
For anyone weighing an actual transplant, the product renders a proposed hairline design — distance from the glabella, temporal angle, transition-zone width — computed against measured facial geometry and Rule-of-Thirds / golden-ratio conventions, with a plain-language summary of how far forward the new hairline would sit relative to the current one.



| Challenge | How We Solved It |
|---|---|
| Getting a general-purpose AI model to behave like a deterministic clinical classifier | Rewrote the prompt as an explicit decision tree with hard per-stage criteria, a default-to-least-severe rule, and a numeric confidence rubric; separately validate required clinical fields instead of trusting "valid JSON" alone. |
| The model was over-cautious exactly where it needed to commit | Added an explicit override: any visible scalp/hair forces a minimum confidence floor, with residual uncertainty expressed via the differential-diagnosis list, plus a worked density-counting method and a sanity-check against the Norwood-context photos. |
| External AI dependencies fail, rate-limit, and get deprecated | Every AI capability runs a primary model plus an ordered fallback chain, swappable via env vars; 404s skip to the next model, 429s back off and retry, and best-effort generation steps fail silently rather than 500. |
| Building an auto-capture camera without a shutter button | A live face-landmark model checks guide alignment, requested-angle rotation, and two full seconds of stillness before firing; scalp close-ups invert the face-detection signal and fall back to a manual button. |
| A database constraint that only bites once real data exists | Firestore rejects arrays-of-arrays (the density-heatmap shape); a recursive sanitizer now strips that field and other non-essential fields before every write. |
| Local storage quota exhaustion from "just cache everything" | Excluded the heaviest fields (base64 image/heatmap payloads) from persisted history, capped history by age and count, and added quota-error retry against a smaller retained set. |
| An honest progress bar for a process with no fixed duration | Modeled as two phases — real fast pre-flight steps, then a forward-only estimate that stalls short of 100% until the response lands. |
| A public "share this report" feature sitting on top of an owner-only data model | Instead of loosening the owner-only security rule, added a narrow server endpoint with elevated server-only credentials for the one legitimate public-read case, keeping the general client-facing rule strict. |
| Two measurement systems that don't fully agree yet | Shipped both the in-browser landmark model and the server-side vision model without blocking launch on full reconciliation; the app is explicit about which figures come from which source, with reconciliation scheduled as follow-up. |
| Duplicated ranking logic across three screens | Flagged as technical debt rather than patched silently — the textbook case for extracting shared domain logic into one utility once a second call site appears. |
A searchable, sortable directory ranks seeded clinic listings by proximity to the user's saved location, surfacing specialties, price tier, an estimated per-graft cost, and direct call/website actions — turning "I now know my situation" into "here's who to call" without leaving the product.
A skippable questionnaire — family history, hair-care habits, lifestyle factors, medical background, and the specifics of the hair loss itself — feeds directly into the personalization layer: the care-tips generator and the AI suggestion cards both read from these answers when they're available.
A simple account surface: editable name, date of birth, location (with live city/state autocomplete), and gender, plus a summary card showing computed age and quick links back into the intake flow and saved report history.
A static knowledge base — hair loss types and the Norwood scale, surgical and non-surgical treatment explainers, a month-by-month recovery timeline, and a categorized FAQ — exists both to build trust before someone commits to the camera flow and to give the product an organic-search footprint independent of the tool itself.




Frontend: Next.js (App Router) + TypeScript + Tailwind, Zustand for client state, a real-time face-mesh model running entirely in-browser for capture guidance.
Backend: Firebase Auth + a non-default named Firestore database for accounts and saved reports, serverless API routes for the AI pipeline, PDF generation, and clinic/location lookups.
AI layer: a hosted multimodal LLM handles both the Norwood classification and the trichoscopy read, driven by heavily engineered prompts rather than a fine-tuned model — the entire clinical behavior of the product lives in prompt design, output validation, and a chain of fallback models.
Shipped: guided multi-angle capture with automated framing, Norwood classification, trichoscopy-style scalp analysis, graft/cost estimation, a branded downloadable PDF, a public share link, accounts with saved history and trend charts, a clinic directory, and a static education library.
Deliberately descoped for v1: a peer community feed, a celebrity hair-analysis showcase, an interactive "simulate my results" editor, in-app consultation booking, a paid subscription tier, a packaged mobile app, and analytics/A-B-testing instrumentation.
A visible mid-build pivot: early planning assumed a different backend and auth provider entirely; the shipped product runs on Firebase instead, with the original schema left in the repository as a dormant historical artifact rather than deleted.
Honest open items: a full cross-browser QA pass, a formal performance audit, and deployment documentation all remain explicitly unfinished internally, despite the product already running live — a realistic state for a fast-moving first release, not a hidden one.