Tim13ekd commited on
Commit
b94d41c
·
verified ·
1 Parent(s): 145f0d6

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +573 -19
index.html CHANGED
@@ -1,19 +1,573 @@
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>Nochmal - Reaction Trainer</title>
7
+ <style>
8
+ /* CSS Variables for consistent theming */
9
+ :root {
10
+ --bg-color: #0f172a;
11
+ --surface-color: #1e293b;
12
+ --primary-color: #3b82f6;
13
+ --accent-color: #8b5cf6;
14
+ --success-color: #10b981;
15
+ --error-color: #ef4444;
16
+ --text-main: #f8fafc;
17
+ --text-muted: #94a3b8;
18
+ --font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
19
+ --card-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3);
20
+ --transition-speed: 0.3s;
21
+ }
22
+
23
+ * {
24
+ box-sizing: border-box;
25
+ margin: 0;
26
+ padding: 0;
27
+ }
28
+
29
+ body {
30
+ font-family: var(--font-family);
31
+ background-color: var(--bg-color);
32
+ background-image: radial-gradient(circle at 10% 20%, #1e293b 0%, #0f172a 90%);
33
+ color: var(--text-main);
34
+ min-height: 100vh;
35
+ display: flex;
36
+ flex-direction: column;
37
+ overflow-x: hidden;
38
+ }
39
+
40
+ /* Header Styling */
41
+ header {
42
+ display: flex;
43
+ justify-content: space-between;
44
+ align-items: center;
45
+ padding: 1.5rem 2rem;
46
+ background: rgba(15, 23, 42, 0.8);
47
+ backdrop-filter: blur(10px);
48
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
49
+ position: sticky;
50
+ top: 0;
51
+ z-index: 100;
52
+ }
53
+
54
+ .logo {
55
+ font-size: 1.5rem;
56
+ font-weight: 800;
57
+ background: linear-gradient(to right, var(--primary-color), var(--accent-color));
58
+ -webkit-background-clip: text;
59
+ -webkit-text-fill-color: transparent;
60
+ letter-spacing: -0.05em;
61
+ }
62
+
63
+ .anycoder-link {
64
+ font-size: 0.85rem;
65
+ color: var(--text-muted);
66
+ text-decoration: none;
67
+ padding: 0.5rem 1rem;
68
+ border: 1px solid rgba(255, 255, 255, 0.1);
69
+ border-radius: 20px;
70
+ transition: all var(--transition-speed);
71
+ }
72
+
73
+ .anycoder-link:hover {
74
+ color: var(--text-main);
75
+ border-color: var(--primary-color);
76
+ background: rgba(59, 130, 246, 0.1);
77
+ }
78
+
79
+ /* Main Layout */
80
+ main {
81
+ flex: 1;
82
+ display: flex;
83
+ flex-direction: column;
84
+ align-items: center;
85
+ justify-content: center;
86
+ padding: 2rem;
87
+ gap: 2rem;
88
+ max-width: 1200px;
89
+ margin: 0 auto;
90
+ width: 100%;
91
+ }
92
+
93
+ /* Interactive Game Area */
94
+ .game-container {
95
+ width: 100%;
96
+ max-width: 600px;
97
+ aspect-ratio: 16/9;
98
+ background: var(--surface-color);
99
+ border-radius: 24px;
100
+ box-shadow: var(--card-shadow);
101
+ position: relative;
102
+ overflow: hidden;
103
+ cursor: pointer;
104
+ user-select: none;
105
+ display: flex;
106
+ flex-direction: column;
107
+ align-items: center;
108
+ justify-content: center;
109
+ text-align: center;
110
+ transition: transform 0.1s ease;
111
+ border: 1px solid rgba(255, 255, 255, 0.05);
112
+ }
113
+
114
+ .game-container:active {
115
+ transform: scale(0.98);
116
+ }
117
+
118
+ /* Dynamic background states for the game container */
119
+ .game-container.state-idle {
120
+ border: 2px solid var(--primary-color);
121
+ }
122
+
123
+ .game-container.state-waiting {
124
+ background: var(--error-color);
125
+ border: none;
126
+ }
127
+
128
+ .game-container.state-go {
129
+ background: var(--success-color);
130
+ border: none;
131
+ }
132
+
133
+ .game-container.state-result {
134
+ border: 2px solid var(--accent-color);
135
+ }
136
+
137
+ .icon-large {
138
+ font-size: 4rem;
139
+ margin-bottom: 1rem;
140
+ opacity: 0.8;
141
+ }
142
+
143
+ .message-title {
144
+ font-size: 2rem;
145
+ font-weight: 700;
146
+ margin-bottom: 0.5rem;
147
+ }
148
+
149
+ .message-subtitle {
150
+ font-size: 1rem;
151
+ color: rgba(255, 255, 255, 0.8);
152
+ }
153
+
154
+ /* Stats Dashboard */
155
+ .stats-grid {
156
+ display: grid;
157
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
158
+ gap: 1.5rem;
159
+ width: 100%;
160
+ max-width: 800px;
161
+ }
162
+
163
+ .stat-card {
164
+ background: rgba(30, 41, 59, 0.5);
165
+ backdrop-filter: blur(5px);
166
+ padding: 1.5rem;
167
+ border-radius: 16px;
168
+ border: 1px solid rgba(255, 255, 255, 0.05);
169
+ text-align: center;
170
+ transition: transform var(--transition-speed);
171
+ }
172
+
173
+ .stat-card:hover {
174
+ transform: translateY(-5px);
175
+ background: rgba(30, 41, 59, 0.8);
176
+ }
177
+
178
+ .stat-value {
179
+ font-size: 2rem;
180
+ font-weight: 700;
181
+ color: var(--primary-color);
182
+ display: block;
183
+ margin-bottom: 0.25rem;
184
+ }
185
+
186
+ .stat-label {
187
+ font-size: 0.875rem;
188
+ color: var(--text-muted);
189
+ text-transform: uppercase;
190
+ letter-spacing: 0.05em;
191
+ }
192
+
193
+ /* Controls */
194
+ .controls {
195
+ display: flex;
196
+ gap: 1rem;
197
+ margin-top: 1rem;
198
+ }
199
+
200
+ .btn {
201
+ padding: 1rem 2.5rem;
202
+ font-size: 1.1rem;
203
+ font-weight: 600;
204
+ border: none;
205
+ border-radius: 12px;
206
+ cursor: pointer;
207
+ transition: all var(--transition-speed);
208
+ text-transform: uppercase;
209
+ letter-spacing: 0.05em;
210
+ }
211
+
212
+ .btn-primary {
213
+ background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
214
+ color: white;
215
+ box-shadow: 0 4px 15px rgba(59, 130, 246, 0.4);
216
+ }
217
+
218
+ .btn-primary:hover {
219
+ box-shadow: 0 6px 20px rgba(59, 130, 246, 0.6);
220
+ transform: translateY(-2px);
221
+ }
222
+
223
+ .btn-primary:active {
224
+ transform: translateY(0);
225
+ }
226
+
227
+ .btn-secondary {
228
+ background: transparent;
229
+ border: 2px solid var(--text-muted);
230
+ color: var(--text-muted);
231
+ }
232
+
233
+ .btn-secondary:hover {
234
+ border-color: var(--text-main);
235
+ color: var(--text-main);
236
+ }
237
+
238
+ /* History List */
239
+ .history-container {
240
+ width: 100%;
241
+ max-width: 600px;
242
+ background: rgba(15, 23, 42, 0.5);
243
+ border-radius: 16px;
244
+ padding: 1.5rem;
245
+ border: 1px solid rgba(255, 255, 255, 0.05);
246
+ }
247
+
248
+ .history-header {
249
+ display: flex;
250
+ justify-content: space-between;
251
+ align-items: center;
252
+ margin-bottom: 1rem;
253
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
254
+ padding-bottom: 0.5rem;
255
+ }
256
+
257
+ .history-list {
258
+ list-style: none;
259
+ max-height: 150px;
260
+ overflow-y: auto;
261
+ }
262
+
263
+ .history-item {
264
+ display: flex;
265
+ justify-content: space-between;
266
+ padding: 0.5rem 0;
267
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
268
+ font-size: 0.9rem;
269
+ }
270
+
271
+ .history-item:last-child {
272
+ border-bottom: none;
273
+ }
274
+
275
+ .history-time {
276
+ font-weight: 600;
277
+ }
278
+
279
+ .history-rank {
280
+ color: var(--text-muted);
281
+ }
282
+
283
+ /* Footer */
284
+ footer {
285
+ text-align: center;
286
+ padding: 2rem;
287
+ color: var(--text-muted);
288
+ font-size: 0.9rem;
289
+ }
290
+
291
+ /* Utilities */
292
+ .hidden {
293
+ display: none !important;
294
+ }
295
+
296
+ .fade-in {
297
+ animation: fadeIn 0.3s ease-in;
298
+ }
299
+
300
+ @keyframes fadeIn {
301
+ from { opacity: 0; transform: translateY(10px); }
302
+ to { opacity: 1; transform: translateY(0); }
303
+ }
304
+
305
+ /* Mobile Adjustments */
306
+ @media (max-width: 600px) {
307
+ .game-container {
308
+ aspect-ratio: 1/1;
309
+ }
310
+ .message-title {
311
+ font-size: 1.5rem;
312
+ }
313
+ .stats-grid {
314
+ grid-template-columns: 1fr 1fr;
315
+ }
316
+ header {
317
+ padding: 1rem;
318
+ }
319
+ }
320
+ </style>
321
+ </head>
322
+ <body>
323
+
324
+ <header>
325
+ <div class="logo">NOCHMAL</div>
326
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
327
+ Built with anycoder
328
+ </a>
329
+ </header>
330
+
331
+ <main>
332
+ <!-- The Interactive Game Stage -->
333
+ <section id="game-stage" class="game-container state-idle" role="button" tabindex="0" aria-label="Game Area">
334
+ <div id="stage-content" class="fade-in">
335
+ <div class="icon-large">⚡</div>
336
+ <div class="message-title">Reaction Test</div>
337
+ <div class="message-subtitle">Click anywhere to start</div>
338
+ </div>
339
+ </section>
340
+
341
+ <!-- Main Action Button -->
342
+ <div class="controls">
343
+ <button id="reset-btn" class="btn btn-primary hidden">Nochmal</button>
344
+ </div>
345
+
346
+ <!-- Statistics Grid -->
347
+ <section class="stats-grid">
348
+ <div class="stat-card">
349
+ <span id="last-score" class="stat-value">--</span>
350
+ <span class="stat-label">Last Time (ms)</span>
351
+ </div>
352
+ <div class="stat-card">
353
+ <span id="best-score" class="stat-value">--</span>
354
+ <span class="stat-label">Best Time (ms)</span>
355
+ </div>
356
+ <div class="stat-card">
357
+ <span id="avg-score" class="stat-value">--</span>
358
+ <span class="stat-label">Average (ms)</span>
359
+ </div>
360
+ </section>
361
+
362
+ <!-- History Section -->
363
+ <section class="history-container">
364
+ <div class="history-header">
365
+ <h3>Recent Attempts</h3>
366
+ <button id="clear-history" class="btn-secondary" style="padding: 0.25rem 0.75rem; font-size: 0.8rem; border-radius: 6px;">Clear</button>
367
+ </div>
368
+ <ul id="history-list" class="history-list">
369
+ <li class="history-item" style="justify-content: center; color: var(--text-muted);">No attempts yet</li>
370
+ </ul>
371
+ </section>
372
+ </main>
373
+
374
+ <footer>
375
+ <p>Train your brain. Improve your focus. Try NOCHMAL.</p>
376
+ </footer>
377
+
378
+ <script>
379
+ /**
380
+ * NOCHMAL - Reaction Time Trainer Logic
381
+ * Handles game states: idle, waiting, ready (go), result
382
+ */
383
+
384
+ // --- DOM Elements ---
385
+ const gameStage = document.getElementById('game-stage');
386
+ const stageContent = document.getElementById('stage-content');
387
+ const resetBtn = document.getElementById('reset-btn');
388
+ const lastScoreEl = document.getElementById('last-score');
389
+ const bestScoreEl = document.getElementById('best-score');
390
+ const avgScoreEl = document.getElementById('avg-score');
391
+ const historyList = document.getElementById('history-list');
392
+ const clearHistoryBtn = document.getElementById('clear-history');
393
+
394
+ // --- State Variables ---
395
+ let gameState = 'idle'; // idle, waiting, ready, result
396
+ let startTime = 0;
397
+ let timeoutId = null;
398
+ let scores = [];
399
+ let bestScore = Infinity;
400
+
401
+ // --- Event Listeners ---
402
+
403
+ // Main interaction area click
404
+ gameStage.addEventListener('mousedown', handleInteraction);
405
+ // Touch support for mobile
406
+ gameStage.addEventListener('touchstart', (e) => {
407
+ e.preventDefault(); // Prevent double firing on some devices
408
+ handleInteraction();
409
+ });
410
+
411
+ // Keyboard support (Space/Enter)
412
+ gameStage.addEventListener('keydown', (e) => {
413
+ if (e.key === 'Enter' || e.key === ' ') {
414
+ e.preventDefault();
415
+ handleInteraction();
416
+ }
417
+ });
418
+
419
+ // Reset button click
420
+ resetBtn.addEventListener('click', (e) => {
421
+ e.stopPropagation(); // Prevent bubbling to gameStage
422
+ resetGame();
423
+ });
424
+
425
+ // Clear history
426
+ clearHistoryBtn.addEventListener('click', () => {
427
+ scores = [];
428
+ bestScore = Infinity;
429
+ updateStatsUI();
430
+ renderHistory();
431
+ });
432
+
433
+ // --- Core Functions ---
434
+
435
+ function handleInteraction() {
436
+ switch (gameState) {
437
+ case 'idle':
438
+ case 'result':
439
+ prepareGame();
440
+ break;
441
+ case 'waiting':
442
+ triggerTooEarly();
443
+ break;
444
+ case 'ready':
445
+ triggerSuccess();
446
+ break;
447
+ }
448
+ }
449
+
450
+ function prepareGame() {
451
+ gameState = 'waiting';
452
+ setStageVisuals('waiting', '⏳', 'Wait for Green...', 'Do not click yet.');
453
+ resetBtn.classList.add('hidden');
454
+
455
+ // Random delay between 2 and 5 seconds
456
+ const delay = Math.floor(Math.random() * 3000) + 2000;
457
+
458
+ timeoutId = setTimeout(() => {
459
+ triggerGo();
460
+ }, delay);
461
+ }
462
+
463
+ function triggerGo() {
464
+ gameState = 'ready';
465
+ startTime = performance.now();
466
+ setStageVisuals('go', '⚡', 'CLICK NOW!', 'Fast!');
467
+ }
468
+
469
+ function triggerTooEarly() {
470
+ clearTimeout(timeoutId);
471
+ gameState = 'result';
472
+ setStageVisuals('result', '⚠️', 'Too Early!', 'Click to try NOCHMAL.');
473
+ resetBtn.classList.remove('hidden');
474
+ }
475
+
476
+ function triggerSuccess() {
477
+ const endTime = performance.now();
478
+ const reactionTime = Math.round(endTime - startTime);
479
+ gameState = 'result';
480
+
481
+ // Update Logic
482
+ scores.push(reactionTime);
483
+ if (reactionTime < bestScore) bestScore = reactionTime;
484
+
485
+ // Update UI
486
+ updateStatsUI();
487
+ renderHistory();
488
+
489
+ let message = reactionTime < 250 ? 'Godlike!' :
490
+ reactionTime < 350 ? 'Great Job!' :
491
+ reactionTime < 500 ? 'Good.' : 'Keep practicing.';
492
+
493
+ setStageVisuals('result', '⏱️', `${reactionTime} ms`, message);
494
+ resetBtn.classList.remove('hidden');
495
+ }
496
+
497
+ function resetGame() {
498
+ gameState = 'idle';
499
+ setStageVisuals('idle', '⚡', 'Reaction Test', 'Click anywhere to start');
500
+ resetBtn.classList.add('hidden');
501
+ }
502
+
503
+ // --- UI Helper Functions ---
504
+
505
+ function setStageVisuals(stateClass, icon, title, subtitle) {
506
+ // Remove all state classes
507
+ gameStage.classList.remove('state-idle', 'state-waiting', 'state-go', 'state-result');
508
+ // Add current state class
509
+ gameStage.classList.add(`state-${stateClass}`);
510
+
511
+ // Update content with a small fade animation
512
+ stageContent.classList.remove('fade-in');
513
+ void stageContent.offsetWidth; // Trigger reflow
514
+ stageContent.classList.add('fade-in');
515
+
516
+ stageContent.innerHTML = `
517
+ <div class="icon-large">${icon}</div>
518
+ <div class="message-title">${title}</div>
519
+ <div class="message-subtitle">${subtitle}</div>
520
+ `;
521
+ }
522
+
523
+ function updateStatsUI() {
524
+ if (scores.length === 0) {
525
+ lastScoreEl.textContent = '--';
526
+ bestScoreEl.textContent = '--';
527
+ avgScoreEl.textContent = '--';
528
+ return;
529
+ }
530
+
531
+ const last = scores[scores.length - 1];
532
+ const sum = scores.reduce((a, b) => a + b, 0);
533
+ const avg = Math.round(sum / scores.length);
534
+
535
+ lastScoreEl.textContent = last;
536
+ bestScoreEl.textContent = bestScore;
537
+ avgScoreEl.textContent = avg;
538
+
539
+ // Color code the last score
540
+ lastScoreEl.style.color = last < 300 ? 'var(--success-color)' :
541
+ last < 500 ? 'var(--primary-color)' : 'var(--text-main)';
542
+ }
543
+
544
+ function renderHistory() {
545
+ if (scores.length === 0) {
546
+ historyList.innerHTML = '<li class="history-item" style="justify-content: center; color: var(--text-muted);">No attempts yet</li>';
547
+ return;
548
+ }
549
+
550
+ // Show last 5 attempts reversed
551
+ const recentScores = scores.slice(-5).reverse();
552
+
553
+ historyList.innerHTML = recentScores.map((score, index) => {
554
+ // Determine rank styling
555
+ let rankColor = 'var(--text-muted)';
556
+ if (score < 250) rankColor = 'var(--success-color)';
557
+ else if (score < 350) rankColor = 'var(--primary-color)';
558
+
559
+ return `
560
+ <li class="history-item fade-in">
561
+ <span class="history-rank">Attempt #${scores.length - index}</span>
562
+ <span class="history-time" style="color: ${rankColor}">${score} ms</span>
563
+ </li>
564
+ `;
565
+ }).join('');
566
+ }
567
+
568
+ // Initialize UI
569
+ resetGame();
570
+
571
+ </script>
572
+ </body>
573
+ </html>