engerl commited on
Commit
feb3e3e
·
verified ·
1 Parent(s): 823432e

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +677 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Neonsanke
3
- emoji: 🌖
4
- colorFrom: gray
5
- colorTo: gray
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: neonsanke
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: yellow
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,677 @@
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>Neon Snake - Ultimate Snake Game</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=Press+Start+2P&family=Orbitron:wght@400;700&display=swap');
11
+
12
+ :root {
13
+ --neon-green: #39ff14;
14
+ --neon-pink: #ff2ced;
15
+ --neon-blue: #00e5ff;
16
+ --neon-purple: #9d00ff;
17
+ --dark-bg: #0f0f1a;
18
+ }
19
+
20
+ body {
21
+ font-family: 'Orbitron', sans-serif;
22
+ background-color: var(--dark-bg);
23
+ color: white;
24
+ overflow: hidden;
25
+ height: 100vh;
26
+ display: flex;
27
+ flex-direction: column;
28
+ align-items: center;
29
+ justify-content: center;
30
+ }
31
+
32
+ .game-container {
33
+ position: relative;
34
+ width: 90vmin;
35
+ height: 90vmin;
36
+ max-width: 600px;
37
+ max-height: 600px;
38
+ border: 4px solid var(--neon-purple);
39
+ border-radius: 8px;
40
+ box-shadow: 0 0 20px var(--neon-purple),
41
+ inset 0 0 20px var(--neon-purple);
42
+ overflow: hidden;
43
+ }
44
+
45
+ #game-canvas {
46
+ width: 100%;
47
+ height: 100%;
48
+ background-color: rgba(15, 15, 26, 0.8);
49
+ }
50
+
51
+ .snake-segment {
52
+ position: absolute;
53
+ width: 20px;
54
+ height: 20px;
55
+ background-color: var(--neon-green);
56
+ border-radius: 4px;
57
+ box-shadow: 0 0 10px var(--neon-green);
58
+ transition: transform 0.1s ease-out;
59
+ }
60
+
61
+ .snake-head {
62
+ background-color: var(--neon-blue);
63
+ box-shadow: 0 0 15px var(--neon-blue);
64
+ z-index: 10;
65
+ }
66
+
67
+ .food {
68
+ position: absolute;
69
+ width: 20px;
70
+ height: 20px;
71
+ background-color: var(--neon-pink);
72
+ border-radius: 50%;
73
+ box-shadow: 0 0 15px var(--neon-pink);
74
+ animation: pulse 1.5s infinite alternate;
75
+ }
76
+
77
+ @keyframes pulse {
78
+ 0% { transform: scale(1); opacity: 1; }
79
+ 100% { transform: scale(1.2); opacity: 0.8; }
80
+ }
81
+
82
+ .score-display {
83
+ font-family: 'Press Start 2P', cursive;
84
+ font-size: 1.5rem;
85
+ color: var(--neon-green);
86
+ text-shadow: 0 0 10px var(--neon-green);
87
+ margin-bottom: 1rem;
88
+ }
89
+
90
+ .controls {
91
+ display: flex;
92
+ gap: 1rem;
93
+ margin-top: 1rem;
94
+ }
95
+
96
+ .btn {
97
+ background: transparent;
98
+ color: white;
99
+ border: 2px solid var(--neon-blue);
100
+ padding: 0.5rem 1rem;
101
+ border-radius: 4px;
102
+ font-family: 'Orbitron', sans-serif;
103
+ cursor: pointer;
104
+ transition: all 0.3s;
105
+ box-shadow: 0 0 10px var(--neon-blue);
106
+ }
107
+
108
+ .btn:hover {
109
+ background: var(--neon-blue);
110
+ color: black;
111
+ transform: translateY(-2px);
112
+ box-shadow: 0 0 20px var(--neon-blue);
113
+ }
114
+
115
+ .modal {
116
+ position: fixed;
117
+ top: 0;
118
+ left: 0;
119
+ width: 100%;
120
+ height: 100%;
121
+ background-color: rgba(0, 0, 0, 0.8);
122
+ display: flex;
123
+ justify-content: center;
124
+ align-items: center;
125
+ z-index: 100;
126
+ opacity: 0;
127
+ pointer-events: none;
128
+ transition: opacity 0.3s;
129
+ }
130
+
131
+ .modal.active {
132
+ opacity: 1;
133
+ pointer-events: all;
134
+ }
135
+
136
+ .modal-content {
137
+ background-color: var(--dark-bg);
138
+ border: 3px solid var(--neon-purple);
139
+ border-radius: 8px;
140
+ padding: 2rem;
141
+ max-width: 500px;
142
+ width: 90%;
143
+ text-align: center;
144
+ box-shadow: 0 0 30px var(--neon-purple);
145
+ transform: scale(0.9);
146
+ transition: transform 0.3s;
147
+ }
148
+
149
+ .modal.active .modal-content {
150
+ transform: scale(1);
151
+ }
152
+
153
+ .modal-title {
154
+ color: var(--neon-green);
155
+ font-size: 2rem;
156
+ margin-bottom: 1rem;
157
+ text-shadow: 0 0 10px var(--neon-green);
158
+ }
159
+
160
+ .game-over {
161
+ color: var(--neon-pink);
162
+ font-size: 3rem;
163
+ margin-bottom: 1rem;
164
+ text-shadow: 0 0 15px var(--neon-pink);
165
+ animation: blink 0.5s infinite alternate;
166
+ }
167
+
168
+ @keyframes blink {
169
+ 0% { opacity: 1; }
170
+ 100% { opacity: 0.5; }
171
+ }
172
+
173
+ .grid-lines {
174
+ position: absolute;
175
+ top: 0;
176
+ left: 0;
177
+ width: 100%;
178
+ height: 100%;
179
+ background-image:
180
+ linear-gradient(rgba(57, 255, 20, 0.05) 1px, transparent 1px),
181
+ linear-gradient(90deg, rgba(57, 255, 20, 0.05) 1px, transparent 1px);
182
+ background-size: 20px 20px;
183
+ pointer-events: none;
184
+ }
185
+
186
+ .particle {
187
+ position: absolute;
188
+ width: 4px;
189
+ height: 4px;
190
+ background-color: var(--neon-blue);
191
+ border-radius: 50%;
192
+ pointer-events: none;
193
+ opacity: 0;
194
+ }
195
+
196
+ @media (max-width: 768px) {
197
+ .controls {
198
+ flex-direction: column;
199
+ gap: 0.5rem;
200
+ }
201
+
202
+ .score-display {
203
+ font-size: 1rem;
204
+ }
205
+ }
206
+ </style>
207
+ </head>
208
+ <body>
209
+ <div class="grid-lines"></div>
210
+
211
+ <h1 class="text-4xl mb-4 font-bold text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-blue-500">
212
+ NEON SNAKE
213
+ </h1>
214
+
215
+ <div class="score-display">
216
+ SCORE: <span id="score">0</span> | HIGH: <span id="high-score">0</span>
217
+ </div>
218
+
219
+ <div class="game-container">
220
+ <canvas id="game-canvas"></canvas>
221
+ <div id="game-elements"></div>
222
+ </div>
223
+
224
+ <div class="controls mt-6">
225
+ <button id="start-btn" class="btn">
226
+ <i class="fas fa-play mr-2"></i> START
227
+ </button>
228
+ <button id="pause-btn" class="btn" disabled>
229
+ <i class="fas fa-pause mr-2"></i> PAUSE
230
+ </button>
231
+ <button id="restart-btn" class="btn">
232
+ <i class="fas fa-redo mr-2"></i> RESTART
233
+ </button>
234
+ </div>
235
+
236
+ <div class="modal" id="game-over-modal">
237
+ <div class="modal-content">
238
+ <div class="game-over">GAME OVER!</div>
239
+ <h2 class="modal-title">Your Score: <span id="final-score">0</span></h2>
240
+ <p class="text-white mb-4">Try again to beat your high score!</p>
241
+ <button id="play-again-btn" class="btn">
242
+ <i class="fas fa-gamepad mr-2"></i> PLAY AGAIN
243
+ </button>
244
+ </div>
245
+ </div>
246
+
247
+ <div class="absolute bottom-4 right-4 text-xs text-gray-500">
248
+ Use arrow keys or swipe to control
249
+ </div>
250
+
251
+ <script>
252
+ document.addEventListener('DOMContentLoaded', () => {
253
+ // Game elements
254
+ const canvas = document.getElementById('game-canvas');
255
+ const ctx = canvas.getContext('2d');
256
+ const gameElements = document.getElementById('game-elements');
257
+ const scoreDisplay = document.getElementById('score');
258
+ const highScoreDisplay = document.getElementById('high-score');
259
+ const finalScoreDisplay = document.getElementById('final-score');
260
+
261
+ // Buttons
262
+ const startBtn = document.getElementById('start-btn');
263
+ const pauseBtn = document.getElementById('pause-btn');
264
+ const restartBtn = document.getElementById('restart-btn');
265
+ const playAgainBtn = document.getElementById('play-again-btn');
266
+
267
+ // Modal
268
+ const gameOverModal = document.getElementById('game-over-modal');
269
+
270
+ // Game settings
271
+ const gridSize = 20;
272
+ let canvasSize = Math.min(600, window.innerWidth - 40, window.innerHeight - 200);
273
+ canvas.width = canvasSize;
274
+ canvas.height = canvasSize;
275
+
276
+ // Game state
277
+ let snake = [];
278
+ let food = {};
279
+ let direction = 'right';
280
+ let nextDirection = 'right';
281
+ let gameSpeed = 150;
282
+ let score = 0;
283
+ let highScore = localStorage.getItem('snakeHighScore') || 0;
284
+ let gameInterval;
285
+ let isPaused = false;
286
+ let isGameOver = false;
287
+ let isGameRunning = false;
288
+
289
+ // Initialize game
290
+ function initGame() {
291
+ // Clear any existing game elements
292
+ gameElements.innerHTML = '';
293
+
294
+ // Reset snake
295
+ snake = [
296
+ {x: 5, y: 10},
297
+ {x: 4, y: 10},
298
+ {x: 3, y: 10}
299
+ ];
300
+
301
+ // Reset direction
302
+ direction = 'right';
303
+ nextDirection = 'right';
304
+
305
+ // Reset score
306
+ score = 0;
307
+ scoreDisplay.textContent = score;
308
+ highScoreDisplay.textContent = highScore;
309
+
310
+ // Generate food
311
+ generateFood();
312
+
313
+ // Reset game state
314
+ isGameOver = false;
315
+ isPaused = false;
316
+
317
+ // Hide modal if visible
318
+ gameOverModal.classList.remove('active');
319
+
320
+ // Render initial state
321
+ render();
322
+ }
323
+
324
+ // Start game
325
+ function startGame() {
326
+ if (!isGameRunning) {
327
+ isGameRunning = true;
328
+ startBtn.disabled = true;
329
+ pauseBtn.disabled = false;
330
+ gameInterval = setInterval(gameLoop, gameSpeed);
331
+ }
332
+ }
333
+
334
+ // Pause game
335
+ function pauseGame() {
336
+ if (isGameRunning && !isPaused) {
337
+ isPaused = true;
338
+ clearInterval(gameInterval);
339
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> RESUME';
340
+ } else if (isGameRunning && isPaused) {
341
+ isPaused = false;
342
+ gameInterval = setInterval(gameLoop, gameSpeed);
343
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> PAUSE';
344
+ }
345
+ }
346
+
347
+ // Game over
348
+ function gameOver() {
349
+ isGameOver = true;
350
+ isGameRunning = false;
351
+ clearInterval(gameInterval);
352
+ startBtn.disabled = false;
353
+ pauseBtn.disabled = true;
354
+
355
+ // Update high score
356
+ if (score > highScore) {
357
+ highScore = score;
358
+ localStorage.setItem('snakeHighScore', highScore);
359
+ highScoreDisplay.textContent = highScore;
360
+ }
361
+
362
+ // Show game over modal
363
+ finalScoreDisplay.textContent = score;
364
+ gameOverModal.classList.add('active');
365
+
366
+ // Create explosion effect
367
+ createExplosion(snake[0].x * gridSize, snake[0].y * gridSize);
368
+ }
369
+
370
+ // Game loop
371
+ function gameLoop() {
372
+ if (isPaused || isGameOver) return;
373
+
374
+ // Update direction
375
+ direction = nextDirection;
376
+
377
+ // Move snake
378
+ const head = {...snake[0]};
379
+
380
+ switch (direction) {
381
+ case 'up':
382
+ head.y -= 1;
383
+ break;
384
+ case 'down':
385
+ head.y += 1;
386
+ break;
387
+ case 'left':
388
+ head.x -= 1;
389
+ break;
390
+ case 'right':
391
+ head.x += 1;
392
+ break;
393
+ }
394
+
395
+ // Check collisions
396
+ if (
397
+ head.x < 0 ||
398
+ head.x >= canvas.width / gridSize ||
399
+ head.y < 0 ||
400
+ head.y >= canvas.height / gridSize ||
401
+ snake.some(segment => segment.x === head.x && segment.y === head.y)
402
+ ) {
403
+ gameOver();
404
+ return;
405
+ }
406
+
407
+ // Add new head
408
+ snake.unshift(head);
409
+
410
+ // Check if snake ate food
411
+ if (head.x === food.x && head.y === food.y) {
412
+ // Increase score
413
+ score += 10;
414
+ scoreDisplay.textContent = score;
415
+
416
+ // Increase speed slightly
417
+ if (gameSpeed > 50 && score % 50 === 0) {
418
+ gameSpeed -= 5;
419
+ clearInterval(gameInterval);
420
+ gameInterval = setInterval(gameLoop, gameSpeed);
421
+ }
422
+
423
+ // Generate new food
424
+ generateFood();
425
+
426
+ // Create particle effect
427
+ createParticles(food.x * gridSize + gridSize/2, food.y * gridSize + gridSize/2);
428
+ } else {
429
+ // Remove tail if no food was eaten
430
+ snake.pop();
431
+ }
432
+
433
+ // Render game
434
+ render();
435
+ }
436
+
437
+ // Generate food at random position
438
+ function generateFood() {
439
+ let newFood;
440
+ do {
441
+ newFood = {
442
+ x: Math.floor(Math.random() * (canvas.width / gridSize)),
443
+ y: Math.floor(Math.random() * (canvas.height / gridSize))
444
+ };
445
+ } while (snake.some(segment => segment.x === newFood.x && segment.y === newFood.y));
446
+
447
+ food = newFood;
448
+
449
+ // Create food element
450
+ const foodElement = document.createElement('div');
451
+ foodElement.className = 'food';
452
+ foodElement.style.left = `${food.x * gridSize}px`;
453
+ foodElement.style.top = `${food.y * gridSize}px`;
454
+ foodElement.style.width = `${gridSize}px`;
455
+ foodElement.style.height = `${gridSize}px`;
456
+ foodElement.id = 'food';
457
+ gameElements.appendChild(foodElement);
458
+ }
459
+
460
+ // Render game
461
+ function render() {
462
+ // Clear canvas
463
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
464
+
465
+ // Draw snake
466
+ snake.forEach((segment, index) => {
467
+ const segmentElement = document.createElement('div');
468
+ segmentElement.className = index === 0 ? 'snake-segment snake-head' : 'snake-segment';
469
+ segmentElement.style.left = `${segment.x * gridSize}px`;
470
+ segmentElement.style.top = `${segment.y * gridSize}px`;
471
+ segmentElement.style.width = `${gridSize}px`;
472
+ segmentElement.style.height = `${gridSize}px`;
473
+ segmentElement.id = `segment-${index}`;
474
+
475
+ // Update or create element
476
+ const existingElement = document.getElementById(`segment-${index}`);
477
+ if (existingElement) {
478
+ existingElement.style.left = `${segment.x * gridSize}px`;
479
+ existingElement.style.top = `${segment.y * gridSize}px`;
480
+ } else {
481
+ gameElements.appendChild(segmentElement);
482
+ }
483
+ });
484
+
485
+ // Remove extra segments if snake got shorter
486
+ const segmentElements = document.querySelectorAll('.snake-segment');
487
+ if (segmentElements.length > snake.length) {
488
+ for (let i = snake.length; i < segmentElements.length; i++) {
489
+ segmentElements[i].remove();
490
+ }
491
+ }
492
+
493
+ // Update food position
494
+ const foodElement = document.getElementById('food');
495
+ if (foodElement) {
496
+ foodElement.style.left = `${food.x * gridSize}px`;
497
+ foodElement.style.top = `${food.y * gridSize}px`;
498
+ }
499
+ }
500
+
501
+ // Create particles
502
+ function createParticles(x, y) {
503
+ for (let i = 0; i < 15; i++) {
504
+ const particle = document.createElement('div');
505
+ particle.className = 'particle';
506
+ particle.style.left = `${x}px`;
507
+ particle.style.top = `${y}px`;
508
+
509
+ // Random direction and speed
510
+ const angle = Math.random() * Math.PI * 2;
511
+ const speed = Math.random() * 3 + 1;
512
+ const vx = Math.cos(angle) * speed;
513
+ const vy = Math.sin(angle) * speed;
514
+
515
+ document.body.appendChild(particle);
516
+
517
+ // Animate particle
518
+ let opacity = 1;
519
+ let size = 4;
520
+ let posX = x;
521
+ let posY = y;
522
+
523
+ const animate = () => {
524
+ opacity -= 0.02;
525
+ size -= 0.1;
526
+ posX += vx;
527
+ posY += vy;
528
+
529
+ if (opacity <= 0 || size <= 0) {
530
+ particle.remove();
531
+ return;
532
+ }
533
+
534
+ particle.style.opacity = opacity;
535
+ particle.style.width = `${size}px`;
536
+ particle.style.height = `${size}px`;
537
+ particle.style.left = `${posX}px`;
538
+ particle.style.top = `${posY}px`;
539
+
540
+ requestAnimationFrame(animate);
541
+ };
542
+
543
+ requestAnimationFrame(animate);
544
+ }
545
+ }
546
+
547
+ // Create explosion effect
548
+ function createExplosion(x, y) {
549
+ for (let i = 0; i < 30; i++) {
550
+ const particle = document.createElement('div');
551
+ particle.className = 'particle';
552
+ particle.style.backgroundColor = i % 2 === 0 ? 'var(--neon-pink)' : 'var(--neon-blue)';
553
+ particle.style.left = `${x + gridSize/2}px`;
554
+ particle.style.top = `${y + gridSize/2}px`;
555
+
556
+ // Random direction and speed
557
+ const angle = Math.random() * Math.PI * 2;
558
+ const speed = Math.random() * 5 + 2;
559
+ const vx = Math.cos(angle) * speed;
560
+ const vy = Math.sin(angle) * speed;
561
+
562
+ document.body.appendChild(particle);
563
+
564
+ // Animate particle
565
+ let opacity = 1;
566
+ let size = Math.random() * 6 + 2;
567
+ let posX = x + gridSize/2;
568
+ let posY = y + gridSize/2;
569
+
570
+ const animate = () => {
571
+ opacity -= 0.02;
572
+ size -= 0.1;
573
+ posX += vx;
574
+ posY += vy;
575
+
576
+ if (opacity <= 0 || size <= 0) {
577
+ particle.remove();
578
+ return;
579
+ }
580
+
581
+ particle.style.opacity = opacity;
582
+ particle.style.width = `${size}px`;
583
+ particle.style.height = `${size}px`;
584
+ particle.style.left = `${posX}px`;
585
+ particle.style.top = `${posY}px`;
586
+
587
+ requestAnimationFrame(animate);
588
+ };
589
+
590
+ requestAnimationFrame(animate);
591
+ }
592
+ }
593
+
594
+ // Handle keyboard input
595
+ function handleKeyDown(e) {
596
+ if (!isGameRunning || isPaused) return;
597
+
598
+ switch (e.key) {
599
+ case 'ArrowUp':
600
+ if (direction !== 'down') nextDirection = 'up';
601
+ break;
602
+ case 'ArrowDown':
603
+ if (direction !== 'up') nextDirection = 'down';
604
+ break;
605
+ case 'ArrowLeft':
606
+ if (direction !== 'right') nextDirection = 'left';
607
+ break;
608
+ case 'ArrowRight':
609
+ if (direction !== 'left') nextDirection = 'right';
610
+ break;
611
+ }
612
+ }
613
+
614
+ // Handle touch events for mobile
615
+ let touchStartX = 0;
616
+ let touchStartY = 0;
617
+
618
+ function handleTouchStart(e) {
619
+ touchStartX = e.touches[0].clientX;
620
+ touchStartY = e.touches[0].clientY;
621
+ }
622
+
623
+ function handleTouchEnd(e) {
624
+ if (!isGameRunning || isPaused) return;
625
+
626
+ const touchEndX = e.changedTouches[0].clientX;
627
+ const touchEndY = e.changedTouches[0].clientY;
628
+
629
+ const dx = touchEndX - touchStartX;
630
+ const dy = touchEndY - touchStartY;
631
+
632
+ // Determine swipe direction
633
+ if (Math.abs(dx) > Math.abs(dy)) {
634
+ // Horizontal swipe
635
+ if (dx > 0 && direction !== 'left') {
636
+ nextDirection = 'right';
637
+ } else if (dx < 0 && direction !== 'right') {
638
+ nextDirection = 'left';
639
+ }
640
+ } else {
641
+ // Vertical swipe
642
+ if (dy > 0 && direction !== 'up') {
643
+ nextDirection = 'down';
644
+ } else if (dy < 0 && direction !== 'down') {
645
+ nextDirection = 'up';
646
+ }
647
+ }
648
+ }
649
+
650
+ // Event listeners
651
+ startBtn.addEventListener('click', startGame);
652
+ pauseBtn.addEventListener('click', pauseGame);
653
+ restartBtn.addEventListener('click', initGame);
654
+ playAgainBtn.addEventListener('click', () => {
655
+ gameOverModal.classList.remove('active');
656
+ initGame();
657
+ startGame();
658
+ });
659
+
660
+ document.addEventListener('keydown', handleKeyDown);
661
+ document.addEventListener('touchstart', handleTouchStart);
662
+ document.addEventListener('touchend', handleTouchEnd);
663
+
664
+ // Handle window resize
665
+ window.addEventListener('resize', () => {
666
+ canvasSize = Math.min(600, window.innerWidth - 40, window.innerHeight - 200);
667
+ canvas.width = canvasSize;
668
+ canvas.height = canvasSize;
669
+ render();
670
+ });
671
+
672
+ // Initialize game
673
+ initGame();
674
+ });
675
+ </script>
676
+ <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=engerl/neonsanke" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
677
+ </html>