Glowup
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GLOW — AI Beauty & Self-Improvement</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0A0A0F;
--surface: #12121A;
--surface2: #1A1A26;
--border: rgba(255,255,255,0.06);
--gold: #C9A96E;
--gold2: #E8C98A;
--rose: #E8A0B0;
--violet: #A78BFA;
--green: #6EE7B7;
--text: #F0EDE8;
--muted: #6B6880;
--muted2: #9B98A8;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: 'Inter', sans-serif;
min-height: 100vh;
overflow-x: hidden;
}
body::before {
content:'';
position:fixed;
inset:0;
background:
radial-gradient(ellipse at 15% 15%, rgba(167,139,250,0.08) 0%, transparent 50%),
radial-gradient(ellipse at 85% 85%, rgba(232,160,176,0.06) 0%, transparent 50%),
radial-gradient(ellipse at 50% 0%, rgba(201,169,110,0.05) 0%, transparent 40%);
pointer-events:none;
z-index:0;
}
/* LAYOUT */
.app { position:relative; z-index:1; max-width:520px; margin:0 auto; padding:0 20px 80px; }
/* SCREENS */
.screen { display:none; animation: fadeUp 0.5s ease both; }
.screen.active { display:block; }
@keyframes fadeUp {
from { opacity:0; transform:translateY(24px); }
to { opacity:1; transform:translateY(0); }
}
/* NAV */
.nav {
display:flex;
align-items:center;
justify-content:space-between;
padding:24px 0 20px;
}
.nav-logo {
font-family:'Playfair Display', serif;
font-size:1.5rem;
font-weight:900;
background: linear-gradient(135deg, var(--gold), var(--rose));
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
letter-spacing:0.05em;
}
.nav-badge {
background: linear-gradient(135deg, var(--gold), var(--gold2));
color: #000;
font-size:0.65rem;
font-weight:600;
padding:4px 10px;
border-radius:20px;
letter-spacing:0.08em;
}
/* HERO */
.hero {
text-align:center;
padding:20px 0 32px;
}
.hero-pill {
display:inline-block;
background: rgba(167,139,250,0.12);
border: 1px solid rgba(167,139,250,0.25);
color: var(--violet);
font-size:0.7rem;
font-weight:500;
letter-spacing:0.15em;
text-transform:uppercase;
padding:6px 16px;
border-radius:20px;
margin-bottom:20px;
}
.hero h1 {
font-family:'Playfair Display', serif;
font-size:clamp(2rem,8vw,2.8rem);
font-weight:900;
line-height:1.1;
margin-bottom:12px;
}
.hero h1 span {
background: linear-gradient(135deg, var(--gold), var(--rose), var(--violet));
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
}
.hero p {
color: var(--muted2);
font-size:0.9rem;
line-height:1.65;
max-width:340px;
margin:0 auto 28px;
}
/* UPLOAD AREA */
.upload-zone {
background: var(--surface);
border: 2px dashed rgba(201,169,110,0.2);
border-radius:20px;
padding:36px 24px;
text-align:center;
cursor:pointer;
transition:all 0.3s;
position:relative;
overflow:hidden;
margin-bottom:20px;
}
.upload-zone:hover {
border-color: var(--gold);
background: rgba(201,169,110,0.05);
}
.upload-zone input { position:absolute; inset:0; opacity:0; cursor:pointer; }
.upload-icon {
width:56px; height:56px;
background: linear-gradient(135deg, rgba(201,169,110,0.15), rgba(232,160,176,0.1));
border-radius:16px;
display:flex; align-items:center; justify-content:center;
font-size:1.6rem;
margin:0 auto 14px;
}
.upload-zone h3 { font-size:0.95rem; font-weight:600; margin-bottom:5px; }
.upload-zone p { font-size:0.78rem; color:var(--muted); }
.preview-img {
width:100%; height:220px;
object-fit:cover;
border-radius:16px;
margin-bottom:20px;
display:none;
border: 2px solid rgba(201,169,110,0.3);
}
/* PROFILE QUESTIONS */
.questions { margin-bottom:20px; }
.q-block { margin-bottom:18px; }
.q-label {
font-size:0.72rem;
font-weight:600;
letter-spacing:0.12em;
text-transform:uppercase;
color:var(--muted2);
margin-bottom:10px;
}
.chips {
display:flex;
flex-wrap:wrap;
gap:8px;
}
.chip {
background: var(--surface);
border: 1px solid var(--border);
border-radius:10px;
padding:8px 14px;
font-size:0.8rem;
color:var(--muted2);
cursor:pointer;
transition:all 0.2s;
font-weight:400;
}
.chip:hover { border-color:rgba(201,169,110,0.4); color:var(--text); }
.chip.active {
background: rgba(201,169,110,0.12);
border-color: var(--gold);
color: var(--gold);
font-weight:500;
}
/* API KEY */
.api-block {
background: var(--surface);
border: 1px solid var(--border);
border-radius:14px;
padding:16px;
margin-bottom:20px;
}
.api-block label {
font-size:0.72rem;
font-weight:600;
letter-spacing:0.1em;
text-transform:uppercase;
color:var(--muted2);
display:block;
margin-bottom:8px;
}
.api-block input {
width:100%;
background:var(--surface2);
border: 1px solid var(--border);
border-radius:8px;
padding:10px 12px;
font-size:0.83rem;
color:var(--text);
outline:none;
font-family:'Inter',sans-serif;
transition:border-color 0.2s;
}
.api-block input:focus { border-color:rgba(201,169,110,0.4); }
.api-block input::placeholder { color:var(--muted); }
.api-note { font-size:0.71rem; color:var(--muted); margin-top:6px; }
.api-note a { color:var(--gold); text-decoration:none; }
/* BUTTONS */
.btn {
width:100%;
padding:17px;
border-radius:14px;
border:none;
font-family:'Inter',sans-serif;
font-size:0.92rem;
font-weight:600;
cursor:pointer;
transition:all 0.3s;
letter-spacing:0.02em;
}
.btn-primary {
background: linear-gradient(135deg, var(--gold), #B8860B);
color:#000;
}
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 8px 30px rgba(201,169,110,0.3); }
.btn-primary:disabled { opacity:0.4; cursor:not-allowed; transform:none; }
.btn-ghost {
background:transparent;
border: 1px solid var(--border);
color:var(--muted2);
margin-top:12px;
}
.btn-ghost:hover { border-color:var(--muted2); color:var(--text); }
/* ERROR */
.error {
background:rgba(239,68,68,0.1);
border:1px solid rgba(239,68,68,0.3);
color:#f87171;
border-radius:10px;
padding:11px 14px;
font-size:0.8rem;
margin-bottom:14px;
display:none;
}
.error.show { display:block; }
/* LOADING */
#loadScreen {
text-align:center;
padding:60px 20px;
}
.scan-animation {
width:120px; height:120px;
margin:0 auto 28px;
position:relative;
}
.scan-ring {
position:absolute; inset:0;
border-radius:50%;
border:2px solid transparent;
animation:scanSpin 2s linear infinite;
}
.scan-ring:nth-child(1) { border-top-color:var(--gold); animation-duration:1.5s; }
.scan-ring:nth-child(2) { inset:12px; border-right-color:var(--rose); animation-duration:2s; animation-direction:reverse; }
.scan-ring:nth-child(3) { inset:24px; border-bottom-color:var(--violet); animation-duration:2.5s; }
.scan-center {
position:absolute;
inset:36px;
background:linear-gradient(135deg, rgba(201,169,110,0.2), rgba(232,160,176,0.2));
border-radius:50%;
display:flex;align-items:center;justify-content:center;
font-size:1.4rem;
}
@keyframes scanSpin { to { transform:rotate(360deg); } }
.load-title {
font-family:'Playfair Display',serif;
font-size:1.4rem;
margin-bottom:8px;
}
.load-sub { color:var(--muted2); font-size:0.83rem; }
.load-steps {
margin-top:28px;
display:flex;
flex-direction:column;
gap:8px;
max-width:280px;
margin-left:auto;
margin-right:auto;
}
.load-step {
display:flex;
align-items:center;
gap:10px;
font-size:0.8rem;
color:var(--muted);
opacity:0;
animation:fadeIn 0.4s ease forwards;
}
.load-step:nth-child(1) { animation-delay:0.3s; }
.load-step:nth-child(2) { animation-delay:1.2s; }
.load-step:nth-child(3) { animation-delay:2.4s; }
.load-step:nth-child(4) { animation-delay:3.6s; }
.step-dot { width:6px;height:6px;border-radius:50%;background:var(--gold);flex-shrink:0; }
@keyframes fadeIn { to { opacity:1; } }
/* RESULTS */
#resultScreen { padding-bottom:40px; }
.score-card {
background: linear-gradient(135deg, var(--surface), var(--surface2));
border: 1px solid rgba(201,169,110,0.2);
border-radius:20px;
padding:28px;
text-align:center;
margin-bottom:16px;
position:relative;
overflow:hidden;
}
.score-card::before {
content:'';
position:absolute;
top:-50%;left:-50%;
width:200%;height:200%;
background:conic-gradient(from 0deg, transparent 70%, rgba(201,169,110,0.05) 80%, transparent 90%);
animation:rotateBg 8s linear infinite;
}
@keyframes rotateBg { to { transform:rotate(360deg); } }
.score-label {
font-size:0.68rem;
font-weight:600;
letter-spacing:0.2em;
text-transform:uppercase;
color:var(--muted2);
margin-bottom:8px;
position:relative;
}
.score-number {
font-family:'Playfair Display',serif;
font-size:5rem;
font-weight:900;
background:linear-gradient(135deg, var(--gold), var(--rose));
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
line-height:1;
margin-bottom:6px;
position:relative;
}
.score-number span { font-size:2rem; }
.score-tag {
display:inline-block;
background:rgba(110,231,183,0.12);
border:1px solid rgba(110,231,183,0.25);
color:var(--green);
font-size:0.72rem;
font-weight:600;
padding:4px 12px;
border-radius:20px;
letter-spacing:0.08em;
position:relative;
}
.bars-row {
display:grid;
grid-template-columns:1fr 1fr;
gap:10px;
margin-bottom:16px;
}
.bar-card {
background:var(--surface);
border:1px solid var(--border);
border-radius:14px;
padding:14px;
}
.bar-label { font-size:0.72rem; color:var(--muted2); margin-bottom:8px; font-weight:500; }
.bar-track {
height:5px;
background:rgba(255,255,255,0.06);
border-radius:3px;
overflow:hidden;
margin-bottom:5px;
}
.bar-fill {
height:100%;
border-radius:3px;
width:0%;
transition:width 1.5s cubic-bezier(0.4,0,0.2,1);
}
.bar-fill.gold { background:linear-gradient(to right, var(--gold), var(--gold2)); }
.bar-fill.rose { background:linear-gradient(to right, var(--rose), #F0B8C8); }
.bar-fill.violet { background:linear-gradient(to right, var(--violet), #C4B5FD); }
.bar-fill.green { background:linear-gradient(to right, var(--green), #A7F3D0); }
.bar-pct { font-size:0.75rem; font-weight:600; color:var(--text); }
/* SECTION CARDS */
.section-card {
background:var(--surface);
border:1px solid var(--border);
border-radius:18px;
padding:22px;
margin-bottom:14px;
}
.section-head {
display:flex;
align-items:center;
gap:10px;
margin-bottom:16px;
}
.section-icon {
width:34px;height:34px;
border-radius:10px;
display:flex;align-items:center;justify-content:center;
font-size:1rem;
flex-shrink:0;
}
.icon-gold { background:rgba(201,169,110,0.15); }
.icon-rose { background:rgba(232,160,176,0.15); }
.icon-violet { background:rgba(167,139,250,0.15); }
.icon-green { background:rgba(110,231,183,0.15); }
.section-title { font-size:0.88rem; font-weight:600; color:var(--text); }
.section-sub { font-size:0.72rem; color:var(--muted); margin-top:1px; }
/* STRENGTHS / WEAKNESSES */
.insight-list { display:flex; flex-direction:column; gap:8px; }
.insight-item {
display:flex;
align-items:flex-start;
gap:10px;
font-size:0.82rem;
line-height:1.55;
color:var(--muted2);
}
.insight-dot {
width:6px;height:6px;border-radius:50%;
margin-top:6px;flex-shrink:0;
}
.dot-green { background:var(--green); }
.dot-rose { background:var(--rose); }
.dot-gold { background:var(--gold); }
/* PLAN STEPS */
.plan-steps { display:flex;flex-direction:column;gap:10px; }
.plan-step {
display:flex;
gap:12px;
align-items:flex-start;
}
.plan-num {
width:26px;height:26px;
background:linear-gradient(135deg, var(--gold), #B8860B);
border-radius:8px;
display:flex;align-items:center;justify-content:center;
font-size:0.72rem;
font-weight:700;
color:#000;
flex-shrink:0;
}
.plan-text { font-size:0.82rem; line-height:1.6; color:var(--muted2); padding-top:3px; }
.plan-text strong { color:var(--text); font-weight:500; }
/* ROUTINE */
.routine-grid { display:grid;gap:8px; }
.routine-item {
display:flex;
align-items:center;
gap:12px;
background:var(--surface2);
border-radius:10px;
padding:11px 13px;
}
.routine-time {
font-size:0.68rem;
font-weight:600;
color:var(--gold);
letter-spacing:0.08em;
width:28px;
flex-shrink:0;
}
.routine-name { font-size:0.82rem;color:var(--text);font-weight:500;flex:1; }
.routine-note { font-size:0.72rem;color:var(--muted);text-align:right; }
/* QUOTE */
.motivation-box {
background: linear-gradient(135deg, rgba(167,139,250,0.08), rgba(232,160,176,0.08));
border: 1px solid rgba(167,139,250,0.15);
border-radius:16px;
padding:22px;
text-align:center;
margin-bottom:14px;
}
.motivation-box p {
font-family:'Playfair Display',serif;
font-size:1.05rem;
font-style:italic;
color:var(--text);
line-height:1.65;
margin-bottom:10px;
}
.motivation-box span { font-size:0.72rem;color:var(--muted);letter-spacing:0.08em; }
/* TABS */
.tabs {
display:flex;
gap:6px;
background:var(--surface);
border:1px solid var(--border);
border-radius:12px;
padding:5px;
margin-bottom:20px;
}
.tab {
flex:1;
padding:9px;
border-radius:8px;
font-size:0.75rem;
font-weight:500;
text-align:center;
cursor:pointer;
transition:all 0.2s;
color:var(--muted2);
border:none;
background:transparent;
font-family:'Inter',sans-serif;
}
.tab.active { background:var(--surface2);color:var(--text); box-shadow:0 1px 6px rgba(0,0,0,0.3); }
.tab-content { display:none; }
.tab-content.active { display:block; animation:fadeUp 0.3s ease both; }
/* PROGRESS TRACKING */
.streak-row {
display:grid;
grid-template-columns:1fr 1fr 1fr;
gap:10px;
margin-bottom:16px;
}
.streak-card {
background:var(--surface);
border:1px solid var(--border);
border-radius:14px;
padding:14px;
text-align:center;
}
.streak-num {
font-family:'Playfair Display',serif;
font-size:1.8rem;
font-weight:700;
background:linear-gradient(135deg, var(--gold), var(--rose));
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
}
.streak-label { font-size:0.68rem;color:var(--muted);margin-top:2px;letter-spacing:0.05em; }
.habit-list { display:flex;flex-direction:column;gap:8px; }
.habit-item {
display:flex;
align-items:center;
gap:12px;
background:var(--surface);
border:1px solid var(--border);
border-radius:12px;
padding:13px 15px;
cursor:pointer;
transition:all 0.2s;
}
.habit-item:hover { border-color:rgba(201,169,110,0.3); }
.habit-check {
width:20px;height:20px;
border-radius:6px;
border:1.5px solid var(--muted);
display:flex;align-items:center;justify-content:center;
transition:all 0.2s;
flex-shrink:0;
font-size:0.75rem;
}
.habit-item.done .habit-check {
background:var(--green);
border-color:var(--green);
color:#000;
}
.habit-name { font-size:0.83rem;color:var(--text);flex:1; }
.habit-xp { font-size:0.7rem;color:var(--gold);font-weight:600; }
/* BOTTOM NAV */
.bottom-nav {
position:fixed;
bottom:0;left:0;right:0;
background:rgba(10,10,15,0.95);
backdrop-filter:blur(20px);
border-top:1px solid var(--border);
display:flex;
justify-content:space-around;
padding:10px 0 18px;
z-index:100;
}
.nav-item {
display:flex;
flex-direction:column;
align-items:center;
gap:3px;
cursor:pointer;
padding:4px 16px;
transition:all 0.2s;
background:none;
border:none;
font-family:'Inter',sans-serif;
}
.nav-item .nav-ico { font-size:1.2rem; }
.nav-item .nav-lbl { font-size:0.62rem;font-weight:500;color:var(--muted);letter-spacing:0.05em; }
.nav-item.active .nav-lbl { color:var(--gold); }
.nav-item.active .nav-ico { filter:drop-shadow(0 0 6px rgba(201,169,110,0.6)); }
/* TIPS SCREEN */
.tip-cards { display:flex;flex-direction:column;gap:12px; }
.tip-card {
background:var(--surface);
border:1px solid var(--border);
border-radius:16px;
padding:18px;
display:flex;
gap:14px;
align-items:flex-start;
}
.tip-emoji { font-size:1.6rem;flex-shrink:0; }
.tip-card h4 { font-size:0.88rem;font-weight:600;color:var(--text);margin-bottom:5px; }
.tip-card p { font-size:0.78rem;color:var(--muted2);line-height:1.6; }
.page-title {
font-family:'Playfair Display',serif;
font-size:1.6rem;
font-weight:700;
margin-bottom:6px;
}
.page-sub { font-size:0.82rem;color:var(--muted2);margin-bottom:20px; }
/* DIVIDER */
.divider { height:1px;background:var(--border);margin:16px 0; }
</style>
</head>
<body>
<div class="app">
<!-- =================== SCREEN: HOME =================== -->
<div class="screen active" id="homeScreen">
<nav class="nav">
<div class="nav-logo">GLOW</div>
<div class="nav-badge">AI POWERED</div>
</nav>
<div class="hero">
<div class="hero-pill">✦ Your Personal Glow-Up Coach</div>
<h1>Unlock Your <span>Best Self</span></h1>
<p>Upload your photo. Our AI analyzes your face and builds a personalized glow-up plan — skincare, makeup, style, and mindset.</p>
</div>
<img id="previewImg" class="preview-img" src="" alt="Your photo">
<div class="upload-zone" id="uploadZone">
<input type="file" id="photoInput" accept="image/*" onchange="handlePhoto(event)">
<div class="upload-icon">📸</div>
<h3>Upload Your Selfie</h3>
<p>Front-facing, good lighting for best results</p>
</div>
<div class="questions" id="questionsBlock" style="display:none">
<div class="q-block">
<div class="q-label">Your Gender</div>
<div class="chips">
<div class="chip" onclick="selectChip(this,'gender','Woman')">Woman</div>
<div class="chip" onclick="selectChip(this,'gender','Man')">Man</div>
<div class="chip" onclick="selectChip(this,'gender','Non-binary')">Non-binary</div>
</div>
</div>
<div class="q-block">
<div class="q-label">Your Age Range</div>
<div class="chips">
<div class="chip" onclick="selectChip(this,'age','16-21')">16–21</div>
<div class="chip" onclick="selectChip(this,'age','22-28')">22–28</div>
<div class="chip" onclick="selectChip(this,'age','29-35')">29–35</div>
<div class="chip" onclick="selectChip(this,'age','35+')">35+</div>
</div>
</div>
<div class="q-block">
<div class="q-label">Main Goal</div>
<div class="chips">
<div class="chip" onclick="selectChip(this,'goal','Look more attractive')">Look more attractive</div>
<div class="chip" onclick="selectChip(this,'goal','Better skin')">Better skin</div>
<div class="chip" onclick="selectChip(this,'goal','Boost confidence')">Boost confidence</div>
<div class="chip" onclick="selectChip(this,'goal','Find my style')">Find my style</div>
</div>
</div>
<div class="q-block">
<div class="q-label">Skin Type</div>
<div class="chips">
<div class="chip" onclick="selectChip(this,'skinType','Oily')">Oily</div>
<div class="chip" onclick="selectChip(this,'skinType','Dry')">Dry</div>
<div class="chip" onclick="selectChip(this,'skinType','Combination')">Combination</div>
<div class="chip" onclick="selectChip(this,'skinType','Normal')">Normal</div>
<div class="chip" onclick="selectChip(this,'skinType','Sensitive')">Sensitive</div>
</div>
</div>
<div class="q-block">
<div class="q-label">Lifestyle</div>
<div class="chips">
<div class="chip" onclick="selectChip(this,'lifestyle','Minimal effort')">Minimal effort</div>
<div class="chip" onclick="selectChip(this,'lifestyle','Natural look')">Natural look</div>
<div class="chip" onclick="selectChip(this,'lifestyle','Full glam')">Full glam</div>
<div class="chip" onclick="selectChip(this,'lifestyle','Active / sporty')">Active / sporty</div>
</div>
</div>
</div>
<div class="api-block" id="apiBlock" style="display:none">
<label>Anthropic API Key</label>
<input type="password" id="apiKey" placeholder="sk-ant-...">
<p class="api-note">Free at <a href="https://console.anthropic.com" target="_blank">console.anthropic.com</a> — stays in your browser only</p>
</div>
<div class="error show" id="errorMsg" style="display:none"></div>
<button class="btn btn-primary" id="analyzeBtn" style="display:none" onclick="startAnalysis()">
✦ Analyze My Face & Build My Plan
</button>
</div>
<!-- =================== SCREEN: LOADING =================== -->
<div class="screen" id="loadScreen">
<div style="padding-top:60px">
<div class="scan-animation">
<div class="scan-ring"></div>
<div class="scan-ring"></div>
<div class="scan-ring"></div>
<div class="scan-center">🔍</div>
</div>
<div class="load-title">Analyzing Your Face</div>
<p class="load-sub">Building your personalized glow-up plan...</p>
<div class="load-steps">
<div class="load-step"><div class="step-dot"></div>Scanning facial features & symmetry...</div>
<div class="load-step"><div class="step-dot"></div>Detecting skin tone & texture...</div>
<div class="load-step"><div class="step-dot"></div>Generating personalized routines...</div>
<div class="load-step"><div class="step-dot"></div>Building your glow-up plan...</div>
</div>
</div>
</div>
<!-- =================== SCREEN: RESULTS =================== -->
<div class="screen" id="resultScreen">
<nav class="nav">
<div class="nav-logo">GLOW</div>
<button onclick="goHome()" style="background:none;border:none;color:var(--muted2);font-size:0.78rem;cursor:pointer;font-family:Inter,sans-serif;">← Restart</button>
</nav>
<!-- SCORE -->
<div class="score-card" id="scoreCard">
<div class="score-label">Your Glow Score</div>
<div class="score-number" id="scoreNum">—<span>/10</span></div>
<div class="score-tag" id="scoreTag">Analyzing...</div>
</div>
<!-- BARS -->
<div class="bars-row">
<div class="bar-card">
<div class="bar-label">Skin Quality</div>
<div class="bar-track"><div class="bar-fill gold" id="bar1"></div></div>
<div class="bar-pct" id="bar1pct">—</div>
</div>
<div class="bar-card">
<div class="bar-label">Symmetry</div>
<div class="bar-track"><div class="bar-fill rose" id="bar2"></div></div>
<div class="bar-pct" id="bar2pct">—</div>
</div>
<div class="bar-card">
<div class="bar-label">Features</div>
<div class="bar-track"><div class="bar-fill violet" id="bar3"></div></div>
<div class="bar-pct" id="bar3pct">—</div>
</div>
<div class="bar-card">
<div class="bar-label">Style Potential</div>
<div class="bar-track"><div class="bar-fill green" id="bar4"></div></div>
<div class="bar-pct" id="bar4pct">—</div>
</div>
</div>
<!-- TABS -->
<div class="tabs">
<button class="tab active" onclick="switchTab('analysis')">Analysis</button>
<button class="tab" onclick="switchTab('plan')">Plan</button>
<button class="tab" onclick="switchTab('routine')">Routine</button>
<button class="tab" onclick="switchTab('track')">Track</button>
</div>
<!-- TAB: ANALYSIS -->
<div class="tab-content active" id="tab-analysis">
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-green">✨</div>
<div>
<div class="section-title">Your Strengths</div>
<div class="section-sub">What makes you naturally attractive</div>
</div>
</div>
<div class="insight-list" id="strengthsList"></div>
</div>
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-rose">🎯</div>
<div>
<div class="section-title">Areas to Improve</div>
<div class="section-sub">Your biggest opportunities</div>
</div>
</div>
<div class="insight-list" id="weaknessesList"></div>
</div>
<div class="motivation-box" id="motivationBox"></div>
</div>
<!-- TAB: PLAN -->
<div class="tab-content" id="tab-plan">
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-gold">🚀</div>
<div>
<div class="section-title">Your 30-Day Glow-Up Plan</div>
<div class="section-sub">Custom action steps for your face & goals</div>
</div>
</div>
<div class="plan-steps" id="planSteps"></div>
</div>
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-rose">💄</div>
<div>
<div class="section-title">Makeup & Style Tips</div>
<div class="section-sub">Tailored for your face shape & skin tone</div>
</div>
</div>
<div class="insight-list" id="makeupTips"></div>
</div>
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-violet">💇</div>
<div>
<div class="section-title">Hair & Grooming</div>
<div class="section-sub">Best styles for your features</div>
</div>
</div>
<div class="insight-list" id="hairTips"></div>
</div>
</div>
<!-- TAB: ROUTINE -->
<div class="tab-content" id="tab-routine">
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-gold">🌅</div>
<div>
<div class="section-title">Morning Routine</div>
<div class="section-sub">Start your day glowing</div>
</div>
</div>
<div class="routine-grid" id="morningRoutine"></div>
</div>
<div class="section-card" style="margin-top:14px">
<div class="section-head">
<div class="section-icon icon-violet">🌙</div>
<div>
<div class="section-title">Night Routine</div>
<div class="section-sub">Repair and restore while you sleep</div>
</div>
</div>
<div class="routine-grid" id="nightRoutine"></div>
</div>
<div class="section-card" style="margin-top:14px">
<div class="section-head">
<div class="section-icon icon-rose">🛒</div>
<div>
<div class="section-title">Must-Have Products</div>
<div class="section-sub">Specifically for your skin type</div>
</div>
</div>
<div class="insight-list" id="productRecs"></div>
</div>
</div>
<!-- TAB: TRACK -->
<div class="tab-content" id="tab-track">
<div class="streak-row">
<div class="streak-card">
<div class="streak-num" id="streakDays">0</div>
<div class="streak-label">Day Streak</div>
</div>
<div class="streak-card">
<div class="streak-num" id="habitsToday">0</div>
<div class="streak-label">Done Today</div>
</div>
<div class="streak-card">
<div class="streak-num" id="totalXp">0</div>
<div class="streak-label">Total XP</div>
</div>
</div>
<div class="section-card">
<div class="section-head">
<div class="section-icon icon-gold">✅</div>
<div>
<div class="section-title">Daily Habits</div>
<div class="section-sub">Tap to mark complete</div>
</div>
</div>
<div class="habit-list" id="habitList"></div>
</div>
<div class="section-card" style="margin-top:14px">
<div class="section-head">
<div class="section-icon icon-violet">🧠</div>
<div>
<div class="section-title">Mindset Coaching</div>
<div class="section-sub">Today's message</div>
</div>
</div>
<div id="coachingMsg" style="font-size:0.85rem;color:var(--muted2);line-height:1.7;"></div>
</div>
</div>
</div><!-- end resultScreen -->
</div><!-- end app -->
<!-- Bottom Nav (hidden until results) -->
<div class="bottom-nav" id="bottomNav" style="display:none">
<button class="nav-item active" onclick="showResultTab('overview')">
<div class="nav-ico">✨</div>
<div class="nav-lbl">Overview</div>
</button>
<button class="nav-item" onclick="showResultTab('tips')">
<div class="nav-ico">💡</div>
<div class="nav-lbl">Tips</div>
</button>
<button class="nav-item" onclick="showResultTab('track2')">
<div class="nav-ico">📊</div>
<div class="nav-lbl">Progress</div>
</button>
</div>
<script>
// STATE
const state = { photo: null, photoBase64: null, selections: {}, result: null, habits: [], habitDone: new Set(), streak: 1, xp: 0 };
// PHOTO HANDLING
function handlePhoto(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
state.photo = ev.target.result;
state.photoBase64 = ev.target.result.split(',')[1];
document.getElementById('previewImg').src = state.photo;
document.getElementById('previewImg').style.display = 'block';
document.getElementById('uploadZone').style.display = 'none';
document.getElementById('questionsBlock').style.display = 'block';
document.getElementById('apiBlock').style.display = 'block';
document.getElementById('analyzeBtn').style.display = 'block';
};
reader.readAsDataURL(file);
}
// CHIP SELECT
function selectChip(el, group, value) {
el.closest('.chips').querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
el.classList.add('active');
state.selections[group] = value;
}
// SCREEN SWITCH
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(id).classList.add('active');
}
// TAB SWITCH
function switchTab(name) {
document.querySelectorAll('.tab').forEach((t,i) => {
t.classList.toggle('active', ['analysis','plan','routine','track'][i] === name);
});
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.getElementById('tab-' + name).classList.add('active');
if (name === 'track') animateBars();
}
// ANALYSIS
async function startAnalysis() {
const apiKey = document.getElementById('apiKey').value.trim();
const err = document.getElementById('errorMsg');
err.style.display = 'none';
if (!apiKey) { showError('Please enter your Anthropic API key.'); return; }
if (!state.photo) { showError('Please upload a selfie first.'); return; }
const required = ['gender','age','goal','skinType','lifestyle'];
if (required.some(k => !state.selections[k])) { showError('Please answer all questions.'); return; }
showScreen('loadScreen');
const s = state.selections;
const prompt = `You are an expert beauty consultant, dermatologist, and personal stylist. Analyze this person's face photo and create a comprehensive personalized glow-up analysis.
Person profile:
- Gender: ${s.gender}
- Age range: ${s.age}
- Main goal: ${s.goal}
- Skin type: ${s.skinType}
- Lifestyle: ${s.lifestyle}
Based on their face in the photo, respond ONLY in this exact JSON (no other text):
{
"score": 7.2,
"scoreTag": "Hidden Gem — Huge Potential",
"skinQuality": 68,
"symmetry": 74,
"features": 71,
"stylePotential": 82,
"strengths": [
"Strong, defined jawline that photographs beautifully",
"High cheekbones that catch light naturally",
"Expressive eyes with natural depth"
],
"weaknesses": [
"Uneven skin texture that can be smoothed with consistent care",
"Under-eye area needs hydration and brightening",
"Eyebrow shape not maximizing facial frame"
],
"motivation": "Your features have incredible untapped potential. Most people you walk past would genuinely envy your natural bone structure — you just need the right tools to reveal it.",
"planSteps": [
{"title": "Week 1: Skin Reset", "desc": "Double cleanse nightly to clear buildup. Add a Vitamin C serum each morning for brightness."},
{"title": "Week 2: Brow Shaping", "desc": "Get a professional brow shape — this single change can transform how your eyes look."},
{"title": "Week 3: Hydration Protocol", "desc": "Add hyaluronic acid serum before moisturizer. Drink 2L water daily. Your skin will visibly plump."},
{"title": "Week 4: Style Upgrade", "desc": "Try a haircut that frames your face shape. Experiment with the makeup techniques below."},
{"title": "Daily Habit: SPF 50", "desc": "Wearing sunscreen every morning is the single highest-ROI beauty habit. Non-negotiable."},
{"title": "Bonus: Jawline Exercises", "desc": "5 minutes of mewing and jaw clenching daily. Visible definition in 30 days."}
],
"makeupTips": [
"A subtle contour along your temples and jaw will add definition — blend well with a damp sponge",
"Warm-toned blush on the apples of your cheeks will balance your features",
"Highlight the inner corners of your eyes and brow bone to open up your eye area",
"A nude lip in your skin's undertone makes your eyes the focal point"
],
"hairTips": [
"Layers around the face will soften and frame your features beautifully",
"Avoid blunt cuts at chin-length — they can shorten the appearance of your neck",
"Your face shape suits middle or side parts — center parts elongate, side parts add softness"
],
"morningRoutine": [
{"time": "AM", "name": "Gentle Cleanser", "note": "30 sec"},
{"time": "AM", "name": "Vitamin C Serum", "note": "3 drops"},
{"time": "AM", "name": "Hyaluronic Acid", "note": "2 drops"},
{"time": "AM", "name": "Moisturizer", "note": "SPF 50+"},
{"time": "AM", "name": "Eye Cream", "note": "Tap gently"}
],
"nightRoutine": [
{"time": "PM", "name": "Micellar Water / Oil", "note": "Remove makeup"},
{"time": "PM", "name": "Gentle Cleanser", "note": "Double cleanse"},
{"time": "PM", "name": "Retinol or Niacinamide", "note": "Alternate nights"},
{"time": "PM", "name": "Rich Night Moisturizer", "note": "Lock in moisture"},
{"time": "PM", "name": "Lip Mask", "note": "Overnight repair"}
],
"products": [
"CeraVe Hydrating Cleanser — gentle for your skin type, won't strip barrier",
"The Ordinary Niacinamide 10% — reduces pores and evening skin tone",
"La Roche-Posay SPF 50 — lightweight, non-greasy daily sunscreen",
"Neutrogena Hydro Boost — hyaluronic acid gel cream for deep hydration",
"e.l.f. Halo Glow Liquid Filter — natural radiance booster for your skin tone"
],
"habits": [
"Morning skincare routine",
"SPF applied before leaving home",
"2 litres of water",
"5 min jawline exercises",
"8 hours sleep",
"No touching your face today",
"Evening skincare routine"
],
"coaching": "Confidence is not something you find — it is something you build, one small habit at a time. Every time you complete your routine, you are sending a signal to yourself: I am worth the effort. That signal compounds. In 30 days you will not recognise yourself, not just in the mirror, but in the way you carry yourself."
}
Make the analysis genuinely specific and insightful. The score should be between 6.0 and 8.5. Make all advice feel truly personalized.`;
try {
const resp = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
'anthropic-version': '2023-06-01',
'anthropic-dangerous-direct-browser-access': 'true'
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 2000,
messages: [{
role: 'user',
content: [
{ type: 'image', source: { type: 'base64', media_type: 'image/jpeg', data: state.photoBase64 } },
{ type: 'text', text: prompt }
]
}]
})
});
if (!resp.ok) {
const e = await resp.json();
throw new Error(e.error?.message || 'API error');
}
const data = await resp.json();
const text = data.content[0].text.replace(/```json|```/g,'').trim();
const r = JSON.parse(text);
state.result = r;
state.habits = r.habits || [];
renderResults(r);
} catch(err) {
showScreen('homeScreen');
showError('Error: ' + err.message);
}
}
function renderResults(r) {
// Score
document.getElementById('scoreNum').innerHTML = r.score + '<span>/10</span>';
document.getElementById('scoreTag').textContent = r.scoreTag;
// Bars (will animate on show)
document.getElementById('bar1').dataset.width = r.skinQuality;
document.getElementById('bar1pct').textContent = r.skinQuality + '%';
document.getElementById('bar2').dataset.width = r.symmetry;
document.getElementById('bar2pct').textContent = r.symmetry + '%';
document.getElementById('bar3').dataset.width = r.features;
document.getElementById('bar3pct').textContent = r.features + '%';
document.getElementById('bar4').dataset.width = r.stylePotential;
document.getElementById('bar4pct').textContent = r.stylePotential + '%';
// Strengths
document.getElementById('strengthsList').innerHTML = r.strengths.map(s =>
`<div class="insight-item"><div class="insight-dot dot-green"></div>${s}</div>`).join('');
// Weaknesses
document.getElementById('weaknessesList').innerHTML = r.weaknesses.map(w =>
`<div class="insight-item"><div class="insight-dot dot-rose"></div>${w}</div>`).join('');
// Motivation
document.getElementById('motivationBox').innerHTML =
`<p>"${r.motivation}"</p><span>— Your AI Glow Coach</span>`;
// Plan
document.getElementById('planSteps').innerHTML = r.planSteps.map((p,i) =>
`<div class="plan-step"><div class="plan-num">${i+1}</div><div class="plan-text"><strong>${p.title}</strong><br>${p.desc}</div></div>`).join('');
// Makeup
document.getElementById('makeupTips').innerHTML = r.makeupTips.map(t =>
`<div class="insight-item"><div class="insight-dot dot-gold"></div>${t}</div>`).join('');
// Hair
document.getElementById('hairTips').innerHTML = r.hairTips.map(t =>
`<div class="insight-item"><div class="insight-dot dot-violet" style="background:var(--violet)"></div>${t}</div>`).join('');
// Morning routine
document.getElementById('morningRoutine').innerHTML = r.morningRoutine.map(item =>
`<div class="routine-item"><div class="routine-time">${item.time}</div><div class="routine-name">${item.name}</div><div class="routine-note">${item.note}</div></div>`).join('');
// Night routine
document.getElementById('nightRoutine').innerHTML = r.nightRoutine.map(item =>
`<div class="routine-item"><div class="routine-time">${item.time}</div><div class="routine-name">${item.name}</div><div class="routine-note">${item.note}</div></div>`).join('');
// Products
document.getElementById('productRecs').innerHTML = r.products.map(p =>
`<div class="insight-item"><div class="insight-dot dot-gold"></div>${p}</div>`).join('');
// Habits
document.getElementById('habitList').innerHTML = r.habits.map((h,i) =>
`<div class="habit-item" id="habit${i}" onclick="toggleHabit(${i})">
<div class="habit-check">✓</div>
<div class="habit-name">${h}</div>
<div class="habit-xp">+10 XP</div>
</div>`).join('');
// Coaching
document.getElementById('coachingMsg').textContent = r.coaching;
showScreen('resultScreen');
document.getElementById('bottomNav').style.display = 'flex';
setTimeout(animateBars, 300);
}
function animateBars() {
['bar1','bar2','bar3','bar4'].forEach(id => {
const el = document.getElementById(id);
if (el) el.style.width = (el.dataset.width || 0) + '%';
});
}
function toggleHabit(i) {
const item = document.getElementById('habit' + i);
if (state.habitDone.has(i)) {
state.habitDone.delete(i);
item.classList.remove('done');
state.xp = Math.max(0, state.xp - 10);
} else {
state.habitDone.add(i);
item.classList.add('done');
state.xp += 10;
}
document.getElementById('habitsToday').textContent = state.habitDone.size;
document.getElementById('totalXp').textContent = state.xp;
document.getElementById('streakDays').textContent = state.streak;
}
function showError(msg) {
const el = document.getElementById('errorMsg');
el.textContent = msg;
el.style.display = 'block';
}
function goHome() {
showScreen('homeScreen');
document.getElementById('bottomNav').style.display = 'none';
document.getElementById('previewImg').style.display = 'none';
document.getElementById('uploadZone').style.display = 'block';
document.getElementById('questionsBlock').style.display = 'none';
document.getElementById('apiBlock').style.display = 'none';
document.getElementById('analyzeBtn').style.display = 'none';
document.getElementById('errorMsg').style.display = 'none';
document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
state.selections = {};
state.habitDone = new Set();
}
function showResultTab(t) {
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
event.currentTarget.classList.add('active');
}
</script>
</body>
</html>
Comments
Post a Comment