ysharma HF Staff commited on
Commit
7521e29
·
verified ·
1 Parent(s): b9760af

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +631 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Modern Tetris Vibe Coded
3
- emoji:
4
- colorFrom: green
5
  colorTo: purple
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: modern-tetris-vibe-coded
3
+ emoji: 🐳
4
+ colorFrom: red
5
  colorTo: purple
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,631 @@
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>Modern Tetris</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
+ @keyframes flash {
11
+ 0%, 100% { opacity: 1; }
12
+ 50% { opacity: 0.5; }
13
+ }
14
+
15
+ .flash-animation {
16
+ animation: flash 0.3s ease-in-out 3;
17
+ }
18
+
19
+ .game-container {
20
+ perspective: 1000px;
21
+ }
22
+
23
+ .tetris-block {
24
+ box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.3);
25
+ transition: all 0.1s ease;
26
+ }
27
+
28
+ .tetris-block.active {
29
+ transform: scale(0.95);
30
+ }
31
+
32
+ .next-piece-container {
33
+ background: rgba(255, 255, 255, 0.1);
34
+ border-radius: 10px;
35
+ }
36
+ </style>
37
+ </head>
38
+ <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
39
+ <div class="max-w-4xl w-full">
40
+ <h1 class="text-4xl font-bold text-center mb-6 text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">
41
+ <i class="fas fa-gamepad mr-2"></i> Modern Tetris
42
+ </h1>
43
+
44
+ <div class="flex flex-col md:flex-row gap-8 items-center justify-center">
45
+ <!-- Game Board -->
46
+ <div class="game-container relative">
47
+ <div class="bg-gray-800 rounded-lg overflow-hidden shadow-2xl">
48
+ <canvas id="tetris" width="300" height="600" class="block"></canvas>
49
+ </div>
50
+
51
+ <!-- Game Over Overlay -->
52
+ <div id="gameOver" class="absolute inset-0 bg-black bg-opacity-70 flex flex-col items-center justify-center hidden">
53
+ <h2 class="text-4xl font-bold mb-4 text-red-500">Game Over!</h2>
54
+ <p class="text-xl mb-6">Your score: <span id="finalScore">0</span></p>
55
+ <button id="restartBtn" class="px-6 py-3 bg-gradient-to-r from-purple-500 to-pink-600 rounded-full font-bold hover:opacity-90 transition">
56
+ <i class="fas fa-redo mr-2"></i> Play Again
57
+ </button>
58
+ </div>
59
+
60
+ <!-- Pause Overlay -->
61
+ <div id="pauseScreen" class="absolute inset-0 bg-black bg-opacity-70 flex flex-col items-center justify-center hidden">
62
+ <h2 class="text-4xl font-bold mb-4 text-yellow-400">Paused</h2>
63
+ <button id="resumeBtn" class="px-6 py-3 bg-gradient-to-r from-blue-500 to-teal-400 rounded-full font-bold hover:opacity-90 transition">
64
+ <i class="fas fa-play mr-2"></i> Resume
65
+ </button>
66
+ </div>
67
+ </div>
68
+
69
+ <!-- Game Info -->
70
+ <div class="flex flex-col gap-6 w-full md:w-auto">
71
+ <!-- Score and Level -->
72
+ <div class="bg-gray-800 p-6 rounded-xl shadow-lg">
73
+ <div class="flex justify-between items-center mb-4">
74
+ <div>
75
+ <p class="text-gray-400">Score</p>
76
+ <p id="score" class="text-3xl font-bold">0</p>
77
+ </div>
78
+ <div>
79
+ <p class="text-gray-400">Level</p>
80
+ <p id="level" class="text-3xl font-bold">1</p>
81
+ </div>
82
+ </div>
83
+ <div class="flex justify-between items-center">
84
+ <div>
85
+ <p class="text-gray-400">Lines</p>
86
+ <p id="lines" class="text-3xl font-bold">0</p>
87
+ </div>
88
+ <div>
89
+ <p class="text-gray-400">High Score</p>
90
+ <p id="highScore" class="text-3xl font-bold">0</p>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- Next Piece -->
96
+ <div class="bg-gray-800 p-6 rounded-xl shadow-lg">
97
+ <h3 class="text-xl font-bold mb-4 text-center">Next Piece</h3>
98
+ <div class="next-piece-container p-4 flex justify-center">
99
+ <canvas id="nextPiece" width="120" height="120" class="block"></canvas>
100
+ </div>
101
+ </div>
102
+
103
+ <!-- Controls -->
104
+ <div class="bg-gray-800 p-6 rounded-xl shadow-lg">
105
+ <h3 class="text-xl font-bold mb-4 text-center">Controls</h3>
106
+ <div class="grid grid-cols-3 gap-3 text-center">
107
+ <div class="bg-gray-700 p-3 rounded-lg">
108
+ <div class="text-2xl mb-1"><i class="fas fa-arrow-up"></i></div>
109
+ <p class="text-sm">Rotate</p>
110
+ </div>
111
+ <div class="bg-gray-700 p-3 rounded-lg">
112
+ <div class="text-2xl mb-1"><i class="fas fa-arrow-left"></i></div>
113
+ <p class="text-sm">Left</p>
114
+ </div>
115
+ <div class="bg-gray-700 p-3 rounded-lg">
116
+ <div class="text-2xl mb-1"><i class="fas fa-arrow-right"></i></div>
117
+ <p class="text-sm">Right</p>
118
+ </div>
119
+ <div class="bg-gray-700 p-3 rounded-lg">
120
+ <div class="text-2xl mb-1"><i class="fas fa-arrow-down"></i></div>
121
+ <p class="text-sm">Down</p>
122
+ </div>
123
+ <div class="bg-gray-700 p-3 rounded-lg col-span-2">
124
+ <div class="text-2xl mb-1"><i class="fas fa-space-shuttle"></i></div>
125
+ <p class="text-sm">Hard Drop</p>
126
+ </div>
127
+ <div class="bg-gray-700 p-3 rounded-lg">
128
+ <div class="text-2xl mb-1"><i class="fas fa-pause"></i></div>
129
+ <p class="text-sm">Pause</p>
130
+ </div>
131
+ </div>
132
+ </div>
133
+
134
+ <!-- Game Buttons -->
135
+ <div class="flex gap-4">
136
+ <button id="startBtn" class="flex-1 px-6 py-3 bg-gradient-to-r from-green-500 to-emerald-600 rounded-full font-bold hover:opacity-90 transition">
137
+ <i class="fas fa-play mr-2"></i> Start
138
+ </button>
139
+ <button id="pauseBtn" class="flex-1 px-6 py-3 bg-gradient-to-r from-blue-500 to-teal-400 rounded-full font-bold hover:opacity-90 transition">
140
+ <i class="fas fa-pause mr-2"></i> Pause
141
+ </button>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+
147
+ <script>
148
+ document.addEventListener('DOMContentLoaded', () => {
149
+ // Game constants
150
+ const COLS = 10;
151
+ const ROWS = 20;
152
+ const BLOCK_SIZE = 30;
153
+ const COLORS = [
154
+ null,
155
+ '#FF0D72', // I - Pink
156
+ '#0DC2FF', // J - Blue
157
+ '#0DFF72', // L - Green
158
+ '#F538FF', // O - Purple
159
+ '#FF8E0D', // S - Orange
160
+ '#FFE138', // T - Yellow
161
+ '#3877FF' // Z - Dark Blue
162
+ ];
163
+
164
+ // Game variables
165
+ let canvas = document.getElementById('tetris');
166
+ let ctx = canvas.getContext('2d');
167
+ let nextPieceCanvas = document.getElementById('nextPiece');
168
+ let nextPieceCtx = nextPieceCanvas.getContext('2d');
169
+ let scoreElement = document.getElementById('score');
170
+ let linesElement = document.getElementById('lines');
171
+ let levelElement = document.getElementById('level');
172
+ let highScoreElement = document.getElementById('highScore');
173
+ let finalScoreElement = document.getElementById('finalScore');
174
+ let gameOverElement = document.getElementById('gameOver');
175
+ let pauseScreenElement = document.getElementById('pauseScreen');
176
+ let startBtn = document.getElementById('startBtn');
177
+ let pauseBtn = document.getElementById('pauseBtn');
178
+ let resumeBtn = document.getElementById('resumeBtn');
179
+ let restartBtn = document.getElementById('restartBtn');
180
+
181
+ // Scale canvas for high DPI displays
182
+ scaleCanvas();
183
+
184
+ let score = 0;
185
+ let lines = 0;
186
+ let level = 1;
187
+ let highScore = localStorage.getItem('tetrisHighScore') || 0;
188
+ let gameOver = true;
189
+ let paused = false;
190
+ let dropCounter = 0;
191
+ let dropInterval = 1000;
192
+ let lastTime = 0;
193
+ let animationId = null;
194
+
195
+ highScoreElement.textContent = highScore;
196
+
197
+ // Game board
198
+ const board = createMatrix(COLS, ROWS);
199
+
200
+ // Current piece
201
+ let player = {
202
+ pos: {x: 0, y: 0},
203
+ matrix: null,
204
+ next: null
205
+ };
206
+
207
+ // Tetromino shapes
208
+ const SHAPES = [
209
+ null,
210
+ [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], // I
211
+ [[2, 0, 0], [2, 2, 2], [0, 0, 0]], // J
212
+ [[0, 0, 3], [3, 3, 3], [0, 0, 0]], // L
213
+ [[0, 4, 4], [0, 4, 4], [0, 0, 0]], // O
214
+ [[0, 5, 5], [5, 5, 0], [0, 0, 0]], // S
215
+ [[0, 6, 0], [6, 6, 6], [0, 0, 0]], // T
216
+ [[7, 7, 0], [0, 7, 7], [0, 0, 0]] // Z
217
+ ];
218
+
219
+ // Event listeners
220
+ document.addEventListener('keydown', handleKeyPress);
221
+ startBtn.addEventListener('click', startGame);
222
+ pauseBtn.addEventListener('click', togglePause);
223
+ resumeBtn.addEventListener('click', togglePause);
224
+ restartBtn.addEventListener('click', startGame);
225
+
226
+ // Initialize the game
227
+ resetGame();
228
+ drawNextPiece();
229
+
230
+ // Game functions
231
+ function createMatrix(w, h) {
232
+ const matrix = [];
233
+ while (h--) {
234
+ matrix.push(new Array(w).fill(0));
235
+ }
236
+ return matrix;
237
+ }
238
+
239
+ function createPiece(type) {
240
+ return SHAPES[type];
241
+ }
242
+
243
+ function drawMatrix(matrix, offset) {
244
+ matrix.forEach((row, y) => {
245
+ row.forEach((value, x) => {
246
+ if (value !== 0) {
247
+ ctx.fillStyle = COLORS[value];
248
+ ctx.fillRect(
249
+ (x + offset.x) * BLOCK_SIZE,
250
+ (y + offset.y) * BLOCK_SIZE,
251
+ BLOCK_SIZE,
252
+ BLOCK_SIZE
253
+ );
254
+
255
+ // Add 3D effect
256
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
257
+ ctx.lineWidth = 2;
258
+ ctx.strokeRect(
259
+ (x + offset.x) * BLOCK_SIZE,
260
+ (y + offset.y) * BLOCK_SIZE,
261
+ BLOCK_SIZE,
262
+ BLOCK_SIZE
263
+ );
264
+
265
+ // Add inner highlight
266
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
267
+ ctx.fillRect(
268
+ (x + offset.x) * BLOCK_SIZE + 2,
269
+ (y + offset.y) * BLOCK_SIZE + 2,
270
+ BLOCK_SIZE - 4,
271
+ BLOCK_SIZE - 4
272
+ );
273
+ }
274
+ });
275
+ });
276
+ }
277
+
278
+ function drawNextPiece() {
279
+ nextPieceCtx.clearRect(0, 0, nextPieceCanvas.width, nextPieceCanvas.height);
280
+
281
+ if (player.next) {
282
+ const matrix = player.next;
283
+ const offsetX = (nextPieceCanvas.width / BLOCK_SIZE - matrix[0].length) / 2;
284
+ const offsetY = (nextPieceCanvas.height / BLOCK_SIZE - matrix.length) / 2;
285
+
286
+ matrix.forEach((row, y) => {
287
+ row.forEach((value, x) => {
288
+ if (value !== 0) {
289
+ nextPieceCtx.fillStyle = COLORS[value];
290
+ nextPieceCtx.fillRect(
291
+ (x + offsetX) * BLOCK_SIZE,
292
+ (y + offsetY) * BLOCK_SIZE,
293
+ BLOCK_SIZE,
294
+ BLOCK_SIZE
295
+ );
296
+
297
+ nextPieceCtx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
298
+ nextPieceCtx.lineWidth = 2;
299
+ nextPieceCtx.strokeRect(
300
+ (x + offsetX) * BLOCK_SIZE,
301
+ (y + offsetY) * BLOCK_SIZE,
302
+ BLOCK_SIZE,
303
+ BLOCK_SIZE
304
+ );
305
+
306
+ nextPieceCtx.fillStyle = 'rgba(255, 255, 255, 0.1)';
307
+ nextPieceCtx.fillRect(
308
+ (x + offsetX) * BLOCK_SIZE + 2,
309
+ (y + offsetY) * BLOCK_SIZE + 2,
310
+ BLOCK_SIZE - 4,
311
+ BLOCK_SIZE - 4
312
+ );
313
+ }
314
+ });
315
+ });
316
+ }
317
+ }
318
+
319
+ function draw() {
320
+ // Clear the board
321
+ ctx.fillStyle = '#111827';
322
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
323
+
324
+ // Draw the board
325
+ drawMatrix(board, {x: 0, y: 0});
326
+
327
+ // Draw the current piece
328
+ if (player.matrix) {
329
+ drawMatrix(player.matrix, player.pos);
330
+ }
331
+
332
+ // Draw grid lines
333
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
334
+ ctx.lineWidth = 1;
335
+
336
+ // Vertical lines
337
+ for (let i = 0; i <= COLS; i++) {
338
+ ctx.beginPath();
339
+ ctx.moveTo(i * BLOCK_SIZE, 0);
340
+ ctx.lineTo(i * BLOCK_SIZE, ROWS * BLOCK_SIZE);
341
+ ctx.stroke();
342
+ }
343
+
344
+ // Horizontal lines
345
+ for (let i = 0; i <= ROWS; i++) {
346
+ ctx.beginPath();
347
+ ctx.moveTo(0, i * BLOCK_SIZE);
348
+ ctx.lineTo(COLS * BLOCK_SIZE, i * BLOCK_SIZE);
349
+ ctx.stroke();
350
+ }
351
+ }
352
+
353
+ function merge() {
354
+ player.matrix.forEach((row, y) => {
355
+ row.forEach((value, x) => {
356
+ if (value !== 0) {
357
+ board[y + player.pos.y][x + player.pos.x] = value;
358
+ }
359
+ });
360
+ });
361
+ }
362
+
363
+ function rotate(matrix) {
364
+ const N = matrix.length;
365
+ const result = createMatrix(N, N);
366
+
367
+ for (let y = 0; y < N; ++y) {
368
+ for (let x = 0; x < N; ++x) {
369
+ result[x][N - 1 - y] = matrix[y][x];
370
+ }
371
+ }
372
+
373
+ return result;
374
+ }
375
+
376
+ function playerRotate() {
377
+ const pos = player.pos.x;
378
+ let offset = 1;
379
+ const matrix = rotate(player.matrix);
380
+
381
+ if (collide(board, {matrix, pos: player.pos})) {
382
+ const left = player.pos.x - offset;
383
+ const right = player.pos.x + offset;
384
+
385
+ if (!collide(board, {matrix, pos: {...player.pos, x: left}})) {
386
+ player.pos.x = left;
387
+ } else if (!collide(board, {matrix, pos: {...player.pos, x: right}})) {
388
+ player.pos.x = right;
389
+ } else {
390
+ return;
391
+ }
392
+ }
393
+
394
+ player.matrix = matrix;
395
+ }
396
+
397
+ function playerMove(dir) {
398
+ player.pos.x += dir;
399
+ if (collide(board, player)) {
400
+ player.pos.x -= dir;
401
+ }
402
+ }
403
+
404
+ function playerDrop() {
405
+ player.pos.y++;
406
+ if (collide(board, player)) {
407
+ player.pos.y--;
408
+ merge();
409
+ playerReset();
410
+ arenaSweep();
411
+ updateScore();
412
+ }
413
+ dropCounter = 0;
414
+ }
415
+
416
+ function playerHardDrop() {
417
+ while (!collide(board, player)) {
418
+ player.pos.y++;
419
+ }
420
+ player.pos.y--;
421
+ merge();
422
+ playerReset();
423
+ arenaSweep();
424
+ updateScore();
425
+ dropCounter = 0;
426
+ }
427
+
428
+ function collide(board, player) {
429
+ const [m, o] = [player.matrix, player.pos];
430
+ for (let y = 0; y < m.length; ++y) {
431
+ for (let x = 0; x < m[y].length; ++x) {
432
+ if (m[y][x] !== 0 &&
433
+ (board[y + o.y] === undefined ||
434
+ board[y + o.y][x + o.x] === undefined ||
435
+ board[y + o.y][x + o.x] !== 0)) {
436
+ return true;
437
+ }
438
+ }
439
+ }
440
+ return false;
441
+ }
442
+
443
+ function playerReset() {
444
+ const pieces = 'IJLOSTZ';
445
+ player.matrix = player.next || createPiece(pieces.charCodeAt(Math.floor(Math.random() * pieces.length)) - 64);
446
+ player.next = createPiece(pieces.charCodeAt(Math.floor(Math.random() * pieces.length)) - 64);
447
+ player.pos.y = 0;
448
+ player.pos.x = Math.floor((COLS / 2) - (player.matrix[0].length / 2));
449
+
450
+ drawNextPiece();
451
+
452
+ if (collide(board, player)) {
453
+ gameOver = true;
454
+ gameOverElement.classList.remove('hidden');
455
+ finalScoreElement.textContent = score;
456
+
457
+ if (score > highScore) {
458
+ highScore = score;
459
+ localStorage.setItem('tetrisHighScore', highScore);
460
+ highScoreElement.textContent = highScore;
461
+ }
462
+ }
463
+ }
464
+
465
+ function arenaSweep() {
466
+ let linesCleared = 0;
467
+
468
+ outer: for (let y = board.length - 1; y >= 0; --y) {
469
+ for (let x = 0; x < board[y].length; ++x) {
470
+ if (board[y][x] === 0) {
471
+ continue outer;
472
+ }
473
+ }
474
+
475
+ // Remove the line and add a new empty one at the top
476
+ const row = board.splice(y, 1)[0].fill(0);
477
+ board.unshift(row);
478
+ ++y;
479
+
480
+ linesCleared++;
481
+ }
482
+
483
+ if (linesCleared > 0) {
484
+ // Add visual effect for cleared lines
485
+ const linesElement = document.createElement('div');
486
+ linesElement.className = 'absolute inset-0 bg-white opacity-30 flash-animation';
487
+ document.querySelector('.game-container').appendChild(linesElement);
488
+
489
+ setTimeout(() => {
490
+ linesElement.remove();
491
+ }, 1000);
492
+
493
+ lines += linesCleared;
494
+ updateLevel();
495
+ }
496
+ }
497
+
498
+ function updateScore() {
499
+ const points = [0, 40, 100, 300, 1200]; // Points for 0, 1, 2, 3, 4 lines
500
+ const linesCleared = Math.min(4, lines - Math.floor(lines / 10) * 10);
501
+
502
+ if (linesCleared > 0) {
503
+ score += points[linesCleared] * level;
504
+ scoreElement.textContent = score;
505
+ linesElement.textContent = lines;
506
+ }
507
+ }
508
+
509
+ function updateLevel() {
510
+ level = Math.floor(lines / 10) + 1;
511
+ levelElement.textContent = level;
512
+ dropInterval = 1000 - (level - 1) * 100;
513
+ if (dropInterval < 100) dropInterval = 100;
514
+ }
515
+
516
+ function handleKeyPress(e) {
517
+ if (gameOver || paused) return;
518
+
519
+ switch (e.keyCode) {
520
+ case 37: // Left arrow
521
+ playerMove(-1);
522
+ break;
523
+ case 39: // Right arrow
524
+ playerMove(1);
525
+ break;
526
+ case 40: // Down arrow
527
+ playerDrop();
528
+ break;
529
+ case 38: // Up arrow
530
+ playerRotate();
531
+ break;
532
+ case 32: // Space
533
+ playerHardDrop();
534
+ break;
535
+ case 80: // P
536
+ togglePause();
537
+ break;
538
+ }
539
+ }
540
+
541
+ function togglePause() {
542
+ if (gameOver) return;
543
+
544
+ paused = !paused;
545
+
546
+ if (paused) {
547
+ pauseScreenElement.classList.remove('hidden');
548
+ cancelAnimationFrame(animationId);
549
+ } else {
550
+ pauseScreenElement.classList.add('hidden');
551
+ lastTime = 0;
552
+ animationId = requestAnimationFrame(update);
553
+ }
554
+ }
555
+
556
+ function resetGame() {
557
+ // Clear the board
558
+ for (let y = 0; y < ROWS; y++) {
559
+ for (let x = 0; x < COLS; x++) {
560
+ board[y][x] = 0;
561
+ }
562
+ }
563
+
564
+ // Reset game state
565
+ score = 0;
566
+ lines = 0;
567
+ level = 1;
568
+ dropInterval = 1000;
569
+
570
+ // Update UI
571
+ scoreElement.textContent = score;
572
+ linesElement.textContent = lines;
573
+ levelElement.textContent = level;
574
+
575
+ // Hide game over screen
576
+ gameOverElement.classList.add('hidden');
577
+ }
578
+
579
+ function startGame() {
580
+ if (!gameOver && !paused) return;
581
+
582
+ resetGame();
583
+ gameOver = false;
584
+ paused = false;
585
+ pauseScreenElement.classList.add('hidden');
586
+ playerReset();
587
+
588
+ if (animationId) {
589
+ cancelAnimationFrame(animationId);
590
+ }
591
+
592
+ lastTime = 0;
593
+ animationId = requestAnimationFrame(update);
594
+ }
595
+
596
+ function update(time = 0) {
597
+ const deltaTime = time - lastTime;
598
+ lastTime = time;
599
+
600
+ dropCounter += deltaTime;
601
+ if (dropCounter > dropInterval) {
602
+ playerDrop();
603
+ }
604
+
605
+ draw();
606
+ animationId = requestAnimationFrame(update);
607
+ }
608
+
609
+ function scaleCanvas() {
610
+ // For the main game canvas
611
+ const scale = window.devicePixelRatio;
612
+ canvas.style.width = canvas.width + 'px';
613
+ canvas.style.height = canvas.height + 'px';
614
+ canvas.width = canvas.width * scale;
615
+ canvas.height = canvas.height * scale;
616
+ ctx.scale(scale, scale);
617
+
618
+ // For the next piece canvas
619
+ nextPieceCanvas.style.width = nextPieceCanvas.width + 'px';
620
+ nextPieceCanvas.style.height = nextPieceCanvas.height + 'px';
621
+ nextPieceCanvas.width = nextPieceCanvas.width * scale;
622
+ nextPieceCanvas.height = nextPieceCanvas.height * scale;
623
+ nextPieceCtx.scale(scale, scale);
624
+ }
625
+
626
+ // Initial draw
627
+ draw();
628
+ });
629
+ </script>
630
+ <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=ysharma/modern-tetris-vibe-coded" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
631
+ </html>