Prince-7878 commited on
Commit
5802f4e
·
verified ·
1 Parent(s): a395c06

Create a tertis game

Browse files
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Blocky Stacky Blitz
3
- emoji: 🏃
4
- colorFrom: gray
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Blocky Stacky Blitz 🎮
3
+ colorFrom: green
4
+ colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/game-controls.js ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class GameControls extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ button {
7
+ transition: all 0.2s ease;
8
+ }
9
+ button:hover {
10
+ transform: translateY(-2px);
11
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
12
+ }
13
+ button:active {
14
+ transform: translateY(0);
15
+ }
16
+ </style>
17
+ <div class="flex flex-col gap-4 bg-gray-800 p-6 rounded-lg shadow-lg">
18
+ <h2 class="text-xl font-semibold text-center text-purple-400 mb-2">Controls</h2>
19
+ <div class="grid grid-cols-3 gap-3">
20
+ <button class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center">
21
+ <i data-feather="arrow-left"></i>
22
+ </button>
23
+ <button class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center">
24
+ <i data-feather="arrow-up"></i>
25
+ </button>
26
+ <button class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center">
27
+ <i data-feather="arrow-right"></i>
28
+ </button>
29
+ <button class="bg-gray-700 hover:bg-gray-600 text-white p-4 rounded-lg flex items-center justify-center">
30
+ <i data-feather="arrow-down"></i>
31
+ </button>
32
+ <button class="bg-purple-600 hover:bg-purple-500 text-white p-4 rounded-lg flex items-center justify-center col-span-2">
33
+ <i data-feather="corner-down-left" class="mr-2"></i>
34
+ <span>Hard Drop</span>
35
+ </button>
36
+ </div>
37
+ <div class="flex gap-3 mt-2">
38
+ <button id="startBtn" class="bg-green-600 hover:bg-green-500 text-white py-3 px-6 rounded-lg flex-1 flex items-center justify-center">
39
+ <i data-feather="play" class="mr-2"></i>
40
+ <span>Start</span>
41
+ </button>
42
+ <button id="resetBtn" class="bg-pink-600 hover:bg-pink-500 text-white py-3 px-6 rounded-lg flex-1 flex items-center justify-center">
43
+ <i data-feather="refresh-cw" class="mr-2"></i>
44
+ <span>Reset</span>
45
+ </button>
46
+ </div>
47
+ </div>
48
+ `;
49
+
50
+ this.shadowRoot.getElementById('startBtn').addEventListener('click', () => {
51
+ this.dispatchEvent(new CustomEvent('start-game'));
52
+ });
53
+
54
+ this.shadowRoot.getElementById('resetBtn').addEventListener('click', () => {
55
+ this.dispatchEvent(new CustomEvent('reset-game'));
56
+ });
57
+
58
+ feather.replace();
59
+ }
60
+ }
61
+ customElements.define('custom-game-controls', GameControls);
components/game-over.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class GameOver extends HTMLElement {
2
+ static get observedAttributes() {
3
+ return ['visible'];
4
+ }
5
+
6
+ constructor() {
7
+ super();
8
+ this.attachShadow({ mode: 'open' });
9
+ this.visible = 'false';
10
+ }
11
+
12
+ connectedCallback() {
13
+ this.render();
14
+ }
15
+
16
+ attributeChangedCallback(name, oldValue, newValue) {
17
+ if (name === 'visible') {
18
+ this.visible = newValue;
19
+ this.render();
20
+ }
21
+ }
22
+
23
+ render() {
24
+ this.shadowRoot.innerHTML = `
25
+ <style>
26
+ .game-over {
27
+ position: absolute;
28
+ top: 0;
29
+ left: 0;
30
+ width: 100%;
31
+ height: 100%;
32
+ background-color: rgba(0, 0, 0, 0.8);
33
+ display: flex;
34
+ flex-direction: column;
35
+ align-items: center;
36
+ justify-content: center;
37
+ opacity: 0;
38
+ pointer-events: none;
39
+ transition: opacity 0.3s ease;
40
+ z-index: 10;
41
+ }
42
+
43
+ .visible {
44
+ opacity: 1;
45
+ pointer-events: all;
46
+ }
47
+
48
+ .game-over h2 {
49
+ color: #fff;
50
+ font-size: 2rem;
51
+ margin-bottom: 2rem;
52
+ text-align: center;
53
+ text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
54
+ }
55
+
56
+ .restart-btn {
57
+ background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
58
+ color: white;
59
+ border: none;
60
+ padding: 0.75rem 2rem;
61
+ font-size: 1rem;
62
+ border-radius: 0.5rem;
63
+ cursor: pointer;
64
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
65
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
66
+ }
67
+
68
+ .restart-btn:hover {
69
+ transform: translateY(-2px);
70
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
71
+ }
72
+
73
+ .restart-btn:active {
74
+ transform: translateY(0);
75
+ }
76
+ </style>
77
+ <div class="game-over ${this.visible === 'true' ? 'visible' : ''}">
78
+ <h2>GAME OVER</h2>
79
+ <button class="restart-btn">
80
+ <i data-feather="refresh-cw" class="mr-2"></i>
81
+ Play Again
82
+ </button>
83
+ </div>
84
+ `;
85
+
86
+ if (this.visible === 'true') {
87
+ const button = this.shadowRoot.querySelector('.restart-btn');
88
+ button.addEventListener('click', () => {
89
+ this.dispatchEvent(new CustomEvent('restart-game'));
90
+ });
91
+ feather.replace();
92
+ }
93
+ }
94
+ }
95
+ customElements.define('custom-game-over', GameOver);
components/score-display.js ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ScoreDisplay extends HTMLElement {
2
+ static get observedAttributes() {
3
+ return ['score'];
4
+ }
5
+
6
+ constructor() {
7
+ super();
8
+ this.attachShadow({ mode: 'open' });
9
+ this.score = 0;
10
+ }
11
+
12
+ connectedCallback() {
13
+ this.render();
14
+ }
15
+
16
+ attributeChangedCallback(name, oldValue, newValue) {
17
+ if (name === 'score') {
18
+ this.score = newValue;
19
+ this.render();
20
+ }
21
+ }
22
+
23
+ render() {
24
+ this.shadowRoot.innerHTML = `
25
+ <style>
26
+ .score-display {
27
+ background: linear-gradient(135deg, #1f2937 0%, #111827 100%);
28
+ border: 2px solid #6b46c1;
29
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
30
+ }
31
+ </style>
32
+ <div class="score-display p-6 rounded-lg text-center">
33
+ <h3 class="text-lg font-semibold text-purple-400 mb-2">SCORE</h3>
34
+ <p class="text-4xl font-bold">${this.score}</p>
35
+ </div>
36
+ `;
37
+ }
38
+ }
39
+ customElements.define('custom-score-display', ScoreDisplay);
index.html CHANGED
@@ -1,19 +1,54 @@
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>Blocky Stacky Blitz - Tetris Game</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <link rel="stylesheet" href="style.css">
11
+ <script src="components/game-controls.js"></script>
12
+ <script src="components/score-display.js"></script>
13
+ <script src="components/game-over.js"></script>
14
+ </head>
15
+ <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
16
+ <header class="mb-8 text-center">
17
+ <h1 class="text-4xl md:text-6xl font-bold bg-gradient-to-r from-purple-500 to-pink-500 bg-clip-text text-transparent">Blocky Stacky Blitz</h1>
18
+ <p class="text-gray-400 mt-2">The ultimate tetris challenge</p>
19
+ </header>
20
+
21
+ <main class="flex flex-col md:flex-row items-center gap-8">
22
+ <div class="relative">
23
+ <canvas id="tetris" class="border-4 border-purple-600 rounded-lg shadow-2xl shadow-purple-900/50"></canvas>
24
+ <custom-game-over></custom-game-over>
25
+ </div>
26
+
27
+ <div class="flex flex-col gap-6">
28
+ <custom-score-display></custom-score-display>
29
+ <custom-game-controls></custom-game-controls>
30
+
31
+ <div class="bg-gray-800 p-4 rounded-lg">
32
+ <h3 class="text-xl font-semibold mb-2 text-purple-400">How to Play</h3>
33
+ <ul class="text-gray-300 space-y-1">
34
+ <li><span class="text-pink-400">← →</span> Move left/right</li>
35
+ <li><span class="text-pink-400">↓</span> Soft drop</li>
36
+ <li><span class="text-pink-400">↑</span> Rotate</li>
37
+ <li><span class="text-pink-400">Space</span> Hard drop</li>
38
+ <li><span class="text-pink-400">P</span> Pause</li>
39
+ </ul>
40
+ </div>
41
+ </div>
42
+ </main>
43
+
44
+ <footer class="mt-12 text-center text-gray-500 text-sm">
45
+ <p>Built with ♥ using HTML5 Canvas</p>
46
+ </footer>
47
+
48
+ <script src="script.js"></script>
49
+ <script>
50
+ feather.replace();
51
+ </script>
52
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
53
+ </body>
54
+ </html>
script.js ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const canvas = document.getElementById('tetris');
3
+ const ctx = canvas.getContext('2d');
4
+
5
+ // Scale canvas
6
+ const scale = window.devicePixelRatio;
7
+ canvas.width = Math.floor(canvas.clientWidth * scale);
8
+ canvas.height = Math.floor(canvas.clientHeight * scale);
9
+ ctx.scale(scale, scale);
10
+
11
+ // Game state
12
+ const COLS = 10;
13
+ const ROWS = 20;
14
+ const BLOCK_SIZE = canvas.width / 10 / scale;
15
+ const COLORS = [
16
+ null,
17
+ '#3B82F6', // I
18
+ '#8B5CF6', // J
19
+ '#F59E0B', // L
20
+ '#10B981', // O
21
+ '#EF4444', // S
22
+ '#EC4899', // T
23
+ '#84CC16' // Z
24
+ ];
25
+
26
+ let board = createBoard();
27
+ let piece = null;
28
+ let score = 0;
29
+ let gameOver = false;
30
+ let dropCounter = 0;
31
+ let lastTime = 0;
32
+ let dropInterval = 1000;
33
+
34
+ // Pieces
35
+ const PIECES = [
36
+ null,
37
+ { shape: [[0,0,0,0], [1,1,1,1], [0,0,0,0], [0,0,0,0]], color: 'I' },
38
+ { shape: [[2,0,0], [2,2,2], [0,0,0]], color: 'J' },
39
+ { shape: [[0,0,3], [3,3,3], [0,0,0]], color: 'L' },
40
+ { shape: [[0,4,4], [0,4,4], [0,0,0]], color: 'O' },
41
+ { shape: [[0,5,5], [5,5,0], [0,0,0]], color: 'S' },
42
+ { shape: [[0,6,0], [6,6,6], [0,0,0]], color: 'T' },
43
+ { shape: [[7,7,0], [0,7,7], [0,0,0]], color: 'Z' }
44
+ ];
45
+
46
+ // Game functions
47
+ function createBoard() {
48
+ return Array.from({length: ROWS}, () => Array(COLS).fill(0));
49
+ }
50
+
51
+ function createPiece() {
52
+ const randomIndex = Math.floor(Math.random() * 7) + 1;
53
+ return {
54
+ position: {x: Math.floor(COLS / 2) - 1, y: 0},
55
+ shape: PIECES[randomIndex].shape,
56
+ color: PIECES[randomIndex].color
57
+ };
58
+ }
59
+
60
+ function draw() {
61
+ // Clear canvas
62
+ ctx.fillStyle = '#111827';
63
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
64
+
65
+ // Draw board
66
+ board.forEach((row, y) => {
67
+ row.forEach((value, x) => {
68
+ if (value !== 0) {
69
+ ctx.fillStyle = COLORS[value];
70
+ ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
71
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
72
+ ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
73
+ }
74
+ });
75
+ });
76
+
77
+ // Draw current piece
78
+ if (piece) {
79
+ piece.shape.forEach((row, y) => {
80
+ row.forEach((value, x) => {
81
+ if (value !== 0) {
82
+ ctx.fillStyle = COLORS[value];
83
+ ctx.fillRect(
84
+ (piece.position.x + x) * BLOCK_SIZE,
85
+ (piece.position.y + y) * BLOCK_SIZE,
86
+ BLOCK_SIZE,
87
+ BLOCK_SIZE
88
+ );
89
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
90
+ ctx.strokeRect(
91
+ (piece.position.x + x) * BLOCK_SIZE,
92
+ (piece.position.y + y) * BLOCK_SIZE,
93
+ BLOCK_SIZE,
94
+ BLOCK_SIZE
95
+ );
96
+ }
97
+ });
98
+ });
99
+ }
100
+ }
101
+
102
+ function collide() {
103
+ for (let y = 0; y < piece.shape.length; y++) {
104
+ for (let x = 0; x < piece.shape[y].length; x++) {
105
+ if (piece.shape[y][x] !== 0 &&
106
+ (board[y + piece.position.y] === undefined ||
107
+ board[y + piece.position.y][x + piece.position.x] === undefined ||
108
+ board[y + piece.position.y][x + piece.position.x] !== 0)) {
109
+ return true;
110
+ }
111
+ }
112
+ }
113
+ return false;
114
+ }
115
+
116
+ function rotate() {
117
+ const rotated = [];
118
+ for (let y = 0; y < piece.shape[0].length; y++) {
119
+ const row = [];
120
+ for (let x = piece.shape.length - 1; x >= 0; x--) {
121
+ row.push(piece.shape[x][y]);
122
+ }
123
+ rotated.push(row);
124
+ }
125
+
126
+ const previousShape = piece.shape;
127
+ piece.shape = rotated;
128
+
129
+ if (collide()) {
130
+ piece.shape = previousShape;
131
+ }
132
+ }
133
+
134
+ function movePiece(direction) {
135
+ piece.position.x += direction;
136
+ if (collide()) {
137
+ piece.position.x -= direction;
138
+ }
139
+ }
140
+
141
+ function hardDrop() {
142
+ while (!collide()) {
143
+ piece.position.y++;
144
+ }
145
+ piece.position.y--;
146
+ merge();
147
+ removeRows();
148
+ piece = createPiece();
149
+
150
+ if (collide()) {
151
+ gameOver = true;
152
+ document.querySelector('custom-game-over').setAttribute('visible', 'true');
153
+ }
154
+ }
155
+
156
+ function merge() {
157
+ piece.shape.forEach((row, y) => {
158
+ row.forEach((value, x) => {
159
+ if (value !== 0) {
160
+ board[y + piece.position.y][x + piece.position.x] = value;
161
+ }
162
+ });
163
+ });
164
+ }
165
+
166
+ function removeRows() {
167
+ let linesCleared = 0;
168
+
169
+ outer: for (let y = board.length - 1; y >= 0; y--) {
170
+ for (let x = 0; x < board[y].length; x++) {
171
+ if (board[y][x] === 0) {
172
+ continue outer;
173
+ }
174
+ }
175
+
176
+ const row = board.splice(y, 1)[0].fill(0);
177
+ board.unshift(row);
178
+ y++;
179
+
180
+ linesCleared++;
181
+ }
182
+
183
+ if (linesCleared > 0) {
184
+ score += calculateScore(linesCleared);
185
+ updateScoreDisplay();
186
+ }
187
+ }
188
+
189
+ function calculateScore(lines) {
190
+ switch(lines) {
191
+ case 1: return 100;
192
+ case 2: return 300;
193
+ case 3: return 500;
194
+ case 4: return 800;
195
+ default: return 0;
196
+ }
197
+ }
198
+
199
+ function updateScoreDisplay() {
200
+ document.querySelector('custom-score-display').setAttribute('score', score.toString());
201
+ }
202
+
203
+ function resetGame() {
204
+ board = createBoard();
205
+ piece = createPiece();
206
+ score = 0;
207
+ gameOver = false;
208
+ dropInterval = 1000;
209
+ updateScoreDisplay();
210
+ document.querySelector('custom-game-over').setAttribute('visible', 'false');
211
+ }
212
+
213
+ // Game loop
214
+ function update(time = 0) {
215
+ if (gameOver) return;
216
+
217
+ const deltaTime = time - lastTime;
218
+ lastTime = time;
219
+
220
+ dropCounter += deltaTime;
221
+ if (dropCounter > dropInterval) {
222
+ piece.position.y++;
223
+ if (collide()) {
224
+ piece.position.y--;
225
+ merge();
226
+ removeRows();
227
+ piece = createPiece();
228
+
229
+ if (collide()) {
230
+ gameOver = true;
231
+ document.querySelector('custom-game-over').setAttribute('visible', 'true');
232
+ }
233
+ }
234
+ dropCounter = 0;
235
+ }
236
+
237
+ draw();
238
+ requestAnimationFrame(update);
239
+ }
240
+
241
+ // Controls
242
+ document.addEventListener('keydown', event => {
243
+ if (gameOver) return;
244
+
245
+ switch(event.keyCode) {
246
+ case 37: // Left
247
+ movePiece(-1);
248
+ break;
249
+ case 39: // Right
250
+ movePiece(1);
251
+ break;
252
+ case 40: // Down
253
+ piece.position.y++;
254
+ if (collide()) {
255
+ piece.position.y--;
256
+ merge();
257
+ removeRows();
258
+ piece = createPiece();
259
+
260
+ if (collide()) {
261
+ gameOver = true;
262
+ document.querySelector('custom-game-over').setAttribute('visible', 'true');
263
+ }
264
+ }
265
+ dropCounter = 0;
266
+ break;
267
+ case 38: // Up
268
+ rotate();
269
+ break;
270
+ case 32: // Space
271
+ hardDrop();
272
+ break;
273
+ case 80: // P
274
+ // Pause logic would go here
275
+ break;
276
+ }
277
+ });
278
+
279
+ // Initialize game
280
+ piece = createPiece();
281
+ update();
282
+
283
+ // Custom element event listeners
284
+ document.addEventListener('start-game', resetGame);
285
+ document.addEventListener('reset-game', resetGame);
286
+ });
style.css CHANGED
@@ -1,28 +1,50 @@
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Rubik:wght@400;600;700&display=swap');
2
+
3
  body {
4
+ font-family: 'Rubik', sans-serif;
5
+ }
6
+
7
+ h1, h2, h3 {
8
+ font-family: 'Press Start 2P', cursive;
9
  }
10
 
11
+ canvas {
12
+ background-color: #111827;
13
+ width: 300px;
14
+ height: 600px;
15
  }
16
 
17
+ @media (min-width: 768px) {
18
+ canvas {
19
+ width: 400px;
20
+ height: 800px;
21
+ }
22
  }
23
 
24
+ .tetris-block {
25
+ position: absolute;
26
+ box-sizing: border-box;
27
+ border: 2px solid rgba(255, 255, 255, 0.3);
 
 
28
  }
29
 
30
+ .I {
31
+ background-color: #3b82f6;
32
+ }
33
+ .J {
34
+ background-color: #8b5cf6;
35
+ }
36
+ .L {
37
+ background-color: #f59e0b;
38
+ }
39
+ .O {
40
+ background-color: #10b981;
41
+ }
42
+ .S {
43
+ background-color: #ef4444;
44
+ }
45
+ .T {
46
+ background-color: #ec4899;
47
  }
48
+ .Z {
49
+ background-color: #84cc16;
50
+ }