This commit is contained in:
gpt-engineer-app[bot]
2026-01-02 22:01:17 +00:00
parent ca38e98ca5
commit b70c67b5b2
6 changed files with 228 additions and 125 deletions
+25 -18
View File
@@ -7,6 +7,7 @@ import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
const PADDLE_HEIGHT = 14;
const BRICK_ROWS = 6;
@@ -53,7 +54,8 @@ const Breakout = () => {
const isMobile = window.innerWidth < 768;
if (isMobile) {
const maxWidth = window.innerWidth - 32;
const maxHeight = window.innerHeight - 280;
// Reserve space for header + fixed controls dock on mobile
const maxHeight = window.innerHeight - 380;
const aspectRatio = 480 / 580;
let width = maxWidth;
let height = width / aspectRatio;
@@ -279,24 +281,29 @@ const Breakout = () => {
)}
{isMobile && (
<div className="mt-4 flex flex-col items-center gap-2 w-full">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LVL</p><p className="font-minecraft text-sm text-primary">{level}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60"></p><p className="font-minecraft text-sm text-primary">{lives}</p></div>
</div>
{gameStarted && !gameOver && (
<div className="flex gap-4 mt-2">
<GameTouchButton onAction={moveLeft} className="p-4 px-8 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={30}></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 px-6 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={moveRight} className="p-4 px-8 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={30}></GameTouchButton>
<>
<MobileControlsSpacer heightClassName="h-36" />
<MobileControlsDock>
<div className="flex flex-col items-center gap-2">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LVL</p><p className="font-minecraft text-sm text-primary">{level}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60"></p><p className="font-minecraft text-sm text-primary">{lives}</p></div>
</div>
{gameStarted && !gameOver ? (
<div className="flex gap-3 mt-2">
<GameTouchButton onAction={moveLeft} className="p-4 px-8 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={30}></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 px-6 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={moveRight} className="p-4 px-8 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={30}></GameTouchButton>
</div>
) : (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameOver ? 'RETRY' : 'START'}</button>
)}
</div>
)}
{(!gameStarted || gameOver) && (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameOver ? 'RETRY' : 'START'}</button>
)}
</div>
</MobileControlsDock>
</>
)}
</div>
+32 -23
View File
@@ -7,6 +7,7 @@ import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
const GRID_WIDTH = 21;
const GRID_HEIGHT = 21;
@@ -76,7 +77,8 @@ const Pacman = () => {
const isMobile = window.innerWidth < 768;
if (isMobile) {
const maxWidth = window.innerWidth - 40;
const maxHeight = window.innerHeight - 300;
// Reserve space for header + fixed controls dock on mobile
const maxHeight = window.innerHeight - 420;
return Math.min(Math.floor(maxWidth / GRID_WIDTH), Math.floor(maxHeight / GRID_HEIGHT), 16);
}
return isFullscreen ? 26 : 20;
@@ -352,29 +354,36 @@ const Pacman = () => {
)}
{isMobile && (
<div className="mt-4 flex flex-col items-center gap-2 w-full">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LVL</p><p className="font-minecraft text-sm text-primary">{level}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete && (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => setNextDirection('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => setNextDirection('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<>
<MobileControlsSpacer />
<MobileControlsDock>
<div className="flex flex-col items-center gap-2">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LVL</p><p className="font-minecraft text-sm text-primary">{level}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete ? (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => setNextDirection('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => setNextDirection('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => setNextDirection('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
</div>
) : (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}
</button>
)}
</div>
)}
{(!gameStarted || gameOver || gameComplete) && (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}</button>
)}
</div>
</MobileControlsDock>
</>
)}
</div>
+32 -25
View File
@@ -7,6 +7,7 @@ import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
const GRID_SIZE = 20;
const TICK_SPEED = 120;
@@ -42,7 +43,8 @@ const Snake = () => {
const isMobile = window.innerWidth < 768;
if (isMobile) {
const maxWidth = window.innerWidth - 40;
const maxHeight = window.innerHeight - 300;
// Reserve space for header + fixed controls dock on mobile
const maxHeight = window.innerHeight - 420;
return Math.min(Math.floor(maxWidth / GRID_SIZE), Math.floor(maxHeight / GRID_SIZE), 18);
}
return isFullscreen ? 28 : 24;
@@ -313,31 +315,36 @@ const Snake = () => {
{/* Mobile Controls */}
{isMobile && (
<div className="mt-4 flex flex-col items-center gap-2 w-full">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LEN</p><p className="font-minecraft text-sm text-primary">{snake.length}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete && (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => directionQueueRef.current.push('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<>
<MobileControlsSpacer />
<MobileControlsDock>
<div className="flex flex-col items-center gap-2">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LEN</p><p className="font-minecraft text-sm text-primary">{snake.length}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete ? (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('up')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('left')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={() => setIsPaused(p => !p)} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={() => directionQueueRef.current.push('right')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<GameTouchButton onAction={() => directionQueueRef.current.push('down')} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
</div>
) : (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}
</button>
)}
</div>
)}
{(!gameStarted || gameOver || gameComplete) && (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}
</button>
)}
</div>
</MobileControlsDock>
</>
)}
</div>
+69 -36
View File
@@ -4,6 +4,7 @@ import { useSettings } from '@/contexts/SettingsContext';
import { Link } from 'react-router-dom';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
const GRID_SIZE = 20;
const TICK_SPEED = 120;
@@ -44,7 +45,8 @@ const SnakeMultiplayer = () => {
const isMobile = window.innerWidth < 768;
if (isMobile) {
const maxWidth = window.innerWidth - 40;
const maxHeight = window.innerHeight - 300;
// Reserve space for header + fixed controls dock on mobile
const maxHeight = window.innerHeight - 420;
return Math.min(Math.floor(maxWidth / GRID_SIZE), Math.floor(maxHeight / GRID_SIZE), 16);
}
return isFullscreen ? 24 : 20;
@@ -292,44 +294,75 @@ const SnakeMultiplayer = () => {
<div className="grid" style={{ gridTemplateColumns: `repeat(${GRID_SIZE}, ${cellSize}px)` }}>{renderGrid()}</div>
</div>
<div className="flex flex-col gap-2 min-w-[160px]">
{/* Player 1 Stats */}
<div className="border border-primary/50 p-3 bg-background/50">
<div className="flex items-center gap-2 mb-1">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[0].color }} />
<p className="font-pixel text-[10px] text-foreground/60">PLAYER 1 (WASD)</p>
{!isMobile && (
<div className="flex flex-col gap-2 min-w-[160px]">
{/* Player 1 Stats */}
<div className="border border-primary/50 p-3 bg-background/50">
<div className="flex items-center gap-2 mb-1">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[0].color }} />
<p className="font-pixel text-[10px] text-foreground/60">PLAYER 1 (WASD)</p>
</div>
<p className="font-minecraft text-lg text-primary text-glow">{players[0].score}</p>
{!players[0].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
</div>
<p className="font-minecraft text-lg text-primary text-glow">{players[0].score}</p>
{!players[0].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
</div>
{/* Player 2 Stats */}
<div className="border border-purple-500/50 p-3 bg-background/50">
<div className="flex items-center gap-2 mb-1">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[1].color }} />
<p className="font-pixel text-[10px] text-foreground/60">PLAYER 2 ()</p>
{/* Player 2 Stats */}
<div className="border border-purple-500/50 p-3 bg-background/50">
<div className="flex items-center gap-2 mb-1">
<div className="w-3 h-3 rounded-sm" style={{ backgroundColor: players[1].color }} />
<p className="font-pixel text-[10px] text-foreground/60">PLAYER 2 ()</p>
</div>
<p className="font-minecraft text-lg text-purple-400">{players[1].score}</p>
{!players[1].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
</div>
<p className="font-minecraft text-lg text-purple-400">{players[1].score}</p>
{!players[1].alive && <p className="font-pixel text-[8px] text-destructive">DEAD</p>}
<div className="border border-primary/50 p-3 bg-background/50">
<p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p>
<p className="font-pixel text-[9px] text-primary">P1: W A S D</p>
<p className="font-pixel text-[9px] text-purple-400">P2: </p>
<p className="font-pixel text-[9px] text-foreground/80 mt-1">P: Pause</p>
</div>
{!gameStarted || gameOver ? (
<button onClick={startGame} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameOver ? 'PLAY AGAIN' : 'START'}
</button>
) : (
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">
{isPaused ? 'RESUME' : 'PAUSE'}
</button>
)}
</div>
<div className="border border-primary/50 p-3 bg-background/50">
<p className="font-pixel text-[10px] text-foreground/60 mb-1">CONTROLS</p>
<p className="font-pixel text-[9px] text-primary">P1: W A S D</p>
<p className="font-pixel text-[9px] text-purple-400">P2: </p>
<p className="font-pixel text-[9px] text-foreground/80 mt-1">P: Pause</p>
</div>
{!gameStarted || gameOver ? (
<button onClick={startGame} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameOver ? 'PLAY AGAIN' : 'START'}
</button>
) : (
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-2 px-4 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all">
{isPaused ? 'RESUME' : 'PAUSE'}
</button>
)}
</div>
)}
{isMobile && (
<>
<MobileControlsSpacer />
<MobileControlsDock>
<div className="flex flex-col items-center gap-2">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">P1</p><p className="font-minecraft text-sm text-primary">{players[0].score}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">P2</p><p className="font-minecraft text-sm text-purple-400">{players[1].score}</p></div>
</div>
{!gameStarted || gameOver ? (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{gameOver ? 'PLAY AGAIN' : 'START'}
</button>
) : (
<button onClick={() => setIsPaused(p => !p)} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
{isPaused ? 'RESUME' : 'PAUSE'}
</button>
)}
<div className="flex gap-3 font-pixel text-[10px] text-foreground/70">
<span className="text-primary">P1: WASD</span>
<span className="text-purple-400">P2: </span>
</div>
</div>
</MobileControlsDock>
</>
)}
</div>
{/* Game Over / Pause Overlay */}
+30 -23
View File
@@ -7,6 +7,7 @@ import GlitchCrash from '@/components/GlitchCrash';
import { Maximize2, Minimize2 } from 'lucide-react';
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
import GameTouchButton from '@/components/GameTouchButton';
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
const BOARD_WIDTH = 10;
const BOARD_HEIGHT = 20;
@@ -79,7 +80,8 @@ const Tetris = () => {
const isMobile = window.innerWidth < 768;
if (isMobile) {
const maxWidth = window.innerWidth - 40;
const maxHeight = window.innerHeight - 320;
// Reserve space for header + fixed controls dock on mobile
const maxHeight = window.innerHeight - 440;
return Math.min(Math.floor(maxWidth / BOARD_WIDTH), Math.floor(maxHeight / BOARD_HEIGHT), 22);
}
return isFullscreen ? 30 : 24;
@@ -326,29 +328,34 @@ const Tetris = () => {
</div>
)}
{isMobile && (
<div className="mt-4 flex flex-col items-center gap-2 w-full">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-primary">{lines}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete && (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={rotatePiece} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={200}></GameTouchButton>
<div />
<GameTouchButton onAction={moveLeft} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<GameTouchButton onAction={hardDrop} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px]" interval={500}>DROP</GameTouchButton>
<GameTouchButton onAction={moveRight} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={togglePause} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={moveDown} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
<>
<MobileControlsSpacer />
<MobileControlsDock>
<div className="flex flex-col items-center gap-2">
<div className="flex gap-4 text-center">
<div><p className="font-pixel text-[8px] text-foreground/60">SCORE</p><p className="font-minecraft text-sm text-primary">{score.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">HIGH</p><p className="font-minecraft text-sm text-primary">{highScore.toLocaleString()}</p></div>
<div><p className="font-pixel text-[8px] text-foreground/60">LINES</p><p className="font-minecraft text-sm text-primary">{lines}</p></div>
</div>
{gameStarted && !gameOver && !gameComplete ? (
<div className="grid grid-cols-3 gap-1 mt-2">
<div />
<GameTouchButton onAction={rotatePiece} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg" interval={200}></GameTouchButton>
<div />
<GameTouchButton onAction={moveLeft} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<GameTouchButton onAction={hardDrop} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px]" interval={500}>DROP</GameTouchButton>
<GameTouchButton onAction={moveRight} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<button onClick={togglePause} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-[10px] select-none">{isPaused ? '▶' : '❚❚'}</button>
<GameTouchButton onAction={moveDown} className="p-4 border border-primary/50 active:bg-primary/40 text-primary font-pixel text-lg"></GameTouchButton>
<div />
</div>
) : (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}</button>
)}
</div>
)}
{(!gameStarted || gameOver || gameComplete) && (
<button onClick={startGame} className="font-minecraft text-sm py-3 px-8 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">{gameComplete ? 'PERFECT!' : gameOver ? 'RETRY' : 'START'}</button>
)}
</div>
</MobileControlsDock>
</>
)}
</div>
{!isMobile && (gameOver || isPaused || gameComplete) && gameStarted && (