Inspiration

Skincare is a $190B industry built on guesswork. Most people don't know what their skin actually needs, can't visualize the long-term cost of inaction, and can't picture which products will work on their face. We wanted to collapse all of that into a single 30-second moment that's emotional enough to actually change behavior — and concrete enough to drive a purchase.

The idea hit when we saw Perfect Corp's Aging Generator API. Most virtual try-on apps make you imagine a better future. We thought: what if we showed people a worse one — the one they're already on — and then handed them the controls to rewrite it?

What it does

Time Mirror turns a single selfie into a full skincare buying decision.

  1. One selfie — taken or uploaded
  2. Two futures, side by sideToday. vs. In 20 years. Aging Generator returns 16 age-progressed frames; we lead with the oldest.
  3. 12-axis skin diagnostic — Skin Analysis quantifies wrinkles, pores, texture, age spots, dark circles, eye bags, redness, oiliness, moisture, radiance, firmness, and acne on a 0–100 scale
  4. Three looks engineered for your face — AI Makeup VTO applies skin smoothing tuned to your measured concerns, with intensity levels that escalate from "30-day refresh" to "Future Self"
  5. Six products, one routine — real brands (CeraVe, La Roche-Posay, SkinCeuticals, The Ordinary, Olay, Kiehl's, Paula's Choice, Supergoop, EltaMD, L'Oréal Paris, Neutrogena, PURITO) chosen by your top measured concerns and shipped via the right retailer (Sephora, Ulta, Amazon, Target)
  6. Cart, checkout, order — slide-out cart, three-step checkout (shipping → payment → review), order confirmation with estimated delivery

The story arc is fear → diagnosis → prescription → purchase. Four Perfect Corp APIs, one continuous funnel.

How we built it

Stack: Next.js 16 (App Router) + TypeScript + Tailwind CSS v4 + Geist & Playfair Display + Sharp + JSZip. Deployed on Vercel.

Perfect Corp APIs integrated (all four):

  • skin-analysis — 12-axis skin diagnostic
  • aging — projects 16 age-progressed frames from one photo
  • skin-tone-analysis — informs which makeup colors flatter the user
  • makeup-vto — applies the chosen look back onto the selfie

The /api/scan endpoint fans out three of these in parallel via Promise.allSettled so the user waits for the slowest, not the sum. Each call follows Perfect Corp's upload-metadata → presigned-PUT → create-task → poll pattern, abstracted in a single runTask() helper.

We discovered the docs can lie: the upload endpoint for aging is /file/aging (not /file/aging-generator as documented), face-analyzer doesn't exist as an endpoint at all, makeup-vto's skin_smooth category needs runtime fields the schema validator doesn't enforce, and the Skin Analysis HD threshold rejects most non-portrait photos. We layered three defenses:

  • Client-side image validation — refuse the upload if short side < 1080 px so users see the error immediately, not after a 15-second scan
  • Server-side aspect-preserving cascade — if HD skin-analysis fails with face_too_small, retry on a 70% center-cropped version with SD names; if that also fails, retry on a 55% tight crop. Aging and skin-tone get the wider original because they handle compositions HD won't.
  • Sharp resize for makeup-vto — phone selfies (5–10 MB) blow past Vercel's 4.5 MB body limit. Client-side canvas resize caps long-edge at 1920 px before upload.

The UI is a tight state machine — idle → scanning → revealing → plan — choreographed so the dramatic Aging reveal lands as a moment, not a panel of widgets. Routine and cart only appear after the user actually applies a look, matching the natural emotional beat: "OK, that's how I could look — now how do I get there?"

Challenges we ran into

  • Defensive parsing of evolving response shapes — Aging used to return a zip URL; now it returns {output: [{res_age, url}]}. Skin Analysis returns scores inside a zip with masks. Makeup VTO returns a direct image URL. We handle all three.
  • The makeup-vto schema is hostile — its oneOf branches throw 70+ "or" errors at once. We had to probe the schema with curl + the live API key to find the one combination that actually validates (category: "skin_smooth" + skinSmoothColorIntensity + skinSmoothStrength).
  • Vercel response & body limits — base64-inlining aging frames blew through the 4.5 MB JSON response cap. We cap at 3 oldest frames and pass through direct S3 URLs when possible.
  • Emotional copy without being preachy — "But you can change this." was the line that took eight rewrites. The whole product hangs on it not feeling like a guilt trip.

Accomplishments we're proud of

  • All four Perfect Corp APIs integrated end-to-end in a single coherent flow
  • Real retail loop: 19-product catalog mapped to skin concerns, working cart with localStorage persistence, three-step checkout with prefilled demo data, order confirmation with delivery estimates
  • A demo that's visually arresting in the first 5 seconds — judges remember the split-screen
  • /demo route lets judges walk every UI stage without spending API units
  • Resilient to face-size, image-size, and schema variation. The user never sees a 500.

What we learned

  • The Aging Generator is criminally underused. Pairing loss aversion with a clear remediation path is more persuasive than aspiration alone.
  • Perfect Corp's parallel-friendly task API design (upload once, poll independently) lets you compose multi-API experiences without orchestration overhead — once you find the right endpoint names.
  • Beauty UX lives or dies on typography and pacing. The same data presented as a dashboard would have zero emotional pull. Playfair Display + a dark-rose-gold palette did half the work.

What's next

  • Repeat scans + progress tracking — log diagnostic deltas across weeks; the Skin Analysis API supports this natively
  • Stripe + retailer SKU APIs — wire the cart to live partner inventory; today the cards link to Sephora/Ulta/Amazon, tomorrow they're a federated checkout
  • Layered try-on — pair Makeup VTO with Hairstyle Generator on the "Future Self" track; show the whole version of you the routine unlocks
  • B2B counter-staff mode — sales associates run Time Mirror in-store as a guided consultation; the diagnostic becomes the upsell
  • Personalized monthly box — every 30 days, generate a refreshed routine based on a new scan; ship the products

Built With

  • ai-aging-generator
  • ai-face-analyzer
  • ai-skin-analysis
  • makeup-vto
  • next.js
  • perfect-corp-api
  • react
  • tailwind-css
  • typescript
  • vercel
Share this project:

Updates