FriedsU commited on
Commit
a80016c
·
verified ·
1 Parent(s): c00679a

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +632 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Tetris
3
- emoji: 📈
4
  colorFrom: gray
5
- colorTo: red
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: tetris
3
+ emoji: 🐳
4
  colorFrom: gray
5
+ colorTo: green
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,632 @@
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 Tetris</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
10
+
11
+ body {
12
+ font-family: 'Press Start 2P', cursive;
13
+ background-color: #0f172a;
14
+ overflow: hidden;
15
+ }
16
+
17
+ .tetris-block {
18
+ box-sizing: border-box;
19
+ border: 2px solid rgba(255, 255, 255, 0.1);
20
+ transition: all 0.1s ease;
21
+ }
22
+
23
+ .tetris-block.I {
24
+ background-color: #00f0f0;
25
+ box-shadow: inset 0 0 10px rgba(0, 240, 240, 0.5), 0 0 10px rgba(0, 240, 240, 0.5);
26
+ }
27
+
28
+ .tetris-block.J {
29
+ background-color: #0000f0;
30
+ box-shadow: inset 0 0 10px rgba(0, 0, 240, 0.5), 0 0 10px rgba(0, 0, 240, 0.5);
31
+ }
32
+
33
+ .tetris-block.L {
34
+ background-color: #f0a000;
35
+ box-shadow: inset 0 0 10px rgba(240, 160, 0, 0.5), 0 0 10px rgba(240, 160, 0, 0.5);
36
+ }
37
+
38
+ .tetris-block.O {
39
+ background-color: #f0f000;
40
+ box-shadow: inset 0 0 10px rgba(240, 240, 0, 0.5), 0 0 10px rgba(240, 240, 0, 0.5);
41
+ }
42
+
43
+ .tetris-block.S {
44
+ background-color: #00f000;
45
+ box-shadow: inset 0 0 10px rgba(0, 240, 0, 0.5), 0 0 10px rgba(0, 240, 0, 0.5);
46
+ }
47
+
48
+ .tetris-block.T {
49
+ background-color: #a000f0;
50
+ box-shadow: inset 0 0 10px rgba(160, 0, 240, 0.5), 0 0 10px rgba(160, 0, 240, 0.5);
51
+ }
52
+
53
+ .tetris-block.Z {
54
+ background-color: #f00000;
55
+ box-shadow: inset 0 0 10px rgba(240, 0, 0, 0.5), 0 0 10px rgba(240, 0, 0, 0.5);
56
+ }
57
+
58
+ .grid-cell {
59
+ background-color: rgba(30, 41, 59, 0.5);
60
+ border: 1px solid rgba(255, 255, 255, 0.05);
61
+ }
62
+
63
+ .next-piece-container {
64
+ background-color: rgba(30, 41, 59, 0.7);
65
+ border: 2px solid rgba(255, 255, 255, 0.1);
66
+ }
67
+
68
+ .game-overlay {
69
+ background-color: rgba(15, 23, 42, 0.9);
70
+ }
71
+
72
+ @keyframes pulse {
73
+ 0% { transform: scale(1); }
74
+ 50% { transform: scale(1.05); }
75
+ 100% { transform: scale(1); }
76
+ }
77
+
78
+ .pulse {
79
+ animation: pulse 1.5s infinite;
80
+ }
81
+
82
+ /* New styles for next piece preview */
83
+ .next-piece-grid {
84
+ display: grid;
85
+ width: 100px;
86
+ height: 100px;
87
+ position: relative;
88
+ }
89
+
90
+ .next-piece-inner {
91
+ position: absolute;
92
+ display: grid;
93
+ gap: 0;
94
+ }
95
+
96
+ .next-piece-cell {
97
+ width: 100%;
98
+ height: 100%;
99
+ }
100
+ </style>
101
+ </head>
102
+ <body class="min-h-screen flex flex-col items-center justify-center text-white p-4">
103
+ <div class="text-center mb-6">
104
+ <h1 class="text-4xl md:text-5xl font-bold mb-2 text-transparent bg-clip-text bg-gradient-to-r from-purple-400 via-pink-500 to-red-500">
105
+ NEON TETRIS
106
+ </h1>
107
+ <p class="text-sm text-gray-400">Use arrow keys to play • ↑ to rotate • ↓ to drop faster</p>
108
+ </div>
109
+
110
+ <div class="flex flex-col md:flex-row items-center gap-8">
111
+ <!-- Game Board -->
112
+ <div class="relative">
113
+ <div id="game-board" class="grid grid-cols-10 grid-rows-20 gap-0 w-[250px] h-[500px] border-4 border-indigo-500/50 rounded-lg overflow-hidden"></div>
114
+ <div id="game-overlay" class="game-overlay absolute inset-0 flex flex-col items-center justify-center hidden">
115
+ <h2 class="text-3xl font-bold mb-4 text-red-500">GAME OVER</h2>
116
+ <button id="restart-btn" class="px-6 py-3 bg-indigo-600 hover:bg-indigo-700 rounded-lg font-bold transition-all pulse">
117
+ PLAY AGAIN
118
+ </button>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- Game Info -->
123
+ <div class="flex flex-col gap-6 w-full max-w-[250px]">
124
+ <div class="next-piece-container p-4 rounded-lg">
125
+ <h3 class="text-center text-lg mb-3">NEXT PIECE</h3>
126
+ <div id="next-piece" class="next-piece-grid">
127
+ <div id="next-piece-inner" class="next-piece-inner"></div>
128
+ </div>
129
+ </div>
130
+
131
+ <div class="bg-slate-800/50 p-4 rounded-lg">
132
+ <div class="flex justify-between mb-2">
133
+ <span>SCORE:</span>
134
+ <span id="score" class="font-bold">0</span>
135
+ </div>
136
+ <div class="flex justify-between mb-2">
137
+ <span>LEVEL:</span>
138
+ <span id="level" class="font-bold">1</span>
139
+ </div>
140
+ <div class="flex justify-between">
141
+ <span>LINES:</span>
142
+ <span id="lines" class="font-bold">0</span>
143
+ </div>
144
+ </div>
145
+
146
+ <div class="bg-slate-800/50 p-4 rounded-lg hidden md:block">
147
+ <h3 class="text-center text-lg mb-2">CONTROLS</h3>
148
+ <div class="grid grid-cols-3 gap-2 text-xs">
149
+ <div class="col-span-3 flex justify-center">
150
+ <div class="bg-slate-700/50 p-2 rounded text-center">↑ Rotate</div>
151
+ </div>
152
+ <div class="flex justify-center">
153
+ <div class="bg-slate-700/50 p-2 rounded text-center">← Left</div>
154
+ </div>
155
+ <div class="flex justify-center">
156
+ <div class="bg-slate-700/50 p-2 rounded text-center">↓ Drop</div>
157
+ </div>
158
+ <div class="flex justify-center">
159
+ <div class="bg-slate-700/50 p-2 rounded text-center">→ Right</div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+
166
+ <div class="mt-8 text-xs text-gray-500 text-center">
167
+ <p>Press any key to start • P to pause</p>
168
+ </div>
169
+
170
+ <script>
171
+ document.addEventListener('DOMContentLoaded', () => {
172
+ // Game constants
173
+ const COLS = 10;
174
+ const ROWS = 20;
175
+ const BLOCK_SIZE = 25;
176
+ const EMPTY = 'empty';
177
+
178
+ // Game variables
179
+ let board = createEmptyBoard();
180
+ let currentPiece = null;
181
+ let nextPiece = null;
182
+ let score = 0;
183
+ let level = 1;
184
+ let lines = 0;
185
+ let gameOver = false;
186
+ let isPaused = false;
187
+ let dropInterval = null;
188
+ let dropSpeed = 1000; // Initial speed (ms)
189
+
190
+ // DOM elements
191
+ const gameBoard = document.getElementById('game-board');
192
+ const nextPieceDisplay = document.getElementById('next-piece-inner');
193
+ const scoreDisplay = document.getElementById('score');
194
+ const levelDisplay = document.getElementById('level');
195
+ const linesDisplay = document.getElementById('lines');
196
+ const gameOverlay = document.getElementById('game-overlay');
197
+ const restartBtn = document.getElementById('restart-btn');
198
+
199
+ // Initialize the game board display
200
+ function initializeBoard() {
201
+ gameBoard.innerHTML = '';
202
+ for (let row = 0; row < ROWS; row++) {
203
+ for (let col = 0; col < COLS; col++) {
204
+ const cell = document.createElement('div');
205
+ cell.className = 'grid-cell w-full h-full';
206
+ cell.dataset.row = row;
207
+ cell.dataset.col = col;
208
+ gameBoard.appendChild(cell);
209
+ }
210
+ }
211
+ }
212
+
213
+ // Create empty game board
214
+ function createEmptyBoard() {
215
+ return Array.from({ length: ROWS }, () => Array(COLS).fill(EMPTY));
216
+ }
217
+
218
+ // Tetromino shapes
219
+ const SHAPES = {
220
+ I: [
221
+ [0, 0, 0, 0],
222
+ [1, 1, 1, 1],
223
+ [0, 0, 0, 0],
224
+ [0, 0, 0, 0]
225
+ ],
226
+ J: [
227
+ [1, 0, 0],
228
+ [1, 1, 1],
229
+ [0, 0, 0]
230
+ ],
231
+ L: [
232
+ [0, 0, 1],
233
+ [1, 1, 1],
234
+ [0, 0, 0]
235
+ ],
236
+ O: [
237
+ [1, 1],
238
+ [1, 1]
239
+ ],
240
+ S: [
241
+ [0, 1, 1],
242
+ [1, 1, 0],
243
+ [0, 0, 0]
244
+ ],
245
+ T: [
246
+ [0, 1, 0],
247
+ [1, 1, 1],
248
+ [0, 0, 0]
249
+ ],
250
+ Z: [
251
+ [1, 1, 0],
252
+ [0, 1, 1],
253
+ [0, 0, 0]
254
+ ]
255
+ };
256
+
257
+ // Tetromino colors
258
+ const COLORS = {
259
+ I: 'I',
260
+ J: 'J',
261
+ L: 'L',
262
+ O: 'O',
263
+ S: 'S',
264
+ T: 'T',
265
+ Z: 'Z'
266
+ };
267
+
268
+ // Get random tetromino
269
+ function getRandomPiece() {
270
+ const pieces = Object.keys(SHAPES);
271
+ const randomPiece = pieces[Math.floor(Math.random() * pieces.length)];
272
+ return {
273
+ shape: SHAPES[randomPiece],
274
+ color: COLORS[randomPiece],
275
+ x: Math.floor(COLS / 2) - Math.floor(SHAPES[randomPiece][0].length / 2),
276
+ y: 0
277
+ };
278
+ }
279
+
280
+ // Draw the game board
281
+ function drawBoard() {
282
+ // Clear the board
283
+ document.querySelectorAll('#game-board div').forEach(cell => {
284
+ cell.className = 'grid-cell w-full h-full';
285
+ });
286
+
287
+ // Draw locked pieces
288
+ for (let row = 0; row < ROWS; row++) {
289
+ for (let col = 0; col < COLS; col++) {
290
+ if (board[row][col] !== EMPTY) {
291
+ const cell = document.querySelector(`#game-board div[data-row="${row}"][data-col="${col}"]`);
292
+ if (cell) {
293
+ cell.className = `tetris-block ${board[row][col]} w-full h-full`;
294
+ }
295
+ }
296
+ }
297
+ }
298
+
299
+ // Draw current piece
300
+ if (currentPiece) {
301
+ for (let row = 0; row < currentPiece.shape.length; row++) {
302
+ for (let col = 0; col < currentPiece.shape[row].length; col++) {
303
+ if (currentPiece.shape[row][col]) {
304
+ const boardRow = currentPiece.y + row;
305
+ const boardCol = currentPiece.x + col;
306
+ if (boardRow >= 0 && boardRow < ROWS && boardCol >= 0 && boardCol < COLS) {
307
+ const cell = document.querySelector(`#game-board div[data-row="${boardRow}"][data-col="${boardCol}"]`);
308
+ if (cell) {
309
+ cell.className = `tetris-block ${currentPiece.color} w-full h-full`;
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ // Draw next piece preview
319
+ function drawNextPiece() {
320
+ if (!nextPiece) return;
321
+
322
+ // Clear the preview
323
+ nextPieceDisplay.innerHTML = '';
324
+
325
+ // Set up the grid based on the piece dimensions
326
+ const rows = nextPiece.shape.length;
327
+ const cols = nextPiece.shape[0].length;
328
+
329
+ // Calculate cell size to fit in the 100x100 container
330
+ const cellSize = Math.min(100 / cols, 100 / rows);
331
+ const containerWidth = cellSize * cols;
332
+ const containerHeight = cellSize * rows;
333
+
334
+ // Position the inner container in the center
335
+ nextPieceDisplay.style.gridTemplateColumns = `repeat(${cols}, ${cellSize}px)`;
336
+ nextPieceDisplay.style.gridTemplateRows = `repeat(${rows}, ${cellSize}px)`;
337
+ nextPieceDisplay.style.width = `${containerWidth}px`;
338
+ nextPieceDisplay.style.height = `${containerHeight}px`;
339
+ nextPieceDisplay.style.left = `${(100 - containerWidth) / 2}px`;
340
+ nextPieceDisplay.style.top = `${(100 - containerHeight) / 2}px`;
341
+
342
+ // Draw the piece
343
+ for (let row = 0; row < rows; row++) {
344
+ for (let col = 0; col < cols; col++) {
345
+ const cell = document.createElement('div');
346
+ if (nextPiece.shape[row][col]) {
347
+ cell.className = `tetris-block ${nextPiece.color} next-piece-cell`;
348
+ } else {
349
+ cell.className = 'next-piece-cell opacity-0';
350
+ }
351
+ nextPieceDisplay.appendChild(cell);
352
+ }
353
+ }
354
+ }
355
+
356
+ // Check for collisions
357
+ function collision(x, y, shape) {
358
+ for (let row = 0; row < shape.length; row++) {
359
+ for (let col = 0; col < shape[row].length; col++) {
360
+ if (shape[row][col]) {
361
+ const newX = x + col;
362
+ const newY = y + row;
363
+
364
+ // Check boundaries
365
+ if (newX < 0 || newX >= COLS || newY >= ROWS) {
366
+ return true;
367
+ }
368
+
369
+ // Check if already locked
370
+ if (newY >= 0 && board[newY][newX] !== EMPTY) {
371
+ return true;
372
+ }
373
+ }
374
+ }
375
+ }
376
+ return false;
377
+ }
378
+
379
+ // Rotate piece
380
+ function rotatePiece() {
381
+ if (!currentPiece || gameOver || isPaused) return;
382
+
383
+ const newShape = [];
384
+ for (let col = currentPiece.shape[0].length - 1; col >= 0; col--) {
385
+ const newRow = [];
386
+ for (let row = 0; row < currentPiece.shape.length; row++) {
387
+ newRow.push(currentPiece.shape[row][col]);
388
+ }
389
+ newShape.push(newRow);
390
+ }
391
+
392
+ // Check if rotation is possible
393
+ if (!collision(currentPiece.x, currentPiece.y, newShape)) {
394
+ currentPiece.shape = newShape;
395
+ drawBoard();
396
+ }
397
+ }
398
+
399
+ // Move piece left
400
+ function moveLeft() {
401
+ if (!currentPiece || gameOver || isPaused) return;
402
+
403
+ if (!collision(currentPiece.x - 1, currentPiece.y, currentPiece.shape)) {
404
+ currentPiece.x--;
405
+ drawBoard();
406
+ }
407
+ }
408
+
409
+ // Move piece right
410
+ function moveRight() {
411
+ if (!currentPiece || gameOver || isPaused) return;
412
+
413
+ if (!collision(currentPiece.x + 1, currentPiece.y, currentPiece.shape)) {
414
+ currentPiece.x++;
415
+ drawBoard();
416
+ }
417
+ }
418
+
419
+ // Move piece down
420
+ function moveDown() {
421
+ if (!currentPiece || gameOver || isPaused) return;
422
+
423
+ if (!collision(currentPiece.x, currentPiece.y + 1, currentPiece.shape)) {
424
+ currentPiece.y++;
425
+ drawBoard();
426
+ } else {
427
+ lockPiece();
428
+ }
429
+ }
430
+
431
+ // Drop piece instantly
432
+ function dropPiece() {
433
+ if (!currentPiece || gameOver || isPaused) return;
434
+
435
+ while (!collision(currentPiece.x, currentPiece.y + 1, currentPiece.shape)) {
436
+ currentPiece.y++;
437
+ }
438
+ lockPiece();
439
+ drawBoard();
440
+ }
441
+
442
+ // Lock piece in place
443
+ function lockPiece() {
444
+ if (!currentPiece) return;
445
+
446
+ // Add piece to the board
447
+ for (let row = 0; row < currentPiece.shape.length; row++) {
448
+ for (let col = 0; col < currentPiece.shape[row].length; col++) {
449
+ if (currentPiece.shape[row][col]) {
450
+ const boardRow = currentPiece.y + row;
451
+ const boardCol = currentPiece.x + col;
452
+
453
+ if (boardRow >= 0 && boardRow < ROWS && boardCol >= 0 && boardCol < COLS) {
454
+ board[boardRow][boardCol] = currentPiece.color;
455
+ }
456
+ }
457
+ }
458
+ }
459
+
460
+ // Check for completed lines
461
+ checkLines();
462
+
463
+ // Check for game over
464
+ if (currentPiece.y <= 0) {
465
+ gameOver = true;
466
+ clearInterval(dropInterval);
467
+ gameOverlay.classList.remove('hidden');
468
+ return;
469
+ }
470
+
471
+ // Get next piece
472
+ currentPiece = nextPiece;
473
+ nextPiece = getRandomPiece();
474
+ drawNextPiece();
475
+ }
476
+
477
+ // Check for completed lines
478
+ function checkLines() {
479
+ let linesCleared = 0;
480
+
481
+ for (let row = ROWS - 1; row >= 0; row--) {
482
+ if (board[row].every(cell => cell !== EMPTY)) {
483
+ // Remove the line
484
+ board.splice(row, 1);
485
+ // Add new empty line at the top
486
+ board.unshift(Array(COLS).fill(EMPTY));
487
+ linesCleared++;
488
+ row++; // Check the same row again
489
+ }
490
+ }
491
+
492
+ if (linesCleared > 0) {
493
+ // Update score
494
+ const points = [0, 40, 100, 300, 1200][linesCleared] * level;
495
+ score += points;
496
+ lines += linesCleared;
497
+
498
+ // Update level every 10 lines
499
+ const newLevel = Math.floor(lines / 10) + 1;
500
+ if (newLevel > level) {
501
+ level = newLevel;
502
+ // Increase speed
503
+ dropSpeed = Math.max(100, 1000 - (level - 1) * 100);
504
+ clearInterval(dropInterval);
505
+ dropInterval = setInterval(moveDown, dropSpeed);
506
+ }
507
+
508
+ updateStats();
509
+ }
510
+ }
511
+
512
+ // Update score, level, and lines
513
+ function updateStats() {
514
+ scoreDisplay.textContent = score;
515
+ levelDisplay.textContent = level;
516
+ linesDisplay.textContent = lines;
517
+ }
518
+
519
+ // Start the game
520
+ function startGame() {
521
+ board = createEmptyBoard();
522
+ score = 0;
523
+ level = 1;
524
+ lines = 0;
525
+ gameOver = false;
526
+ isPaused = false;
527
+ dropSpeed = 1000;
528
+
529
+ updateStats();
530
+
531
+ currentPiece = getRandomPiece();
532
+ nextPiece = getRandomPiece();
533
+
534
+ drawBoard();
535
+ drawNextPiece();
536
+
537
+ gameOverlay.classList.add('hidden');
538
+
539
+ clearInterval(dropInterval);
540
+ dropInterval = setInterval(moveDown, dropSpeed);
541
+ }
542
+
543
+ // Pause the game
544
+ function togglePause() {
545
+ if (gameOver) return;
546
+
547
+ isPaused = !isPaused;
548
+
549
+ if (isPaused) {
550
+ clearInterval(dropInterval);
551
+ document.querySelector('h1').textContent = 'PAUSED';
552
+ } else {
553
+ dropInterval = setInterval(moveDown, dropSpeed);
554
+ document.querySelector('h1').textContent = 'NEON TETRIS';
555
+ }
556
+ }
557
+
558
+ // Event listeners
559
+ document.addEventListener('keydown', (e) => {
560
+ if (gameOver && e.key === ' ') {
561
+ startGame();
562
+ return;
563
+ }
564
+
565
+ switch (e.key) {
566
+ case 'ArrowLeft':
567
+ moveLeft();
568
+ break;
569
+ case 'ArrowRight':
570
+ moveRight();
571
+ break;
572
+ case 'ArrowDown':
573
+ moveDown();
574
+ break;
575
+ case 'ArrowUp':
576
+ rotatePiece();
577
+ break;
578
+ case ' ':
579
+ dropPiece();
580
+ break;
581
+ case 'p':
582
+ case 'P':
583
+ togglePause();
584
+ break;
585
+ }
586
+ });
587
+
588
+ restartBtn.addEventListener('click', startGame);
589
+
590
+ // Touch controls for mobile
591
+ let touchStartX = 0;
592
+ let touchStartY = 0;
593
+
594
+ gameBoard.addEventListener('touchstart', (e) => {
595
+ touchStartX = e.touches[0].clientX;
596
+ touchStartY = e.touches[0].clientY;
597
+ }, false);
598
+
599
+ gameBoard.addEventListener('touchend', (e) => {
600
+ if (!touchStartX || !touchStartY || gameOver || isPaused) return;
601
+
602
+ const touchEndX = e.changedTouches[0].clientX;
603
+ const touchEndY = e.changedTouches[0].clientY;
604
+
605
+ const diffX = touchStartX - touchEndX;
606
+ const diffY = touchStartY - touchEndY;
607
+
608
+ // Swipe left
609
+ if (diffX > 50 && Math.abs(diffY) < 100) {
610
+ moveLeft();
611
+ }
612
+ // Swipe right
613
+ else if (diffX < -50 && Math.abs(diffY) < 100) {
614
+ moveRight();
615
+ }
616
+ // Swipe down
617
+ else if (diffY < -50 && Math.abs(diffX) < 100) {
618
+ dropPiece();
619
+ }
620
+ // Swipe up or tap
621
+ else if (Math.abs(diffX) < 50 && Math.abs(diffY) < 50) {
622
+ rotatePiece();
623
+ }
624
+ }, false);
625
+
626
+ // Initialize the game
627
+ initializeBoard();
628
+ startGame();
629
+ });
630
+ </script>
631
+ <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=FriedsU/tetris" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
632
+ </html>