Track: Skin AI + Apparel VTO. Both APIs are live and causally connected, not two features on one page.

Looking good in something and deciding to buy it are not the same question. Virtual try-on answers the first. MAVIE answers the second.

Inspiration

Everyone has the piece. The one you loved online, bought, and never wore. It's still in the wardrobe with the tag on.

Online shopping asks you to run five calculations in your head at once: Would this work on me? Does it suit the occasion? Is it how I actually dress? Will I ever wear it again? Is it worth $98?

Virtual try-on answers the first one beautifully. Nothing answers the other four — so you guess, and the guess is where the regret comes from.

We wanted to build the thing that answers the other four. Not a prettier way to want something, but a way to decide.

What it does

MAVIE is a decision layer for beauty and fashion that can see.

You describe the situation in your own words — "dinner date tonight, feminine but not overdressed, budget $100." MAVIE parses that into structured constraints, then:

  • Analyses your skin with Perfect Corp's Skin AI, and translates eight concern scores into styling direction — preferred finish, makeup intensity — rather than a number out of a hundred
  • Composes three complete looks from a real catalog of 60 garments, each carrying material, formality, fit, season, versatility and maintenance attributes, so reasoning is attribute-based rather than a hard-coded occasion → product lookup
  • Shows you wearing them with Perfect Corp's Apparel VTO — photoreal, on your own photo
  • Argues about it. A Stylist agent makes the case for the piece. A Skeptic makes the case against — closet overlap by name, rewear potential, care burden, budget pressure
  • Decides. BUY, WAIT, or SKIP, with an alternative that reduces the specific risk it just named

MAVIE is fully responsive and runs on mobile, which is where the decision actually happens. You're not at a desk when you're scrolling Instagram at midnight and wondering whether to buy something.

And it works on anything, not just the catalog. Screenshot a piece from Instagram or a store page and it runs through the identical engine — same agents, same weights, same thresholds.

MAVIE will tell you not to buy something. Often, specifically, with its reasoning fully exposed — and the alternative it offers instead usually costs less. A recommendation engine that can never say no isn't giving advice. It's selling.

How we built it

The governing principle: the language model never decides anything.

Both agents receive the same evidence packet and opposing briefs. Every claim either one makes must cite a real numeric field — a claim that can't be traced back to a number is rejected before it reaches the user. Zod validates model output exactly the way it validates an incoming request body, because an LLM is an untrusted input source.

The verdict itself is plain deterministic code. Two independent scores computed from real garment attributes:

  • MAVIE Match — occasion 25%, style 20%, preference 15%, budget 15%, comfort 10%, beauty compatibility 10%, closet fit 5%
  • Decision Risk — context mismatch 20%, preference mismatch 20%, versatility 15%, rewear 15%, closet overlap 10%, maintenance 10%, budget pressure 10%

BUY at risk ≤ 30 and match ≥ 78. WAIT at risk ≤ 60. SKIP above that.

Each high-severity Skeptic claim adds +6 to the risk score. That is the only channel through which a language model can influence the outcome — and it can only ever push toward caution. A model having a bad day cannot talk you into a purchase.

Stack: React 18 · Vite · Tailwind · Framer Motion on the front end. Node 20 · Express · Zod on the back. Supabase Postgres over raw PostgREST. Gemini for context parsing, agent reasoning and product vision. Perfect Corp YouCam for Skin Analysis and Apparel VTO.

Both Perfect Corp APIs are live and load-bearing

Not decoration around a mock — the two capabilities are causally connected. Your skin analysis sets the makeup finish for every look and feeds the Beauty compatibility factor that scores the verdict. Change your skin profile and MAVIE recommends differently.

Endpoint Use
POST /s2s/v1.0/client/auth Exchange an RSA-encrypted id_token for a bearer token
POST /s2s/v1.0/file/{feature} Reserve an upload slot → signed PUT + file_id
POST /s2s/v2.0/task/skin-analysis Eight concern scores
POST /s2s/v2.0/task/cloth-v4 Photoreal apparel try-on

Challenges we ran into

The ISP was hijacking DNS. Every perfectcorp.com hostname resolved to a single sinkhole address. The account was fine, the keys were fine, the route was fine. Changing the OS resolver didn't help — IPv6 DNS is configured separately and the interception was at port 53 regardless. MAVIE now resolves Perfect Corp hostnames over DNS-over-HTTPS via Cloudflare, then connects to the returned IP with explicit SNI so TLS still validates. On an unaffected network it behaves identically.

Every API path we had was from the wrong version namespace. A v1.0 skin endpoint genuinely exists and authenticates — it just silently rejects v2 concern names with dst_actions cannot be empty, which reads exactly like a provisioning failure. We recovered the real paths from the vendor's sitemap, where each documented endpoint is JSON-Pointer encoded. Decoding it yielded the method, path and version for 171 endpoints across 61 APIs, shipped as npm run discover.

SECRET_KEY is not a credential to send. It's an RSA public key, and the API expects proof you hold it: base64(RSA_PKCS1_encrypt("client_id=…&timestamp=…")). The raw secret arrives as bare base64 and has to be reassembled into PEM before Node's crypto will accept it. Sending the secret directly authenticates nothing and fails with a generic error that points nowhere near RSA.

dress is not a valid garment_category. Despite dresses being the most obvious apparel case, cloth-v4 accepts only upper_body, lower_body, full_body. Worse, the API validates its request as a union and returns every branch's complaint at once — so a valid request with garment_category: "dress" returns a message that reads like the file fields are wrong. Every dress try-on failed with what looked like a generic malformed-request error.

Try-on doesn't require deployment. The documented path is src_file_url + ref_file_url, which Perfect Corp fetches itself — so local catalog images seem to make try-on impossible until you deploy. But /s2s/v1.0/file/cloth-v4 exists and the task accepts ids, so staging the bytes removes the requirement entirely. Photoreal try-on runs on localhost with no tunnel.

v1 and v2 signal completion differently. v1 reports a string status; v2 returns HTTP 200 throughout and signals completion by populating data.results. A poller waiting for status === "success" against a v2 endpoint polls a finished task until it times out.

What we're proud of

The Skeptic is handed the names of colliding closet pieces, not an overlap percentage — because "you already own a black slip dress, a black wrap dress and a black mini dress" is an argument, while "closet overlap: 34%" is a statistic.

Every layer fails toward something truthful. No credentials → labelled mock. No photo → an explanation. API unreachable → composite preview plus the reason. The user is always told which one they're looking at, because a silent fallback that resembles success is worse than an error.

And we deliberately declined the easy screenshot. Skin AI returns numbers that would be trivial to render as a score out of a hundred. That would look more impressive and be a worse, less responsible product. MAVIE has no opinion about your face.

What we learned

That the hard part of building with an LLM is deciding what you won't let it do. Once the agents were confined to producing evidence — and the arithmetic was confined to plain code — the whole system became something you could reason about, test, and disagree with.

Also that "the API is broken" is almost always "you are calling it wrong," and the answer is usually in a machine-readable place nobody thought to look.

What's next

  • Retail integration — swapping the curated catalog for live merchant feeds; the attribute contract already exists
  • Longitudinal regret tracking — asking, six weeks later, whether you actually wore it, and feeding the answer back into the weights
  • Fit and sizing — MAVIE reasons about occasion, versatility and duplication, not physical fit
  • Full Makeup VTO — mapping the complete effects schema

Anyone can show you the outfit. MAVIE tells you the truth about it.

Built With

Share this project:

Updates