Inspiration

Hair-progress tracking is noisy: lighting, angles, and inconsistent selfies make it hard to tell whether a routine (minoxidil, finasteride, or grooming) is working. We wanted a tiny, repeatable loop that makes photos comparable, preserves user privacy, and gives clear, non-diagnostic feedback people can act on.

What it does

  • Guides a consistent crown/scalp photo capture (fixed oval guide + countdown) so images are comparable.
  • Runs on-device object detection (ONNX Runtime Web + YOLOv8n) to find visible hair/scalp concerns.
  • Applies deterministic image-quality checks and a deterministic 0–100 visible-health score derived from model detections.
  • Enforces a fixed safety review (symptom/quality flags) that the coach cannot alter.
  • Produces an educational coach summary (optional LLM provider with a validated mock fallback).
  • Persists profiles, check-ins, coach output, and metadata to Neon Postgres (Neon Auth + Drizzle ORM).
  • Provides dashboard, history, and progress views that stay empty until a real, authenticated check-in exists.

How we built it

  • Frontend: Next.js App Router + React 19 + Tailwind CSS (motion + responsive mobile-first UI).
  • Vision: ONNX Runtime Web in-browser inference with YOLOv8n, letterbox preprocessing, and class-aware NMS.
  • Validation & services: Zod-validated analyze API, deterministic scoring and safety services written in TypeScript.
  • Data & auth: Neon Auth + Neon Postgres; Drizzle ORM with forward-only migrations and idempotent import of existing browser-only records.
  • Coach: Optional Groq provider with timeout and schema-validated mock fallback.
  • Deploy: Vercel with Neon marketplace integration; camera requires HTTPS or localhost.

Pipeline (simplified): Guide-aligned capture → quality checks → browser YOLO inference → validated detections → deterministic 0–100 score → fixed safety review → coach wording → save to Neon

Challenges we ran into

  • Keeping the product useful while remaining explicitly non-diagnostic.
  • Making browser-based inference feel fast and reliable across camera/lighting variability.
  • Ensuring the LLM coach cannot overwrite or reinterpret detections, scores, or safety rules.
  • Designing honest, polished empty-first-run states (no fake seed data).
  • Dataset limitations: small, imbalanced training exports and limited demographic/generalization coverage.

Accomplishments that we're proud of

  • End-to-end authenticated app with on-device vision — no cloud vision API required.
  • Safety firewall: coach receives only fixed score/detections/safety output and cannot change them.
  • Polished, brand-forward UI (ScoreOrb, guided capture, mobile bottom nav) and a clear demo path.
  • Honest data UX: import is idempotent and no fake history is presented as real user data.
  • Reusable architecture: deterministic scoring, Zod schemas, and a clear separation between detection, scoring, safety, and coach layers.

What we learned

  • Technical depth is more credible when the UI names the systems (on-device YOLO, deterministic scoring, safety-first).
  • Medical-adjacent tooling builds trust by clearly stating limitations and what it will not do.
  • A carefully designed empty state is a product feature, not a placeholder.
  • Browser inference improves privacy but needs extra engineering to be trustworthy in production (pose/quality checks, server-side validation).

What's next for CrownScore

  • Stronger image-quality and head-pose checks to reduce false subjects and improve repeatability.
  • Optional trusted server-side re-inference for higher assurance and better auditability.
  • Improve dataset balance, evaluation, and expanded test coverage (see KNOWN_LIMITATIONS).
  • Offline write queue and richer account export / portability controls.
  • Upgrade and harden Neon Auth SDK dependency once compatible releases are available.

Built With

Share this project:

Updates