Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Picnic Panic Pals</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/cannon-es@0.19.0/dist/cannon-es.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> | |
| <style> | |
| #gameCanvas { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: -1; | |
| } | |
| .ragdoll { | |
| transition: all 0.3s ease; | |
| } | |
| .food-item { | |
| cursor: grab; | |
| transition: transform 0.2s; | |
| } | |
| .food-item:active { | |
| cursor: grabbing; | |
| transform: scale(1.1); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-green-50 overflow-hidden"> | |
| <canvas id="gameCanvas"></canvas> | |
| <div class="min-h-screen flex flex-col items-center justify-center p-4"> | |
| <div class="bg-white bg-opacity-90 rounded-3xl shadow-2xl p-8 max-w-4xl w-full"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h1 class="text-4xl font-bold text-green-700">Picnic Panic Pals</h1> | |
| <div class="flex items-center space-x-4"> | |
| <div class="bg-yellow-100 px-4 py-2 rounded-full flex items-center"> | |
| <i data-feather="clock" class="text-yellow-600 mr-2"></i> | |
| <span class="font-bold text-yellow-800" id="timer">03:00</span> | |
| </div> | |
| <div class="bg-red-100 px-4 py-2 rounded-full flex items-center"> | |
| <i data-feather="heart" class="text-red-600 mr-2"></i> | |
| <span class="font-bold text-red-800" id="dateMeter">❤️ 100%</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-8"> | |
| <div class="bg-green-100 rounded-2xl p-6"> | |
| <h2 class="text-2xl font-semibold text-green-800 mb-4">Your Picnic Setup</h2> | |
| <div class="grid grid-cols-3 gap-3"> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="coffee" class="text-amber-700 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Thermos</span> | |
| </div> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="pie-chart" class="text-red-500 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Pie</span> | |
| </div> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="box" class="text-yellow-600 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Basket</span> | |
| </div> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="glass" class="text-blue-400 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Glass</span> | |
| </div> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="wine" class="text-purple-600 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Bottle</span> | |
| </div> | |
| <div class="food-item bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="utensils" class="text-gray-700 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Utensils</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-amber-100 rounded-2xl p-6 relative"> | |
| <h2 class="text-2xl font-semibold text-amber-800 mb-4">Picnic Blanket</h2> | |
| <div id="picnicBlanket" class="bg-white bg-opacity-70 border-2 border-dashed border-amber-400 rounded-xl h-64 flex items-center justify-center"> | |
| <p class="text-amber-600 text-center">Drag items here to set up your perfect date picnic!</p> | |
| </div> | |
| <div class="absolute bottom-4 right-4"> | |
| <button id="startDateBtn" class="bg-pink-500 hover:bg-pink-600 text-white px-6 py-2 rounded-full shadow-lg transform transition hover:scale-105"> | |
| <i data-feather="heart" class="inline mr-2"></i> Start Date | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-8 bg-red-100 rounded-2xl p-6"> | |
| <h2 class="text-2xl font-semibold text-red-800 mb-4">Animal Intruders</h2> | |
| <div class="flex flex-wrap gap-4"> | |
| <div class="animal bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="github" class="text-gray-800 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Squirrel</span> | |
| </div> | |
| <div class="animal bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="twitter" class="text-blue-400 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Bird</span> | |
| </div> | |
| <div class="animal bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="codesandbox" class="text-amber-700 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Raccoon</span> | |
| </div> | |
| <div class="animal bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center ragdoll" draggable="true"> | |
| <i data-feather="cpu" class="text-gray-600 w-8 h-8"></i> | |
| <span class="text-xs mt-1">Dog</span> | |
| </div> | |
| </div> | |
| <p class="mt-4 text-red-700">Drag and throw them away from your picnic!</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize Vanta.js background | |
| VANTA.GLOBE({ | |
| el: "#gameCanvas", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x3a5a40, | |
| backgroundColor: 0xe9ecef | |
| }); | |
| // Initialize feather icons | |
| feather.replace(); | |
| // Game state | |
| let gameTime = 180; // 3 minutes in seconds | |
| let dateMeter = 100; | |
| let gameActive = false; | |
| let itemsPlaced = 0; | |
| const totalItems = 6; | |
| // Timer function | |
| function updateTimer() { | |
| if (!gameActive) return; | |
| gameTime--; | |
| const minutes = Math.floor(gameTime / 60); | |
| const seconds = gameTime % 60; | |
| document.getElementById('timer').textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; | |
| if (gameTime <= 0) { | |
| endGame(); | |
| } else { | |
| setTimeout(updateTimer, 1000); | |
| } | |
| } | |
| // Date meter function | |
| function updateDateMeter(change) { | |
| dateMeter = Math.max(0, Math.min(100, dateMeter + change)); | |
| const hearts = Math.ceil(dateMeter / 20); | |
| document.getElementById('dateMeter').textContent = '❤️'.repeat(hearts) + ` ${dateMeter}%`; | |
| } | |
| // Start game function | |
| function startGame() { | |
| gameActive = true; | |
| gameTime = 180; | |
| dateMeter = 100; | |
| itemsPlaced = 0; | |
| updateTimer(); | |
| document.getElementById('startDateBtn').textContent = "Date in Progress!"; | |
| document.getElementById('startDateBtn').classList.remove('bg-pink-500', 'hover:bg-pink-600'); | |
| document.getElementById('startDateBtn').classList.add('bg-purple-500', 'hover:bg-purple-600'); | |
| // Start animal intrusions | |
| startAnimalIntrusions(); | |
| } | |
| // End game function | |
| function endGame() { | |
| gameActive = false; | |
| clearInterval(animalInterval); | |
| let message; | |
| if (dateMeter >= 80) { | |
| message = "Perfect Date! ❤️"; | |
| } else if (dateMeter >= 50) { | |
| message = "Nice Try! 😊"; | |
| } else { | |
| message = "Better Luck Next Time! 😅"; | |
| } | |
| alert(`Game Over!\n${message}\nFinal Date Meter: ${dateMeter}%`); | |
| document.getElementById('startDateBtn').innerHTML = '<i data-feather="heart" class="inline mr-2"></i> Try Again'; | |
| document.getElementById('startDateBtn').classList.remove('bg-purple-500', 'hover:bg-purple-600'); | |
| document.getElementById('startDateBtn').classList.add('bg-pink-500', 'hover:bg-pink-600'); | |
| feather.replace(); | |
| } | |
| // Animal intrusion function | |
| let animalInterval; | |
| function startAnimalIntrusions() { | |
| animalInterval = setInterval(() => { | |
| if (!gameActive) return; | |
| // Random chance to decrease date meter | |
| if (Math.random() < 0.3) { | |
| updateDateMeter(-5); | |
| } | |
| // Add random animal to picnic | |
| const animals = document.querySelectorAll('.animal'); | |
| const randomAnimal = animals[Math.floor(Math.random() * animals.length)].cloneNode(true); | |
| const blanket = document.getElementById('picnicBlanket'); | |
| randomAnimal.style.position = 'absolute'; | |
| randomAnimal.style.left = `${Math.random() * 80 + 10}%`; | |
| randomAnimal.style.top = `${Math.random() * 80 + 10}%`; | |
| randomAnimal.classList.add('animate-bounce'); | |
| blanket.appendChild(randomAnimal); | |
| feather.replace(); | |
| // Remove animal after some time | |
| setTimeout(() => { | |
| if (randomAnimal.parentNode) { | |
| randomAnimal.remove(); | |
| updateDateMeter(2); // Small bonus for animal leaving | |
| } | |
| }, 3000); | |
| }, 2000); | |
| } | |
| // Drag and drop functionality | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const foodItems = document.querySelectorAll('.food-item'); | |
| const blanket = document.getElementById('picnicBlanket'); | |
| const startBtn = document.getElementById('startDateBtn'); | |
| // Setup drag for food items | |
| foodItems.forEach(item => { | |
| item.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', item.innerHTML); | |
| e.dataTransfer.effectAllowed = 'copy'; | |
| }); | |
| }); | |
| // Setup drop for picnic blanket | |
| blanket.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| e.dataTransfer.dropEffect = 'copy'; | |
| blanket.classList.add('bg-amber-50'); | |
| }); | |
| blanket.addEventListener('dragleave', () => { | |
| blanket.classList.remove('bg-amber-50'); | |
| }); | |
| blanket.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| blanket.classList.remove('bg-amber-50'); | |
| if (!gameActive && e.dataTransfer.getData('text/plain')) { | |
| const data = e.dataTransfer.getData('text/plain'); | |
| const newItem = document.createElement('div'); | |
| newItem.className = 'food-item bg-white p-3 rounded-lg shadow-md absolute flex flex-col items-center justify-center'; | |
| newItem.innerHTML = data; | |
| newItem.style.left = `${e.offsetX - 25}px`; | |
| newItem.style.top = `${e.offsetY - 25}px`; | |
| newItem.draggable = true; | |
| // Make placed items draggable within blanket | |
| newItem.addEventListener('dragstart', (ev) => { | |
| ev.dataTransfer.setData('text/plain', newItem.innerHTML); | |
| ev.dataTransfer.effectAllowed = 'move'; | |
| }); | |
| blanket.appendChild(newItem); | |
| feather.replace(); | |
| // Count placed items | |
| itemsPlaced++; | |
| if (itemsPlaced >= totalItems) { | |
| startBtn.disabled = false; | |
| } | |
| } | |
| }); | |
| // Start date button | |
| startBtn.addEventListener('click', () => { | |
| if (!gameActive && itemsPlaced >= totalItems) { | |
| startGame(); | |
| } else if (!gameActive) { | |
| alert('Please set up your picnic with all items first!'); | |
| } | |
| }); | |
| // Setup animal throwing | |
| document.addEventListener('dragover', (e) => { | |
| if (e.target.classList.contains('animal')) { | |
| e.preventDefault(); | |
| e.dataTransfer.dropEffect = 'move'; | |
| } | |
| }); | |
| document.addEventListener('drop', (e) => { | |
| if (e.target.classList.contains('animal')) { | |
| e.preventDefault(); | |
| const animal = e.target; | |
| animal.style.transform = `translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 - 100}px) rotate(${Math.random() * 360}deg)`; | |
| setTimeout(() => { | |
| animal.remove(); | |
| if (gameActive) { | |
| updateDateMeter(5); // Bonus for throwing animal | |
| } | |
| }, 500); | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |