Uvie: Your Personalized UV Health Companion
Uvie is an AI Sun Protection assistant that displays your local UV forecast and creates a sunscreen reapplication schedule based on your day. She notices as to how fast you will burn without sunscreen application, Uvie also recommends sunscreens based on your skin tone, budget, and skin sensitivity. Uvie also has a ton of personality as a 16-bit sun who feels the heat just like you!
VandyHacks 2026 — Health Tech Track
Team: Ericka Tyndall, Reagan Crockett, Carolina De Sousa, Jade Huynh
🌟 Inspiration
Sunscreen is one of the most important things you can do for your skin, but most people have no idea what SPF they actually need, when to reapply, or whether the sunscreen they're already using is even safe. We wanted to build something that made UV protection feel personal and approachable rather than overwhelming.
The idea came from a simple frustration: UV index apps exist, but none of them tell you what to do with that number based on you and your day. We wanted Uvie to bridge that gap, taking raw UV data and turning it into real, personalized recommendations that actually help people protect themselves.
We also thought about health equity. Outdoor workers, people with limited access to dermatologists, and communities with darker skin tones that are often left out of "standard" sunscreen advice. Uvie was built with all of us in mind.
🔨 How We Built It
Uvie is a full-stack Progressive Web App (PWA) built over the course of the hackathon weekend.
Backend
We built the server in Python using Flask, with SQLAlchemy managing a SQLite database. User accounts, skin type preferences, wake time, and notification settings are all stored per user. All API calls to Gemini and Open-Meteo are proxied through Flask routes so no API keys are ever exposed on the frontend.
Frontend
The UI is built in HTML, CSS, and vanilla JavaScript — no frontend framework. We designed a cozy pixel-art aesthetic using VT323 (pixel font) and Nunito (body font) from Google Fonts, with a warm cream and orange color palette. The app is fully mobile-first and installs as a PWA on iPhone via Safari.
APIs
- Open-Meteo API — live UV index and hourly UV forecast by coordinates or city
- Google Gemini 1.5 Flash — powers Uvie, our AI chat companion, which gives personalized UV protection plans based on the user's daily schedule and skin type
UV Personalization Model
The core of Uvie's recommendations is based on the Fitzpatrick skin phototype scale, which classifies skin into 6 types based on melanin content and UV sensitivity. We use this to compute personalized burn times and SPF requirements.
The estimated minimal erythemal dose (MED) for a given skin type under a UV index U can be approximated as:
Tburn = MED_k/(E0*U)
Where:
- Tburn is the estimated time to sunburn (in minutes)
- MEDk is the minimal erythemal dose for Fitzpatrick type k (in J/m²)
- E0 = 25 mW/m² is the standard erythemally weighted irradiance per UV index unit
- U is the current UV index
In practice we use a lookup table derived from this model:
| Fitzpatrick Type | MED (J/m²) | Burn time at UV 8 |
|---|---|---|
| Type I | 200 | ~6 min |
| Type II | 250 | ~8 min |
| Type III | 350 | ~10 min |
| Type IV | 450 | ~15 min |
| Type V | 600 | ~20 min |
| Type VI | 800 | ~25 min |
SPF recommendations follow the standard photoprotection formula:
SPFrequired = Tprotected/Tburn
For a target protection time of 2 hours, this gives us SPF 30 at moderate UV and SPF 50+ at high UV — which aligns with AAD guidelines.
🧠 What We Learned
- Flask + SQLAlchemy — none of us had built a full Flask app with a relational database before. We learned how to structure routes, handle sessions, and manage user data properly.
- PWA mechanics — getting a web app to install on iPhone and behave like a native app taught us a lot about service workers, web manifests, and iOS Safari quirks.
- Gemini API — prompting an LLM to return structured JSON reliably is harder than it looks. We learned to be very explicit in our system prompts and handle malformed responses gracefully.
- CSS on mobile — fixed positioning, safe area insets, and viewport height on iOS behave very differently from desktop. We spent a lot of time getting the layout right on real devices.
- Health-informed design — building around the Fitzpatrick scale pushed us to think about inclusivity in tech. Sunscreen recommendations for darker skin tones (white cast, hyperpigmentation) are genuinely different and we tried to reflect that in our curated product database.
- Custom UI/UX Design — made custom pixelated animated and static icons to make Uvie more personal.
🚧 Challenges We Faced
The biggest challenge was time. We were building, debugging, and designing simultaneously across four different laptops with different operating systems, Python versions, and environments. Getting everyone on the same working setup took longer than expected.
iOS Safari is a nightmare for PWAs. Web Push Notifications on iOS require HTTPS, a home screen install, AND a direct user gesture to request permission — all three at once. We got it working on Railway but it was one of the most frustrating debugging sessions of the weekend.
SQLAlchemy v2 breaking changes — we hit a wall when User.query.get() was deprecated in SQLAlchemy 2.0. Every route that loaded user data was throwing LegacyAPIWarning and silently failing. The fix was replacing every instance with db.session.get(User, id) but finding every occurrence took time.
Gemini model deprecation — gemini-pro was deprecated mid-project. We switched to gemini-1.5-flash and had to update our prompts since the new model responds differently to structured JSON requests.
Windows PowerShell execution policies — team members on Windows couldn't activate the virtual environment until we ran Set-ExecutionPolicy -ExecutionPolicy RemoteSigned. A small thing that cost us 30 minutes.
🚀 What's Next
- 🔔 Push notifications for UV alerts and reapply reminders
- ⌚ Apple Watch integration for haptic UV warnings
- ❤️ Apple Health sync to log daily UV exposure
- 🔍 Live ingredient scanner with product database lookup
- 🌍 Health equity mode with UPF clothing recommendations
- 🚀 Full cloud deployment with persistent user accounts
⚙️ Setup
1. Clone the repo
git clone https://github.com/mini-tinfish/Vandy-Hacks26.git
cd Vandy-Hacks26/Vandy-Project
2. Create a virtual environment
python -m venv venv
venv\Scripts\activate # Windows
source venv/bin/activate # Mac/Linux
3. Install dependencies
pip install -r requirements.txt
pip install flask-sqlalchemy
4. Set up environment variables
cp .env.example .env
Fill in .env:
SECRET_KEY=any-random-string
GEMINI_API_KEY=your_gemini_key
OPENWEATHER_API_KEY=your_openweather_key
5. Run the app
python app.py
Visit → http://localhost:5000
🔑 API Keys
| Key | Where to get it | Cost |
|---|---|---|
GEMINI_API_KEY |
aistudio.google.com | Free |
📁 Project Structure
Vandy-Project/
├── app.py # Flask routes + Gemini/OWM proxy + SQLAlchemy
├── requirements.txt # Python dependencies
├── Procfile # Railway deployment config
├── runtime.txt # Python version for Railway
├── .env.example # Copy to .env and fill in keys
├── templates/
│ ├── base.html # Shared layout + PWA meta + bottom nav
│ ├── login.html
│ ├── register.html
│ ├── onboarding.html # Fitzpatrick skin type selector
│ ├── uv.html # Main UV dashboard + exposure log
│ ├── plan.html # Uvie AI chat (Gemini)
│ ├── scanner.html # Sunscreen recommendations + ingredient scanner
│ └── settings.html # Profile, alerts, integrations, skin type
└── static/
├── css/style.css # Full design system (pixel art aesthetic)
├── js/
│ ├── glowie.js # UV logic, Uvie chat, sunscreen DB, notifications
│ └── main.js # Shared helpers
├── manifest.json # PWA manifest
├── service-worker.js # Offline cache + push notifications
└── icons/
├── icon_sun.png # Uvie mascot
├── sun-low.png # UV 0–2
├── sun-mod.png # UV 3–5
├── sun-high.gif # UV 6–7
├── sun-vhigh.gif # UV 8–10
└── sun-ext.gif # UV 11+
📱 Install as iPhone App
- Deploy to Railway or Render (HTTPS required)
- Open the live URL in Safari on iPhone
- Tap Share → Add to Home Screen
- Uvie appears as a native app icon
🛠️ Tech Stack
| Layer | Technology |
|---|---|
| Backend | Python, Flask, SQLAlchemy |
| Database | SQLite |
| Frontend | HTML, CSS, Vanilla JavaScript |
| AI | Google Gemini 1.5 Flash |
| Weather | OpenWeatherMap One Call 3.0 |
| Fonts | VT323, Nunito (Google Fonts) |
| Deployment | Railway |
| Mobile | PWA (Progressive Web App) |
Made at VandyHacks 2026
Log in or sign up for Devpost to join the conversation.