A zinc sunscreen's label tells you how much zinc oxide is in it. It doesn't tell you how white it's going to look on your face, and you usually find that out after you've already bought the bottle.
That gap hits some people a lot harder than others. In a 2024 dermatology survey, 25% of respondents with skin of color said white cast was a concern, compared to 7% of non-Hispanic White respondents, and 41% said they didn't know how to find suitable products (Wang et al., J Drugs Dermatol 2024).
So I built Cast Forecast for the YouCam API Skin AI & eCommerce VTO Hackathon. You take a selfie, pick a mineral sunscreen, and it shows that bottle's predicted white cast on your own face before you buy it.
How it works
- Take a selfie or upload one. There's no login and nothing to install.
- Tap Suggest my tone. YouCam's Fitzpatrick Skin Type Analysis reads your skin type and the site suggests a starting tone. You can always change it.
- Tap a bottle, or search any of 687 FDA-listed zinc sunscreens. YouCam Makeup VTO paints an approximation of that bottle's predicted cast on your face, and you drag a slider to see before and after.
No selfie handy? Tap Use a sample face and you'll see recorded results without uploading anything.
Where the number comes from
Every prediction starts from the bottle's FDA label, the zinc oxide percent, linked to its DailyMed page. My model is fitted to the raw data of a 2025 PLOS ONE study of 13 volunteers (Maldonado Lopez et al.). Tested on data it never saw, it misses by 1.61 L* on average, and 1.80 on darker skin. Every result shows its range.
It also refuses instead of guessing. If your skin is deeper than the study covered, or the zinc is outside 5 to 30%, you get no number and a sentence saying why.
One thing it shows really clearly is that the same bottle is predicted to leave more cast on deeper skin, from +5.3 to +8.3 L* across five tones.
You can check the main number yourself:
curl -s https://cast-forecast.vercel.app/api/label-model
That returns the 1.61, computed by the shipped code from the study's raw data.
The plan that didn't work
My first plan was to measure every bottle myself, on cards and on skin, and run it through a film model. I decided to ship without in-person testing, so I needed a prediction I could actually defend.
I tested a simple model based on the label's zinc percent against my film model, on data neither one had seen, and the simple one won by a lot (1.61 versus 4.79 L*). So I went with the simple one and I show its error on every number.
Two times the YouCam API surprised me
The makeup try-on failed my first test when I used coverage as the strength. When I switched to color intensity, it passed every check, and the lightening followed a smooth curve. I ran 16 renders of my own selfie across the full strength range and fitted that curve (R² 0.98). Now the app turns it around to pick the strength for each bottle and tone.
The skin tone analysis gave the same answer every time for the same photo, but it barely moved when I made the photo brighter. It reports a tone corrected for lighting, not the color in the photo. That's good for a shopper, but it meant I couldn't use it as a measurement, so the Fitzpatrick analysis suggests a tone and the shopper confirms it.
How it's built
- Two YouCam APIs, each for the job it's best at: Fitzpatrick Skin Type Analysis (Skin) to suggest a tone, and Makeup VTO (Beauty) to render the cast. Both run server side through Perfect Corp's REST flow (upload, create task, poll), so the key never reaches the browser, with per-session and per-IP limits and a credit floor.
- The bottles come from the FDA. openFDA's drug label API had 4,034 zinc records, and 687 zinc-only sunscreen labels are kept after leaving out tinted, powder, lip, unreadable and duplicate labels.
- The model is fitted in Python and ported to TypeScript, and tests pin the port to the Python numbers.
- The web app is Next.js on Vercel. GitHub Actions runs lint, type checks, tests, the build and a scan for leaked keys on every push, and a daily job checks the live site and the credit balance.
- For AI shopping agents, /api/mcp is a Model Context Protocol server (search the labels, predict a cast, get the held-out error) and /llms.txt explains it in plain text.
- The look comes from Lullabuy, my HackGT 13 project.
Honest limits
Every cast is a prediction from the label, not a measurement on a person, and the render was calibrated on one person (me). It shows how a sunscreen looks, not how well it works.
Try it
- Live: https://cast-forecast.vercel.app
- Demo film: https://youtu.be/sUUfVjgdH28
- Code: https://github.com/StephenSook/cast-forecast
- Devpost: https://devpost.com/software/cast-forecast
If you've ever bought a mineral sunscreen and regretted it the first time you put it on, I'd really love to know which one it was.
Top comments (0)