Changes to blocks.scroll.pub

root
root
2 days ago
Initial commit
index.scroll
Changed around line 1
+ buildHtml
+ baseUrl https://blocks.scroll.pub
+ metaTags
+ viewport width=device-width,initial-scale=1
+ title Blocks - Modern Tetris
+ style.css
+ favicon.svg
+
+ header
+ class game-header
+ h1 BLOCKS
+ class glitch
+ data-text="BLOCKS"
+ div
+ class stats
+ p Score:
+ id score 0
+ p Lines:
+ id lines 0
+ main
+ class game-container
+ div
+ class grid-container
+ canvas
+ id gameCanvas
+ div
+ class side-panel
+ h2 NEXT
+ canvas
+ id nextCanvas
+ div
+ class mobile-controls
+ button
+ class control-btn left-btn
+ ←
+ div
+ class vertical-controls
+ button
+ class control-btn rotate-btn
+ ↻
+ button
+ class control-btn down-btn
+ ↓
+ button
+ class control-btn right-btn
+ →
+ footer
+ class game-footer
+ p Use ←→ to move, ↑ to rotate, ↓ to soft drop, Space to hard drop
+
+ script.js
prompt.json
Changed around line 1
+ {
+ "id": "77ac0470-2c8e-4499-a8a7-180cb521e3b2",
+ "object": "chat.completion",
+ "created": 1738072506,
+ "model": "deepseek-reasoner",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nblocks.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://blocks.scroll.pub\nmetaTags\n viewport width=device-width,initial-scale=1\ntitle Blocks - Modern Tetris\nstyle.css\nfavicon.svg\n\nheader\n class game-header\n h1 BLOCKS\n class glitch\n data-text=\"BLOCKS\"\n div\n class stats\n p Score: \n id score 0\n p Lines: \n id lines 0\nmain\n class game-container\n div\n class grid-container\n canvas\n id gameCanvas\n div\n class side-panel\n h2 NEXT\n canvas\n id nextCanvas\n div\n class mobile-controls\n button\n class control-btn left-btn\n ←\n div\n class vertical-controls\n button\n class control-btn rotate-btn\n ↻\n button\n class control-btn down-btn\n ↓\n button\n class control-btn right-btn\n →\nfooter\n class game-footer\n p Use ←→ to move, ↑ to rotate, ↓ to soft drop, Space to hard drop\n\nscript.js\n---style.css---\n:root {\n --bg: #1a1a2e;\n --primary: #0f3460;\n --accent: #e94560;\n --text: #f1f1f1;\n --neon: #4fdcff;\n}\n\nbody {\n margin: 0;\n background: linear-gradient(45deg, var(--bg), #16213e);\n color: var(--text);\n font-family: system-ui, -apple-system, sans-serif;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n}\n\n.game-header {\n text-align: center;\n padding: 2rem;\n position: relative;\n overflow: hidden;\n}\n\n.glitch {\n position: relative;\n font-size: 4rem;\n text-transform: uppercase;\n letter-spacing: 0.5rem;\n color: var(--neon);\n text-shadow: 0 0 10px var(--neon);\n}\n\n.glitch::before {\n content: attr(data-text);\n position: absolute;\n left: -2px;\n text-shadow: 2px 0 #ff00c1;\n animation: glitch-1 2s infinite linear alternate-reverse;\n}\n\n@keyframes glitch-1 {\n 0% { clip-path: inset(20% 0 30% 0); }\n 100% { clip-path: inset(10% 0 40% 0); }\n}\n\n.game-container {\n display: grid;\n grid-template-columns: auto 150px;\n gap: 2rem;\n justify-content: center;\n padding: 1rem;\n}\n\n#gameCanvas {\n border: 3px solid var(--primary);\n border-radius: 5px;\n box-shadow: 0 0 20px var(--primary);\n background: rgba(0,0,0,0.3);\n}\n\n.side-panel {\n display: flex;\n flex-direction: column;\n gap: 2rem;\n}\n\n#nextCanvas {\n border: 2px solid var(--accent);\n border-radius: 5px;\n background: rgba(0,0,0,0.2);\n width: 100%;\n}\n\n.stats {\n font-size: 1.5rem;\n display: flex;\n gap: 1rem;\n justify-content: center;\n}\n\n.mobile-controls {\n display: none;\n gap: 0.5rem;\n justify-content: center;\n}\n\n.control-btn {\n background: var(--primary);\n border: 2px solid var(--accent);\n color: var(--text);\n padding: 1rem;\n border-radius: 50%;\n font-size: 1.5rem;\n cursor: pointer;\n touch-action: manipulation;\n transition: all 0.2s;\n}\n\n.control-btn:active {\n background: var(--accent);\n transform: scale(0.9);\n}\n\n.game-footer {\n text-align: center;\n padding: 2rem;\n margin-top: auto;\n}\n\n@media (max-width: 600px) {\n .game-container {\n grid-template-columns: 1fr;\n grid-template-rows: auto auto;\n }\n \n .mobile-controls {\n display: flex;\n margin-top: 1rem;\n }\n \n #gameCanvas {\n width: 100%;\n height: auto;\n }\n}\n---script.js---\nconst canvas = document.getElementById('gameCanvas');\nconst ctx = canvas.getContext('2d');\nconst nextCanvas = document.getElementById('nextCanvas');\nconst nextCtx = nextCanvas.getContext('2d');\nconst BLOCK_SIZE = 30;\nconst BOARD_WIDTH = 10;\nconst BOARD_HEIGHT = 20;\n\n// Set canvas sizes\ncanvas.width = BLOCK_SIZE * BOARD_WIDTH;\ncanvas.height = BLOCK_SIZE * BOARD_HEIGHT;\nnextCanvas.width = BLOCK_SIZE * 4;\nnextCanvas.height = BLOCK_SIZE * 4;\n\nlet board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));\nlet score = 0;\nlet lines = 0;\nlet currentPiece = null;\nlet nextPiece = null;\n\nconst PIECES = [\n [[1,1,1,1]], // I\n [[1,1,1],[0,1,0]], // T\n [[1,1,1],[1,0,0]], // L\n [[1,1,1],[0,0,1]], // J\n [[1,1],[1,1]], // O\n [[1,1,0],[0,1,1]], // S\n [[0,1,1],[1,1,0]] // Z\n];\n\nconst COLORS = ['#4fdcff', '#ff6b6b', '#45ffa5', '#ffd93d', '#ff8d4f', '#ba68c8', '#69a3ff'];\n\nfunction createPiece() {\n const pieceIndex = Math.floor(Math.random() * PIECES.length);\n return {\n shape: PIECES[pieceIndex],\n color: COLORS[pieceIndex],\n x: Math.floor(BOARD_WIDTH/2) - 1,\n y: 0\n };\n}\n\nfunction drawBlock(ctx, x, y, color) {\n ctx.fillStyle = color;\n ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1);\n ctx.strokeStyle = 'rgba(255,255,255,0.2)';\n ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1);\n}\n\nfunction drawBoard() {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n \n // Draw board\n for(let y = 0; y < BOARD_HEIGHT; y++) {\n for(let x = 0; x < BOARD_WIDTH; x++) {\n if(board[y][x]) {\n drawBlock(ctx, x, y, board[y][x]);\n }\n }\n }\n \n // Draw current piece\n if(currentPiece) {\n currentPiece.shape.forEach((row, y) => {\n row.forEach((value, x) => {\n if(value) {\n drawBlock(ctx, currentPiece.x + x, currentPiece.y + y, currentPiece.color);\n }\n });\n });\n }\n}\n\nfunction drawNextPiece() {\n nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);\n if(nextPiece) {\n nextPiece.shape.forEach((row, y) => {\n row.forEach((value, x) => {\n if(value) {\n drawBlock(nextCtx, x + 1, y + 1, nextPiece.color);\n }\n });\n });\n }\n}\n\nfunction isValidMove(piece, newX, newY) {\n return piece.shape.every((row, dy) => {\n return row.every((value, dx) => {\n let x = newX + dx;\n let y = newY + dy;\n return (\n value === 0 ||\n (x >= 0 && x < BOARD_WIDTH && y < BOARD_HEIGHT && !board[y]?.[x])\n );\n });\n });\n}\n\nfunction rotate(piece) {\n const newShape = piece.shape[0].map((_, i) =>\n piece.shape.map(row => row[i]).reverse()\n );\n return { ...piece, shape: newShape };\n}\n\nfunction mergePiece() {\n currentPiece.shape.forEach((row, y) => {\n row.forEach((value, x) => {\n if(value) {\n board[currentPiece.y + y][currentPiece.x + x] = currentPiece.color;\n }\n });\n });\n}\n\nfunction clearLines() {\n let linesCleared = 0;\n \n for(let y = BOARD_HEIGHT - 1; y >= 0; y--) {\n if(board[y].every(cell => cell)) {\n board.splice(y, 1);\n board.unshift(Array(BOARD_WIDTH).fill(0));\n linesCleared++;\n y++;\n }\n }\n \n if(linesCleared > 0) {\n lines += linesCleared;\n score += [40, 100, 300, 1200][linesCleared - 1];\n document.getElementById('score').textContent = score;\n document.getElementById('lines').textContent = lines;\n }\n}\n\nfunction gameLoop() {\n if(currentPiece && isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n } else {\n if(currentPiece) {\n mergePiece();\n clearLines();\n }\n currentPiece = nextPiece || createPiece();\n nextPiece = createPiece();\n drawNextPiece();\n \n if(!isValidMove(currentPiece, currentPiece.x, currentPiece.y)) {\n alert('Game Over! Score: ' + score);\n resetGame();\n }\n }\n \n drawBoard();\n requestAnimationFrame(gameLoop);\n}\n\nfunction resetGame() {\n board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));\n score = 0;\n lines = 0;\n document.getElementById('score').textContent = score;\n document.getElementById('lines').textContent = lines;\n}\n\n// Controls\ndocument.addEventListener('keydown', e => {\n if(!currentPiece) return;\n\n switch(e.key) {\n case 'ArrowLeft':\n if(isValidMove(currentPiece, currentPiece.x - 1, currentPiece.y)) {\n currentPiece.x--;\n drawBoard();\n }\n break;\n case 'ArrowRight':\n if(isValidMove(currentPiece, currentPiece.x + 1, currentPiece.y)) {\n currentPiece.x++;\n drawBoard();\n }\n break;\n case 'ArrowDown':\n if(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n drawBoard();\n }\n break;\n case 'ArrowUp':\n const rotated = rotate(currentPiece);\n if(isValidMove(rotated, rotated.x, rotated.y)) {\n currentPiece = rotated;\n drawBoard();\n }\n break;\n case ' ':\n while(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n }\n drawBoard();\n break;\n }\n});\n\n// Mobile controls\ndocument.querySelectorAll('.control-btn').forEach(btn => {\n btn.addEventListener('touchstart', (e) => {\n e.preventDefault();\n btn.dispatchEvent(new Event('click'));\n });\n});\n\ndocument.querySelector('.left-btn').addEventListener('click', () => {\n if(isValidMove(currentPiece, currentPiece.x - 1, currentPiece.y)) {\n currentPiece.x--;\n drawBoard();\n }\n});\n\ndocument.querySelector('.right-btn').addEventListener('click', () => {\n if(isValidMove(currentPiece, currentPiece.x + 1, currentPiece.y)) {\n currentPiece.x++;\n drawBoard();\n }\n});\n\ndocument.querySelector('.rotate-btn').addEventListener('click', () => {\n const rotated = rotate(currentPiece);\n if(isValidMove(rotated, rotated.x, rotated.y)) {\n currentPiece = rotated;\n drawBoard();\n }\n});\n\ndocument.querySelector('.down-btn').addEventListener('click', () => {\n if(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n drawBoard();\n }\n});\n\n// Start game\nnextPiece = createPiece();\ngameLoop();\n---end---",
+ "reasoning_content": "Okay, I need to create a Tetris game using only HTML, CSS, and JavaScript without any frameworks or external dependencies. The user specified using Scroll syntax for the HTML, which uses indentation for nesting elements. Let me start by breaking down the requirements.\n\nFirst, the domain name. It should end with scroll.pub and be memorable. Since it's a Tetris game, maybe something like \"blocks.scroll.pub\"? That's short and relevant.\n\nNext, the structure. The game needs a grid-based board, score display, and controls. Using semantic HTML5 elements, so maybe a main container with a game board and side panel for stats. For mobile responsiveness, I'll use CSS Grid or Flexbox with media queries.\n\nFor the Scroll markup, the body starts with the header, main, and footer. The header has the title and score/lines display. The main area holds the game canvas and the side panel with next piece preview and controls. The footer can have a simple message.\n\nStyling is crucial. The user wants it dazzling with advanced CSS. Maybe a dark gradient background, neon borders for the game board, and sleek buttons. Using CSS variables for colors to keep it consistent. Animations for clearing lines or game over.\n\nJavaScript will handle the game logic. The Tetris board can be a 2D array. Each piece is an object with its shape and color. The game loop uses requestAnimationFrame for smooth movement. Collision detection, rotation, and line clearing functions are needed. Event listeners for keyboard controls, including mobile touch buttons.\n\nAccessibility: Ensure keyboard navigation, ARIA labels for buttons, and color contrast. Mobile responsiveness with touch-friendly controls hidden on desktop and shown on mobile via media queries.\n\nTesting the Scroll syntax indentation carefully. Each child element is indented with one space. Classes and attributes are properly assigned. The CSS should be minimal but effective, using flex and grid layouts. JavaScript must handle both keyboard and touch events, with the game state updating correctly.\n\nPotential issues: Making sure the canvas scales correctly on different screens. Handling rotation of Tetris pieces without overlap. Ensuring the game loop runs smoothly without memory leaks. Testing on mobile devices to ensure touch controls work.\n\nPutting it all together: The Scroll markup defines the structure, CSS styles it with modern techniques, and JavaScript implements the game mechanics. The domain name is blocks.scroll.pub, which fits the theme. The final code should be clean, efficient, and meet all the user's requirements."
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 731,
+ "completion_tokens": 3276,
+ "total_tokens": 4007,
+ "prompt_tokens_details": {
+ "cached_tokens": 0
+ },
+ "completion_tokens_details": {
+ "reasoning_tokens": 508
+ },
+ "prompt_cache_hit_tokens": 0,
+ "prompt_cache_miss_tokens": 731
+ },
+ "system_fingerprint": "fp_7e73fd9a08"
+ }
readme.scroll
Changed around line 1
+ # blocks.scroll.pub
+
+ Prompt: website
+ Agent: deepseekreasoner
+ Model: deepseek-reasoner
+
+ ## User prompt
+ creat a tetris game
+
+ ## System prompt
+ You are an expert web developer. Create a website based on this request: "creat a tetris game"
+
+ Requirements:
+ - Use only Scroll, CSS, and JavaScript (NO frameworks, NO external dependencies)
+ - Create clean, semantic HTML5
+ - Make it mobile-responsive
+ - Follow modern best practices and accessibility guidelines
+ - Keep it simple but professional
+ - Use only relative links and no external resources
+ - Do not put a copyright symbol or all rights reserved in the footer.
+ - Make it beautiful. Dazzling. Advanced used of CSS.
+
+ As a refresher, for doing the html body, Scroll is a whitespace based language that uses a single indented space to mark a line (aka particle) as a subparticle of a parent line.
+
+ For example:
+
+ header
+ class hero
+ nav
+ div Scroll
+ class logo
+ div
+ class nav-links
+ a Features
+ href #features
+ a Examples
+ href #examples
+ a Edit
+ href edit.html
+ a GitHub
+ class cta-button
+ href https://github.com/breck7/scroll
+ div
+ class hero-content
+ h1 Write Better with Scroll
+ p The extendible markup language that makes source beautiful and compiles to anything
+ a Get Started
+ class primary-button
+ href https://hub.scroll.pub/
+ main
+ section
+ id features
+ class features
+ h2 Why Scroll?
+ div
+ class feature-grid
+ div
+ class feature-card
+ div ⚡
+ class feature-icon
+ h3 Simple Syntax
+ p Like Markdown, but more powerful. No parentheses needed.
+ div
+ class feature-card
+ div 🧩
+ class feature-icon
+ h3 Extendible
+ p Build your own custom parsers.
+ div
+ class feature-card
+ div 🎨
+ class feature-icon
+ h3 Beautiful Output
+ p Create stunning documents with minimal effort.
+ div
+ class feature-card
+ div 🚀
+ class feature-icon
+ h3 Fast & Light
+ p Built on the efficient PPS Stack.
+ section
+ id examples
+ class code-demo
+ h2 See It In Action
+ div
+ class code-container
+ pre
+ class code-example
+ div
+ class code-output
+ footer
+ div
+ class footer-content
+ div
+ class footer-links
+ a Documentation
+ href https://scroll.pub/tutorial.html
+ a Community
+ href https://www.reddit.com/r/WorldWideScroll/
+ a Blog
+ href https://scroll.pub/blog
+ p Started by Breck Yunits. Evolved by a community.
+ https://twitter.com/breckyunits Breck Yunits
+ https://github.com/breck7/scroll/graphs/contributors community
+
+
+ First suggest a short, memorable domain name ending in scroll.pub that represents this website. Then provide the website files. Use this exact format:
+
+ ---domain---
+ (domainscroll.pub here)
+ ---index.scroll---
+ buildHtml
+ baseUrl https://(domainscroll.pub here)
+ metaTags
+ editButton /edit.html
+ title (Title here)
+ style.css
+
+ (body content here. no blank lines please.)
+
+ script.js
+ ---style.css---
+ (CSS content here)
+ ---script.js---
+ (JavaScript content here)
+ ---end---
script.js
Changed around line 1
+ const canvas = document.getElementById('gameCanvas');
+ const ctx = canvas.getContext('2d');
+ const nextCanvas = document.getElementById('nextCanvas');
+ const nextCtx = nextCanvas.getContext('2d');
+ const BLOCK_SIZE = 30;
+ const BOARD_WIDTH = 10;
+ const BOARD_HEIGHT = 20;
+
+ // Set canvas sizes
+ canvas.width = BLOCK_SIZE * BOARD_WIDTH;
+ canvas.height = BLOCK_SIZE * BOARD_HEIGHT;
+ nextCanvas.width = BLOCK_SIZE * 4;
+ nextCanvas.height = BLOCK_SIZE * 4;
+
+ let board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));
+ let score = 0;
+ let lines = 0;
+ let currentPiece = null;
+ let nextPiece = null;
+
+ const PIECES = [
+ [[1,1,1,1]], // I
+ [[1,1,1],[0,1,0]], // T
+ [[1,1,1],[1,0,0]], // L
+ [[1,1,1],[0,0,1]], // J
+ [[1,1],[1,1]], // O
+ [[1,1,0],[0,1,1]], // S
+ [[0,1,1],[1,1,0]] // Z
+ ];
+
+ const COLORS = ['#4fdcff', '#ff6b6b', '#45ffa5', '#ffd93d', '#ff8d4f', '#ba68c8', '#69a3ff'];
+
+ function createPiece() {
+ const pieceIndex = Math.floor(Math.random() * PIECES.length);
+ return {
+ shape: PIECES[pieceIndex],
+ color: COLORS[pieceIndex],
+ x: Math.floor(BOARD_WIDTH/2) - 1,
+ y: 0
+ };
+ }
+
+ function drawBlock(ctx, x, y, color) {
+ ctx.fillStyle = color;
+ ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1);
+ ctx.strokeStyle = 'rgba(255,255,255,0.2)';
+ ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1);
+ }
+
+ function drawBoard() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // Draw board
+ for(let y = 0; y < BOARD_HEIGHT; y++) {
+ for(let x = 0; x < BOARD_WIDTH; x++) {
+ if(board[y][x]) {
+ drawBlock(ctx, x, y, board[y][x]);
+ }
+ }
+ }
+
+ // Draw current piece
+ if(currentPiece) {
+ currentPiece.shape.forEach((row, y) => {
+ row.forEach((value, x) => {
+ if(value) {
+ drawBlock(ctx, currentPiece.x + x, currentPiece.y + y, currentPiece.color);
+ }
+ });
+ });
+ }
+ }
+
+ function drawNextPiece() {
+ nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);
+ if(nextPiece) {
+ nextPiece.shape.forEach((row, y) => {
+ row.forEach((value, x) => {
+ if(value) {
+ drawBlock(nextCtx, x + 1, y + 1, nextPiece.color);
+ }
+ });
+ });
+ }
+ }
+
+ function isValidMove(piece, newX, newY) {
+ return piece.shape.every((row, dy) => {
+ return row.every((value, dx) => {
+ let x = newX + dx;
+ let y = newY + dy;
+ return (
+ value === 0 ||
+ (x >= 0 && x < BOARD_WIDTH && y < BOARD_HEIGHT && !board[y]?.[x])
+ );
+ });
+ });
+ }
+
+ function rotate(piece) {
+ const newShape = piece.shape[0].map((_, i) =>
+ piece.shape.map(row => row[i]).reverse()
+ );
+ return { ...piece, shape: newShape };
+ }
+
+ function mergePiece() {
+ currentPiece.shape.forEach((row, y) => {
+ row.forEach((value, x) => {
+ if(value) {
+ board[currentPiece.y + y][currentPiece.x + x] = currentPiece.color;
+ }
+ });
+ });
+ }
+
+ function clearLines() {
+ let linesCleared = 0;
+
+ for(let y = BOARD_HEIGHT - 1; y >= 0; y--) {
+ if(board[y].every(cell => cell)) {
+ board.splice(y, 1);
+ board.unshift(Array(BOARD_WIDTH).fill(0));
+ linesCleared++;
+ y++;
+ }
+ }
+
+ if(linesCleared > 0) {
+ lines += linesCleared;
+ score += [40, 100, 300, 1200][linesCleared - 1];
+ document.getElementById('score').textContent = score;
+ document.getElementById('lines').textContent = lines;
+ }
+ }
+
+ function gameLoop() {
+ if(currentPiece && isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {
+ currentPiece.y++;
+ } else {
+ if(currentPiece) {
+ mergePiece();
+ clearLines();
+ }
+ currentPiece = nextPiece || createPiece();
+ nextPiece = createPiece();
+ drawNextPiece();
+
+ if(!isValidMove(currentPiece, currentPiece.x, currentPiece.y)) {
+ alert('Game Over! Score: ' + score);
+ resetGame();
+ }
+ }
+
+ drawBoard();
+ requestAnimationFrame(gameLoop);
+ }
+
+ function resetGame() {
+ board = Array(BOARD_HEIGHT).fill().map(() => Array(BOARD_WIDTH).fill(0));
+ score = 0;
+ lines = 0;
+ document.getElementById('score').textContent = score;
+ document.getElementById('lines').textContent = lines;
+ }
+
+ // Controls
+ document.addEventListener('keydown', e => {
+ if(!currentPiece) return;
+
+ switch(e.key) {
+ case 'ArrowLeft':
+ if(isValidMove(currentPiece, currentPiece.x - 1, currentPiece.y)) {
+ currentPiece.x--;
+ drawBoard();
+ }
+ break;
+ case 'ArrowRight':
+ if(isValidMove(currentPiece, currentPiece.x + 1, currentPiece.y)) {
+ currentPiece.x++;
+ drawBoard();
+ }
+ break;
+ case 'ArrowDown':
+ if(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {
+ currentPiece.y++;
+ drawBoard();
+ }
+ break;
+ case 'ArrowUp':
+ const rotated = rotate(currentPiece);
+ if(isValidMove(rotated, rotated.x, rotated.y)) {
+ currentPiece = rotated;
+ drawBoard();
+ }
+ break;
+ case ' ':
+ while(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {
+ currentPiece.y++;
+ }
+ drawBoard();
+ break;
+ }
+ });
+
+ // Mobile controls
+ document.querySelectorAll('.control-btn').forEach(btn => {
+ btn.addEventListener('touchstart', (e) => {
+ e.preventDefault();
+ btn.dispatchEvent(new Event('click'));
+ });
+ });
+
+ document.querySelector('.left-btn').addEventListener('click', () => {
+ if(isValidMove(currentPiece, currentPiece.x - 1, currentPiece.y)) {
+ currentPiece.x--;
+ drawBoard();
+ }
+ });
+
+ document.querySelector('.right-btn').addEventListener('click', () => {
+ if(isValidMove(currentPiece, currentPiece.x + 1, currentPiece.y)) {
+ currentPiece.x++;
+ drawBoard();
+ }
+ });
+
+ document.querySelector('.rotate-btn').addEventListener('click', () => {
+ const rotated = rotate(currentPiece);
+ if(isValidMove(rotated, rotated.x, rotated.y)) {
+ currentPiece = rotated;
+ drawBoard();
+ }
+ });
+
+ document.querySelector('.down-btn').addEventListener('click', () => {
+ if(isValidMove(currentPiece, currentPiece.x, currentPiece.y + 1)) {
+ currentPiece.y++;
+ drawBoard();
+ }
+ });
+
+ // Start game
+ nextPiece = createPiece();
+ gameLoop();
style.css
Changed around line 1
+ :root {
+ --bg: #1a1a2e;
+ --primary: #0f3460;
+ --accent: #e94560;
+ --text: #f1f1f1;
+ --neon: #4fdcff;
+ }
+
+ body {
+ margin: 0;
+ background: linear-gradient(45deg, var(--bg), #16213e);
+ color: var(--text);
+ font-family: system-ui, -apple-system, sans-serif;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .game-header {
+ text-align: center;
+ padding: 2rem;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .glitch {
+ position: relative;
+ font-size: 4rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5rem;
+ color: var(--neon);
+ text-shadow: 0 0 10px var(--neon);
+ }
+
+ .glitch::before {
+ content: attr(data-text);
+ position: absolute;
+ left: -2px;
+ text-shadow: 2px 0 #ff00c1;
+ animation: glitch-1 2s infinite linear alternate-reverse;
+ }
+
+ @keyframes glitch-1 {
+ 0% { clip-path: inset(20% 0 30% 0); }
+ 100% { clip-path: inset(10% 0 40% 0); }
+ }
+
+ .game-container {
+ display: grid;
+ grid-template-columns: auto 150px;
+ gap: 2rem;
+ justify-content: center;
+ padding: 1rem;
+ }
+
+ #gameCanvas {
+ border: 3px solid var(--primary);
+ border-radius: 5px;
+ box-shadow: 0 0 20px var(--primary);
+ background: rgba(0,0,0,0.3);
+ }
+
+ .side-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+ }
+
+ #nextCanvas {
+ border: 2px solid var(--accent);
+ border-radius: 5px;
+ background: rgba(0,0,0,0.2);
+ width: 100%;
+ }
+
+ .stats {
+ font-size: 1.5rem;
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+ }
+
+ .mobile-controls {
+ display: none;
+ gap: 0.5rem;
+ justify-content: center;
+ }
+
+ .control-btn {
+ background: var(--primary);
+ border: 2px solid var(--accent);
+ color: var(--text);
+ padding: 1rem;
+ border-radius: 50%;
+ font-size: 1.5rem;
+ cursor: pointer;
+ touch-action: manipulation;
+ transition: all 0.2s;
+ }
+
+ .control-btn:active {
+ background: var(--accent);
+ transform: scale(0.9);
+ }
+
+ .game-footer {
+ text-align: center;
+ padding: 2rem;
+ margin-top: auto;
+ }
+
+ @media (max-width: 600px) {
+ .game-container {
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto;
+ }
+
+ .mobile-controls {
+ display: flex;
+ margin-top: 1rem;
+ }
+
+ #gameCanvas {
+ width: 100%;
+ height: auto;
+ }
+ }