| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>AI PONG SHOWDOWN</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); |
| |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
| |
| body { |
| background-color: #0a0a1a; |
| font-family: 'Orbitron', sans-serif; |
| color: #00fffc; |
| overflow: hidden; |
| height: 100vh; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| #game-container { |
| position: relative; |
| width: 100%; |
| max-width: 800px; |
| height: auto; |
| aspect-ratio: 8/5; |
| border: 2px solid #00fffc; |
| box-shadow: 0 0 20px #00fffc, inset 0 0 20px #00fffc; |
| overflow: hidden; |
| background-color: rgba(0, 0, 20, 0.7); |
| } |
| |
| #game-canvas { |
| width: 100%; |
| height: 100%; |
| background-color: transparent; |
| display: block; |
| } |
| |
| #score { |
| display: flex; |
| justify-content: space-between; |
| width: 100%; |
| max-width: 800px; |
| margin-bottom: 20px; |
| font-size: clamp(16px, 3vw, 24px); |
| text-shadow: 0 0 10px #00fffc; |
| } |
| |
| .score-display { |
| padding: clamp(5px, 1.5vw, 10px) clamp(10px, 4vw, 30px); |
| background-color: rgba(0, 255, 252, 0.1); |
| border: 1px solid #00fffc; |
| border-radius: 5px; |
| } |
| |
| #settings-panel { |
| position: absolute; |
| top: 10px; |
| right: 10px; |
| z-index: 20; |
| display: flex; |
| flex-direction: column; |
| gap: 5px; |
| } |
| |
| #start-screen, #game-over { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| background-color: rgba(0, 0, 20, 0.8); |
| z-index: 10; |
| } |
| |
| h1 { |
| font-size: clamp(24px, 6vw, 48px); |
| margin-bottom: clamp(15px, 4vw, 30px); |
| text-shadow: 0 0 15px #00fffc; |
| letter-spacing: 3px; |
| text-align: center; |
| } |
| |
| button { |
| background-color: transparent; |
| color: #00fffc; |
| border: 2px solid #00fffc; |
| padding: clamp(10px, 2.5vw, 15px) clamp(15px, 4vw, 30px); |
| font-family: 'Orbitron', sans-serif; |
| font-size: clamp(14px, 3vw, 18px); |
| cursor: pointer; |
| margin: clamp(5px, 1.5vw, 10px); |
| transition: all 0.3s; |
| text-shadow: 0 0 5px #00fffc; |
| box-shadow: 0 0 10px #00fffc; |
| } |
| |
| button:hover { |
| background-color: rgba(0, 255, 252, 0.2); |
| transform: scale(1.05); |
| } |
| |
| .sm-btn { |
| padding: 5px 10px; |
| font-size: 12px; |
| margin: 0; |
| } |
| |
| #game-over { |
| display: none; |
| } |
| |
| #grid { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background: |
| linear-gradient(rgba(0, 255, 252, 0.05) 1px, transparent 1px), |
| linear-gradient(90deg, rgba(0, 255, 252, 0.05) 1px, transparent 1px); |
| background-size: 20px 20px; |
| z-index: -1; |
| } |
| |
| .particle { |
| position: absolute; |
| width: 2px; |
| height: 2px; |
| background-color: #00fffc; |
| border-radius: 50%; |
| pointer-events: none; |
| z-index: -1; |
| } |
| |
| #instructions { |
| margin-top: clamp(10px, 3vw, 20px); |
| font-size: clamp(10px, 2vw, 14px); |
| color: rgba(0, 255, 252, 0.7); |
| text-align: center; |
| padding: 0 10px; |
| } |
| |
| .ai-selector { |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| margin-bottom: 20px; |
| } |
| |
| .ai-option { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| |
| .ai-option input { |
| accent-color: #00fffc; |
| } |
| |
| |
| .switch { |
| position: relative; |
| display: inline-block; |
| width: 50px; |
| height: 24px; |
| } |
| |
| .switch input { |
| opacity: 0; |
| width: 0; |
| height: 0; |
| } |
| |
| .slider { |
| position: absolute; |
| cursor: pointer; |
| top: 0; |
| left: 0; |
| right: 0; |
| bottom: 0; |
| background-color: rgba(0, 255, 252, 0.2); |
| transition: .4s; |
| border: 1px solid #00fffc; |
| } |
| |
| .slider:before { |
| position: absolute; |
| content: ""; |
| height: 16px; |
| width: 16px; |
| left: 4px; |
| bottom: 3px; |
| background-color: #00fffc; |
| transition: .4s; |
| } |
| |
| input:checked + .slider { |
| background-color: rgba(0, 255, 252, 0.4); |
| } |
| |
| input:checked + .slider:before { |
| transform: translateX(26px); |
| } |
| |
| .slider.round { |
| border-radius: 24px; |
| } |
| |
| .slider.round:before { |
| border-radius: 50%; |
| } |
| |
| |
| .difficulty-selector { |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| margin-bottom: 20px; |
| } |
| |
| .difficulty-option { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| |
| |
| @media (max-width: 600px) { |
| #settings-panel { |
| top: 5px; |
| right: 5px; |
| } |
| |
| button.sm-btn { |
| font-size: 10px; |
| padding: 3px 6px; |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div id="score"> |
| <div id="left-ai-score" class="score-display">AI-1: 0</div> |
| <div id="right-ai-score" class="score-display">AI-2: 0</div> |
| </div> |
| |
| <div id="game-container"> |
| <div id="grid"></div> |
| <canvas id="game-canvas"></canvas> |
| |
| <div id="settings-panel"> |
| <button id="pause-btn" class="sm-btn">⏸ PAUSE</button> |
| <button id="speed-btn" class="sm-btn">⚡ 1X</button> |
| </div> |
| |
| <div id="start-screen"> |
| <h1>AI PONG SHOWDOWN</h1> |
| |
| <div class="ai-selector"> |
| <div class="ai-option"> |
| <label class="switch"> |
| <input type="checkbox" id="human-player-toggle"> |
| <span class="slider round"></span> |
| </label> |
| <span>Human Player?</span> |
| </div> |
| </div> |
| |
| <div class="difficulty-selector"> |
| <h3>AI DIFFICULTY:</h3> |
| <div class="difficulty-option"> |
| <input type="radio" id="easy" name="difficulty" value="easy" checked> |
| <label for="easy">Easy</label> |
| </div> |
| <div class="difficulty-option"> |
| <input type="radio" id="medium" name="difficulty" value="medium"> |
| <label for="medium">Medium</label> |
| </div> |
| <div class="difficulty-option"> |
| <input type="radio" id="hard" name="difficulty" value="hard"> |
| <label for="hard">Hard</label> |
| </div> |
| </div> |
| |
| <button id="start-button">START SHOWDOWN</button> |
| <div id="instructions"> |
| OBSERVE THE AI BATTLE OR PLAY AGAINST THEM<br> |
| FIRST TO SCORE 5 WINS |
| </div> |
| </div> |
| |
| <div id="game-over"> |
| <h1 id="result-text">AI-1 VICTORY!</h1> |
| <button id="restart-button">NEW SHOWDOWN</button> |
| </div> |
| </div> |
| |
| <audio id="paddle-hit" src="data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU..."></audio> |
| <audio id="wall-hit" src="data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU..."></audio> |
| <audio id="score-sound" src="data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU..."></audio> |
| |
| <script> |
| |
| const canvas = document.getElementById('game-canvas'); |
| const ctx = canvas.getContext('2d'); |
| const startScreen = document.getElementById('start-screen'); |
| const gameOverScreen = document.getElementById('game-over'); |
| const resultText = document.getElementById('result-text'); |
| const startButton = document.getElementById('start-button'); |
| const restartButton = document.getElementById('restart-button'); |
| const leftScoreDisplay = document.getElementById('left-ai-score'); |
| const rightScoreDisplay = document.getElementById('right-ai-score'); |
| const pauseBtn = document.getElementById('pause-btn'); |
| const speedBtn = document.getElementById('speed-btn'); |
| const humanPlayerToggle = document.getElementById('human-player-toggle'); |
| |
| |
| const paddleHitSound = document.getElementById('paddle-hit'); |
| const wallHitSound = document.getElementById('wall-hit'); |
| const scoreSound = document.getElementById('score-sound'); |
| |
| |
| let gameRunning = false; |
| let gamePaused = false; |
| let leftScore = 0; |
| let rightScore = 0; |
| const winningScore = 5; |
| let gameSpeed = 1; |
| let humanPlayer = false; |
| let aiStrength = 'medium'; |
| |
| |
| function resizeCanvas() { |
| const container = document.getElementById('game-container'); |
| canvas.width = container.clientWidth; |
| canvas.height = container.clientHeight; |
| } |
| |
| window.addEventListener('resize', () => { |
| resizeCanvas(); |
| resetPositions(); |
| }); |
| |
| |
| resizeCanvas(); |
| |
| |
| let paddleWidth, paddleHeight, paddleSpeed; |
| |
| function calculateDimensions() { |
| paddleWidth = Math.max(10, canvas.width * 0.015); |
| paddleHeight = Math.max(60, canvas.height * 0.2); |
| paddleSpeed = canvas.height * 0.012; |
| } |
| |
| const leftPaddle = { |
| x: 30, |
| y: 0, |
| width: 0, |
| height: 0, |
| dy: 0 |
| }; |
| |
| const rightPaddle = { |
| x: 0, |
| y: 0, |
| width: 0, |
| height: 0, |
| dy: 0 |
| }; |
| |
| |
| let ballSize; |
| let ball = { |
| x: 0, |
| y: 0, |
| width: 0, |
| height: 0, |
| dx: 0, |
| dy: 0 |
| }; |
| |
| function resetPositions() { |
| calculateDimensions(); |
| |
| |
| leftPaddle.width = paddleWidth; |
| leftPaddle.height = paddleHeight; |
| leftPaddle.y = canvas.height / 2 - paddleHeight / 2; |
| leftPaddle.x = canvas.width * 0.03; |
| |
| rightPaddle.width = paddleWidth; |
| rightPaddle.height = paddleHeight; |
| rightPaddle.y = canvas.height / 2 - paddleHeight / 2; |
| rightPaddle.x = canvas.width - (canvas.width * 0.03) - paddleWidth; |
| |
| |
| ballSize = Math.max(8, Math.min(canvas.width * 0.015, canvas.height * 0.02)); |
| ball.width = ballSize; |
| ball.height = ballSize; |
| |
| resetBall(); |
| } |
| |
| |
| const aiProfiles = { |
| easy: { |
| reactionDelay: 0.5, |
| accuracy: 0.7, |
| prediction: 0.4, |
| speedMultiplier: 0.7 |
| }, |
| medium: { |
| reactionDelay: 0.3, |
| accuracy: 0.85, |
| prediction: 0.6, |
| speedMultiplier: 0.85 |
| }, |
| hard: { |
| reactionDelay: 0.1, |
| accuracy: 0.95, |
| prediction: 0.8, |
| speedMultiplier: 1.0 |
| } |
| }; |
| |
| |
| const trail = []; |
| const maxTrailLength = 10; |
| |
| |
| function createParticles() { |
| const particles = []; |
| const particleCount = Math.floor(canvas.width * canvas.height / 2000); |
| |
| for (let i = 0; i < particleCount; i++) { |
| particles.push({ |
| x: Math.random() * canvas.width, |
| y: Math.random() * canvas.height, |
| size: Math.random() * 2 + 1, |
| speed: Math.random() * 2 + 1 |
| }); |
| } |
| |
| return particles; |
| } |
| |
| let particles = createParticles(); |
| |
| |
| function drawPaddle(x, y, width, height, color = '#00fffc') { |
| ctx.fillStyle = color; |
| ctx.shadowBlur = 15; |
| ctx.shadowColor = color; |
| ctx.fillRect(x, y, width, height); |
| ctx.shadowBlur = 0; |
| } |
| |
| function drawBall(x, y, width, height, color = '#ff00f7') { |
| ctx.fillStyle = color; |
| ctx.shadowBlur = 15; |
| ctx.shadowColor = color; |
| ctx.beginPath(); |
| ctx.arc(x + width / 2, y + height / 2, width / 2, 0, Math.PI * 2); |
| ctx.fill(); |
| ctx.shadowBlur = 0; |
| } |
| |
| function drawTrail() { |
| for (let i = 0; i < trail.length; i++) { |
| const opacity = i / trail.length; |
| ctx.fillStyle = `rgba(255, 0, 247, ${opacity})`; |
| ctx.beginPath(); |
| ctx.arc(trail[i].x, trail[i].y, ballSize / 2 * opacity, 0, Math.PI * 2); |
| ctx.fill(); |
| } |
| } |
| |
| function drawParticles() { |
| particles.forEach(particle => { |
| ctx.fillStyle = `rgba(0, 255, 252, ${Math.random() * 0.5})`; |
| ctx.fillRect(particle.x, particle.y, particle.size, particle.size); |
| |
| |
| particle.y += particle.speed; |
| if (particle.y > canvas.height) { |
| particle.y = 0; |
| particle.x = Math.random() * canvas.width; |
| } |
| }); |
| } |
| |
| function drawCenterLine() { |
| ctx.strokeStyle = 'rgba(0, 255, 252, 0.2)'; |
| ctx.lineWidth = 2; |
| ctx.setLineDash([10, 10]); |
| ctx.beginPath(); |
| ctx.moveTo(canvas.width / 2, 0); |
| ctx.lineTo(canvas.width / 2, canvas.height); |
| ctx.stroke(); |
| ctx.setLineDash([]); |
| } |
| |
| |
| function decideAIMovement(paddle, ball, isLeftPaddle, profile) { |
| const paddleCenter = paddle.y + paddle.height / 2; |
| const ballCenter = ball.y + ball.height / 2; |
| |
| |
| let predictedY = ballCenter; |
| if (profile.prediction > 0) { |
| if (ball.dx !== 0) { |
| const framesToContact = Math.abs((paddle.x - ball.x) / ball.dx); |
| predictedY = ballCenter + (ball.dy * framesToContact * profile.prediction); |
| } |
| } |
| |
| |
| predictedY = Math.max(0, Math.min(canvas.height, predictedY)); |
| |
| |
| const targetY = predictedY + (Math.random() - 0.5) * paddle.height * (1 - profile.accuracy); |
| |
| |
| if (paddleCenter < targetY - 10) { |
| return paddleSpeed * profile.speedMultiplier; |
| } else if (paddleCenter > targetY + 10) { |
| return -paddleSpeed * profile.speedMultiplier; |
| } else { |
| return 0; |
| } |
| } |
| |
| |
| function update() { |
| if (gamePaused) return; |
| |
| |
| const difficulty = document.querySelector('input[name="difficulty"]:checked').value; |
| const profile = aiProfiles[difficulty]; |
| |
| |
| if (!humanPlayer || !gameRunning) { |
| leftPaddle.dy = decideAIMovement(leftPaddle, ball, true, profile); |
| } |
| |
| |
| rightPaddle.dy = decideAIMovement(rightPaddle, ball, false, profile); |
| |
| |
| leftPaddle.y += leftPaddle.dy * gameSpeed; |
| rightPaddle.y += rightPaddle.dy * gameSpeed; |
| |
| |
| if (leftPaddle.y < 0) leftPaddle.y = 0; |
| if (leftPaddle.y + leftPaddle.height > canvas.height) { |
| leftPaddle.y = canvas.height - leftPaddle.height; |
| } |
| |
| if (rightPaddle.y < 0) rightPaddle.y = 0; |
| if (rightPaddle.y + rightPaddle.height > canvas.height) { |
| rightPaddle.y = canvas.height - rightPaddle.height; |
| } |
| |
| |
| ball.x += ball.dx * gameSpeed; |
| ball.y += ball.dy * gameSpeed; |
| |
| |
| trail.push({ x: ball.x + ball.width / 2, y: ball.y + ball.height / 2 }); |
| if (trail.length > maxTrailLength) { |
| trail.shift(); |
| } |
| |
| |
| if (ball.y < 0 || ball.y + ball.height > canvas.height) { |
| ball.dy = -ball.dy; |
| wallHitSound.currentTime = 0; |
| wallHitSound.play(); |
| } |
| |
| |
| if ( |
| ball.x < leftPaddle.x + leftPaddle.width && |
| ball.x + ball.width > leftPaddle.x && |
| ball.y < leftPaddle.y + leftPaddle.height && |
| ball.y + ball.height > leftPaddle.y |
| ) { |
| |
| const hitPosition = (ball.y + ball.height / 2) - (leftPaddle.y + leftPaddle.height / 2); |
| const normalizedHit = hitPosition / (leftPaddle.height / 2); |
| ball.dy = normalizedHit * 5 * (humanPlayer ? 1.2 : 1); |
| |
| ball.dx = Math.abs(ball.dx); |
| ball.dx *= humanPlayer ? 1.1 : 1.05; |
| |
| paddleHitSound.currentTime = 0; |
| paddleHitSound.play(); |
| |
| |
| ball.dy += (Math.random() * 2 - 1) * 0.5; |
| } |
| |
| if ( |
| ball.x < rightPaddle.x + rightPaddle.width && |
| ball.x + ball.width > rightPaddle.x && |
| ball.y < rightPaddle.y + rightPaddle.height && |
| ball.y + ball.height > rightPaddle.y |
| ) { |
| |
| const hitPosition = (ball.y + ball.height / 2) - (rightPaddle.y + rightPaddle.height / 2); |
| const normalizedHit = hitPosition / (rightPaddle.height / 2); |
| ball.dy = normalizedHit * 5; |
| |
| ball.dx = -Math.abs(ball.dx); |
| ball.dx *= 1.05; |
| |
| paddleHitSound.currentTime = 0; |
| paddleHitSound.play(); |
| |
| |
| ball.dy += (Math.random() * 2 - 1) * 0.5; |
| } |
| |
| |
| if (ball.x + ball.width < 0) { |
| |
| rightScore++; |
| rightScoreDisplay.textContent = `AI-2: ${rightScore}`; |
| resetBall(); |
| scoreSound.currentTime = 0; |
| scoreSound.play(); |
| |
| if (rightScore >= winningScore) { |
| endGame(false); |
| } |
| } |
| |
| if (ball.x > canvas.width) { |
| |
| leftScore++; |
| leftScoreDisplay.textContent = `AI-1: ${leftScore}`; |
| resetBall(); |
| scoreSound.currentTime = 0; |
| scoreSound.play(); |
| |
| if (leftScore >= winningScore) { |
| endGame(true); |
| } |
| } |
| } |
| |
| function resetBall() { |
| ball.x = canvas.width / 2 - ball.width / 2; |
| ball.y = canvas.height / 2 - ball.height / 2; |
| |
| |
| if (humanPlayer && leftScore !== rightScore) { |
| const direction = leftScore < rightScore ? 1 : -1; |
| ball.dx = direction * 5; |
| } else { |
| |
| ball.dx = (Math.random() > 0.5 ? 1 : -1) * 5; |
| } |
| |
| ball.dy = (Math.random() * 4 - 2); |
| |
| |
| trail.length = 0; |
| } |
| |
| function render() { |
| |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| |
| |
| drawParticles(); |
| drawCenterLine(); |
| |
| |
| drawTrail(); |
| drawPaddle( |
| leftPaddle.x, |
| leftPaddle.y, |
| leftPaddle.width, |
| leftPaddle.height, |
| humanPlayer ? '#00ff9d' : '#00fffc' |
| ); |
| drawPaddle( |
| rightPaddle.x, |
| rightPaddle.y, |
| rightPaddle.width, |
| rightPaddle.height, |
| '#ff00f7' |
| ); |
| drawBall(ball.x, ball.y, ball.width, ball.height); |
| } |
| |
| function gameLoop() { |
| if (gameRunning && !gamePaused) { |
| update(); |
| render(); |
| requestAnimationFrame(gameLoop); |
| } |
| } |
| |
| |
| function startGame() { |
| humanPlayer = humanPlayerToggle.checked; |
| leftScore = 0; |
| rightScore = 0; |
| leftScoreDisplay.textContent = `AI-1: ${leftScore}`; |
| rightScoreDisplay.textContent = humanPlayer ? `YOU: ${rightScore}` : `AI-2: ${rightScore}`; |
| |
| resetPositions(); |
| startScreen.style.display = 'none'; |
| gameOverScreen.style.display = 'none'; |
| gameRunning = true; |
| gamePaused = false; |
| gameLoop(); |
| } |
| |
| function endGame(leftWon) { |
| gameRunning = false; |
| gameOverScreen.style.display = 'flex'; |
| |
| if (humanPlayer) { |
| resultText.textContent = leftWon ? "AI DEFEATED YOU!" : "YOU DEFEATED AI!"; |
| } else { |
| resultText.textContent = leftWon ? "AI-1 IS VICTORIOUS!" : "AI-2 IS VICTORIOUS!"; |
| } |
| } |
| |
| function togglePause() { |
| gamePaused = !gamePaused; |
| pauseBtn.textContent = gamePaused ? "▶ RESUME" : "⏸ PAUSE"; |
| if (gameRunning && !gamePaused) { |
| gameLoop(); |
| } |
| } |
| |
| function cycleGameSpeed() { |
| const speeds = [1, 1.5, 2, 3]; |
| const currentIndex = speeds.indexOf(gameSpeed); |
| const nextIndex = (currentIndex + 1) % speeds.length; |
| gameSpeed = speeds[nextIndex]; |
| speedBtn.textContent = `⚡ ${gameSpeed}X`; |
| } |
| |
| |
| startButton.addEventListener('click', startGame); |
| restartButton.addEventListener('click', startGame); |
| pauseBtn.addEventListener('click', togglePause); |
| speedBtn.addEventListener('click', cycleGameSpeed); |
| |
| humanPlayerToggle.addEventListener('change', function() { |
| rightScoreDisplay.textContent = this.checked ? `YOU: ${rightScore}` : `AI-2: ${rightScore}`; |
| }); |
| |
| |
| document.addEventListener('keydown', (e) => { |
| if (!humanPlayer || !gameRunning) return; |
| |
| if (e.key === 'ArrowUp') { |
| leftPaddle.dy = -paddleSpeed * gameSpeed; |
| } else if (e.key === 'ArrowDown') { |
| leftPaddle.dy = paddleSpeed * gameSpeed; |
| } |
| }); |
| |
| document.addEventListener('keyup', (e) => { |
| if (!humanPlayer || !gameRunning) return; |
| |
| if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { |
| leftPaddle.dy = 0; |
| } |
| }); |
| |
| |
| canvas.addEventListener('mousemove', (e) => { |
| if (!humanPlayer || !gameRunning) return; |
| |
| const rect = canvas.getBoundingClientRect(); |
| const mouseY = e.clientY - rect.top - leftPaddle.height / 2; |
| |
| if (mouseY >= 0 && mouseY <= canvas.height - leftPaddle.height) { |
| leftPaddle.y = mouseY; |
| } |
| }); |
| |
| |
| resetPositions(); |
| particles = createParticles(); |
| </script> |
| <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=Ravisil/pong-ai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |