<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DeepSetPoint</title>
<link rel="manifest" href="/manifest.json">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #0f0f0f;
color: #fff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
overflow-x: hidden;
}
.container {
max-width: 500px;
width: 100%;
text-align: center;
margin-top: 20vh;
}
h1 {
font-size: 2.5rem;
margin-bottom: 2rem;
background: linear-gradient(45deg, #ffd700, #ffaa00);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
line-height: 1.2;
}
.btn-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
margin-top: 1.5rem;
}
.btn {
background: #1a1a1a;
border: 1px solid #333;
color: #fff;
padding: 1.2rem;
border-radius: 16px;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
min-height: 60px;
}
.btn:hover {
background: #2a2a2a;
transform: translateY(-2px);
}
.btn:active {
transform: translateY(0);
}
.back-btn {
margin-top: 2rem;
background: transparent;
border: none;
color: #888;
font-size: 0.9rem;
cursor: pointer;
}
.mantra {
font-size: 1.8rem;
line-height: 1.5;
margin: 2.5rem 0;
font-style: italic;
color: #ffd700;
min-height: 80px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1rem;
}
.step {
margin: 1.5rem 0;
font-size: 1.1rem;
color: #888;
line-height: 1.4;
}
.hidden { display: none; }
.loading {
margin-top: 1.5rem;
color: #888;
font-style: italic;
}
.breath-circle {
width: 80px;
height: 80px;
border-radius: 50%;
background: rgba(255, 215, 0, 0.1);
margin: 2rem auto;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #ffd700;
animation: pulse 4s infinite;
}
@keyframes pulse {
0% { transform: scale(1); opacity: 0.7; }
50% { transform: scale(1.1); opacity: 1; }
100% { transform: scale(1); opacity: 0.7; }
}
.payment-btn {
background: #ffd700;
color: #000;
font-weight: bold;
margin-top: 1.5rem;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<!-- Step 1: Language -->
<div id="step1">
<h1>Set Your Day</h1>
<div class="btn-grid">
<button class="btn" onclick="setLang('en')">English</button>
<button class="btn" onclick="setLang('es')">Español</button>
<button class="btn" onclick="setLang('de')">Deutsch</button>
<button class="btn" onclick="setLang('pt')">Português</button>
<button class="btn" onclick="setLang('it')">Italiano</button>
</div>
</div>
<!-- Step 2: Emotion -->
<div id="step2" class="hidden">
<h1 id="emotion-title">Choose Emotion</h1>
<div class="btn-grid" id="emotion-grid"></div>
<button class="back-btn" onclick="backToLang()">← Back</button>
</div>
<!-- Step 3: Mantra -->
<div id="step3" class="hidden">
<h1>Your Mantra</h1>
<div class="mantra" id="mantra-text">Loading...</div>
<div class="breath-circle"></div>
<div class="step" id="breath-text">Press thumb + forefinger. Breathe once. Say it silently.</div>
<button class="btn payment-btn" onclick="unlockPremium()">
Unlock Daily ($9.99/mo)
</button>
<button class="back-btn" onclick="backToEmotion()">← Choose Again</button>
<div class="loading" id="loading" style="display:none">Generating your mantra...</div>
</div>
</div>
<script>
// Emotions by language
const emotions = {
en: ['Calm', 'Courage', 'Clarity', 'Grounded', 'Focus', 'Joy', 'Fierce', 'Playful', 'Patience', 'Strength', 'Stillness', 'Kindness'],
es: ['Calmo', 'Coraje', 'Claridad', 'Conectado', 'Enfoque', 'Alegría', 'Feroz', 'Juguetón', 'Paciencia', 'Fuerza', 'Quietud', 'Amabilidad'],
de: ['Ruhe', 'Mut', 'Klarheit', 'Erdung', 'Fokus', 'Freude', 'Wild', 'Verspielt', 'Geduld', 'Stärke', 'Stille', 'Freundlichkeit'],
pt: ['Calmo', 'Coragem', 'Clareza', 'Enraizado', 'Foco', 'Alegria', 'Feroz', 'Brincalhão', 'Paciência', 'Força', 'Imobilidade', 'Gentileza'],
it: ['Calmo', 'Coraggio', 'Chiarezza', 'Radicato', 'Concentrazione', 'Gioia', 'Fiero', 'Gioioso', 'Pazienza', 'Forza', 'Immobilità', 'Gentilezza']
};
// Fallback mantras (non-generic, human-crafted)
const fallbackMantras = {
en: {
'Calm': 'Ocean breath. Storm passes. You remain.',
'Courage': 'Knees shake. Heart leads. Step forward.',
'Clarity': 'Mud settles. Water clear. Truth appears.',
'Grounded': 'Feet earth. Head sky. You are bridge.',
'Focus': 'One flame. Dark room. That is enough.',
'Joy': 'Child laugh. Inner sun. Shine anyway.',
'Fierce': 'Soft hands. Fire eyes. Protect what matters.',
'Playful': 'Gravity light. Heart curious. Leap now.',
'Patience': 'Seed knows. Dark soil. Growth comes.',
'Strength': 'Quiet river. Deep current. Move mountains.',
'Stillness': 'Wind howls. Tree roots. Stand anyway.',
'Kindness': 'Open palm. Warm cup. Give freely.'
},
es: {
'Calmo': 'Respira océano. Tormenta pasa. Tú quedas.',
'Coraje': 'Rodillas tiemblan. Corazón guía. Avanza.',
'Claridad': 'Lodo asienta. Agua clara. Verdad aparece.',
'Conectado': 'Pies tierra. Cabeza cielo. Puente eres.',
'Enfoque': 'Una llama. Cuarto oscuro. Basta así.',
'Alegría': 'Risa niña. Sol interno. Brilla igual.',
'Feroz': 'Manos suaves. Ojos fuego. Protege lo que importa.',
'Juguetón': 'Gravedad ligera. Corazón curioso. Salta ahora.',
'Paciencia': 'Semilla sabe. Tierra oscura. Crecimiento viene.',
'Fuerza': 'Río tranquilo. Corriente honda. Mueve montañas.',
'Quietud': 'Viento aúlla. Raíces árbol. Aguanta igual.',
'Amabilidad': 'Palma abierta. Taza caliente. Da libre.'
},
de: {
'Ruhe': 'Ozean atmen. Sturm vergeht. Du bleibst.',
'Mut': 'Knie zittern. Herz führt. Schritt vorwärts.',
'Klarheit': 'Schlamm setzt. Wasser klar. Wahrheit erscheint.',
'Erdung': 'Füße Erde. Kopf Himmel. Du bist Brücke.',
'Fokus': 'Eine Flamme. Dunkler Raum. Das genügt.',
'Freude': 'Kind Lachen. Inner Sonne. Scheine trotzdem.',
'Wild': 'Sanfte Hände. Feueraugen. Schütze was zählt.',
'Verspielt': 'Schwerkraft leicht. Herz neugierig. Spring jetzt.',
'Geduld': 'Samen weiß. Dunkle Erde. Wachstum kommt.',
'Stärke': 'Stiller Fluss. Tiefe Strömung. Bewegt Berge.',
'Stille': 'Wind heult. Baumwurzeln. Stehe trotzdem.',
'Freundlichkeit': 'Offene Handfläche. Warmer Becher. Gib frei.'
},
pt: {
'Calmo': 'Respira oceano. Tempestade passa. Você permanece.',
'Coragem': 'Joelhos tremem. Coração lidera. Passo adiante.',
'Clareza': 'Lama assenta. Água clara. Verdade aparece.',
'Enraizado': 'Pés terra. Cabeça céu. Você é ponte.',
'Foco': 'Uma chama. Quarto escuro. Isso basta.',
'Alegria': 'Riso criança. Sol interno. Brilha mesmo assim.',
'Feroz': 'Mãos suaves. Olhos fogo. Proteja o que importa.',
'Brincalhão': 'Gravidade leve. Coração curioso. Salte agora.',
'Paciência': 'Semente sabe. Solo escuro. Crescimento vem.',
'Força': 'Rio calmo. Corrente profunda. Move montanhas.',
'Imobilidade': 'Vento uiva. Raízes árvore. Fique assim.',
'Gentileza': 'Palma aberta. Xícara quente. Dê livremente.'
},
it: {
'Calmo': 'Respira oceano. Tempesta passa. Tu resti.',
'Coraggio': 'Ginocchia tremano. Cuore guida. Passo avanti.',
'Chiarezza': 'Fango si deposita. Acqua chiara. Verità appare.',
'Radicato': 'Piedi terra. Testa cielo. Ponte sei.',
'Concentrazione': 'Una fiamma. Stanza buia. Basta così.',
'Gioia': 'Risata bambino. Sole interno. Brilla comunque.',
'Fiero': 'Mani morbide. Occhi fuoco. Proteggi ciò che conta.',
'Gioioso': 'Gravità leggera. Cuore curioso. Salta ora.',
'Pazienza': 'Seme sa. Terra scura. Crescita viene.',
'Forza': 'Fiume tranquillo. Corrente profonda. Muovi montagne.',
'Immobilità': 'Vento urla. Radici albero. Resta comunque.',
'Gentilezza': 'Palmo aperto. Tazza calda. Dai liberamente.'
}
};
let currentLang = 'en';
let currentEmotion = '';
let OPENROUTER_KEY = ''; // You'll set this in Cloudflare
function setLang(lang) {
currentLang = lang;
document.getElementById('step1').classList.add('hidden');
document.getElementById('step2').classList.remove('hidden');
// Update title
const titles = {
en: 'Choose Emotion',
es: 'Elige Emoción',
de: 'Wähle Emotion',
pt: 'Escolha Emoção',
it: 'Scegli Emozione'
};
document.getElementById('emotion-title').textContent = titles[lang];
// Build emotion grid
const grid = document.getElementById('emotion-grid');
grid.innerHTML = '';
emotions[lang].forEach(emotion => {
const btn = document.createElement('button');
btn.className = 'btn';
btn.textContent = emotion;
btn.onclick = () => setEmotion(emotion);
grid.appendChild(btn);
});
}
async function setEmotion(emotion) {
currentEmotion = emotion;
document.getElementById('step2').classList.add('hidden');
document.getElementById('step3').classList.remove('hidden');
// Show loading state
document.getElementById('mantra-text').textContent = '...';
document.getElementById('loading').style.display = 'block';
try {
// Check for OpenRouter key (set in Cloudflare environment)
OPENROUTER_KEY = OPENROUTER_KEY || localStorage.getItem('openrouter_key') || '';
let mantra = '';
if (OPENROUTER_KEY) {
mantra = await generateAIMantra(emotion, currentLang);
} else {
// Use fallback if no API key
mantra = fallbackMantras[currentLang][emotion] || 'Breathe deep. Truth lives here. Carry on.';
// Gentle nudge to set up AI (only in dev)
if (window.location.hostname === 'localhost' || window.location.hostname.includes('pages.dev')) {
setTimeout(() => {
alert('✨ For truly personal mantras, add your OpenRouter API key in Cloudflare dashboard. This fallback mantra is generic.');
}, 3000);
}
}
document.getElementById('mantra-text').textContent = mantra;
// Save to local storage (no personal data sent)
const cacheKey = `mantra_${emotion}_${currentLang}`;
localStorage.setItem(cacheKey, JSON.stringify({
text: mantra,
timestamp: Date.now()
}));
} catch (error) {
console.error('Mantra generation failed:', error);
// Fallback to human-crafted mantra
const fallback = fallbackMantras[currentLang][emotion] || fallbackMantras.en[emotion] || 'Breathe. You are safe here.';
document.getElementById('mantra-text').textContent = fallback;
} finally {
document.getElementById('loading').style.display = 'none';
}
}
async function generateAIMantra(emotion, language) {
// First check cache (24 hour TTL)
const cacheKey = `mantra_${emotion}_${language}`;
const cached = localStorage.getItem(cacheKey);
if (cached) {
const { text, timestamp } = JSON.parse(cached);
if (Date.now() - timestamp < 86400000) { // 24 hours
return text;
}
}
// Get time context
const hour = new Date().getHours();
const timeContext = hour < 12 ? 'morning' : hour < 17 ? 'afternoon' : 'night';
// Language names for prompt
const langNames = {
'en': 'English',
'es': 'Spanish',
'de': 'German',
'pt': 'Portuguese',
'it': 'Italian'
};
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${OPENROUTER_KEY}`,
'Content-Type': 'application/json',
'HTTP-Referer': window.location.origin,
'X-Title': 'DeepSetPoint'
},
body: JSON.stringify({
model: "anthropic/claude-3.5-sonnet",
messages: [{
role: "user",
content: `
You are a mindfulness master who has sat with thousands in their rawest moments.
User selected emotion: "${emotion}" in ${langNames[language]} during ${timeContext}.
Generate EXACTLY ONE 8-word mantra that feels like:
- A warm hand on their shoulder
- Something their grandmother might whisper
- True *right now*
NO explanations. NO numbering. ONLY the mantra.
If generic, you fail this human.
`
}]
})
});
if (!response.ok) {
throw new Error(`AI failed: ${response.status}`);
}
const data = await response.json();
return data.choices[0].message.content.trim();
}
function backToLang() {
document.getElementById('step2').classList.add('hidden');
document.getElementById('step1').classList.remove('hidden');
}
function backToEmotion() {
document.getElementById('step3').classList.add('hidden');
document.getElementById('step2').classList.remove('hidden');
}
function unlockPremium() {
// This will be your Stripe link later
alert('Premium unlocks tomorrow! For now, enjoy your personal mantra.');
}
// Auto-show language picker on load
window.onload = () => {
document.getElementById('step1').classList.remove('hidden');
// Load OpenRouter key if set in localStorage (for testing)
if (localStorage.getItem('openrouter_key')) {
OPENROUTER_KEY = localStorage.getItem('openrouter_key');
}
};
</script>
</body>
</html>