piecurus commited on
Commit
5701e16
·
verified ·
1 Parent(s): d76a750

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +671 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Neon Snake
3
- emoji: 🌍
4
- colorFrom: indigo
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: neon-snake
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: blue
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,671 @@
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 Adventure</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: 'Orbitron', sans-serif;
17
+ background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
18
+ height: 100vh;
19
+ display: flex;
20
+ flex-direction: column;
21
+ justify-content: center;
22
+ align-items: center;
23
+ color: white;
24
+ overflow: hidden;
25
+ position: relative;
26
+ }
27
+
28
+ .game-container {
29
+ position: relative;
30
+ width: 500px;
31
+ height: 500px;
32
+ background-color: rgba(0, 0, 0, 0.3);
33
+ border-radius: 10px;
34
+ box-shadow: 0 0 30px rgba(255, 255, 255, 0.2);
35
+ overflow: hidden;
36
+ border: 2px solid rgba(255, 255, 255, 0.1);
37
+ }
38
+
39
+ canvas {
40
+ display: block;
41
+ border-radius: 8px;
42
+ }
43
+
44
+ .score-display {
45
+ position: absolute;
46
+ top: 20px;
47
+ left: 20px;
48
+ font-size: 1.5rem;
49
+ color: #fff;
50
+ z-index: 10;
51
+ text-shadow: 0 0 10px #00f3ff;
52
+ }
53
+
54
+ .game-over {
55
+ position: absolute;
56
+ top: 0;
57
+ left: 0;
58
+ width: 100%;
59
+ height: 100%;
60
+ background-color: rgba(0, 0, 0, 0.7);
61
+ display: none;
62
+ flex-direction: column;
63
+ justify-content: center;
64
+ align-items: center;
65
+ z-index: 20;
66
+ border-radius: 8px;
67
+ }
68
+
69
+ .game-over h2 {
70
+ font-size: 3rem;
71
+ margin-bottom: 20px;
72
+ color: #ff4d4d;
73
+ text-shadow: 0 0 15px #ff0000;
74
+ animation: pulse 1.5s infinite;
75
+ }
76
+
77
+ .final-score {
78
+ font-size: 1.8rem;
79
+ margin-bottom: 30px;
80
+ color: #00ff9d;
81
+ text-shadow: 0 0 10px #00ffaa;
82
+ }
83
+
84
+ .btn {
85
+ padding: 12px 30px;
86
+ background: linear-gradient(45deg, #00c6ff, #0072ff);
87
+ border: none;
88
+ border-radius: 50px;
89
+ color: white;
90
+ font-size: 1.2rem;
91
+ font-family: 'Orbitron', sans-serif;
92
+ cursor: pointer;
93
+ transition: all 0.3s;
94
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
95
+ outline: none;
96
+ }
97
+
98
+ .btn:hover {
99
+ transform: translateY(-3px);
100
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
101
+ }
102
+
103
+ .btn:active {
104
+ transform: translateY(1px);
105
+ }
106
+
107
+ .controls {
108
+ margin-top: 20px;
109
+ text-align: center;
110
+ }
111
+
112
+ .controls p {
113
+ margin-bottom: 10px;
114
+ color: #ffffffaa;
115
+ }
116
+
117
+ .mobile-controls {
118
+ display: none;
119
+ grid-template-columns: repeat(3, 1fr);
120
+ grid-template-rows: repeat(3, 1fr);
121
+ gap: 10px;
122
+ width: 200px;
123
+ margin-top: 20px;
124
+ }
125
+
126
+ .mobile-btn {
127
+ width: 60px;
128
+ height: 60px;
129
+ background-color: rgba(255, 255, 255, 0.1);
130
+ border: none;
131
+ border-radius: 50%;
132
+ color: white;
133
+ font-size: 1.5rem;
134
+ display: flex;
135
+ justify-content: center;
136
+ align-items: center;
137
+ cursor: pointer;
138
+ user-select: none;
139
+ }
140
+
141
+ .mobile-btn:active {
142
+ background-color: rgba(255, 255, 255, 0.3);
143
+ }
144
+
145
+ .up {
146
+ grid-column: 2;
147
+ grid-row: 1;
148
+ }
149
+
150
+ .down {
151
+ grid-column: 2;
152
+ grid-row: 3;
153
+ }
154
+
155
+ .left {
156
+ grid-column: 1;
157
+ grid-row: 2;
158
+ }
159
+
160
+ .right {
161
+ grid-column: 3;
162
+ grid-row: 2;
163
+ }
164
+
165
+ .title {
166
+ font-size: 3rem;
167
+ margin-bottom: 20px;
168
+ background: linear-gradient(to right, #00f3ff, #00ff9d);
169
+ -webkit-background-clip: text;
170
+ background-clip: text;
171
+ color: transparent;
172
+ text-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
173
+ }
174
+
175
+ @keyframes pulse {
176
+ 0% { transform: scale(1); }
177
+ 50% { transform: scale(1.05); }
178
+ 100% { transform: scale(1); }
179
+ }
180
+
181
+ .particle {
182
+ position: absolute;
183
+ background-color: rgba(255, 255, 255, 0.7);
184
+ border-radius: 50%;
185
+ pointer-events: none;
186
+ z-index: 5;
187
+ }
188
+
189
+ @media (max-width: 600px) {
190
+ .game-container {
191
+ width: 300px;
192
+ height: 300px;
193
+ }
194
+
195
+ .mobile-controls {
196
+ display: grid;
197
+ }
198
+
199
+ .controls p {
200
+ display: none;
201
+ }
202
+
203
+ .title {
204
+ font-size: 2rem;
205
+ }
206
+ }
207
+ </style>
208
+ </head>
209
+ <body>
210
+ <h1 class="title">NEON SNAKE</h1>
211
+ <div class="game-container">
212
+ <div class="score-display">Score: 0</div>
213
+ <canvas id="gameCanvas"></canvas>
214
+ <div class="game-over">
215
+ <h2>GAME OVER</h2>
216
+ <div class="final-score">Score: 0</div>
217
+ <button class="btn" id="restartBtn">PLAY AGAIN</button>
218
+ </div>
219
+ </div>
220
+ <div class="controls">
221
+ <p>Use arrow keys to control the snake</p>
222
+ <div class="mobile-controls">
223
+ <button class="mobile-btn up" id="upBtn">↑</button>
224
+ <button class="mobile-btn down" id="downBtn">↓</button>
225
+ <button class="mobile-btn left" id="leftBtn">←</button>
226
+ <button class="mobile-btn right" id="rightBtn">→</button>
227
+ </div>
228
+ </div>
229
+
230
+ <script>
231
+ // Game variables
232
+ const canvas = document.getElementById('gameCanvas');
233
+ const ctx = canvas.getContext('2d');
234
+ const scoreDisplay = document.querySelector('.score-display');
235
+ const gameOverScreen = document.querySelector('.game-over');
236
+ const finalScoreDisplay = document.querySelector('.final-score');
237
+ const restartBtn = document.getElementById('restartBtn');
238
+
239
+ // Set canvas size
240
+ canvas.width = canvas.parentElement.offsetWidth;
241
+ canvas.height = canvas.parentElement.offsetHeight;
242
+
243
+ // Game settings
244
+ const gridSize = 20;
245
+ const tileCountX = Math.floor(canvas.width / gridSize);
246
+ const tileCountY = Math.floor(canvas.height / gridSize);
247
+
248
+ // Game state
249
+ let snake = [];
250
+ let food = {};
251
+ let direction = 'right';
252
+ let nextDirection = 'right';
253
+ let score = 0;
254
+ let gameSpeed = 120;
255
+ let gameRunning = false;
256
+ let gameLoop;
257
+ let particles = [];
258
+
259
+ // Sound effects
260
+ const eatSound = new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...'); // Short base64 encoded sound
261
+ const gameOverSound = new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...'); // Short base64 encoded sound
262
+
263
+ // Initialize game
264
+ function initGame() {
265
+ snake = [
266
+ {x: 5, y: 10},
267
+ {x: 4, y: 10},
268
+ {x: 3, y: 10}
269
+ ];
270
+
271
+ spawnFood();
272
+ direction = 'right';
273
+ nextDirection = 'right';
274
+ score = 0;
275
+ gameSpeed = 120;
276
+ scoreDisplay.textContent = `Score: ${score}`;
277
+ particles = [];
278
+ gameRunning = true;
279
+
280
+ if (gameLoop) clearInterval(gameLoop);
281
+ gameLoop = setInterval(gameStep, gameSpeed);
282
+ }
283
+
284
+ // Spawn food at random position
285
+ function spawnFood() {
286
+ food = {
287
+ x: Math.floor(Math.random() * tileCountX),
288
+ y: Math.floor(Math.random() * tileCountY)
289
+ };
290
+
291
+ // Make sure food doesn't spawn on snake
292
+ for (let segment of snake) {
293
+ if (segment.x === food.x && segment.y === food.y) {
294
+ return spawnFood();
295
+ }
296
+ }
297
+
298
+ createParticles(food.x * gridSize + gridSize/2, food.y * gridSize + gridSize/2, 10, '#FF5252');
299
+ }
300
+
301
+ // Main game loop step
302
+ function gameStep() {
303
+ if (!gameRunning) return;
304
+
305
+ moveSnake();
306
+ checkCollision();
307
+ if (gameRunning) {
308
+ drawGame();
309
+ }
310
+ }
311
+
312
+ // Move the snake
313
+ function moveSnake() {
314
+ direction = nextDirection;
315
+
316
+ // Get the head of the snake
317
+ const head = {x: snake[0].x, y: snake[0].y};
318
+
319
+ // Move head based on direction
320
+ switch (direction) {
321
+ case 'up':
322
+ head.y -= 1;
323
+ break;
324
+ case 'down':
325
+ head.y += 1;
326
+ break;
327
+ case 'left':
328
+ head.x -= 1;
329
+ break;
330
+ case 'right':
331
+ head.x += 1;
332
+ break;
333
+ }
334
+
335
+ // Add new head
336
+ snake.unshift(head);
337
+
338
+ // Check if snake ate food
339
+ if (head.x === food.x && head.y === food.y) {
340
+ score += 10;
341
+ scoreDisplay.textContent = `Score: ${score}`;
342
+
343
+ // Play sound and create particles
344
+ if (eatSound) {
345
+ eatSound.currentTime = 0;
346
+ eatSound.play();
347
+ }
348
+ createParticles(food.x * gridSize + gridSize/2, food.y * gridSize + gridSize/2, 15, '#4CAF50');
349
+
350
+ // Increase speed every 50 points
351
+ if (score % 50 === 0 && gameSpeed > 50) {
352
+ gameSpeed -= 10;
353
+ clearInterval(gameLoop);
354
+ gameLoop = setInterval(gameStep, gameSpeed);
355
+ }
356
+
357
+ spawnFood();
358
+ } else {
359
+ // Remove tail only if didn't eat food
360
+ snake.pop();
361
+ }
362
+ }
363
+
364
+ // Check for collisions
365
+ function checkCollision() {
366
+ const head = snake[0];
367
+
368
+ // Wall collision
369
+ if (head.x < 0 || head.x >= tileCountX || head.y < 0 || head.y >= tileCountY) {
370
+ gameOver();
371
+ return;
372
+ }
373
+
374
+ // Self collision (skip head)
375
+ for (let i = 1; i < snake.length; i++) {
376
+ if (head.x === snake[i].x && head.y === snake[i].y) {
377
+ gameOver();
378
+ return;
379
+ }
380
+ }
381
+ }
382
+
383
+ // Game over sequence
384
+ function gameOver() {
385
+ gameRunning = false;
386
+ clearInterval(gameLoop);
387
+
388
+ // Play sound
389
+ if (gameOverSound) {
390
+ gameOverSound.currentTime = 0;
391
+ gameOverSound.play();
392
+ }
393
+
394
+ // Create explosion particles
395
+ for (let segment of snake) {
396
+ createParticles(segment.x * gridSize + gridSize/2, segment.y * gridSize + gridSize/2, 5, '#FFEB3B');
397
+ }
398
+
399
+ // Show game over screen
400
+ finalScoreDisplay.textContent = `Score: ${score}`;
401
+ gameOverScreen.style.display = 'flex';
402
+ }
403
+
404
+ // Draw game elements
405
+ function drawGame() {
406
+ // Clear canvas
407
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
408
+
409
+ // Draw background grid
410
+ drawGrid();
411
+
412
+ // Draw food
413
+ drawFood();
414
+
415
+ // Draw snake
416
+ drawSnake();
417
+
418
+ // Draw particles
419
+ drawParticles();
420
+ }
421
+
422
+ // Draw background grid
423
+ function drawGrid() {
424
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
425
+ for (let x = 0; x < tileCountX; x++) {
426
+ for (let y = 0; y < tileCountY; y++) {
427
+ ctx.fillRect(x * gridSize, y * gridSize, gridSize - 1, gridSize - 1);
428
+ }
429
+ }
430
+ }
431
+
432
+ // Draw food with glow effect
433
+ function drawFood() {
434
+ const centerX = food.x * gridSize + gridSize / 2;
435
+ const centerY = food.y * gridSize + gridSize / 2;
436
+ const radius = gridSize / 2 - 2;
437
+
438
+ // Glow effect
439
+ const gradient = ctx.createRadialGradient(
440
+ centerX, centerY, radius * 0.2,
441
+ centerX, centerY, radius * 1.5
442
+ );
443
+ gradient.addColorStop(0, 'rgba(255, 82, 82, 0.8)');
444
+ gradient.addColorStop(1, 'rgba(255, 82, 82, 0)');
445
+
446
+ ctx.beginPath();
447
+ ctx.arc(centerX, centerY, radius * 1.5, 0, Math.PI * 2);
448
+ ctx.fillStyle = gradient;
449
+ ctx.fill();
450
+
451
+ // Main food circle
452
+ ctx.beginPath();
453
+ ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
454
+ ctx.fillStyle = '#FF5252';
455
+ ctx.fill();
456
+ ctx.shadowBlur = 15;
457
+ ctx.shadowColor = '#FF5252';
458
+ ctx.fill();
459
+ ctx.shadowBlur = 0;
460
+
461
+ // Inner detail
462
+ ctx.beginPath();
463
+ ctx.arc(centerX, centerY, radius / 2, 0, Math.PI * 2);
464
+ ctx.fillStyle = '#FF8A80';
465
+ ctx.fill();
466
+ }
467
+
468
+ // Draw snake with gradient and glow
469
+ function drawSnake() {
470
+ for (let i = 0; i < snake.length; i++) {
471
+ const segment = snake[i];
472
+ const posX = segment.x * gridSize;
473
+ const posY = segment.y * gridSize;
474
+ const size = gridSize - 2;
475
+
476
+ // Head gets different color
477
+ if (i === 0) {
478
+ const gradient = ctx.createLinearGradient(
479
+ posX, posY,
480
+ posX + size, posY + size
481
+ );
482
+ gradient.addColorStop(0, '#00E5FF');
483
+ gradient.addColorStop(1, '#00B0FF');
484
+ ctx.fillStyle = gradient;
485
+ } else {
486
+ // Body gradient based on position
487
+ const gradient = ctx.createLinearGradient(
488
+ posX, posY,
489
+ posX + size, posY + size
490
+ );
491
+ const hue = (120 + i * 2) % 360;
492
+ gradient.addColorStop(0, `hsl(${hue}, 100%, 65%)`);
493
+ gradient.addColorStop(1, `hsl(${(hue + 20) % 360}, 100%, 50%)`);
494
+ ctx.fillStyle = gradient;
495
+ }
496
+
497
+ // Glow effect
498
+ ctx.shadowBlur = 10;
499
+ ctx.shadowColor = ctx.fillStyle;
500
+
501
+ // Rounded corners
502
+ const cornerRadius = 5;
503
+ ctx.beginPath();
504
+ ctx.moveTo(posX + cornerRadius, posY);
505
+ ctx.lineTo(posX + size - cornerRadius, posY);
506
+ ctx.quadraticCurveTo(posX + size, posY, posX + size, posY + cornerRadius);
507
+ ctx.lineTo(posX + size, posY + size - cornerRadius);
508
+ ctx.quadraticCurveTo(posX + size, posY + size, posX + size - cornerRadius, posY + size);
509
+ ctx.lineTo(posX + cornerRadius, posY + size);
510
+ ctx.quadraticCurveTo(posX, posY + size, posX, posY + size - cornerRadius);
511
+ ctx.lineTo(posX, posY + cornerRadius);
512
+ ctx.quadraticCurveTo(posX, posY, posX + cornerRadius, posY);
513
+ ctx.closePath();
514
+ ctx.fill();
515
+
516
+ // Reset shadow
517
+ ctx.shadowBlur = 0;
518
+
519
+ // Eyes on head
520
+ if (i === 0) {
521
+ const eyeSize = size / 6;
522
+ ctx.fillStyle = 'white';
523
+
524
+ // Calculate eye positions based on direction
525
+ let leftEyeX, leftEyeY, rightEyeX, rightEyeY;
526
+
527
+ switch (direction) {
528
+ case 'up':
529
+ leftEyeX = posX + size / 3;
530
+ leftEyeY = posY + size / 3;
531
+ rightEyeX = posX + size * 2/3;
532
+ rightEyeY = posY + size / 3;
533
+ break;
534
+ case 'down':
535
+ leftEyeX = posX + size / 3;
536
+ leftEyeY = posY + size * 2/3;
537
+ rightEyeX = posX + size * 2/3;
538
+ rightEyeY = posY + size * 2/3;
539
+ break;
540
+ case 'left':
541
+ leftEyeX = posX + size / 3;
542
+ leftEyeY = posY + size / 3;
543
+ rightEyeX = posX + size / 3;
544
+ rightEyeY = posY + size * 2/3;
545
+ break;
546
+ case 'right':
547
+ leftEyeX = posX + size * 2/3;
548
+ leftEyeY = posY + size / 3;
549
+ rightEyeX = posX + size * 2/3;
550
+ rightEyeY = posY + size * 2/3;
551
+ break;
552
+ }
553
+
554
+ // Draw eyes
555
+ ctx.beginPath();
556
+ ctx.arc(leftEyeX, leftEyeY, eyeSize, 0, Math.PI * 2);
557
+ ctx.fill();
558
+
559
+ ctx.beginPath();
560
+ ctx.arc(rightEyeX, rightEyeY, eyeSize, 0, Math.PI * 2);
561
+ ctx.fill();
562
+
563
+ // Pupils
564
+ ctx.fillStyle = '#222';
565
+ const pupilSize = eyeSize / 2;
566
+ ctx.beginPath();
567
+ ctx.arc(leftEyeX, leftEyeY, pupilSize, 0, Math.PI * 2);
568
+ ctx.fill();
569
+
570
+ ctx.beginPath();
571
+ ctx.arc(rightEyeX, rightEyeY, pupilSize, 0, Math.PI * 2);
572
+ ctx.fill();
573
+ }
574
+ }
575
+ }
576
+
577
+ // Create particles
578
+ function createParticles(x, y, count, color) {
579
+ for (let i = 0; i < count; i++) {
580
+ particles.push({
581
+ x: x,
582
+ y: y,
583
+ size: Math.random() * 3 + 1,
584
+ color: color,
585
+ speedX: Math.random() * 6 - 3,
586
+ speedY: Math.random() * 6 - 3,
587
+ life: 30 + Math.random() * 30,
588
+ opacity: 1
589
+ });
590
+ }
591
+ }
592
+
593
+ // Draw and update particles
594
+ function drawParticles() {
595
+ for (let i = particles.length - 1; i >= 0; i--) {
596
+ const p = particles[i];
597
+
598
+ // Update position and life
599
+ p.x += p.speedX;
600
+ p.y += p.speedY;
601
+ p.life--;
602
+ p.opacity = p.life / 60;
603
+
604
+ // Remove if life is over
605
+ if (p.life <= 0) {
606
+ particles.splice(i, 1);
607
+ continue;
608
+ }
609
+
610
+ // Draw particle
611
+ ctx.globalAlpha = p.opacity;
612
+ ctx.fillStyle = p.color;
613
+ ctx.beginPath();
614
+ ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
615
+ ctx.fill();
616
+ }
617
+ ctx.globalAlpha = 1;
618
+ }
619
+
620
+ // Keyboard controls
621
+ function handleKeyDown(e) {
622
+ const key = e.key;
623
+
624
+ // Prevent reverse direction
625
+ if (key === 'ArrowUp' && direction !== 'down') {
626
+ nextDirection = 'up';
627
+ } else if (key === 'ArrowDown' && direction !== 'up') {
628
+ nextDirection = 'down';
629
+ } else if (key === 'ArrowLeft' && direction !== 'right') {
630
+ nextDirection = 'left';
631
+ } else if (key === 'ArrowRight' && direction !== 'left') {
632
+ nextDirection = 'right';
633
+ }
634
+ }
635
+
636
+ // Mobile controls
637
+ document.getElementById('upBtn').addEventListener('click', () => {
638
+ if (direction !== 'down') nextDirection = 'up';
639
+ });
640
+
641
+ document.getElementById('downBtn').addEventListener('click', () => {
642
+ if (direction !== 'up') nextDirection = 'down';
643
+ });
644
+
645
+ document.getElementById('leftBtn').addEventListener('click', () => {
646
+ if (direction !== 'right') nextDirection = 'left';
647
+ });
648
+
649
+ document.getElementById('rightBtn').addEventListener('click', () => {
650
+ if (direction !== 'left') nextDirection = 'right';
651
+ });
652
+
653
+ // Restart game
654
+ restartBtn.addEventListener('click', () => {
655
+ gameOverScreen.style.display = 'none';
656
+ initGame();
657
+ });
658
+
659
+ // Handle window resize
660
+ window.addEventListener('resize', () => {
661
+ canvas.width = canvas.parentElement.offsetWidth;
662
+ canvas.height = canvas.parentElement.offsetHeight;
663
+ if (gameRunning) drawGame();
664
+ });
665
+
666
+ // Initialize
667
+ document.addEventListener('keydown', handleKeyDown);
668
+ initGame();
669
+ </script>
670
+ <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 <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
671
+ </html>