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.
- One selfie — taken or uploaded
- Two futures, side by side — Today. vs. In 20 years. Aging Generator returns 16 age-progressed frames; we lead with the oldest.
- 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
- 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"
- 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)
- 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 diagnosticaging— projects 16 age-progressed frames from one photoskin-tone-analysis— informs which makeup colors flatter the usermakeup-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
/demoroute 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


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