-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
366 lines (326 loc) · 25.5 KB
/
Copy pathindex.html
File metadata and controls
366 lines (326 loc) · 25.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Between Us</title>
<!-- React & DOM (Switched to cdnjs for better local/server support) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<!-- Babel -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.9/babel.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0..1&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<script>
if (window.tailwind) {
window.tailwind.config = {
theme: {
extend: {
fontFamily: {
serif: ['"Instrument Serif"', 'serif'],
sans: ['"Inter"', 'sans-serif'],
},
colors: {
black: '#000000',
gray: { 400: '#6F6F6F', 500: '#555555' }
},
animation: {
'fade-rise': 'fadeRise 0.8s ease-out forwards',
'fade-rise-delay': 'fadeRise 0.8s ease-out 0.2s forwards',
'fade-rise-delay-2': 'fadeRise 0.8s ease-out 0.4s forwards',
},
keyframes: {
fadeRise: {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
}
}
}
}
}
}
</script>
<style>
body, html {
height: 100%;
width: 100%;
overflow: hidden;
background-color: #FFFFFF;
color: #000000;
margin: 0;
padding: 0;
-webkit-font-smoothing: antialiased;
}
.hero-bg-fallback {
background-image: url('https://images.unsplash.com/photo-1492633423870-43d1cd2775eb?q=80&w=800&auto=format&fit=crop');
background-size: cover;
background-position: center;
filter: grayscale(100%);
}
.hero-video-container {
position: absolute;
inset: 0;
height: 100%;
width: 100%;
overflow: hidden;
z-index: 0;
opacity: 0.5;
pointer-events: none;
}
.hero-video {
width: 100%;
height: 100%;
object-fit: cover;
filter: grayscale(20%);
}
.gradient-overlay {
background: linear-gradient(to bottom, #FFFFFF 0%, rgba(255,255,255,0.8) 15%, rgba(255,255,255,0) 40%, rgba(255,255,255,0) 80%, #FFFFFF 100%);
}
.error-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
font-family: 'Inter', sans-serif;
text-align: center;
padding: 2rem;
background: #fafafa;
}
</style>
</head>
<body>
<div id="root" style="height: 100%; width: 100%;">
<div class="error-container">
<h2 style="color: #000; margin-bottom: 1rem;">Loading Experience...</h2>
</div>
</div>
<script>
// 1. Detect if user is opening file directly (file:///) which breaks Babel
if (window.location.protocol === 'file:') {
document.getElementById('root').innerHTML = `
<div class="error-container">
<h2 style="color: #000; font-size: 1.5rem; margin-bottom: 1rem;">⚠️ Local File Error</h2>
<p style="color: #555; max-width: 400px; line-height: 1.6;">
You are opening this file directly from your computer. Browsers block React/Babel from working this way for security reasons.
</p>
<br>
<p style="color: #000; font-weight: 600;">
How to fix:<br>
<span style="font-weight: 400; color: #555;">
If using VS Code, install <b>"Live Server"</b> extension and click "Go Live".<br>
Otherwise, upload this file to <b>Netlify Drop</b> (free).
</span>
</p>
</div>
`;
throw new Error("Blocked file:// protocol to prevent Babel crash");
}
// 2. Catch any other unexpected errors
window.onerror = function(message, source, lineno, colno, error) {
document.getElementById('root').innerHTML = `
<div class="error-container">
<h2 style="color: red; margin-bottom: 1rem;">App Crashed</h2>
<p style="color: #555;">${message} (Line ${lineno})</p>
</div>
`;
return false;
};
</script>
<script type="text/babel" data-presets="react">
const { useState, useEffect, useRef } = window.React;
const playSound = (type) => {
try {
const AudioContext = window.AudioContext || window.webkitAudioContext;
if (!AudioContext) return;
const ctx = new AudioContext();
if (ctx.state === 'suspended') ctx.resume();
const t = ctx.currentTime;
if (type === 'tap') {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(800, t);
osc.frequency.exponentialRampToValueAtTime(300, t + 0.05);
gain.gain.setValueAtTime(0.05, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.05);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(t);
osc.stop(t + 0.05);
} else if (type === 'transition') {
const bufferSize = ctx.sampleRate * 0.2;
const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) data[i] = Math.random() * 2 - 1;
const noise = ctx.createBufferSource();
noise.buffer = buffer;
const filter = ctx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.setValueAtTime(400, t);
filter.frequency.linearRampToValueAtTime(100, t + 0.2);
const gain = ctx.createGain();
gain.gain.setValueAtTime(0.03, t);
gain.gain.linearRampToValueAtTime(0, t + 0.2);
noise.connect(filter);
filter.connect(gain);
gain.connect(ctx.destination);
noise.start(t);
}
} catch (e) { console.error(e); }
};
const DATA = {
deep: ["What is something you've never fully gotten over?", "What part of yourself do you hide most often?", "What fear influences your life the most?", "When was the last time you felt truly understood?", "What memory shaped who you are today?", "What do you wish more people knew about you?", "What lesson took you the longest to learn?", "What is your biggest insecurity right now?", "What do you think people misunderstand about you?", "What motivates you when nobody is watching?", "What would your younger self think of you today?", "What are you still trying to heal from?", "What keeps you awake at night?", "What does happiness actually mean to you?", "What is something you've never forgiven yourself for?", "What is your greatest strength?", "What do you fear losing most?", "What kind of person do you want to become?", "What belief has changed your life?", "What is something you've never told anyone?", "What do you think happens when people drift apart?", "What is your biggest regret?", "What makes life meaningful?", "What are you most proud of?", "What is one thing you wish you could change?", "What would you do if you knew you couldn't fail?", "What do you hope people remember about you?", "What do you think love really is?", "What scares you about the future?", "What's a question you've always wanted someone to ask you?"],
connection: ["What was your first impression of me?", "What made you trust me?", "When do you feel closest to me?", "What's your favorite memory of us?", "What do you appreciate most about me?", "What makes you feel loved?", "What's something I do that makes you smile?", "What's something you wish we did more often?", "What's one thing we've overcome together?", "What makes our relationship unique?", "When did you realize I mattered to you?", "What's your favorite conversation we've had?", "What quality in me do you admire most?", "What's something you've learned from me?", "What's one thing you hope never changes about us?", "When have you felt most supported by me?", "What is one thing we understand about each other better than anyone else?", "What memory would you relive with me?", "What does a healthy relationship mean to you?", "What's a small thing I do that means a lot?", "What's something you wish I knew without having to tell me?", "What's one thing we should prioritize more?", "What makes you feel safe with someone?", "What's your favorite thing about spending time together?", "What's one challenge that made us stronger?", "What habit of mine do you secretly love?", "What makes you feel appreciated?", "How do you think we've changed each other?", "What does loyalty mean to you?", "How can I be a better partner or friend to you?"],
future: ["What does your dream life look like?", "Where do you see yourself in 10 years?", "What is your biggest goal right now?", "What kind of home do you want someday?", "What's something you're excited about?", "What country do you want to visit most?", "What would your perfect day look like?", "What skill do you want to learn?", "What's on your bucket list?", "What kind of lifestyle do you want?", "What does success mean to you?", "What adventure should we take together?", "What's your dream career?", "What motivates your future plans?", "What's a dream you're afraid to chase?", "What tradition would you like to create?", "What kind of people do you want around you?", "What would make you feel fulfilled?", "What's one thing worth sacrificing for?", "What project would you love to start?", "What does financial freedom mean to you?", "What achievement would make you proud?", "What's one thing you don't want to regret?", "What legacy would you like to leave?", "What's a place you'd love to live?", "What kind of future relationship do you want?", "What inspires you most?", "What challenge do you want to overcome?", "What dream have you had since childhood?", "What's one thing you hope happens this year?"],
unfiltered: ["What's a fantasy you've never told anyone but have thought about more than once?", "Where on your body do you love to be touched that most people wouldn't guess?", "What's the most attractive thing a partner has ever done that caught you off guard?", "What's your biggest turn-on that you'd be embarrassed to admit out loud?", "Have you ever had a dream about someone unexpected? Who?", "What's one thing you wish your partner would initiate more often?", "What's the most daring thing you've done to impress someone you were attracted to?", "What's your opinion on public displays of affection — where do you draw the line?", "Have you ever faked a feeling to keep the peace in bed? What happened?", "What's something you've always wanted to try but haven't asked for yet?", "What's a location you've always wanted to be intimate in but haven't?", "What's the boldest move you've ever made on someone you were attracted to?", "Have you ever been caught in a compromising situation? What's the story?", "What's your most memorable intimate experience and why did it stand out?", "What's one thing a partner did that instantly made you more attracted to them?", "What's a role or scenario that secretly intrigues you?", "What's something you consider a hard no that you'd be willing to reconsider with the right person?", "How do you feel about sending or receiving spicy photos — any rules you live by?", "What's the longest you've gone without physical intimacy and how did it affect you?", "What's one thing you've never done but your curiosity keeps coming back to?", "What's the most unexpected thing you find deeply attractive in a partner?", "If you could design a perfect night with your partner with zero limits, what would it look like?", "Have you ever had feelings for someone while in a relationship? What did you do?", "What's the most risqué thing you've done and felt zero regret about?", "What do you think about keeping secrets from a partner — where's the line?", "What's something you've never done in a relationship that you secretly want to experience?", "Have you ever developed feelings for a friend? Did anything happen?", "What's the most vulnerable thing you can share about your desires right now?", "What's a question you hope I never ask you — and what's your answer?", "What's something about your desires or needs you've never fully said out loud until now?"]
};
const Navbar = ({ onViewChange }) => (
<nav className="flex justify-start px-6 py-4 md:px-8 md:py-6 max-w-7xl mx-auto z-10 relative w-full">
<div className="font-serif text-2xl md:text-3xl tracking-tight text-black cursor-pointer hover:opacity-70 transition-opacity select-none" onClick={() => { playSound('tap'); onViewChange('hero'); }}>
Between Us
</div>
</nav>
);
const Hero = ({ onBegin }) => {
const videoRef = useRef(null);
const [videoError, setVideoError] = useState(false);
useEffect(() => {
const video = videoRef.current;
if (!video) return;
video.play().catch(() => {});
}, []);
return (
<div className="relative w-full h-[100dvh] flex flex-col bg-white overflow-hidden">
<div className="hero-video-container">
<div className={`absolute inset-0 hero-bg-fallback transition-opacity duration-500 ${videoError ? 'opacity-100' : 'opacity-0'}`}></div>
<video ref={videoRef} className="hero-video" muted playsInline loop autoPlay onError={() => setVideoError(true)}>
<source src="https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260506_031045_0e1165dd-ab48-46e3-ad3d-5fe77f217647.mp4" type="video/mp4" />
</video>
<div className="absolute inset-0 gradient-overlay z-10"></div>
</div>
<Navbar onViewChange={onBegin} />
<div className="flex-1 flex flex-col justify-center items-center text-center px-4 z-20 w-full">
<h1 className="font-serif tracking-tight text-black mb-4 animate-fade-rise leading-tight selection:bg-gray-200" style={{ fontSize: 'clamp(2rem, 5vw, 3.5rem)' }}>
Beyond <span className="text-gray-400 italic">silence</span>, we build the <span className="text-gray-400 italic">eternal</span>.
</h1>
<p className="font-sans max-w-2xl mt-4 leading-relaxed text-gray-500 font-light animate-fade-rise-delay" style={{ fontSize: 'clamp(0.9rem, 2vw, 1.1rem)' }}>
Some of the best moments in a relationship begin with a question.<br/>Take your time. Listen carefully. Be honest.
</p>
<button onClick={() => { playSound('tap'); onBegin(); }} className="mt-8 bg-black text-white rounded-full px-10 py-3 md:px-14 md:py-4 text-xs md:text-sm tracking-[0.15em] uppercase hover:scale-105 hover:bg-gray-800 active:scale-95 transition-all duration-300 animate-fade-rise-delay-2 shadow-lg">
Begin Journey
</button>
</div>
<div className="absolute bottom-8 w-full text-center z-30 animate-fade-rise-delay-2 pb-6">
<p className="font-sans text-[10px] tracking-[0.2em] uppercase text-gray-400 hover:text-black transition-opacity cursor-default">Made by Gajee Hub</p>
</div>
</div>
);
};
const Categories = ({ onSelect, onAgeCheck }) => {
const categories = [
{ id: 'deep', label: 'Deep', icon: <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path> },
{ id: 'connection', label: 'Connection', icon: <g><circle cx="12" cy="12" r="10" /><circle cx="12" cy="12" r="4" /></g> },
{ id: 'future', label: 'Future', icon: <g><path d="M12 2v20"/><path d="M12 12l5-5"/><path d="M12 12l-5-5"/></g> },
{ id: 'unfiltered', label: 'Unfiltered', icon: <rect x="4" y="4" width="16" height="16" rx="4" transform="rotate(45 12 12)"></rect> }
];
return (
<div className="h-screen flex flex-col justify-center items-center bg-white px-4 relative overflow-y-auto">
<h2 className="font-serif tracking-tight mb-1 md:mb-2 text-black animate-fade-rise" style={{ fontSize: 'clamp(1.5rem, 4vw, 2.5rem)' }}>The Conversation</h2>
<p className="font-sans text-gray-400 max-w-md mx-auto mb-4 md:mb-8 animate-fade-rise-delay text-xs md:text-sm">Choose a path.</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-4 w-full max-w-4xl animate-fade-rise-delay-2 pb-10">
{categories.map((cat) => (
<div key={cat.id} onClick={() => { playSound('tap'); cat.id === 'unfiltered' ? onAgeCheck() : onSelect(cat.id); }}
className="group relative bg-gray-50 rounded-2xl md:rounded-3xl p-3 md:p-10 flex flex-col items-center justify-center cursor-pointer transition-all duration-300 hover:bg-white hover:shadow-xl hover:-translate-y-1 border border-transparent hover:border-gray-100 h-32 md:h-48">
<div className="w-10 h-10 md:w-16 md:h-16 mb-2 md:mb-6 text-gray-300 group-hover:text-black transition-colors duration-300">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="w-full h-full">{cat.icon}</svg>
</div>
<h3 className="font-sans tracking-widest uppercase font-medium text-gray-400 group-hover:text-black transition-colors text-[10px] md:text-sm">{cat.label}</h3>
</div>
))}
</div>
</div>
);
};
const QuestionView = ({ category, onBack }) => {
const [index, setIndex] = useState(0);
const [animating, setAnimating] = useState(false);
const questions = DATA[category];
const next = () => {
if (index < questions.length - 1 && !animating) {
setAnimating(true); playSound('tap');
setTimeout(() => { setIndex(prev => prev + 1); setAnimating(false); }, 300);
}
};
const prev = () => {
if (index > 0 && !animating) {
setAnimating(true); playSound('tap');
setTimeout(() => { setIndex(prev => prev - 1); setAnimating(false); }, 300);
}
};
return (
<div className="flex flex-col bg-white relative overflow-hidden" style={{ height: '100dvh' }}>
<div className="pt-4 px-6 shrink-0 h-16 flex items-center">
<button onClick={() => { playSound('tap'); onBack(); }} className="font-sans text-[10px] md:text-xs tracking-widest uppercase text-gray-400 hover:text-black transition-colors flex items-center gap-2">
<span>←</span> Categories
</button>
</div>
<div className="flex-1 flex items-center justify-center overflow-hidden px-6 md:px-12 min-h-0">
<div className={`w-full text-center transition-all duration-300 ${animating ? 'opacity-0 translate-y-2' : 'opacity-100 translate-y-0'}`}>
<p className="font-serif italic text-gray-300 text-[8px] md:text-xs tracking-[0.2em] uppercase mb-4 md:mb-8">{index + 1} / {questions.length}</p>
<h2 className="font-serif leading-tight tracking-tight text-black px-2" style={{ fontSize: 'clamp(1.2rem, 3.5vw, 2.5rem)' }}>{questions[index]}</h2>
<div className="mt-6 md:mt-10 h-px w-10 md:w-16 bg-gray-100 mx-auto"></div>
</div>
</div>
<div className="shrink-0 px-6 py-6 md:px-20 md:py-10 bg-white pb-[max(1.5rem,env(safe-area-inset-bottom))]">
<div className="flex justify-between items-center max-w-4xl mx-auto">
<button onClick={prev} disabled={index === 0} className="font-sans text-[10px] md:text-xs tracking-widest uppercase text-gray-400 hover:text-black disabled:opacity-20 transition-all px-4 py-2">Previous</button>
<button onClick={next} disabled={index === questions.length - 1} className="px-6 py-3 md:px-10 md:py-3 rounded-full bg-black text-white text-[10px] md:text-xs tracking-widest uppercase hover:scale-105 active:scale-95 transition-all disabled:opacity-50 disabled:scale-100 shadow-md">
{index === questions.length - 1 ? 'Finish' : 'Next'}
</button>
</div>
</div>
</div>
);
};
const Modal = ({ isOpen, onClose, onConfirm }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm animate-fade-rise px-4">
<div className="bg-white/95 backdrop-blur-md p-6 md:p-10 rounded-2xl md:rounded-3xl max-w-sm w-full text-center shadow-2xl border border-white/20">
<h3 className="font-serif text-2xl md:text-3xl mb-3 md:mb-4">Age Verification</h3>
<p className="font-sans text-gray-500 mb-6 md:mb-8 leading-relaxed text-xs md:text-sm">This section contains mature conversation prompts. Are you 18 or older?</p>
<div className="flex gap-3 md:gap-4 justify-center">
<button onClick={() => { playSound('tap'); onClose(); }} className="px-5 py-2 md:px-6 md:py-2 rounded-full border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors uppercase text-[10px] md:text-[11px] tracking-wider">Return</button>
<button onClick={() => { playSound('tap'); onConfirm(); }} className="px-5 py-2 md:px-6 md:py-2 rounded-full bg-black text-white hover:scale-105 active:scale-95 transition-transform uppercase text-[10px] md:text-[11px] tracking-wider shadow-lg">Continue</button>
</div>
</div>
</div>
);
};
const App = () => {
const [view, setView] = useState('hero');
const [selectedCategory, setSelectedCategory] = useState(null);
const [isModalOpen, setModalOpen] = useState(false);
return (
<div className="h-screen bg-white font-sans">
{view === 'hero' && <Hero onBegin={() => { playSound('transition'); setView('categories'); }} />}
{(view === 'categories' || view === 'question') && (
<main className="h-full flex flex-col">
{view === 'categories' && <Categories onSelect={(cat) => { setSelectedCategory(cat); setView('question'); }} onAgeCheck={() => setModalOpen(true)} />}
{view === 'question' && <QuestionView category={selectedCategory} onBack={() => { playSound('transition'); setView('categories'); }} />}
</main>
)}
<Modal isOpen={isModalOpen} onClose={() => setModalOpen(false)} onConfirm={() => { setModalOpen(false); setSelectedCategory('unfiltered'); setView('question'); }} />
</div>
);
};
const root = window.ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>