Tingchenliang commited on
Commit
4f3d2c9
·
verified ·
1 Parent(s): 38e2dd1

Make the UI like the TV show Alien - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +678 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Rthythm Captcha
3
- emoji: 🦀
4
- colorFrom: blue
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: rthythm-captcha
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,678 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Nostromo Rhythm Verification</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
11
+
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ font-family: 'Orbitron', monospace;
17
+ }
18
+
19
+ body {
20
+ background: #0a0a12;
21
+ min-height: 100vh;
22
+ display: flex;
23
+ justify-content: center;
24
+ align-items: center;
25
+ padding: 16px;
26
+ background-image:
27
+ radial-gradient(circle at 20% 30%, rgba(28, 122, 131, 0.1) 0%, transparent 40%),
28
+ radial-gradient(circle at 80% 70%, rgba(28, 122, 131, 0.1) 0%, transparent 40%);
29
+ }
30
+
31
+ .container {
32
+ background: #111725;
33
+ border: 2px solid #1C7A83;
34
+ padding: 25px;
35
+ width: 100%;
36
+ max-width: 500px;
37
+ position: relative;
38
+ overflow: hidden;
39
+ box-shadow: 0 0 30px rgba(28, 122, 131, 0.4);
40
+ }
41
+
42
+ .container::before {
43
+ content: '';
44
+ position: absolute;
45
+ top: 0;
46
+ left: 0;
47
+ right: 0;
48
+ height: 2px;
49
+ background: linear-gradient(90deg, transparent, #1C7A83, transparent);
50
+ animation: scanline 3s linear infinite;
51
+ }
52
+
53
+ .beat-indicator {
54
+ width: 60px;
55
+ height: 60px;
56
+ margin: 0 auto 20px;
57
+ display: flex;
58
+ justify-content: center;
59
+ align-items: center;
60
+ background: #0d1117;
61
+ border: 2px solid #1C7A83;
62
+ border-radius: 2px;
63
+ position: relative;
64
+ overflow: hidden;
65
+ }
66
+
67
+ .beat-indicator::before {
68
+ content: '';
69
+ position: absolute;
70
+ top: 0;
71
+ left: 0;
72
+ right: 0;
73
+ bottom: 0;
74
+ background: rgba(28, 122, 131, 0.1);
75
+ opacity: 0;
76
+ transition: opacity 0.3s ease;
77
+ }
78
+
79
+ .beat-active::before {
80
+ opacity: 1;
81
+ }
82
+
83
+ .beat-text {
84
+ font-size: 18px;
85
+ color: #8BD4E3;
86
+ font-weight: bold;
87
+ text-shadow: 0 0 5px rgba(139, 212, 227, 0.7);
88
+ }
89
+
90
+ .progress-container {
91
+ width: 100%;
92
+ height: 10px;
93
+ background: #0d1117;
94
+ margin: 20px 0;
95
+ overflow: hidden;
96
+ border: 1px solid #1C7A83;
97
+ position: relative;
98
+ }
99
+
100
+ .progress-container::after {
101
+ content: '';
102
+ position: absolute;
103
+ top: 0;
104
+ left: 0;
105
+ right: 0;
106
+ bottom: 0;
107
+ background: linear-gradient(90deg, transparent 0%, rgba(28, 122, 131, 0.2) 50%, transparent 100%);
108
+ animation: shimmer 2s linear infinite;
109
+ }
110
+
111
+ .progress-bar {
112
+ height: 100%;
113
+ width: 0%;
114
+ background: linear-gradient(90deg, #1C7A83, #8BD4E3);
115
+ transition: width 0.3s ease;
116
+ position: relative;
117
+ z-index: 1;
118
+ }
119
+
120
+ .beat-pattern {
121
+ display: flex;
122
+ justify-content: center;
123
+ margin: 25px 0;
124
+ gap: 10px;
125
+ }
126
+
127
+ .beat-dot {
128
+ width: 18px;
129
+ height: 18px;
130
+ background: #0d1117;
131
+ border: 1px solid #1C7A83;
132
+ transition: all 0.2s ease;
133
+ position: relative;
134
+ }
135
+
136
+ .beat-dot::after {
137
+ content: '';
138
+ position: absolute;
139
+ top: 2px;
140
+ left: 2px;
141
+ right: 2px;
142
+ bottom: 2px;
143
+ background: rgba(28, 122, 131, 0.2);
144
+ opacity: 0;
145
+ transition: opacity 0.2s ease;
146
+ }
147
+
148
+ .beat-dot.active::after {
149
+ opacity: 1;
150
+ }
151
+
152
+ .beat-dot.target {
153
+ border: 1px solid #8BD4E3;
154
+ box-shadow: 0 0 5px rgba(139, 212, 227, 0.5);
155
+ }
156
+
157
+ .beat-dot.target::after {
158
+ background: rgba(139, 212, 227, 0.3);
159
+ }
160
+
161
+ .beat-dot.target.active::after {
162
+ background: rgba(139, 212, 227, 0.8);
163
+ box-shadow: 0 0 10px rgba(139, 212, 227, 0.8);
164
+ }
165
+
166
+ .instructions {
167
+ color: #8BD4E3;
168
+ text-align: center;
169
+ margin-bottom: 25px;
170
+ line-height: 1.5;
171
+ font-size: 12px;
172
+ text-shadow: 0 0 3px rgba(139, 212, 227, 0.5);
173
+ }
174
+
175
+ .status-popup {
176
+ position: fixed;
177
+ top: 50%;
178
+ left: 50%;
179
+ transform: translate(-50%, -50%) scale(0);
180
+ background: #0d1117;
181
+ border: 2px solid #1C7A83;
182
+ padding: 25px;
183
+ text-align: center;
184
+ z-index: 1000;
185
+ min-width: 300px;
186
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
187
+ opacity: 0;
188
+ box-shadow: 0 0 30px rgba(28, 122, 131, 0.6);
189
+ }
190
+
191
+ .status-popup::before {
192
+ content: '';
193
+ position: absolute;
194
+ top: 0;
195
+ left: 0;
196
+ right: 0;
197
+ height: 2px;
198
+ background: linear-gradient(90deg, transparent, #8BD4E3, transparent);
199
+ }
200
+
201
+ .status-popup.active {
202
+ transform: translate(-50%, -50%) scale(1);
203
+ opacity: 1;
204
+ }
205
+
206
+ .status-emoji {
207
+ font-size: 36px;
208
+ margin-bottom: 15px;
209
+ display: block;
210
+ }
211
+
212
+ .status-message {
213
+ font-size: 14px;
214
+ margin-bottom: 20px;
215
+ color: #8BD4E3;
216
+ text-shadow: 0 0 3px rgba(139, 212, 227, 0.5);
217
+ }
218
+
219
+ .status-close {
220
+ background: transparent;
221
+ color: #8BD4E3;
222
+ border: 1px solid #1C7A83;
223
+ padding: 8px 20px;
224
+ font-size: 12px;
225
+ cursor: pointer;
226
+ text-transform: uppercase;
227
+ letter-spacing: 1px;
228
+ transition: all 0.3s ease;
229
+ }
230
+
231
+ .status-close:hover {
232
+ background: rgba(28, 122, 131, 0.2);
233
+ box-shadow: 0 0 10px rgba(28, 122, 131, 0.4);
234
+ }
235
+
236
+ .overlay {
237
+ position: fixed;
238
+ top: 0;
239
+ left: 0;
240
+ width: 100%;
241
+ height: 100%;
242
+ background: rgba(5, 8, 15, 0.9);
243
+ z-index: 999;
244
+ opacity: 0;
245
+ visibility: hidden;
246
+ transition: all 0.3s ease;
247
+ }
248
+
249
+ .overlay.active {
250
+ opacity: 1;
251
+ visibility: visible;
252
+ }
253
+
254
+ .btn {
255
+ background: transparent;
256
+ color: #8BD4E3;
257
+ border: 1px solid #1C7A83;
258
+ padding: 12px;
259
+ font-size: 12px;
260
+ cursor: pointer;
261
+ display: block;
262
+ width: 100%;
263
+ margin: 10px 0;
264
+ text-transform: uppercase;
265
+ letter-spacing: 1px;
266
+ transition: all 0.3s ease;
267
+ position: relative;
268
+ overflow: hidden;
269
+ }
270
+
271
+ .btn::before {
272
+ content: '';
273
+ position: absolute;
274
+ top: 0;
275
+ left: -100%;
276
+ width: 100%;
277
+ height: 100%;
278
+ background: linear-gradient(90deg, transparent, rgba(28, 122, 131, 0.2), transparent);
279
+ transition: left 0.5s ease;
280
+ }
281
+
282
+ .btn:hover::before {
283
+ left: 100%;
284
+ }
285
+
286
+ .btn:hover {
287
+ background: rgba(28, 122, 131, 0.1);
288
+ box-shadow: 0 0 10px rgba(28, 122, 131, 0.4);
289
+ }
290
+
291
+ .btn:disabled {
292
+ color: #4a5c6b;
293
+ border-color: #2a3b4a;
294
+ cursor: not-allowed;
295
+ }
296
+
297
+ .btn:disabled:hover::before {
298
+ left: -100%;
299
+ }
300
+
301
+ .restart-btn {
302
+ position: absolute;
303
+ top: 20px;
304
+ right: 20px;
305
+ background: transparent;
306
+ color: #8BD4E3;
307
+ width: 36px;
308
+ height: 36px;
309
+ display: flex;
310
+ justify-content: center;
311
+ align-items: center;
312
+ cursor: pointer;
313
+ border: 1px solid #1C7A83;
314
+ transition: all 0.3s ease;
315
+ }
316
+
317
+ .restart-btn:hover {
318
+ background: rgba(28, 122, 131, 0.1);
319
+ box-shadow: 0 0 10px rgba(28, 122, 131, 0.4);
320
+ }
321
+
322
+ .space-key {
323
+ display: inline-flex;
324
+ align-items: center;
325
+ justify-content: center;
326
+ background: #0d1117;
327
+ padding: 4px 10px;
328
+ font-size: 10px;
329
+ margin: 0 4px;
330
+ border: 1px solid #1C7A83;
331
+ color: #8BD4E3;
332
+ }
333
+
334
+ .countdown {
335
+ font-size: 36px;
336
+ text-align: center;
337
+ margin: 30px 0;
338
+ color: #8BD4E3;
339
+ text-shadow: 0 0 5px rgba(139, 212, 227, 0.7);
340
+ }
341
+
342
+ .swing-animation {
343
+ animation: swing 0.5s ease-in-out infinite;
344
+ }
345
+
346
+ @keyframes swing {
347
+ 0%, 100% { transform: rotate(0deg); }
348
+ 25% { transform: rotate(3deg); }
349
+ 75% { transform: rotate(-3deg); }
350
+ }
351
+
352
+ @keyframes scanline {
353
+ 0% { transform: translateX(-100%); }
354
+ 100% { transform: translateX(100%); }
355
+ }
356
+
357
+ @keyframes shimmer {
358
+ 0% { transform: translateX(-100%); }
359
+ 100% { transform: translateX(100%); }
360
+ }
361
+
362
+ @media (max-width: 640px) {
363
+ .container {
364
+ padding: 20px;
365
+ }
366
+
367
+ .beat-pattern {
368
+ gap: 8px;
369
+ }
370
+
371
+ .beat-dot {
372
+ width: 14px;
373
+ height: 14px;
374
+ }
375
+
376
+ .instructions {
377
+ font-size: 11px;
378
+ }
379
+ }
380
+ </style>
381
+ </head>
382
+ <body>
383
+ <div class="container">
384
+ <button class="restart-btn" id="restartBtn">
385
+ <i class="fas fa-redo"></i>
386
+ </button>
387
+
388
+ <h1 class="text-center mb-3" style="font-size: 20px; color: #8BD4E3; text-shadow: 0 0 5px rgba(139, 212, 227, 0.7); letter-spacing: 1px;">NOSTROMO RHYTHM VERIFICATION</h1>
389
+ <p class="instructions">PRESS <span class="space-key">SPACE</span> ON THE <span style="color: #8BD4E3; text-shadow: 0 0 3px rgba(139, 212, 227, 0.7);">SEVENTH BEAT</span> TO VERIFY HUMAN BIOSIGNATURE</p>
390
+
391
+ <div class="beat-pattern" id="beatPattern">
392
+ <div class="beat-dot" data-beat="1"></div>
393
+ <div class="beat-dot" data-beat="2"></div>
394
+ <div class="beat-dot" data-beat="3"></div>
395
+ <div class="beat-dot" data-beat="4"></div>
396
+ <div class="beat-dot" data-beat="5"></div>
397
+ <div class="beat-dot" data-beat="6"></div>
398
+ <div class="beat-dot target" data-beat="7"></div>
399
+ </div>
400
+
401
+ <div class="beat-indicator" id="beatIndicator">
402
+ <span class="beat-text" id="beatText">-</span>
403
+ </div>
404
+
405
+ <div class="progress-container">
406
+ <div class="progress-bar" id="progressBar"></div>
407
+ </div>
408
+
409
+ <div class="status-text" id="statusText" style="display: none;"></div>
410
+ <div class="overlay" id="overlay"></div>
411
+ <div class="status-popup" id="statusPopup">
412
+ <span class="status-emoji" id="statusEmoji"></span>
413
+ <div class="status-message" id="statusMessage"></div>
414
+ <button class="status-close" id="statusClose">Continue</button>
415
+ </div>
416
+
417
+ <div class="countdown" id="countdown">3</div>
418
+
419
+ <button class="btn" id="startBtn">Initialize Sequence</button>
420
+ <button class="btn" id="verifyBtn" disabled>Verify Biosignature</button>
421
+ </div>
422
+
423
+ <script>
424
+ document.addEventListener('DOMContentLoaded', function() {
425
+ // Elements
426
+ const startBtn = document.getElementById('startBtn');
427
+ const verifyBtn = document.getElementById('verifyBtn');
428
+ const restartBtn = document.getElementById('restartBtn');
429
+ const beatIndicator = document.getElementById('beatIndicator');
430
+ const beatText = document.getElementById('beatText');
431
+ const progressBar = document.getElementById('progressBar');
432
+ const statusText = document.getElementById('statusText');
433
+ const countdownEl = document.getElementById('countdown');
434
+ const beatDots = document.querySelectorAll('.beat-dot');
435
+ const statusPopup = document.getElementById('statusPopup');
436
+ const statusEmoji = document.getElementById('statusEmoji');
437
+ const statusMessage = document.getElementById('statusMessage');
438
+ const statusClose = document.getElementById('statusClose');
439
+ const overlay = document.getElementById('overlay');
440
+
441
+ // Game state
442
+ let gameState = 'idle'; // 'idle', 'countingDown', 'playing', 'finished'
443
+ let currentBeat = 0;
444
+ let totalBeats = 7;
445
+ let tempo = 157; // BPM - Beats per minute
446
+ let beatInterval;
447
+ let countdownInterval;
448
+ let spacePressedOnTarget = false;
449
+
450
+ // Audio context for sound
451
+ let audioContext;
452
+
453
+ // Initialize audio context on user interaction
454
+ function initAudio() {
455
+ if (!audioContext) {
456
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
457
+ }
458
+ }
459
+
460
+ // Play a tone for the beat
461
+ function playTone(frequency, duration, type = 'sine') {
462
+ if (!audioContext) return;
463
+
464
+ const oscillator = audioContext.createOscillator();
465
+ const gainNode = audioContext.createGain();
466
+
467
+ oscillator.type = type;
468
+ oscillator.frequency.value = frequency;
469
+
470
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
471
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
472
+
473
+ oscillator.connect(gainNode);
474
+ gainNode.connect(audioContext.destination);
475
+
476
+ oscillator.start();
477
+ oscillator.stop(audioContext.currentTime + duration);
478
+ }
479
+
480
+ // Start the game
481
+ function startGame() {
482
+ initAudio();
483
+ gameState = 'countingDown';
484
+ startBtn.disabled = true;
485
+ verifyBtn.disabled = true;
486
+ statusText.textContent = '';
487
+ statusText.className = 'status-text';
488
+ countdownEl.style.display = 'block';
489
+
490
+ let count = 3;
491
+ countdownEl.textContent = count;
492
+
493
+ countdownInterval = setInterval(() => {
494
+ count--;
495
+ countdownEl.textContent = count;
496
+
497
+ if (count <= 0) {
498
+ clearInterval(countdownInterval);
499
+ countdownEl.style.display = 'none';
500
+ startBeatGame();
501
+ }
502
+ }, 1000);
503
+ }
504
+
505
+ // Start the beat game
506
+ function startBeatGame() {
507
+ gameState = 'playing';
508
+ currentBeat = 0;
509
+ spacePressedOnTarget = false;
510
+ progressBar.style.width = '0%';
511
+
512
+ // Calculate interval based on BPM (swing rhythm)
513
+ const beatDuration = (60 / tempo) * 1000;
514
+
515
+ beatInterval = setInterval(() => {
516
+ currentBeat++;
517
+
518
+ if (currentBeat > totalBeats) {
519
+ currentBeat = 1;
520
+ }
521
+
522
+ // Update UI
523
+ updateBeatIndicator();
524
+
525
+ // Play sound - different sound for the target beat
526
+ if (currentBeat === 7) {
527
+ playTone(440, 0.1, 'square');
528
+ } else if (currentBeat % 2 === 1) {
529
+ playTone(330, 0.1); // Odd beats
530
+ } else {
531
+ playTone(220, 0.08); // Even beats (softer)
532
+ }
533
+
534
+ // Update progress
535
+ progressBar.style.width = `${(currentBeat / totalBeats) * 100}%`;
536
+
537
+ }, beatDuration);
538
+ }
539
+
540
+ // Update the beat indicator
541
+ function updateBeatIndicator() {
542
+ // Reset all dots
543
+ beatDots.forEach(dot => {
544
+ dot.classList.remove('active');
545
+ });
546
+
547
+ // Activate current beat dot
548
+ const currentDot = document.querySelector(`.beat-dot[data-beat="${currentBeat}"]`);
549
+ if (currentDot) {
550
+ currentDot.classList.add('active');
551
+ }
552
+
553
+ // Update indicator text
554
+ beatText.textContent = currentBeat;
555
+
556
+ // Add animation to indicator
557
+ beatIndicator.classList.add('beat-active');
558
+ setTimeout(() => {
559
+ beatIndicator.classList.remove('beat-active');
560
+ }, 200);
561
+ }
562
+
563
+ // Check if user pressed space on the target beat
564
+ function checkBeat() {
565
+ if (gameState !== 'playing') return;
566
+
567
+ if (currentBeat === 7) {
568
+ spacePressedOnTarget = true;
569
+ showStatusPopup('🎯', 'Perfect timing! Space pressed at the right moment!', 'success');
570
+
571
+ // Enable verify button
572
+ verifyBtn.disabled = false;
573
+ } else {
574
+ showStatusPopup('⏱️', 'Too early! Wait for the green beat.', 'error');
575
+ }
576
+ }
577
+
578
+ // Show status popup
579
+ function showStatusPopup(emoji, message, type) {
580
+ statusEmoji.textContent = emoji;
581
+ statusMessage.textContent = message;
582
+ statusMessage.className = 'status-message';
583
+ if (type === 'success') {
584
+ statusMessage.classList.add('success');
585
+ } else if (type === 'error') {
586
+ statusMessage.classList.add('error');
587
+ }
588
+
589
+ overlay.classList.add('active');
590
+ setTimeout(() => {
591
+ statusPopup.classList.add('active');
592
+ }, 10);
593
+ }
594
+
595
+ // Hide status popup
596
+ function hideStatusPopup() {
597
+ statusPopup.classList.remove('active');
598
+ setTimeout(() => {
599
+ overlay.classList.remove('active');
600
+ }, 300);
601
+ }
602
+
603
+ // Verify if user is human
604
+ function verifyHuman() {
605
+ if (spacePressedOnTarget) {
606
+ showStatusPopup('✅', 'Verification successful! You are human.', 'success');
607
+
608
+ // Stop the game
609
+ clearInterval(beatInterval);
610
+ gameState = 'finished';
611
+
612
+ // Add celebration effect
613
+ beatIndicator.classList.add('swing-animation');
614
+ setTimeout(() => {
615
+ beatIndicator.classList.remove('swing-animation');
616
+ }, 2000);
617
+ } else {
618
+ showStatusPopup('❌', 'Verification failed. Try again.', 'error');
619
+ }
620
+ }
621
+
622
+ // Restart the game
623
+ function restartGame() {
624
+ // Clear any intervals
625
+ clearInterval(beatInterval);
626
+ clearInterval(countdownInterval);
627
+
628
+ // Reset state
629
+ gameState = 'idle';
630
+ currentBeat = 0;
631
+ spacePressedOnTarget = false;
632
+
633
+ // Reset UI
634
+ beatText.textContent = '-';
635
+ progressBar.style.width = '0%';
636
+ statusText.textContent = '';
637
+ statusText.className = 'status-text';
638
+ countdownEl.style.display = 'none';
639
+
640
+ // Enable start button
641
+ startBtn.disabled = false;
642
+ verifyBtn.disabled = true;
643
+
644
+ // Reset beat dots
645
+ beatDots.forEach(dot => {
646
+ dot.classList.remove('active');
647
+ });
648
+
649
+ // Remove animations
650
+ beatIndicator.classList.remove('beat-active', 'swing-animation');
651
+ }
652
+
653
+ // Event listeners
654
+ startBtn.addEventListener('click', startGame);
655
+ verifyBtn.addEventListener('click', verifyHuman);
656
+ restartBtn.addEventListener('click', restartGame);
657
+ statusClose.addEventListener('click', hideStatusPopup);
658
+ overlay.addEventListener('click', hideStatusPopup);
659
+
660
+ // Space bar press detection
661
+ document.addEventListener('keydown', (e) => {
662
+ if (e.code === 'Space' && gameState === 'playing') {
663
+ e.preventDefault(); // Prevent scrolling
664
+ checkBeat();
665
+ }
666
+ });
667
+
668
+ // Add success/error classes to CSS for the popup messages
669
+ const style = document.createElement('style');
670
+ style.textContent = `
671
+ .status-message.success { color: #41a6f6; }
672
+ .status-message.error { color: #ff3864; }
673
+ `;
674
+ document.head.appendChild(style);
675
+ });
676
+ </script>
677
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Tingchenliang/rthythm-captcha" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
678
+ </html>