Built for the YouCam API Hackathon · Topic C — Skin AI × Apparel VTO

Six bridesmaids. Six skin tones. One dress color — provably no one's worst option.

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.

Engine proven live against 5 YouCam (Perfect Corp) endpoints · product UI in build

OneDress hero illustration: six bridesmaid silhouettes spanning six skin tones, all wearing the same dusty-sage dress, with measured skin-hex chips and Fitzpatrick numerals beside each.
The thesis, drawn: one garment, six measured complexions, zero guesswork.
5/5
YouCam endpoints proven live, end-to-end
ΔE ≈ 7.7
measured render fidelity (CIEDE2000)
43units
measured API cost of one full run
31tests
passing on the published scoring engine

The problem

One color. Final sale. Chosen by eyeballing a stranger.

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.

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.

Usually final-sale

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."

Decided by guesswork

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

Not "what's my season?" — "which color harms the group least?"

Every personal-color tool answers a one-person question. OneDress inverts the primitive.

The familiar question

"What are my best colors?"

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.

The OneDress question

"Given one garment all N must wear — which single color harms the group least?"

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

Measure. Score. Render. Finish.

Four moves, five live YouCam endpoints — the measured skin values drive the render; they aren't decoration beside it.

Measure every complexion

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.

skin-tone-analysis fitzpatrick-scale-analyzer face-attr-analysis

Score 24 colorways against the whole party

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.

deterministic engine 31 passing tests

Render it on every bridesmaid

The winning colorway is rendered photorealistically on each bridesmaid's own full-length photo with AI Clothes Try-On — measured render fidelity ΔE00 ≈ 7.7 against the intended swatch. Seeing all six in the same color is the proof no swatch kit can give.

cloth-v3

Finish with the right earrings

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.

2d-vto/earring undertone → metal

The palette

24 colorways, engineered coverage

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.

Warm family — 8

Terracotta
#C0674C
Rust
#A34F33
Marigold
#D9964A
Warm Champagne
#DBBE93
Caramel
#B07E4F
Warm Burgundy
#7E3B41
Tomato Red
#C24A3D
Amber
#C98B37

Cool family — 10

Dusty Blue
#7D93AC
Slate
#5E6B7C
Navy
#2C3A55
Emerald
#2F6B57
Eucalyptus
#7FA08D
Plum
#6D4265
Wine
#6E2F43
Cool Berry
#9E4467
Lavender
#A08DBE
Amethyst
#71559B

Neutral family — 6

Dusty Rose
#D98BA3
Mauve
#B0808F
Taupe
#A79488
Stormy Grey
#8B8B93
Blush Neutral
#DBB2AD
frequent winner
Dusty Sage
#9CAF88

The math

A published formula, not a black box

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."

How every score is computed

// 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.

group average worst bridesmaid

Illustrative scores, shown to explain the mechanism. In the engine's real measured demo run, the maximin winner lands in the dusty sage / mauve family with nobody scoring below ≈57 — while the mean-maximizing pick drops the most-hurt bridesmaid far lower.

Verified live

The engine is proven. Here's the receipt.

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.

Five YouCam API endpoints and their verified live results
EndpointRole in the flowVerified live result
skin-tone-analysis measured skin hex — the scoring input #bb9982 → ITA° 43 · hue° 61
fitzpatrick-scale-analyzer Type I–VI depth cross-check 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 ≈ 7.7
2d-vto/earring chained finishing touch (undertone → metal) gold hoop landed on the dress render
5/5
endpoints proven end-to-end by a live spike
43units
measured cost of a full single-person run
ΔE ≈ 7.7
measured render fidelity vs the intended swatch
0units
to re-score all 24 colorways — measure once, math forever

Status, honestly: the typed API client, the live five-endpoint integration, and the published scoring engine (31 passing tests) are done and reproducible — run npm run spike. The interactive product UI is in build. Nothing on this page is a screenshot of an app that doesn't exist yet.

Status

Engine proven, product in build

Done & verified

  • Live 5-endpoint integration — reproducible via npm run spike
  • Typed, Zod-validated API client — rate-limited, retrying, server-side key
  • Published scoring engine — CIELAB physics + maximin objective, 31 passing tests
  • Full CI harness — lint, typecheck, unit + E2E, CodeQL, secret scanning

In build → submission

  • The 7-step product UI — Create · Measure · Score · Compare · Render · Finish · Verdict
  • Cached zero-unit demo party — instant judge-facing demo, no key required
  • The counterfactual Compare screen — by-eye pick vs maximin pick on the most-hurt bridesmaid
  • Demo video — live browser run, ≤3 minutes

Devpost submission deadline Aug 17, 2026

Six bridesmaids. One color. Zero arguments.

The full story — problem, inversion, math, and the live-API receipts — in ten slides.