robennong commited on
Commit
c906018
·
verified ·
1 Parent(s): 707a7c4

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +951 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Sparklesnake
3
- emoji: 📉
4
- colorFrom: yellow
5
- colorTo: yellow
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: sparklesnake
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,951 @@
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 - The Sparkling Adventure</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: 'Arial', sans-serif;
17
+ background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
18
+ color: white;
19
+ height: 100vh;
20
+ overflow: hidden;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ justify-content: center;
25
+ position: relative;
26
+ }
27
+
28
+ body::before {
29
+ content: '';
30
+ position: absolute;
31
+ top: 0;
32
+ left: 0;
33
+ width: 100%;
34
+ height: 100%;
35
+ background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="0.5" fill="white" opacity="0.1"/></svg>');
36
+ z-index: -1;
37
+ animation: stars 50s linear infinite;
38
+ }
39
+
40
+ @keyframes stars {
41
+ 0% { background-position: 0 0; }
42
+ 100% { background-position: 1000px 1000px; }
43
+ }
44
+
45
+ .game-container {
46
+ position: relative;
47
+ width: 500px;
48
+ height: 500px;
49
+ border-radius: 10px;
50
+ overflow: hidden;
51
+ box-shadow: 0 0 40px rgba(100, 65, 255, 0.5);
52
+ border: 2px solid rgba(255, 255, 255, 0.1);
53
+ }
54
+
55
+ canvas {
56
+ background-color: rgba(15, 10, 40, 0.7);
57
+ display: block;
58
+ }
59
+
60
+ .overlay {
61
+ position: absolute;
62
+ top: 0;
63
+ left: 0;
64
+ width: 100%;
65
+ height: 100%;
66
+ display: flex;
67
+ flex-direction: column;
68
+ justify-content: center;
69
+ align-items: center;
70
+ background-color: rgba(0, 0, 0, 0.7);
71
+ z-index: 10;
72
+ }
73
+
74
+ .game-title {
75
+ font-size: 3rem;
76
+ font-weight: bold;
77
+ margin-bottom: 20px;
78
+ background: linear-gradient(90deg, #ff00cc, #3333ff);
79
+ -webkit-background-clip: text;
80
+ background-clip: text;
81
+ color: transparent;
82
+ text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
83
+ }
84
+
85
+ .btn {
86
+ padding: 12px 30px;
87
+ font-size: 1.2rem;
88
+ background: linear-gradient(135deg, #833ab4, #fd1d1d, #fcb045);
89
+ border: none;
90
+ color: white;
91
+ border-radius: 50px;
92
+ cursor: pointer;
93
+ margin: 10px;
94
+ box-shadow: 0 0 20px rgba(252, 176, 69, 0.5);
95
+ transition: all 0.3s ease;
96
+ position: relative;
97
+ overflow: hidden;
98
+ }
99
+
100
+ .btn:hover {
101
+ transform: translateY(-3px);
102
+ box-shadow: 0 0 30px rgba(252, 176, 69, 0.8);
103
+ }
104
+
105
+ .btn::before {
106
+ content: '';
107
+ position: absolute;
108
+ top: -50%;
109
+ left: -50%;
110
+ width: 200%;
111
+ height: 200%;
112
+ background: linear-gradient(
113
+ to bottom right,
114
+ transparent,
115
+ transparent,
116
+ transparent,
117
+ rgba(255, 255, 255, 0.2),
118
+ transparent,
119
+ transparent,
120
+ transparent
121
+ );
122
+ animation: shine 3s infinite;
123
+ }
124
+
125
+ @keyframes shine {
126
+ 0% { transform: rotate(0deg) translate(-30%, -30%); }
127
+ 100% { transform: rotate(360deg) translate(-30%, -30%); }
128
+ }
129
+
130
+ .score-display {
131
+ position: absolute;
132
+ top: 20px;
133
+ right: 20px;
134
+ font-size: 1.5rem;
135
+ background: rgba(0, 0, 0, 0.5);
136
+ padding: 10px 20px;
137
+ border-radius: 50px;
138
+ border: 1px solid rgba(255, 255, 255, 0.2);
139
+ box-shadow: 0 0 15px rgba(255, 255, 255, 0.1);
140
+ }
141
+
142
+ .controls {
143
+ position: absolute;
144
+ bottom: 20px;
145
+ display: flex;
146
+ gap: 10px;
147
+ flex-wrap: wrap;
148
+ justify-content: center;
149
+ width: 100%;
150
+ }
151
+
152
+ .control-btn {
153
+ width: 60px;
154
+ height: 60px;
155
+ background: rgba(255, 255, 255, 0.1);
156
+ border-radius: 50%;
157
+ display: flex;
158
+ justify-content: center;
159
+ align-items: center;
160
+ cursor: pointer;
161
+ border: 1px solid rgba(255, 255, 255, 0.2);
162
+ transition: all 0.2s ease;
163
+ }
164
+
165
+ .control-btn:hover {
166
+ background: rgba(255, 255, 255, 0.2);
167
+ }
168
+
169
+ .control-btn i {
170
+ font-size: 1.5rem;
171
+ color: rgba(255, 255, 255, 0.7);
172
+ }
173
+
174
+ .sparkle {
175
+ position: absolute;
176
+ width: 10px;
177
+ height: 10px;
178
+ background: white;
179
+ border-radius: 50%;
180
+ pointer-events: none;
181
+ transform: scale(1);
182
+ opacity: 0;
183
+ animation: sparkle 1s forwards;
184
+ }
185
+
186
+ @keyframes sparkle {
187
+ 0% {
188
+ transform: translate(var(--tx), var(--ty)) scale(0);
189
+ opacity: 0;
190
+ }
191
+ 50% {
192
+ opacity: 0.8;
193
+ }
194
+ 100% {
195
+ transform: translate(var(--tx), var(--ty)) scale(1.5);
196
+ opacity: 0;
197
+ }
198
+ }
199
+
200
+ .game-over {
201
+ text-align: center;
202
+ }
203
+
204
+ .final-score {
205
+ font-size: 2rem;
206
+ margin: 20px 0;
207
+ color: #fcb045;
208
+ }
209
+
210
+ .instructions {
211
+ position: absolute;
212
+ top: 20px;
213
+ left: 20px;
214
+ background: rgba(0, 0, 0, 0.5);
215
+ padding: 15px;
216
+ border-radius: 10px;
217
+ font-size: 1rem;
218
+ max-width: 250px;
219
+ border: 1px solid rgba(255, 255, 255, 0.2);
220
+ }
221
+
222
+ .power-ups {
223
+ position: absolute;
224
+ bottom: 100px;
225
+ left: 20px;
226
+ background: rgba(0, 0, 0, 0.5);
227
+ padding: 15px;
228
+ border-radius: 10px;
229
+ font-size: 1rem;
230
+ max-width: 250px;
231
+ border: 1px solid rgba(255, 255, 255, 0.2);
232
+ }
233
+
234
+ .power-up-item {
235
+ display: flex;
236
+ align-items: center;
237
+ margin: 5px 0;
238
+ }
239
+
240
+ .power-up-color {
241
+ width: 20px;
242
+ height: 20px;
243
+ border-radius: 50%;
244
+ margin-right: 10px;
245
+ }
246
+
247
+ .hidden {
248
+ display: none;
249
+ }
250
+
251
+ /* Responsive adjustments */
252
+ @media (max-width: 600px) {
253
+ .game-container {
254
+ width: 90vw;
255
+ height: 90vw;
256
+ }
257
+
258
+ .game-title {
259
+ font-size: 2rem;
260
+ }
261
+
262
+ .instructions, .power-ups {
263
+ max-width: 200px;
264
+ font-size: 0.8rem;
265
+ }
266
+ }
267
+ </style>
268
+ </head>
269
+ <body>
270
+ <div class="game-container">
271
+ <canvas id="gameCanvas"></canvas>
272
+
273
+ <div class="score-display hidden">
274
+ Score: <span id="score">0</span>
275
+ </div>
276
+
277
+ <div class="overlay" id="startScreen">
278
+ <h1 class="game-title">Neon Snake</h1>
279
+ <button class="btn" id="startBtn">Start Game</button>
280
+ <button class="btn" id="howToPlayBtn">How to Play</button>
281
+ </div>
282
+
283
+ <div class="overlay hidden" id="gameOverScreen">
284
+ <div class="game-over">
285
+ <h1 class="game-title">Game Over!</h1>
286
+ <div class="final-score">Your score: <span id="finalScore">0</span></div>
287
+ <button class="btn" id="restartBtn">Play Again</button>
288
+ </div>
289
+ </div>
290
+
291
+ <div class="instructions hidden" id="instructions">
292
+ <h3>How to Play</h3>
293
+ <p>Use arrow keys or on-screen controls to guide the snake 🐍</p>
294
+ <p>Eat the colorful food to grow larger and earn points 💎</p>
295
+ <p>Avoid hitting the walls or your own tail ⚠️</p>
296
+ <p>Special power-ups appear occasionally - grab them for bonuses ✨</p>
297
+ <button class="btn" id="backBtn" style="margin-top: 10px;">Back</button>
298
+ </div>
299
+
300
+ <div class="power-ups hidden">
301
+ <h3>Power-Ups</h3>
302
+ <div class="power-up-item">
303
+ <div class="power-up-color" style="background: gold;"></div>
304
+ <span>+5 points</span>
305
+ </div>
306
+ <div class="power-up-item">
307
+ <div class="power-up-color" style="background: #ff00ff;"></div>
308
+ <span>Speed boost</span>
309
+ </div>
310
+ <div class="power-up-item">
311
+ <div class="power-up-color" style="background: #00ffff;"></div>
312
+ <span>Invincibility</span>
313
+ </div>
314
+ </div>
315
+
316
+ <div class="controls hidden">
317
+ <div class="control-btn" id="upBtn"><i class="fas fa-arrow-up"></i></div>
318
+ <div class="control-btn" id="leftBtn"><i class="fas fa-arrow-left"></i></div>
319
+ <div class="control-btn" id="downBtn"><i class="fas fa-arrow-down"></i></div>
320
+ <div class="control-btn" id="rightBtn"><i class="fas fa-arrow-right"></i></div>
321
+ </div>
322
+ </div>
323
+
324
+ <script>
325
+ document.addEventListener('DOMContentLoaded', () => {
326
+ // Game elements
327
+ const canvas = document.getElementById('gameCanvas');
328
+ const ctx = canvas.getContext('2d');
329
+ const startScreen = document.getElementById('startScreen');
330
+ const gameOverScreen = document.getElementById('gameOverScreen');
331
+ const instructionsScreen = document.getElementById('instructions');
332
+ const scoreDisplay = document.querySelector('.score-display');
333
+ const gameScore = document.getElementById('score');
334
+ const finalScore = document.getElementById('finalScore');
335
+ const startBtn = document.getElementById('startBtn');
336
+ const restartBtn = document.getElementById('restartBtn');
337
+ const howToPlayBtn = document.getElementById('howToPlayBtn');
338
+ const backBtn = document.getElementById('backBtn');
339
+
340
+ // Control buttons
341
+ const upBtn = document.getElementById('upBtn');
342
+ const leftBtn = document.getElementById('leftBtn');
343
+ const downBtn = document.getElementById('downBtn');
344
+ const rightBtn = document.getElementById('rightBtn');
345
+
346
+ // Set canvas size
347
+ canvas.width = canvas.parentElement.offsetWidth;
348
+ canvas.height = canvas.parentElement.offsetHeight;
349
+
350
+ // Game variables
351
+ let snake = [];
352
+ let food = {};
353
+ let powerUp = null;
354
+ let direction = 'right';
355
+ let nextDirection = 'right';
356
+ let gridSize = 20;
357
+ let tileCountX = Math.floor(canvas.width / gridSize);
358
+ let tileCountY = Math.floor(canvas.height / gridSize);
359
+ let speed = 7; // Initial speed
360
+ let speedBoost = 0;
361
+ let score = 0;
362
+ let gameLoop;
363
+ let invincible = false;
364
+ let gameRunning = false;
365
+ let foodType = 'normal';
366
+ let powerUpActive = false;
367
+ let powerUpTime = 0;
368
+
369
+ // Colors
370
+ const colors = {
371
+ snakeHead: '#4dffea',
372
+ snakeBody: '#00ff9d',
373
+ snakeTail: '#009dff',
374
+ normalFood: '#ff3e3e',
375
+ powerFood: '#FFD700',
376
+ speedFood: '#ff00ff',
377
+ invincibleFood: '#00ffff',
378
+ powerUpText: '#ffffff',
379
+ speedBoost: '#ff0000'
380
+ };
381
+
382
+ // Initialize game
383
+ function initGame() {
384
+ snake = [];
385
+ for (let i = 3; i >= 0; i--) {
386
+ snake.push({
387
+ x: i,
388
+ y: 0
389
+ });
390
+ }
391
+
392
+ direction = 'right';
393
+ nextDirection = 'right';
394
+ speed = 7;
395
+ speedBoost = 0;
396
+ score = 0;
397
+ invincible = false;
398
+ powerUp = null;
399
+ powerUpActive = false;
400
+ foodType = 'normal';
401
+
402
+ spawnFood();
403
+ updateScore();
404
+
405
+ // Hide screens
406
+ startScreen.classList.add('hidden');
407
+ gameOverScreen.classList.add('hidden');
408
+ instructionsScreen.classList.add('hidden');
409
+
410
+ // Show game elements
411
+ scoreDisplay.classList.remove('hidden');
412
+ document.querySelector('.power-ups').classList.remove('hidden');
413
+ document.querySelector('.controls').classList.remove('hidden');
414
+
415
+ gameRunning = true;
416
+ }
417
+
418
+ // Main game loop
419
+ function gameUpdate() {
420
+ if (!gameRunning) return;
421
+
422
+ // Clear canvas with partial transparency for trail effect
423
+ ctx.fillStyle = 'rgba(15, 10, 40, 0.2)';
424
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
425
+
426
+ // Update direction
427
+ direction = nextDirection;
428
+
429
+ // Move snake
430
+ let headX = snake[0].x;
431
+ let headY = snake[0].y;
432
+
433
+ if (direction === 'right') headX++;
434
+ if (direction === 'left') headX--;
435
+ if (direction === 'up') headY--;
436
+ if (direction === 'down') headY++;
437
+
438
+ // Wrap around screen
439
+ if (headX < 0) headX = tileCountX - 1;
440
+ if (headX >= tileCountX) headX = 0;
441
+ if (headY < 0) headY = tileCountY - 1;
442
+ if (headY >= tileCountY) headY = 0;
443
+
444
+ // Check for collision with self (unless invincible)
445
+ if (!invincible) {
446
+ for (let i = 0; i < snake.length; i++) {
447
+ if (snake[i].x === headX && snake[i].y === headY) {
448
+ gameOver();
449
+ return;
450
+ }
451
+ }
452
+ }
453
+
454
+ // Create new head
455
+ const newHead = {
456
+ x: headX,
457
+ y: headY
458
+ };
459
+
460
+ snake.unshift(newHead);
461
+
462
+ // Check if snake ate food
463
+ if (headX === food.x && headY === food.y) {
464
+ // Play sound (not included in this example)
465
+
466
+ // Add sparkles
467
+ createSparkles(food.x * gridSize + gridSize/2, food.y * gridSize + gridSize/2, foodType);
468
+
469
+ // Different effects based on food type
470
+ if (foodType === 'power') {
471
+ score += 5; // Bonus points for power food
472
+ } else if (foodType === 'speed') {
473
+ speedBoost = 3;
474
+ } else if (foodType === 'invincible') {
475
+ invincible = true;
476
+ setTimeout(() => {
477
+ invincible = false;
478
+ }, 10000); // 10 seconds of invincibility
479
+ } else {
480
+ score++; // Normal food
481
+ }
482
+
483
+ updateScore();
484
+
485
+ // Spawn new food
486
+ spawnFood();
487
+
488
+ // Random chance to spawn a power-up
489
+ if (Math.random() < 0.1 && !powerUp) {
490
+ spawnPowerUp();
491
+ }
492
+ } else if (powerUp && headX === powerUp.x && headY === powerUp.y) {
493
+ // Snake ate power-up
494
+ createSparkles(powerUp.x * gridSize + gridSize/2, powerUp.y * gridSize + gridSize/2, 'power');
495
+
496
+ // Activate power-up effect
497
+ if (Math.random() < 0.7) {
498
+ // Speed boost (more common)
499
+ speedBoost = 5;
500
+ } else {
501
+ // Invincibility (less common)
502
+ invincible = true;
503
+ setTimeout(() => {
504
+ invincible = false;
505
+ }, 5000); // 5 seconds of invincibility
506
+ }
507
+
508
+ score += 2;
509
+ updateScore();
510
+ powerUp = null;
511
+ } else {
512
+ // Remove tail (unless we ate food)
513
+ snake.pop();
514
+ }
515
+
516
+ // Draw food
517
+ drawFood();
518
+
519
+ if (powerUp) {
520
+ drawPowerUp();
521
+ }
522
+
523
+ // Draw snake
524
+ drawSnake();
525
+
526
+ // Check if power-up should disappear
527
+ if (powerUp && powerUpTime + 5000 < Date.now()) {
528
+ powerUp = null;
529
+ }
530
+
531
+ // Calculate speed with any boosts
532
+ const currentSpeed = speed + speedBoost;
533
+ speedBoost = Math.max(0, speedBoost - 0.1);
534
+
535
+ // Schedule next frame
536
+ setTimeout(gameUpdate, 1000 / currentSpeed);
537
+ }
538
+
539
+ // Draw the snake
540
+ function drawSnake() {
541
+ for (let i = 0; i < snake.length; i++) {
542
+ // Calculate color gradient from head to tail
543
+ let ratio = i / snake.length;
544
+ let r, g, b;
545
+
546
+ if (invincible) {
547
+ // Rainbow effect when invincible
548
+ r = Math.floor(Math.sin(ratio * Math.PI + Date.now() * 0.01) * 127 + 128);
549
+ g = Math.floor(Math.sin(ratio * Math.PI + Date.now() * 0.01 + 2) * 127 + 128);
550
+ b = Math.floor(Math.sin(ratio * Math.PI + Date.now() * 0.01 + 4) * 127 + 128);
551
+ } else {
552
+ // Normal gradient
553
+ r = 0 + ratio * (0x4d - 0);
554
+ g = 0xff - ratio * (0xff - 0x9d);
555
+ b = 0xff - ratio * (0xff - 0x3e);
556
+ }
557
+
558
+ ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
559
+
560
+ // Add glow effect
561
+ if (i === 0) { // Head has stronger glow
562
+ ctx.shadowBlur = 15;
563
+ ctx.shadowColor = `rgb(${r}, ${g}, ${b})`;
564
+ } else {
565
+ ctx.shadowBlur = 8 - (5 * ratio);
566
+ ctx.shadowColor = `rgba(${r}, ${g}, ${b}, ${0.5 + ratio * 0.5})`;
567
+ }
568
+
569
+ // Draw snake segment
570
+ ctx.fillRect(
571
+ snake[i].x * gridSize,
572
+ snake[i].y * gridSize,
573
+ gridSize - 2,
574
+ gridSize - 2
575
+ );
576
+
577
+ // Reset shadow
578
+ ctx.shadowBlur = 0;
579
+
580
+ // Draw eyes on head
581
+ if (i === 0) {
582
+ ctx.fillStyle = 'white';
583
+ let eyeSize = gridSize / 5;
584
+ let eyeOffsetX = gridSize / 3;
585
+ let eyeOffsetY = gridSize / 3;
586
+
587
+ // Position eyes based on direction
588
+ if (direction === 'right') {
589
+ ctx.fillRect(
590
+ snake[i].x * gridSize + gridSize - eyeSize - 2,
591
+ snake[i].y * gridSize + eyeOffsetY,
592
+ eyeSize,
593
+ eyeSize
594
+ );
595
+ ctx.fillRect(
596
+ snake[i].x * gridSize + gridSize - eyeSize - 2,
597
+ snake[i].y * gridSize + gridSize - eyeOffsetY - eyeSize,
598
+ eyeSize,
599
+ eyeSize
600
+ );
601
+ } else if (direction === 'left') {
602
+ ctx.fillRect(
603
+ snake[i].x * gridSize + 2,
604
+ snake[i].y * gridSize + eyeOffsetY,
605
+ eyeSize,
606
+ eyeSize
607
+ );
608
+ ctx.fillRect(
609
+ snake[i].x * gridSize + 2,
610
+ snake[i].y * gridSize + gridSize - eyeOffsetY - eyeSize,
611
+ eyeSize,
612
+ eyeSize
613
+ );
614
+ } else if (direction === 'up') {
615
+ ctx.fillRect(
616
+ snake[i].x * gridSize + eyeOffsetX,
617
+ snake[i].y * gridSize + 2,
618
+ eyeSize,
619
+ eyeSize
620
+ );
621
+ ctx.fillRect(
622
+ snake[i].x * gridSize + gridSize - eyeOffsetX - eyeSize,
623
+ snake[i].y * gridSize + 2,
624
+ eyeSize,
625
+ eyeSize
626
+ );
627
+ } else if (direction === 'down') {
628
+ ctx.fillRect(
629
+ snake[i].x * gridSize + eyeOffsetX,
630
+ snake[i].y * gridSize + gridSize - eyeSize - 2,
631
+ eyeSize,
632
+ eyeSize
633
+ );
634
+ ctx.fillRect(
635
+ snake[i].x * gridSize + gridSize - eyeOffsetX - eyeSize,
636
+ snake[i].y * gridSize + gridSize - eyeSize - 2,
637
+ eyeSize,
638
+ eyeSize
639
+ );
640
+ }
641
+ }
642
+ }
643
+ }
644
+
645
+ // Draw food
646
+ function drawFood() {
647
+ ctx.shadowBlur = 15;
648
+
649
+ if (foodType === 'power') {
650
+ ctx.fillStyle = colors.powerFood;
651
+ ctx.shadowColor = 'rgba(255, 215, 0, 0.7)';
652
+ } else if (foodType === 'speed') {
653
+ ctx.fillStyle = colors.speedFood;
654
+ ctx.shadowColor = 'rgba(255, 0, 255, 0.7)';
655
+ } else if (foodType === 'invincible') {
656
+ ctx.fillStyle = colors.invincibleFood;
657
+ ctx.shadowColor = 'rgba(0, 255, 255, 0.7)';
658
+ } else {
659
+ ctx.fillStyle = colors.normalFood;
660
+ ctx.shadowColor = 'rgba(255, 62, 62, 0.7)';
661
+ }
662
+
663
+ // Draw rotating diamond shape
664
+ const centerX = food.x * gridSize + gridSize / 2;
665
+ const centerY = food.y * gridSize + gridSize / 2;
666
+ const size = gridSize - 4;
667
+ const rotation = (Date.now() * 0.05) % 360;
668
+
669
+ ctx.save();
670
+ ctx.translate(centerX, centerY);
671
+ ctx.rotate(rotation * Math.PI / 180);
672
+
673
+ ctx.beginPath();
674
+ ctx.moveTo(0, -size/2);
675
+ ctx.lineTo(size/2, 0);
676
+ ctx.lineTo(0, size/2);
677
+ ctx.lineTo(-size/2, 0);
678
+ ctx.closePath();
679
+ ctx.fill();
680
+
681
+ ctx.restore();
682
+ ctx.shadowBlur = 0;
683
+ }
684
+
685
+ // Draw power-up
686
+ function drawPowerUp() {
687
+ if (!powerUp) return;
688
+
689
+ ctx.shadowBlur = 20;
690
+ ctx.shadowColor = 'rgba(255, 255, 255, 0.8)';
691
+
692
+ const size = gridSize - 4;
693
+ const centerX = powerUp.x * gridSize + gridSize / 2;
694
+ const centerY = powerUp.y * gridSize + gridSize / 2;
695
+
696
+ // Draw pulsing star
697
+ const pulse = 0.8 + 0.2 * Math.sin(Date.now() * 0.01);
698
+
699
+ ctx.save();
700
+ ctx.translate(centerX, centerY);
701
+ ctx.scale(pulse, pulse);
702
+
703
+ ctx.fillStyle = 'rgba(255, 215, 0, 0.8)';
704
+
705
+ // Draw star shape
706
+ ctx.beginPath();
707
+ for (let i = 0; i < 5; i++) {
708
+ const angle = (i * 2 * Math.PI / 5) - Math.PI/2;
709
+ const outerX = Math.cos(angle) * size/2;
710
+ const outerY = Math.sin(angle) * size/2;
711
+ const innerX = Math.cos(angle + Math.PI/5) * size/4;
712
+ const innerY = Math.sin(angle + Math.PI/5) * size/4;
713
+
714
+ if (i === 0) ctx.moveTo(outerX, outerY);
715
+ else ctx.lineTo(outerX, outerY);
716
+
717
+ ctx.lineTo(innerX, innerY);
718
+ }
719
+ ctx.closePath();
720
+ ctx.fill();
721
+
722
+ ctx.restore();
723
+ ctx.shadowBlur = 0;
724
+ }
725
+
726
+ // Spawn food at random location
727
+ function spawnFood() {
728
+ // Decide food type randomly
729
+ const r = Math.random();
730
+
731
+ if (r < 0.1) {
732
+ foodType = 'power'; // 10% chance
733
+ } else if (r < 0.2) {
734
+ foodType = 'speed'; // 10% chance
735
+ } else if (r < 0.25) {
736
+ foodType = 'invincible'; // 5% chance
737
+ } else {
738
+ foodType = 'normal'; // 75% chance
739
+ }
740
+
741
+ // Find empty spot
742
+ let emptySpot = false;
743
+ let foodX, foodY;
744
+
745
+ while (!emptySpot) {
746
+ foodX = Math.floor(Math.random() * tileCountX);
747
+ foodY = Math.floor(Math.random() * tileCountY);
748
+
749
+ emptySpot = true;
750
+
751
+ // Check if spot is occupied by snake
752
+ for (let i = 0; i < snake.length; i++) {
753
+ if (snake[i].x === foodX && snake[i].y === foodY) {
754
+ emptySpot = false;
755
+ break;
756
+ }
757
+ }
758
+
759
+ // Check if spot is occupied by power-up
760
+ if (powerUp && powerUp.x === foodX && powerUp.y === foodY) {
761
+ emptySpot = false;
762
+ }
763
+ }
764
+
765
+ food = {
766
+ x: foodX,
767
+ y: foodY
768
+ };
769
+ }
770
+
771
+ // Spawn power-up
772
+ function spawnPowerUp() {
773
+ let emptySpot = false;
774
+ let puX, puY;
775
+
776
+ while (!emptySpot) {
777
+ puX = Math.floor(Math.random() * tileCountX);
778
+ puY = Math.floor(Math.random() * tileCountY);
779
+
780
+ emptySpot = true;
781
+
782
+ // Check if spot is occupied by snake
783
+ for (let i = 0; i < snake.length; i++) {
784
+ if (snake[i].x === puX && snake[i].y === puY) {
785
+ emptySpot = false;
786
+ break;
787
+ }
788
+ }
789
+
790
+ // Check if spot is occupied by food
791
+ if (food.x === puX && food.y === puY) {
792
+ emptySpot = false;
793
+ }
794
+ }
795
+
796
+ powerUp = {
797
+ x: puX,
798
+ y: puY
799
+ };
800
+
801
+ powerUpTime = Date.now();
802
+ }
803
+
804
+ // Update score display
805
+ function updateScore() {
806
+ gameScore.textContent = score;
807
+ }
808
+
809
+ // Game over
810
+ function gameOver() {
811
+ gameRunning = false;
812
+ clearTimeout(gameLoop);
813
+
814
+ // Create explosion effect
815
+ for (let i = 0; i < snake.length; i++) {
816
+ setTimeout(() => {
817
+ createSparkles(
818
+ snake[i].x * gridSize + gridSize/2,
819
+ snake[i].y * gridSize + gridSize/2,
820
+ 'explosion'
821
+ );
822
+ }, i * 50);
823
+ }
824
+
825
+ // Show game over screen
826
+ setTimeout(() => {
827
+ finalScore.textContent = score;
828
+ gameOverScreen.classList.remove('hidden');
829
+ scoreDisplay.classList.add('hidden');
830
+ document.querySelector('.power-ups').classList.add('hidden');
831
+ document.querySelector('.controls').classList.add('hidden');
832
+ }, 500);
833
+ }
834
+
835
+ // Create sparkle effects
836
+ function createSparkles(x, y, type) {
837
+ const colors = {
838
+ normal: ['#ff3e3e', '#ff7b7b', '#ff9999'],
839
+ power: ['#FFD700', '#FFEE58', '#FFF59D'],
840
+ speed: ['#ff00ff', '#ff66ff', '#ff99ff'],
841
+ invincible: ['#00ffff', '#66ffff', '#99ffff'],
842
+ explosion: ['#ff0000', '#ff6600', '#ffff00']
843
+ };
844
+
845
+ const sparkleCount = type === 'explosion' ? 30 : 15;
846
+ const sparkleSize = type === 'explosion' ? 6 : 4;
847
+ const lifetime = type === 'explosion' ? '1s' : '0.8s';
848
+
849
+ for (let i = 0; i < sparkleCount; i++) {
850
+ const sparkle = document.createElement('div');
851
+ sparkle.className = 'sparkle';
852
+
853
+ // Random properties for each sparkle
854
+ const angle = Math.random() * Math.PI * 2;
855
+ const distance = Math.random() * 30 + 20;
856
+ const tx = Math.cos(angle) * distance;
857
+ const ty = Math.sin(angle) * distance;
858
+ const size = Math.random() * sparkleSize + sparkleSize/2;
859
+ const delay = Math.random() * 0.2;
860
+ const color = colors[type][Math.floor(Math.random() * colors[type].length)];
861
+
862
+ sparkle.style.setProperty('--tx', tx + 'px');
863
+ sparkle.style.setProperty('--ty', ty + 'px');
864
+ sparkle.style.width = size + 'px';
865
+ sparkle.style.height = size + 'px';
866
+ sparkle.style.background = color;
867
+ sparkle.style.left = x + 'px';
868
+ sparkle.style.top = y + 'px';
869
+ sparkle.style.animation = `sparkle ${lifetime} ${delay}s forwards`;
870
+
871
+ document.body.appendChild(sparkle);
872
+
873
+ // Remove sparkle after animation
874
+ setTimeout(() => {
875
+ sparkle.remove();
876
+ }, 1000);
877
+ }
878
+ }
879
+
880
+ // Event listeners
881
+ startBtn.addEventListener('click', () => {
882
+ initGame();
883
+ gameUpdate();
884
+ });
885
+
886
+ restartBtn.addEventListener('click', () => {
887
+ initGame();
888
+ gameUpdate();
889
+ });
890
+
891
+ howToPlayBtn.addEventListener('click', () => {
892
+ startScreen.classList.add('hidden');
893
+ instructionsScreen.classList.remove('hidden');
894
+ });
895
+
896
+ backBtn.addEventListener('click', () => {
897
+ instructionsScreen.classList.add('hidden');
898
+ startScreen.classList.remove('hidden');
899
+ });
900
+
901
+ // Keyboard controls
902
+ document.addEventListener('keydown', (e) => {
903
+ if (!gameRunning) return;
904
+
905
+ switch (e.key) {
906
+ case 'ArrowUp':
907
+ if (direction !== 'down') nextDirection = 'up';
908
+ break;
909
+ case 'ArrowDown':
910
+ if (direction !== 'up') nextDirection = 'down';
911
+ break;
912
+ case 'ArrowLeft':
913
+ if (direction !== 'right') nextDirection = 'left';
914
+ break;
915
+ case 'ArrowRight':
916
+ if (direction !== 'left') nextDirection = 'right';
917
+ break;
918
+ }
919
+ });
920
+
921
+ // Touch controls
922
+ upBtn.addEventListener('click', () => {
923
+ if (gameRunning && direction !== 'down') nextDirection = 'up';
924
+ });
925
+
926
+ leftBtn.addEventListener('click', () => {
927
+ if (gameRunning && direction !== 'right') nextDirection = 'left';
928
+ });
929
+
930
+ downBtn.addEventListener('click', () => {
931
+ if (gameRunning && direction !== 'up') nextDirection = 'down';
932
+ });
933
+
934
+ rightBtn.addEventListener('click', () => {
935
+ if (gameRunning && direction !== 'left') nextDirection = 'right';
936
+ });
937
+
938
+ // Handle window resize
939
+ window.addEventListener('resize', () => {
940
+ const container = canvas.parentElement;
941
+ canvas.width = container.offsetWidth;
942
+ canvas.height = container.offsetHeight;
943
+
944
+ // Recalculate tile counts
945
+ tileCountX = Math.floor(canvas.width / gridSize);
946
+ tileCountY = Math.floor(canvas.height / gridSize);
947
+ });
948
+ });
949
+ </script>
950
+ <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>
951
+ </html>