eloigil6 Claude Opus 4.8 commited on
Commit
2ee332e
·
1 Parent(s): 40c5c0c

Gate the intro camera descent behind a 'click to start' button

Browse files

The descent auto-fired HOLD_MS after load; now the camera holds on the sky until the user clicks a 'click to start' button on the title overlay (a glass pill matching the subtitle, revealed once assets + fonts are ready). The same click is the user gesture that also starts the lobby music. Drops the now-unused HOLD_MS and the auto-descent timer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files changed (3) hide show
  1. frontend/index.html +1 -0
  2. frontend/main.js +6 -2
  3. frontend/style.css +50 -0
frontend/index.html CHANGED
@@ -70,6 +70,7 @@
70
  <div class="subtitle-wrap">
71
  <p id="subtitle">♪ chill beats, freshly vended</p>
72
  </div>
 
73
  </div>
74
  <div id="vending-label" class="hover-label"><span>♪ vend a vibe</span></div>
75
  <div id="collection-label" class="hover-label">
 
70
  <div class="subtitle-wrap">
71
  <p id="subtitle">♪ chill beats, freshly vended</p>
72
  </div>
73
+ <button id="start-btn" type="button">▶ click to start</button>
74
  </div>
75
  <div id="vending-label" class="hover-label"><span>♪ vend a vibe</span></div>
76
  <div id="collection-label" class="hover-label">
frontend/main.js CHANGED
@@ -539,7 +539,6 @@ import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js")
539
  // Intro: hold on the sky, then ease the gaze down to the scene
540
  // ---------------------------------------------------------------------------
541
 
542
- const HOLD_MS = 3000; // sky time after everything (fonts included) has loaded
543
  const DESCENT_MS = 4600;
544
 
545
  const intro = { phase: "loading", t0: 0, idleStart: 0 };
@@ -558,9 +557,14 @@ const pageLoaded = new Promise((resolve) =>
558
  ? resolve()
559
  : window.addEventListener("load", resolve),
560
  );
 
 
 
 
561
  Promise.all([pageLoaded, document.fonts.ready]).then(() =>
562
- setTimeout(startDescent, HOLD_MS),
563
  );
 
564
 
565
  const easeInOutCubic = (t) =>
566
  t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
 
539
  // Intro: hold on the sky, then ease the gaze down to the scene
540
  // ---------------------------------------------------------------------------
541
 
 
542
  const DESCENT_MS = 4600;
543
 
544
  const intro = { phase: "loading", t0: 0, idleStart: 0 };
 
557
  ? resolve()
558
  : window.addEventListener("load", resolve),
559
  );
560
+ // Click-to-start: the camera holds on the sky until the user clicks. The button
561
+ // is revealed (and made clickable) once assets + fonts are ready; the same click
562
+ // also kicks off the lobby music (audio autoplay needs a user gesture).
563
+ const startBtn = document.getElementById("start-btn");
564
  Promise.all([pageLoaded, document.fonts.ready]).then(() =>
565
+ startBtn.classList.add("ready"),
566
  );
567
+ startBtn.addEventListener("click", startDescent);
568
 
569
  const easeInOutCubic = (t) =>
570
  t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
frontend/style.css CHANGED
@@ -109,6 +109,56 @@ body {
109
  }
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  @keyframes title-bob {
113
  from {
114
  transform: translateY(0);
 
109
  }
110
  }
111
 
112
+ #start-btn {
113
+ margin-top: 2.4rem;
114
+ pointer-events: none; /* the overlay ignores pointers; we opt in once ready */
115
+ cursor: pointer;
116
+ font-family: "Baloo 2", sans-serif;
117
+ font-weight: 700;
118
+ font-size: clamp(0.95rem, 2.2vw, 1.25rem);
119
+ letter-spacing: 0.12em;
120
+ text-transform: lowercase;
121
+ color: #ffffff;
122
+ padding: 0.7em 1.9em;
123
+ border-radius: 999px;
124
+ background: rgba(255, 255, 255, 0.16);
125
+ border: 1px solid rgba(255, 255, 255, 0.4);
126
+ backdrop-filter: blur(6px);
127
+ -webkit-backdrop-filter: blur(6px);
128
+ /* fades in via opacity only (a transform here would kill the backdrop blur,
129
+ per the subtitle note above); the glow uses box-shadow, also transform-free */
130
+ opacity: 0;
131
+ transition:
132
+ opacity 0.8s ease,
133
+ background 0.2s ease,
134
+ border-color 0.2s ease;
135
+ }
136
+
137
+ #start-btn.ready {
138
+ opacity: 1;
139
+ pointer-events: auto;
140
+ animation: start-glow 2.6s ease-in-out 0.6s infinite;
141
+ }
142
+
143
+ #start-btn:hover {
144
+ background: rgba(255, 255, 255, 0.3);
145
+ border-color: rgba(255, 255, 255, 0.7);
146
+ }
147
+
148
+ #start-btn:active {
149
+ background: rgba(255, 255, 255, 0.4);
150
+ }
151
+
152
+ @keyframes start-glow {
153
+ 0%,
154
+ 100% {
155
+ box-shadow: 0 0 0 0 rgba(173, 211, 255, 0);
156
+ }
157
+ 50% {
158
+ box-shadow: 0 0 22px 2px rgba(173, 211, 255, 0.5);
159
+ }
160
+ }
161
+
162
  @keyframes title-bob {
163
  from {
164
  transform: translateY(0);