Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Voice Controlled Jumping Jack Game</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @keyframes jump { | |
| 0%, 100% { transform: translateY(0) rotate(0deg); } | |
| 25% { transform: translateY(-100px) rotate(0deg); } | |
| 50% { transform: translateY(0) rotate(0deg); } | |
| 75% { transform: translateY(-100px) rotate(0deg); } | |
| } | |
| @keyframes armsUp { | |
| 0%, 100% { transform: rotate(0deg); } | |
| 50% { transform: rotate(180deg); } | |
| } | |
| @keyframes legsOut { | |
| 0%, 100% { transform: rotate(0deg); } | |
| 50% { transform: rotate(45deg); } | |
| } | |
| .character { | |
| transition: all 0.3s ease; | |
| } | |
| .jumping { | |
| animation: jump 1s infinite; | |
| } | |
| .arms-up .arm { | |
| animation: armsUp 1s infinite; | |
| } | |
| .legs-out .leg { | |
| animation: legsOut 1s infinite; | |
| } | |
| .pulse { | |
| animation: pulse 1.5s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); } | |
| 50% { transform: scale(1.1); } | |
| 100% { transform: scale(1); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gradient-to-b from-blue-100 to-purple-100 min-h-screen flex flex-col items-center justify-center p-4"> | |
| <div class="max-w-2xl w-full bg-white rounded-2xl shadow-xl overflow-hidden"> | |
| <div class="bg-gradient-to-r from-purple-500 to-blue-500 p-6 text-white text-center"> | |
| <h1 class="text-3xl md:text-4xl font-bold mb-2">Jumping Jack Challenge</h1> | |
| <p class="text-lg">Use your voice to do jumping jacks!</p> | |
| </div> | |
| <div class="p-6 md:p-8"> | |
| <div class="flex flex-col md:flex-row items-center justify-between gap-8 mb-8"> | |
| <div class="relative w-48 h-64 flex items-center justify-center"> | |
| <div id="character" class="character relative w-24 h-48"> | |
| <!-- Head --> | |
| <div class="absolute w-12 h-12 bg-yellow-300 rounded-full top-0 left-1/2 transform -translate-x-1/2"></div> | |
| <!-- Body --> | |
| <div class="absolute w-6 h-20 bg-blue-500 top-12 left-1/2 transform -translate-x-1/2"></div> | |
| <!-- Arms --> | |
| <div class="arm absolute w-16 h-4 bg-blue-500 top-16 left-1/2 transform -translate-x-1/2"></div> | |
| <div class="arm absolute w-16 h-4 bg-blue-500 top-16 left-1/2 transform -translate-x-1/2"></div> | |
| <!-- Legs --> | |
| <div class="leg absolute w-4 h-16 bg-blue-700 top-32 left-1/2 transform -translate-x-1/2"></div> | |
| <div class="leg absolute w-4 h-16 bg-blue-700 top-32 left-1/2 transform -translate-x-1/2"></div> | |
| </div> | |
| </div> | |
| <div class="flex-1"> | |
| <div class="bg-gray-100 rounded-lg p-4 mb-4"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <h3 class="font-semibold text-lg">Voice Commands</h3> | |
| <div id="micStatus" class="flex items-center"> | |
| <span class="w-3 h-3 rounded-full bg-red-500 mr-2"></span> | |
| <span class="text-sm">Mic Off</span> | |
| </div> | |
| </div> | |
| <p class="text-gray-700 mb-2">Say these commands:</p> | |
| <ul class="grid grid-cols-2 gap-2"> | |
| <li class="bg-white px-3 py-1 rounded-full text-sm flex items-center"> | |
| <i class="fas fa-volume-up mr-2 text-blue-500"></i> "Start jumping" | |
| </li> | |
| <li class="bg-white px-3 py-1 rounded-full text-sm flex items-center"> | |
| <i class="fas fa-volume-up mr-2 text-blue-500"></i> "Stop jumping" | |
| </li> | |
| <li class="bg-white px-3 py-1 rounded-full text-sm flex items-center"> | |
| <i class="fas fa-volume-up mr-2 text-blue-500"></i> "Faster" | |
| </li> | |
| <li class="bg-white px-3 py-1 rounded-full text-sm flex items-center"> | |
| <i class="fas fa-volume-up mr-2 text-blue-500"></i> "Slower" | |
| </li> | |
| </ul> | |
| </div> | |
| <button id="startBtn" class="w-full bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-4 rounded-lg transition duration-200 flex items-center justify-center pulse"> | |
| <i class="fas fa-microphone mr-2"></i> Start Voice Control | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-gray-100 rounded-lg p-4"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <h3 class="font-semibold text-lg">Activity Log</h3> | |
| <button id="clearLog" class="text-sm text-blue-500 hover:text-blue-700">Clear</button> | |
| </div> | |
| <div id="log" class="h-24 overflow-y-auto text-sm"> | |
| <p class="text-gray-500 italic">Waiting for commands...</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-100 p-4 flex justify-between items-center"> | |
| <div class="flex items-center"> | |
| <div class="w-10 h-10 bg-purple-500 rounded-full flex items-center justify-center text-white mr-3"> | |
| <i class="fas fa-fire"></i> | |
| </div> | |
| <div> | |
| <p class="text-xs text-gray-500">Jumping Jacks</p> | |
| <p id="counter" class="font-bold">0</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button id="resetBtn" class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition duration-200"> | |
| <i class="fas fa-redo mr-1"></i> Reset | |
| </button> | |
| <button id="helpBtn" class="w-10 h-10 bg-blue-500 hover:bg-blue-600 text-white rounded-full transition duration-200"> | |
| <i class="fas fa-question"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Help Modal --> | |
| <div id="helpModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white rounded-xl p-6 max-w-md w-full mx-4"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-bold">How to Play</h3> | |
| <button id="closeHelp" class="text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="space-y-3"> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 text-blue-600 w-8 h-8 rounded-full flex items-center justify-center mr-3 flex-shrink-0"> | |
| <i class="fas fa-microphone"></i> | |
| </div> | |
| <p>Click "Start Voice Control" and allow microphone access when prompted.</p> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 text-blue-600 w-8 h-8 rounded-full flex items-center justify-center mr-3 flex-shrink-0"> | |
| <i class="fas fa-comment-alt"></i> | |
| </div> | |
| <p>Say commands like "Start jumping", "Stop jumping", "Faster", or "Slower".</p> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 text-blue-600 w-8 h-8 rounded-full flex items-center justify-center mr-3 flex-shrink-0"> | |
| <i class="fas fa-running"></i> | |
| </div> | |
| <p>The character will animate based on your commands.</p> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 text-blue-600 w-8 h-8 rounded-full flex items-center justify-center mr-3 flex-shrink-0"> | |
| <i class="fas fa-chart-line"></i> | |
| </div> | |
| <p>Your jumping jacks are counted automatically.</p> | |
| </div> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-200"> | |
| <p class="text-sm text-gray-500">Note: For best results, use Chrome browser in a quiet environment.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const startBtn = document.getElementById('startBtn'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const helpBtn = document.getElementById('helpBtn'); | |
| const closeHelp = document.getElementById('closeHelp'); | |
| const helpModal = document.getElementById('helpModal'); | |
| const clearLog = document.getElementById('clearLog'); | |
| const log = document.getElementById('log'); | |
| const counter = document.getElementById('counter'); | |
| const character = document.getElementById('character'); | |
| const micStatus = document.getElementById('micStatus'); | |
| // Game state | |
| let isJumping = false; | |
| let jumpCount = 0; | |
| let recognition; | |
| let animationSpeed = 1; | |
| // Initialize speech recognition | |
| function initSpeechRecognition() { | |
| const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (!SpeechRecognition) { | |
| addToLog("Your browser doesn't support speech recognition. Try Chrome.", true); | |
| startBtn.disabled = true; | |
| return; | |
| } | |
| recognition = new SpeechRecognition(); | |
| recognition.continuous = true; | |
| recognition.interimResults = true; | |
| recognition.lang = 'en-US'; | |
| recognition.onstart = function() { | |
| micStatus.innerHTML = '<span class="w-3 h-3 rounded-full bg-green-500 mr-2"></span><span class="text-sm">Listening...</span>'; | |
| startBtn.innerHTML = '<i class="fas fa-microphone-slash mr-2"></i> Stop Voice Control'; | |
| startBtn.classList.remove('bg-green-500', 'pulse'); | |
| startBtn.classList.add('bg-red-500'); | |
| addToLog("Voice recognition activated. Start speaking commands."); | |
| }; | |
| recognition.onerror = function(event) { | |
| console.error('Speech recognition error', event.error); | |
| micStatus.innerHTML = '<span class="w-3 h-3 rounded-full bg-red-500 mr-2"></span><span class="text-sm">Error</span>'; | |
| addToLog("Error occurred in speech recognition: " + event.error, true); | |
| }; | |
| recognition.onend = function() { | |
| if (isJumping) { | |
| recognition.start(); // Restart if we're still in jumping mode | |
| } else { | |
| micStatus.innerHTML = '<span class="w-3 h-3 rounded-full bg-red-500 mr-2"></span><span class="text-sm">Mic Off</span>'; | |
| startBtn.innerHTML = '<i class="fas fa-microphone mr-2"></i> Start Voice Control'; | |
| startBtn.classList.remove('bg-red-500'); | |
| startBtn.classList.add('bg-green-500', 'pulse'); | |
| } | |
| }; | |
| recognition.onresult = function(event) { | |
| const transcript = Array.from(event.results) | |
| .map(result => result[0]) | |
| .map(result => result.transcript) | |
| .join(''); | |
| if (event.results[0].isFinal) { | |
| processCommand(transcript); | |
| } | |
| }; | |
| } | |
| // Process voice commands | |
| function processCommand(command) { | |
| command = command.toLowerCase().trim(); | |
| addToLog("You said: " + command); | |
| if (command.includes('start jumping') || command.includes('start jump')) { | |
| startJumping(); | |
| } else if (command.includes('stop jumping') || command.includes('stop jump')) { | |
| stopJumping(); | |
| } else if (command.includes('faster')) { | |
| speedUp(); | |
| } else if (command.includes('slower')) { | |
| slowDown(); | |
| } else if (command.includes('reset')) { | |
| resetGame(); | |
| } | |
| } | |
| // Start jumping animation | |
| function startJumping() { | |
| if (!isJumping) { | |
| isJumping = true; | |
| character.classList.add('jumping', 'arms-up', 'legs-out'); | |
| updateAnimationSpeed(); | |
| addToLog("Started jumping jacks!"); | |
| } | |
| } | |
| // Stop jumping animation | |
| function stopJumping() { | |
| if (isJumping) { | |
| isJumping = false; | |
| character.classList.remove('jumping', 'arms-up', 'legs-out'); | |
| addToLog("Stopped jumping jacks."); | |
| } | |
| } | |
| // Increase animation speed | |
| function speedUp() { | |
| if (animationSpeed < 3) { | |
| animationSpeed += 0.5; | |
| updateAnimationSpeed(); | |
| addToLog(`Increased speed to ${animationSpeed}x`); | |
| } | |
| } | |
| // Decrease animation speed | |
| function slowDown() { | |
| if (animationSpeed > 0.5) { | |
| animationSpeed -= 0.5; | |
| updateAnimationSpeed(); | |
| addToLog(`Decreased speed to ${animationSpeed}x`); | |
| } | |
| } | |
| // Update animation speed | |
| function updateAnimationSpeed() { | |
| const arms = document.querySelectorAll('.arm'); | |
| const legs = document.querySelectorAll('.leg'); | |
| character.style.animationDuration = `${1 / animationSpeed}s`; | |
| arms.forEach(arm => arm.style.animationDuration = `${1 / animationSpeed}s`); | |
| legs.forEach(leg => leg.style.animationDuration = `${1 / animationSpeed}s`); | |
| // Count jumps based on animation cycles | |
| if (isJumping) { | |
| jumpCount += Math.floor(animationSpeed); | |
| counter.textContent = jumpCount; | |
| } | |
| } | |
| // Reset game | |
| function resetGame() { | |
| stopJumping(); | |
| jumpCount = 0; | |
| animationSpeed = 1; | |
| counter.textContent = '0'; | |
| addToLog("Counter reset to 0"); | |
| } | |
| // Add message to log | |
| function addToLog(message, isError = false) { | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString(); | |
| const logEntry = document.createElement('p'); | |
| logEntry.className = isError ? 'text-red-500' : 'text-gray-700'; | |
| logEntry.innerHTML = `<span class="text-gray-500">[${timeString}]</span> ${message}`; | |
| // If "Waiting for commands..." is still there, remove it | |
| if (log.firstChild && log.firstChild.classList.contains('italic')) { | |
| log.removeChild(log.firstChild); | |
| } | |
| log.appendChild(logEntry); | |
| log.scrollTop = log.scrollHeight; | |
| } | |
| // Clear log | |
| function clearActivityLog() { | |
| log.innerHTML = '<p class="text-gray-500 italic">Waiting for commands...</p>'; | |
| } | |
| // Event listeners | |
| startBtn.addEventListener('click', function() { | |
| if (!recognition) { | |
| initSpeechRecognition(); | |
| } | |
| if (startBtn.classList.contains('bg-green-500')) { | |
| // Start recognition | |
| try { | |
| recognition.start(); | |
| } catch (e) { | |
| addToLog("Error starting speech recognition: " + e.message, true); | |
| } | |
| } else { | |
| // Stop recognition | |
| recognition.stop(); | |
| stopJumping(); | |
| } | |
| }); | |
| resetBtn.addEventListener('click', resetGame); | |
| helpBtn.addEventListener('click', function() { | |
| helpModal.classList.remove('hidden'); | |
| }); | |
| closeHelp.addEventListener('click', function() { | |
| helpModal.classList.add('hidden'); | |
| }); | |
| clearLog.addEventListener('click', clearActivityLog); | |
| // Initialize | |
| initSpeechRecognition(); | |
| // Simulate jumping jack counting when animating | |
| setInterval(() => { | |
| if (isJumping) { | |
| jumpCount++; | |
| counter.textContent = jumpCount; | |
| } | |
| }, 1000 / animationSpeed); | |
| }); | |
| </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=udhyojakman/hi" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |