tttesttttttt / index.html
LULDev's picture
multiplayer web game using socket.io - Follow Up Deployment
ed3eb16 verified
<!DOCTYPE html>
<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>