Inspiration
Being told which colors suit you is a real, paid service. Sessions run $80–$300, the well-known analysts have months-long waiting lists, and the whole industry comes down to one person holding fabric under your chin and giving you their opinion. Ask two analysts and you get two answers.
But the idea underneath it is not folklore. Whether a color flatters you depends on things that are genuinely measurable: the undertone of your skin, how deep your coloring is, and how much contrast sits between your hair and your face. Those are numbers. Nobody was measuring them — they were being eyeballed.
YouCam's Facial Color Tones Analyzer returns exactly those numbers. That is the whole reason this project exists.
What it does
TrueTone turns one selfie into a color profile you can see on yourself.
- Measures your coloring. The Facial Color Tones Analyzer returns the actual hex values of your skin, hair, eyes, brows and lips — on the test subject,
skin #967054,hair #000000,eyes #1e161a. - Reads your skin. YouCam Skin AI scores redness, under-eye shadow, radiance, texture, shine and eye bags, plus a skin age — so the advice fits the skin you have today, not a generic type.
- Derives your profile. Those values are converted to CIELAB and reduced to the four axes a color analyst actually works from — undertone (the b*/a* ratio of skin), depth (skin L*), contrast (the L* gap between hair and skin) and clarity (skin chroma) — landing on a season such as True Autumn.
- Ranks a palette, scoring each garment by CIEDE2000 distance, lightness step and hue geometry, weighted by what the skin reading found. Every verdict comes with its reasoning in plain words.
- Proves it. Apparel VTO renders your picks onto your body, and the render is then measured: the fabric color is read back out of the image and compared against your skin tone in CIELAB.
It also shows its working. Skin AI's per-concern mask overlays are displayed on your analyzed face, so a score becomes something you can point at. And the palette is scored twice — with the skin reading and without — so you can see exactly how much your skin's current condition moved the ranking. On a clear complexion that shift is small, and the app says so rather than implying the skin data did work it did not do.
How we built it
React Native (Expo SDK 57, TypeScript), one codebase running as an Android app and as a web build on Vercel. Server-side API routes hold the API key and orchestrate three YouCam APIs; the same route implementation serves both platforms.
| API | Endpoint | Role |
|---|---|---|
| Facial Color Tones Analyzer | POST /s2s/v2.0/task/skin-tone-analysis |
Measured skin, hair, eye, brow and lip hex |
| AI Skin Analysis (HD) | POST /s2s/v2.1/task/skin-analysis |
Concern scores + skin age, weighting the palette |
| AI Clothes (Apparel VTO) | POST /s2s/v2.0/task/cloth-v4 |
Renders each garment onto the user |
Each feature is pinned to the newest engine it publishes, which is not the same version across the suite. Uploads and polling run in parallel, so a full analysis is one round trip of about eight seconds.
The color reasoning is mine. CIELAB conversion, CIEDE2000 difference, the four-axis profile and the garment scoring all live in src/logic/ and make no API calls at all — they can be checked offline without spending a credit. The APIs supply measurements; the engine supplies judgment.
Challenges we ran into
The original premise was wrong, and testing caught it. The first design ran Skin AI on the try-on render, compared it against the baseline, and claimed a garment improved your skin by a measured amount. It was a great pitch. It was also false: coral (predicted +33) and teal (predicted −16) both moved the measured skin scores by −1. Apparel VTO replaces fabric without relighting the face, so the face pixels are essentially unchanged and any skin analyzer must return the same scores. There was no effect to measure, by construction.
Rather than ship a claim a judge could disprove in two try-ons, I moved the measurement to something the garment genuinely determines — the fabric-to-skin color relationship, taken off the render itself.
The two APIs want opposite things from the same photo. Skin AI and the tone analyzer reject frames whose face spans less than 60% of the image width (error_src_face_too_small) — an ordinary chest-up selfie fails outright. Apparel VTO needs the untouched frame and rejects a face crop with error_no_shoulder. The app therefore sends two versions of the same photo: cropped for analysis, whole for try-on. face_quality.area flips from toosmall to good once cropped.
A silent image-processing bug. Every sampled fabric color came back identical, because sharp's .stats() reads the input image and ignores a queued .extract(). It was returning whole-image averages while looking perfectly plausible — the kind of bug that produces numbers rather than errors.
And then sharp could not ship at all. It worked locally and died on Vercel: Metro bundles it into the serverless function and rewrites its import.meta.url to globalThis.__ExpoImportMetaRegistry.url, which exists only inside Expo's own server runtime. On Vercel that is undefined, so the function crashed before any of my code ran — every request returned 500, empty bodies included. Fabric sampling now decodes JPEG in pure JavaScript, and cropping moved to the client, where expo-image-manipulator does it natively on the phone and via canvas on the web. That turned out both faster and better quality than the server-side version.
Accomplishments that we're proud of
Every number in the app is one it observed. No score is invented for effect, and where the engine makes a prediction it is printed next to the measurement taken off the actual render. They can be compared, and sometimes they agree for the right reason: the engine marked Deep Teal down partly because its lightness sits too close to the wearer's skin, and measured off the render the lightness step was 1.9.
Choosing the honest product over the impressive one, after the false premise had already been built, demoed and written up.
The app admits when an API barely contributed. On a clear complexion the skin reading moves almost nothing, and the screen says that in plain words instead of dressing it up.
Chasing the newest engine paid off measurably. cloth-v4 cut the render's drift from the requested swatch from 7.0 ΔE to 1.8 ΔE — which matters here, because this app measures rendered fabric color. Skin Analysis v2.1 returns scores inline instead of a ~1 MB ZIP, cutting analysis from ~11 s to ~8 s and removing a dependency.
One codebase, two platforms, one server implementation — the API key lives only on the server in both.
What we learned
Undocumented API behavior I mapped by probing the live endpoints: the apparel segment is cloth, singular — clothes returns 404; v2.0 takes a flat task payload and wraps responses in data, while v1.0 nests the payload and wraps in result; polling is a path parameter, not a query string, and reports progress under task_status; Skin AI's v2.0 path returns a ZIP of score_info.json plus a mask PNG per concern rather than inline scores; and the SD concern set has no dark_circle, which is why this app pays for HD.
More broadly: the honest version of a product is usually better than the impressive-sounding one, and it is worth finding that out before a judge does. Two extreme colors were all it took.
What's next for TrueTone
Your own wardrobe. Photograph a shirt you already own, get it scored against your profile and rendered on you. That closes the loop from "here is your palette" to "here is what to wear tomorrow" without needing a catalogue at all.
A real catalogue. YouCam publishes 250 predefined garments across categories via GET /s2s/v2.0/task/template/cloth. Ranking those by fit with your measured profile turns the app into a shopping surface rather than a demo.
The rest of the suite. The same four axes apply to bags, scarves, hats and jewellery — every one of which has its own YouCam try-on endpoint.
A standalone Android build via EAS, pointed at the same deployment the web app already uses.
Built With
- android
- apparel-vto
- ciede2000
- cielab
- expo-camera
- expo-image-manipulator
- expo-image-picker
- expo-router
- expo.io
- facial-color-tones
- github
- javascript
- jpeg-js
- metro
- node.js
- perfect-corp
- react
- react-native
- react-native-web
- rest-api
- serverless
- skin-analysis
- typescript
- vercel
- youcam-api

Log in or sign up for Devpost to join the conversation.