One color for every complexion
Four to eight women, often spanning Fitzpatrick I–VI, must wear the same colorway. The shade that flatters the bride's own skin can drain every other complexion in the photos — the photos that last forever.
Built for the YouCam API Hackathon · Topic C — Skin AI × Apparel VTO
Bridesmaid dresses are one color for the whole party — and usually final-sale. OneDress measures every bridesmaid's real skin hex and Fitzpatrick depth, solves for the single color that harms the group least, and renders it photorealistically on each of them.
The app opens on a cached demo party — six measured bridesmaids, zero API units spent, no key required. Engine proven live against 5 YouCam (Perfect Corp) endpoints.
The problem
The bridal party is the one wardrobe decision made for a group — and it's made with less measurement than buying a pair of shoes.
Four to eight women, often spanning Fitzpatrick I–VI, must wear the same colorway. The shade that flatters the bride's own skin can drain every other complexion in the photos — the photos that last forever.
Bridesmaid dresses are ordered months ahead and are frequently non-refundable. Once the color is chosen, it's effectively irreversible — there is no "return it if it washes someone out."
Today the color is picked from one retailer model who matches nobody in the party, then debated over group-chat screenshots. Mailed swatch kits and the "mismatched dresses" trend exist precisely because one-color-for-all keeps failing across skin tones.
The inversion
Every personal-color tool answers a one-person question. OneDress inverts the primitive.
One selfie → one verdict. Run it for five bridesmaids and you get five different answers — which chooses zero dresses. Single-user verdicts don't compose into a group constraint.
A fixed garment constraint, N measured complexions, one answer. This is a constrained group-optimization problem — no amount of personal-color analysis composes into it.
It's a max-of-minimum — Rawlsian — fairness problem: optimize the least-flattered person, not the average. The winner is never any individual's top pick, and by construction the deepest-skin bridesmaid — the one the industry has historically served worst — is the protected one, not the sacrificed one.
How it works
Four moves, five live YouCam endpoints — the measured skin values drive the render; they aren't decoration beside it.
Two phone photos per bridesmaid — a face selfie and a full-length. Three live analyses return her measured skin hex, her Fitzpatrick depth (I–VI), and her face shape. Real values, printed on the card: #bb9982 · ITA° 43 · hue° 61.
Every curated colorway is scored against every measured profile with a published formula — undertone harmony, value contrast, saturation. It's pure math on cached measurements: re-scoring all 24 costs zero API units. The winner is the max-of-minimum pick.
The winning colorway is rendered photorealistically on each bridesmaid's own full-length photo with AI Clothes Try-On — measured render fidelity ΔE00 median 7.8, range 5.5–11.2 against the intended swatch. Seeing all six in the same color is the proof no swatch kit can give.
Face shape picks each woman's silhouette — stud, hoop, or drop — and her undertone picks the metal: gold for warm, silver for cool. It's a second, smaller color-harmony decision rendered onto the try-on, chained from the dress render.
The palette
Warm × cool × neutral, each at light / medium / deep, muted / saturated — so every skin tone I–VI has at least one strong candidate. The maximin winner is chosen from real options, never a floor of desperation. All names are original; no trademarked colors.
The math
The whole engine is disclosed: fixed color physics (sRGB → CIELAB, ITA°, hue angle, ΔE2000) plus three calibratable weights. Toggle the objective below and watch who pays for the "prettier average."
// each (bridesmaid p, colorway c) flatter(p,c) = 0.50·U + 0.30·C + 0.20·S U undertone harmony — dress warmth vs skin warmth (CIELAB hue°) C value contrast — |ΔL*| inside a flattering band S saturation harmony — enough chroma to read as its own color // group objective — Rawlsian maximin groupScore(c) = minₚ flatter(p,c) winner = argmax_c groupScore(c) // the counterfactual — today's way by-eye = argmax_c mean flatter
Why maximin? Averages hide victims. Maximizing the mean happily sacrifices one bridesmaid to make the group photo "mostly nice." Maximizing the minimum makes the least-flattered person the whole objective — nobody can be quietly thrown under the bus.
Full derivation and constants live in lib/colorway/engine.ts — unit-tested against CIELAB reference anchors.
Real engine output, not a mock-up: the per-person scores for the six synthetic Fitzpatrick I–VI profiles in lib/demo/demo-party.ts. The engine picks marigold with nobody below 57.8; the mean-maximizing pick (rust) drops the deepest-skin member to 38.8. Treat the size of that gap as illustrative — a units bug in our own undertone term inflates it, and we published the defect rather than patching it (docs/scoring-defect.md). What survives every correction is the shape: the objective you choose changes who pays.
Verified live
Every load-bearing endpoint has been run end-to-end against the live YouCam (Perfect Corp) API — not mocked, not planned. One command reproduces it.
| Endpoint | Role in the flow | Verified live result |
|---|---|---|
| skin-tone-analysis | measured skin hex — the scoring input | #bb9982 → ITA° 43 · hue° 61 |
| fitzpatrick-scale-analyzer | Type I–VI depth badge — displayed, never scored | Type II returned on the test face |
| face-attr-analysis | face shape → earring silhouette | "Heart" returned on the test face |
| cloth-v3 | renders the winning color on each bridesmaid | photoreal render · fidelity ΔE00 median 7.8 (5.5–11.2) |
| 2d-vto/earring | chained finishing touch (undertone → metal) | gold hoop landed on the dress render |
Status, honestly: the typed API client, the live five-endpoint integration, and the published scoring engine (82 passing tests) are done and reproducible — run npm run spike. The interactive product UI ships in this same deploy — open it at /party, where it runs on a cached demo party with zero API units spent. Nothing on this page is a screenshot of an app that doesn't exist.
Sponsor track
Three Skin AI endpoints feed the math; two VTO endpoints make its answer visible. The categories aren't stacked side by side — one drives the other.
Remove any one endpoint and the flow visibly breaks — that is what "the API is the engine" means.
Status
npm run spikeDevpost submission deadline Aug 17, 2026
Walk the seven-step run yourself on the cached party, or read the full story — problem, inversion, math, and the live-API receipts — in ten slides.