Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PixelCanvas - Multiplayer Drawing Game</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.min.js"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#6366f1', | |
| secondary: '#8b5cf6', | |
| accent: '#ec4899', | |
| dark: '#1e293b', | |
| light: '#f8fafc' | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| .pixelated { | |
| image-rendering: pixelated; | |
| } | |
| .glow { | |
| box-shadow: 0 0 15px rgba(139, 92, 246, 0.5); | |
| } | |
| .canvas-container { | |
| position: relative; | |
| overflow: hidden; | |
| border-radius: 0.75rem; | |
| } | |
| .drawing-cursor { | |
| cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='5'/%3E%3C/svg%3E") 8 8, auto; | |
| } | |
| #messageContainer::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| #messageContainer::-webkit-scrollbar-track { | |
| background: #1e293b; | |
| } | |
| #messageContainer::-webkit-scrollbar-thumb { | |
| background: #6366f1; | |
| border-radius: 4px; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-dark text-light min-h-screen flex flex-col"> | |
| <header class="bg-gradient-to-r from-primary to-secondary py-4 px-6"> | |
| <div class="container mx-auto flex justify-between items-center"> | |
| <div class="flex items-center space-x-2"> | |
| <i class="fas fa-paint-brush text-3xl"></i> | |
| <h1 class="text-2xl font-bold">PixelCanvas</h1> | |
| </div> | |
| <div id="playerStatus" class="flex items-center space-x-2"> | |
| <div class="h-3 w-3 rounded-full bg-green-500 animate-pulse"></div> | |
| <span id="onlineCount">0</span> players online | |
| </div> | |
| </div> | |
| </header> | |
| <main class="flex-grow container mx-auto px-4 py-8"> | |
| <div id="gameScreen" class="hidden grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <div class="lg:col-span-2"> | |
| <div class="bg-gray-800 rounded-xl p-4 shadow-lg"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-bold">Collaborative Canvas</h2> | |
| <div id="timer" class="bg-secondary px-3 py-1 rounded-md">02:30</div> | |
| </div> | |
| <div class="canvas-container relative border-2 border-gray-700 rounded-lg bg-white glow"> | |
| <canvas id="drawingCanvas" width="800" height="500" class="drawing-cursor w-full"></canvas> | |
| <div class="absolute top-2 left-2 bg-gray-900 bg-opacity-80 text-white rounded-lg px-3 py-2 text-sm"> | |
| <span id="currentTool">Brush</span> | |
| </div> | |
| </div> | |
| <div class="mt-4 flex flex-wrap gap-2"> | |
| <button id="brushBtn" class="tool-btn bg-primary px-3 py-2 rounded-md hover:opacity-90"> | |
| <i class="fas fa-paintbrush mr-1"></i> Brush | |
| </button> | |
| <button id="eraserBtn" class="tool-btn bg-gray-600 px-3 py-2 rounded-md hover:opacity-90"> | |
| <i class="fas fa-eraser mr-1"></i> Eraser | |
| </button> | |
| <button id="clearBtn" class="tool-btn bg-red-600 px-3 py-2 rounded-md hover:opacity-90"> | |
| <i class="fas fa-trash mr-1"></i> Clear | |
| </button> | |
| <div class="ml-auto flex items-center"> | |
| <span class="text-sm mr-2">Color:</span> | |
| <input type="color" id="colorPicker" value="#6366f1" class="w-10 h-10 rounded cursor-pointer"> | |
| </div> | |
| <div class="flex items-center"> | |
| <span class="text-sm mr-2">Size:</span> | |
| <input type="range" id="brushSize" min="1" max="50" value="5" class="w-32 rounded"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="lg:col-span-1 space-y-6"> | |
| <div class="bg-gray-800 rounded-xl p-4 shadow-lg"> | |
| <h2 class="text-xl font-bold mb-4">Players</h2> | |
| <div id="playersList" class="space-y-2"> | |
| <div class="flex items-center bg-gray-700 p-2 rounded-md"> | |
| <div class="h-10 w-10 rounded-full bg-primary flex items-center justify-center mr-3"> | |
| <span class="font-bold">P</span> | |
| </div> | |
| <div> | |
| <span class="font-medium">Player1</span> | |
| <div class="text-xs text-green-400">Drawing...</div> | |
| </div> | |
| <div class="ml-auto bg-secondary px-2 py-1 rounded text-sm">123</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-800 rounded-xl p-4 shadow-lg"> | |
| <h2 class="text-xl font-bold mb-4">Chat</h2> | |
| <div id="messageContainer" class="h-64 overflow-y-auto mb-4 bg-gray-900 rounded-lg p-3"> | |
| <div class="text-center text-gray-500 italic">Game starting...</div> | |
| </div> | |
| <div class="flex"> | |
| <input type="text" id="messageInput" placeholder="Type your message..." class="flex-grow bg-gray-700 rounded-l-lg px-4 py-2 focus:outline-none"> | |
| <button id="sendBtn" class="bg-primary hover:bg-indigo-600 px-4 py-2 rounded-r-lg"> | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="lobby" class="max-w-2xl mx-auto"> | |
| <div class="text-center py-12"> | |
| <div class="bg-gradient-to-r from-primary to-secondary w-32 h-32 mx-auto rounded-full flex items-center justify-center mb-6 glow"> | |
| <i class="fas fa-palette text-6xl text-white"></i> | |
| </div> | |
| <h1 class="text-4xl font-bold mb-2">PixelCanvas</h1> | |
| <p class="text-gray-300 mb-8 text-lg">Collaborative drawing with players around the world</p> | |
| <div class="bg-gray-800 rounded-xl p-8 mb-8"> | |
| <div class="flex flex-col md:flex-row gap-4 mb-6"> | |
| <input type="text" id="username" placeholder="Enter your username" class="bg-gray-700 rounded-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-primary flex-grow" value="Player"> | |
| <button id="joinBtn" class="bg-gradient-to-r from-primary to-secondary hover:from-indigo-700 hover:to-purple-700 rounded-lg px-8 py-3 font-medium transform transition hover:scale-105"> | |
| <i class="fas fa-play mr-2"></i> Join Game | |
| </button> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="bg-gray-900 p-4 rounded-lg"> | |
| <div class="text-accent mb-2"><i class="fas fa-users fa-2x"></i></div> | |
| <h3 class="font-bold mb-1">Multiplayer</h3> | |
| <p class="text-sm text-gray-400">Play with anyone around the world</p> | |
| </div> | |
| <div class="bg-gray-900 p-4 rounded-lg"> | |
| <div class="text-green-400 mb-2"><i class="fas fa-paint-brush fa-2x"></i></div> | |
| <h3 class="font-bold mb-1">Real-time</h3> | |
| <p class="text-sm text-gray-400">See drawings appear instantly</p> | |
| </div> | |
| <div class="bg-gray-900 p-4 rounded-lg"> | |
| <div class="text-yellow-400 mb-2"><i class="fas fa-trophy fa-2x"></i></div> | |
| <h3 class="font-bold mb-1">Competitive</h3> | |
| <p class="text-sm text-gray-400">Earn points for creativity</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-800 rounded-xl p-6"> | |
| <h2 class="text-xl font-bold mb-4">How to Play</h2> | |
| <ol class="space-y-3 text-left max-w-md mx-auto"> | |
| <li class="flex items-start"> | |
| <div class="bg-primary rounded-full h-6 w-6 flex items-center justify-center text-xs mr-3 mt-1">1</div> | |
| <p>Join a game and wait for players</p> | |
| </li> | |
| <li class="flex items-start"> | |
| <div class="bg-primary rounded-full h-6 w-6 flex items-center justify-center text-xs mr-3 mt-1">2</div> | |
| <p>When your turn comes, draw the assigned word</p> | |
| </li> | |
| <li class="flex items-start"> | |
| <div class="bg-primary rounded-full h-6 w-6 flex items-center justify-center text-xs mr-3 mt-1">3</div> | |
| <p>Other players guess what you're drawing in chat</p> | |
| </li> | |
| <li class="flex items-start"> | |
| <div class="bg-primary rounded-full h-6 w-6 flex items-center justify-center text-xs mr-3 mt-1">4</div> | |
| <p>Earn points for correct guesses and creative drawings</p> | |
| </li> | |
| </ol> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <footer class="bg-gray-900 py-6"> | |
| <div class="container mx-auto text-center text-gray-500"> | |
| <p>PixelCanvas Multiplayer Game | Made with Socket.io, HTML, CSS & JavaScript</p> | |
| <div class="mt-2 flex justify-center space-x-4"> | |
| <a href="#" class="hover:text-primary"><i class="fab fa-github"></i></a> | |
| <a href="#" class="hover:text-primary"><i class="fab fa-twitter"></i></a> | |
| <a href="#" class="hover:text-primary"><i class="fab fa-discord"></i></a> | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // DOM elements | |
| const lobby = document.getElementById('lobby'); | |
| const gameScreen = document.getElementById('gameScreen'); | |
| const joinBtn = document.getElementById('joinBtn'); | |
| const usernameInput = document.getElementById('username'); | |
| const onlineCount = document.getElementById('onlineCount'); | |
| const playersList = document.getElementById('playersList'); | |
| const messageContainer = document.getElementById('messageContainer'); | |
| const messageInput = document.getElementById('messageInput'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const drawingCanvas = document.getElementById('drawingCanvas'); | |
| const brushBtn = document.getElementById('brushBtn'); | |
| const eraserBtn = document.getElementById('eraserBtn'); | |
| const clearBtn = document.getElementById('clearBtn'); | |
| const colorPicker = document.getElementById('colorPicker'); | |
| const brushSize = document.getElementById('brushSize'); | |
| const currentTool = document.getElementById('currentTool'); | |
| const timer = document.getElementById('timer'); | |
| // Canvas context | |
| const ctx = drawingCanvas.getContext('2d'); | |
| // State variables | |
| let isDrawing = false; | |
| let lastX = 0; | |
| let lastY = 0; | |
| let currentColor = '#6366f1'; | |
| let currentSize = 5; | |
| let isEraser = false; | |
| let socket; | |
| // Initialize canvas | |
| ctx.fillStyle = 'white'; | |
| ctx.fillRect(0, 0, drawingCanvas.width, drawingCanvas.height); | |
| ctx.lineJoin = 'round'; | |
| ctx.lineCap = 'round'; | |
| ctx.lineWidth = currentSize; | |
| // Drawing functions | |
| function startDrawing(e) { | |
| isDrawing = true; | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| } | |
| function draw(e) { | |
| if (!isDrawing) return; | |
| ctx.strokeStyle = isEraser ? 'white' : currentColor; | |
| ctx.lineWidth = currentSize; | |
| ctx.beginPath(); | |
| ctx.moveTo(lastX, lastY); | |
| ctx.lineTo(e.offsetX, e.offsetY); | |
| ctx.stroke(); | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| // Simulate sending drawing data to server | |
| const drawingData = { | |
| startX: lastX, | |
| startY: lastY, | |
| endX: e.offsetX, | |
| endY: e.offsetY, | |
| color: isEraser ? 'white' : currentColor, | |
| size: currentSize | |
| }; | |
| console.log("Drawing data:", drawingData); | |
| } | |
| function stopDrawing() { | |
| isDrawing = false; | |
| } | |
| // Canvas event listeners | |
| drawingCanvas.addEventListener('mousedown', startDrawing); | |
| drawingCanvas.addEventListener('mousemove', draw); | |
| drawingCanvas.addEventListener('mouseup', stopDrawing); | |
| drawingCanvas.addEventListener('mouseout', stopDrawing); | |
| // Tool selection | |
| brushBtn.addEventListener('click', () => { | |
| isEraser = false; | |
| currentTool.textContent = 'Brush'; | |
| brushBtn.classList.add('bg-primary'); | |
| eraserBtn.classList.remove('bg-primary'); | |
| eraserBtn.classList.add('bg-gray-600'); | |
| }); | |
| eraserBtn.addEventListener('click', () => { | |
| isEraser = true; | |
| currentTool.textContent = 'Eraser'; | |
| eraserBtn.classList.add('bg-primary'); | |
| eraserBtn.classList.remove('bg-gray-600'); | |
| brushBtn.classList.remove('bg-primary'); | |
| brushBtn.classList.add('bg-gray-600'); | |
| }); | |
| clearBtn.addEventListener('click', () => { | |
| ctx.fillStyle = 'white'; | |
| ctx.fillRect(0, 0, drawingCanvas.width, drawingCanvas.height); | |
| }); | |
| // Color and size pickers | |
| colorPicker.addEventListener('input', (e) => { | |
| currentColor = e.target.value; | |
| }); | |
| brushSize.addEventListener('input', (e) => { | |
| currentSize = e.target.value; | |
| }); | |
| // Chat functionality | |
| function sendMessage() { | |
| const message = messageInput.value.trim(); | |
| if (message) { | |
| // Simulate message sending | |
| addMessage("You", message, true); | |
| // Clear input | |
| messageInput.value = ''; | |
| } | |
| } | |
| sendBtn.addEventListener('click', sendMessage); | |
| messageInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| function addMessage(name, text, isSelf = false) { | |
| const messageElement = document.createElement('div'); | |
| messageElement.classList.add('mb-3', 'last:mb-0'); | |
| if (isSelf) { | |
| messageElement.innerHTML = ` | |
| <div class="flex justify-end"> | |
| <div class="bg-primary text-white rounded-xl rounded-tr-none p-3 max-w-xs md:max-w-md"> | |
| <div class="font-medium mb-1">${name}</div> | |
| <div>${text}</div> | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| messageElement.innerHTML = ` | |
| <div class="flex"> | |
| <div class="bg-gray-700 rounded-xl rounded-tl-none p-3 max-w-xs md:max-w-md"> | |
| <div class="font-medium mb-1">${name}</div> | |
| <div>${text}</div> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| messageContainer.appendChild(messageElement); | |
| messageContainer.scrollTop = messageContainer.scrollHeight; | |
| } | |
| // Fake messages to simulate gameplay | |
| function simulateGameplay() { | |
| setTimeout(() => { | |
| addMessage("System", "Word to draw: Cat"); | |
| }, 1000); | |
| setTimeout(() => { | |
| addMessage("Player2", "Is it an animal?"); | |
| }, 3000); | |
| setTimeout(() => { | |
| addMessage("Player3", "I think it's a cat!"); | |
| addMessage("System", "Player3 guessed correctly! +10 points"); | |
| }, 6000); | |
| } | |
| // Join game | |
| joinBtn.addEventListener('click', () => { | |
| const username = usernameInput.value || "Player"; | |
| // Simulate connecting to the server | |
| console.log(`Connecting as ${username}...`); | |
| // Show loading state | |
| joinBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Connecting...'; | |
| joinBtn.disabled = true; | |
| // Simulate connection process | |
| setTimeout(() => { | |
| // Switch to game screen | |
| lobby.classList.add('hidden'); | |
| gameScreen.classList.remove('hidden'); | |
| // Add fake players | |
| playersList.innerHTML = ` | |
| <div class="flex items-center bg-gray-700 p-2 rounded-md"> | |
| <div class="h-10 w-10 rounded-full bg-primary flex items-center justify-center mr-3"> | |
| <span class="font-bold">${username.charAt(0)}</span> | |
| </div> | |
| <div> | |
| <span class="font-medium">${username}</span> | |
| <div class="text-xs text-purple-400">You</div> | |
| </div> | |
| <div class="ml-auto bg-secondary px-2 py-1 rounded text-sm">0</div> | |
| </div> | |
| <div class="flex items-center bg-gray-700 p-2 rounded-md"> | |
| <div class="h-10 w-10 rounded-full bg-purple-500 flex items-center justify-center mr-3"> | |
| <span class="font-bold">A</span> | |
| </div> | |
| <div> | |
| <span class="font-medium">Artist123</span> | |
| <div class="text-xs text-green-400">Drawing...</div> | |
| </div> | |
| <div class="ml-auto bg-secondary px-2 py-1 rounded text-sm">87</div> | |
| </div> | |
| <div class="flex items-center bg-gray-700 p-2 rounded-md"> | |
| <div class="h-10 w-10 rounded-full bg-pink-500 flex items-center justify-center mr-3"> | |
| <span class="font-bold">G</span> | |
| </div> | |
| <div> | |
| <span class="font-medium">Guesser99</span> | |
| <div class="text-xs text-gray-400">Waiting</div> | |
| </div> | |
| <div class="ml-auto bg-secondary px-2 py-1 rounded text-sm">42</div> | |
| </div> | |
| <div class="flex items-center bg-gray-700 p-2 rounded-md"> | |
| <div class="h-10 w-10 rounded-full bg-yellow-500 flex items-center justify-center mr-3"> | |
| <span class="font-bold">C</span> | |
| </div> | |
| <div> | |
| <span class="font-medium">CreativeDrawer</span> | |
| <div class="text-xs text-gray-400">Waiting</div> | |
| </div> | |
| <div class="ml-auto bg-secondary px-2 py-1 rounded text-sm">65</div> | |
| </div> | |
| `; | |
| // Update online count | |
| onlineCount.textContent = '4'; | |
| // Start timer | |
| startTimer(150); // 2 minutes 30 seconds | |
| // Simulate gameplay messages | |
| simulateGameplay(); | |
| }, 1500); | |
| }); | |
| // Timer function | |
| function startTimer(duration) { | |
| let timerValue = duration; | |
| const interval = setInterval(() => { | |
| const minutes = Math.floor(timerValue / 60); | |
| const seconds = timerValue % 60; | |
| timer.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; | |
| if (--timerValue < 0) { | |
| clearInterval(interval); | |
| timer.textContent = "00:00"; | |
| addMessage("System", "Round completed! New round starting..."); | |
| } | |
| }, 1000); | |
| } | |
| // Initialize placeholder socket connection | |
| console.log("Socket.IO client loaded. This would connect to a real server."); | |
| }); | |
| </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=LULDev/tttesttttttt" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |