| <!DOCTYPE html> |
| <html lang="es"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Simulador de Limpieza Facial</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> |
| #faceCanvas { |
| touch-action: none; |
| background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlZWVlZWUiIHN0cm9rZS13aWR0aD0iMSI+CiAgPGNpcmNsZSBjeD0iMTAwIiBjeT0iMTAwIiByPSI4MCIvPgogIDxjaXJjbGUgY3g9IjcwIiBjeT0iODAiIHI9IjgiLz4KICA8Y2lyY2xlIGN4PSIxMzAiIGN5PSI4MCIgcj0iOCIvPgogIDxwYXRoIGQ9Ik03MCAxMzBMMTMwIDEzMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+Cjwvc3ZnPg=='); |
| background-size: contain; |
| background-repeat: no-repeat; |
| background-position: center; |
| border-radius: 10px; |
| } |
| |
| .tool-icon { |
| transition: all 0.3s ease; |
| } |
| |
| .tool-icon:hover { |
| transform: scale(1.1); |
| } |
| |
| .tool-icon.active { |
| border-color: #4f46e5; |
| box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.5); |
| } |
| |
| .progress-bar { |
| transition: width 0.5s ease; |
| } |
| |
| #gameCanvas { |
| background-color: #f3f4f6; |
| border-radius: 10px; |
| } |
| </style> |
| </head> |
| <body class="bg-gradient-to-br from-purple-50 to-pink-50 min-h-screen"> |
| <div class="container mx-auto px-4 py-8"> |
| <header class="text-center mb-8"> |
| <h1 class="text-4xl font-bold text-purple-800 mb-2">Simulador de Limpieza Facial</h1> |
| <p class="text-lg text-gray-600">Aprende a limpiar tu rostro según tu tipo de piel</p> |
| </header> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-8"> |
| |
| <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-1"> |
| <h2 class="text-2xl font-bold text-purple-700 mb-4">Tipos de Piel</h2> |
| <div class="space-y-4"> |
| <div class="border-b pb-4"> |
| <h3 class="text-lg font-semibold text-pink-600 flex items-center"> |
| <i class="fas fa-tint mr-2"></i> Piel Grasa |
| </h3> |
| <p class="text-gray-600 mt-2">Brillo excesivo, poros dilatados y tendencia al acné. Requiere limpiadores seboreguladores.</p> |
| </div> |
| <div class="border-b pb-4"> |
| <h3 class="text-lg font-semibold text-blue-600 flex items-center"> |
| <i class="fas fa-wind mr-2"></i> Piel Seca |
| </h3> |
| <p class="text-gray-600 mt-2">Sensación de tirantez, descamación y falta de luminosidad. Necesita ingredientes hidratantes.</p> |
| </div> |
| <div class="border-b pb-4"> |
| <h3 class="text-lg font-semibold text-green-600 flex items-center"> |
| <i class="fas fa-balance-scale mr-2"></i> Piel Mixta |
| </h3> |
| <p class="text-gray-600 mt-2">Zona T grasosa (frente, nariz, mentón) y mejillas secas/normales. Requiere equilibrio.</p> |
| </div> |
| <div> |
| <h3 class="text-lg font-semibold text-yellow-600 flex items-center"> |
| <i class="fas fa-sun mr-2"></i> Piel Sensible |
| </h3> |
| <p class="text-gray-600 mt-2">Enrojecimiento, irritación fácil. Necesita productos suaves sin fragancia.</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-2"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-2xl font-bold text-purple-700">Simulador de Limpieza</h2> |
| <div class="flex items-center"> |
| <span class="mr-2 text-gray-600">Progreso:</span> |
| <div class="w-32 h-4 bg-gray-200 rounded-full overflow-hidden"> |
| <div id="progressBar" class="h-full bg-gradient-to-r from-purple-400 to-pink-500 progress-bar" style="width:0%"></div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2">Selecciona tu tipo de piel:</label> |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-2"> |
| <button id="btnOily" class="py-2 px-4 rounded-lg border-2 border-transparent bg-pink-100 text-pink-700 hover:bg-pink-200 transition">Grasa</button> |
| <button id="btnDry" class="py-2 px-4 rounded-lg border-2 border-transparent bg-blue-100 text-blue-700 hover:bg-blue-200 transition">Seca</button> |
| <button id="btnCombination" class="py-2 px-4 rounded-lg border-2 border-transparent bg-green-100 text-green-700 hover:bg-green-200 transition">Mixta</button> |
| <button id="btnSensitive" class="py-2 px-4 rounded-lg border-2 border-transparent bg-yellow-100 text-yellow-700 hover:bg-yellow-200 transition">Sensible</button> |
| </div> |
| </div> |
|
|
| <div class="mb-4 relative"> |
| <canvas id="faceCanvas" width="500" height="400" class="w-full bg-gray-50 border-2 border-gray-200"></canvas> |
| <div id="instructions" class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-70 text-white rounded-xl"> |
| <div class="text-center p-4"> |
| <i class="fas fa-hand-pointer text-4xl mb-4"></i> |
| <p class="text-xl">Selecciona tu tipo de piel para comenzar</p> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="mt-4"> |
| <h3 class="text-lg font-semibold text-gray-700 mb-2">Selecciona un producto:</h3> |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-3"> |
| <button data-tool="cleanser" class="flex flex-col items-center justify-center p-3 rounded-lg border-2 border-transparent hover:bg-gray-50 transition tool-icon"> |
| <div class="w-12 h-12 flex items-center justify-center bg-purple-100 rounded-full mb-2"> |
| <i class="fas fa-hand-holding-water text-purple-600"></i> |
| </div> |
| <span class="text-sm text-center">Limpiador</span> |
| </button> |
| <button data-tool="toner" class="flex flex-col items-center justify-center p-3 rounded-lg border-2 border-transparent hover:bg-gray-50 transition tool-icon"> |
| <div class="w-12 h-12 flex items-center justify-center bg-blue-100 rounded-full mb-2"> |
| <i class="fas fa-spray-can text-blue-600"></i> |
| </div> |
| <span class="text-sm text-center">Tónico</span> |
| </button> |
| <button data-tool="serum" class="flex flex-col items-center justify-center p-3 rounded-lg border-2 border-transparent hover:bg-gray-50 transition tool-icon"> |
| <div class="w-12 h-12 flex items-center justify-center bg-pink-100 rounded-full mb-2"> |
| <i class="fas fa-flask text-pink-600"></i> |
| </div> |
| <span class="text-sm text-center">Sérum</span> |
| </button> |
| <button data-tool="moisturizer" class="flex flex-col items-center justify-center p-3 rounded-lg border-2 border-transparent hover:bg-gray-50 transition tool-icon"> |
| <div class="w-12 h-12 flex items-center justify-center bg-green-100 rounded-full mb-2"> |
| <i class="fas fa-pump-soap text-green-600"></i> |
| </div> |
| <span class="text-sm text-center">Hidratante</span> |
| </button> |
| </div> |
| </div> |
|
|
| <div id="recommendations" class="mt-6 hidden"> |
| <h3 class="text-lg font-semibold text-gray-700 mb-2">Recomendaciones para tu tipo de piel:</h3> |
| <div id="recommendationContent" class="bg-gray-50 rounded-lg p-4 text-gray-700"></div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg p-6 mb-8"> |
| <h2 class="text-2xl font-bold text-purple-700 mb-4 text-center">Juego: Elimina las impurezas</h2> |
| <p class="text-gray-600 mb-4 text-center">Ayuda a limpiar el rostro eliminando las impurezas antes de que caigan al suelo</p> |
| |
| <div class="flex flex-col md:flex-row gap-8"> |
| <div class="md:w-1/2"> |
| <canvas id="gameCanvas" width="400" height="400" class="w-full border-2 border-gray-200"></canvas> |
| </div> |
| <div class="md:w-1/2"> |
| <div class="flex justify-between mb-4"> |
| <div> |
| <span class="text-gray-700">Puntaje:</span> |
| <span id="score" class="text-xl font-bold text-purple-600 ml-2">0</span> |
| </div> |
| <div> |
| <span class="text-gray-700">Vidas:</span> |
| <span id="lives" class="text-xl font-bold text-pink-600 ml-2">3</span> |
| </div> |
| </div> |
| |
| <div class="mb-4"> |
| <p class="text-gray-600">Instrucciones:</p> |
| <ul class="list-disc pl-5 text-gray-600 mt-2"> |
| <li>Haz clic o toca las impurezas para eliminarlas</li> |
| <li>Gana puntos por cada impureza eliminada</li> |
| <li>Pierdes una vida si una impureza llega al suelo</li> |
| <li>Juego termina cuando pierdes todas tus vidas</li> |
| </ul> |
| </div> |
| |
| <div class="flex justify-center mt-4"> |
| <button id="startGame" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-6 rounded-lg transition duration-300"> |
| Iniciar Juego |
| </button> |
| <button id="resetGame" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-6 rounded-lg transition duration-300 ml-4 hidden"> |
| Reiniciar |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg p-6"> |
| <h2 class="text-2xl font-bold text-purple-700 mb-4 text-center">Consejos para una rutina de limpieza facial</h2> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> |
| <div class="bg-purple-50 rounded-lg p-4"> |
| <h3 class="text-lg font-semibold text-purple-700 mb-2 flex items-center"> |
| <i class="fas fa-clock mr-2"></i> Frecuencia |
| </h3> |
| <p class="text-gray-700">Limpia tu rostro 2 veces al día: mañana y noche. Evita lavarlo en exceso, ya que puede alterar el equilibrio natural de tu piel.</p> |
| </div> |
| <div class="bg-pink-50 rounded-lg p-4"> |
| <h3 class="text-lg font-semibold text-pink-700 mb-2 flex items-center"> |
| <i class="fas fa-temperature-low mr-2"></i> Temperatura del Agua |
| </h3> |
| <p class="text-gray-700">Usa agua tibia para abrir los poros y facilitar la limpieza, pero termina con un enjuague de agua fría para cerrarlos.</p> |
| </div> |
| <div class="bg-blue-50 rounded-lg p-4"> |
| <h3 class="text-lg font-semibold text-blue-700 mb-2 flex items-center"> |
| <i class="fas fa-hands-wash mr-2"></i> Técnica |
| </h3> |
| <p class="text-gray-700">Realiza movimientos circulares suaves con las yemas de los dedos. Evita frotar demasiado fuerte, especialmente en piel sensible.</p> |
| </div> |
| </div> |
| </div> |
|
|
| <footer class="mt-12 text-center text-gray-600"> |
| <p>Simulador de Limpieza Facial © 2023</p> |
| <p class="text-sm mt-2">Demuestra tu cuidado personal aprendiendo sobre el cuidado de la piel</p> |
| </footer> |
| </div> |
|
|
| <script> |
| |
| let skinType = ''; |
| let selectedTool = ''; |
| let progress = 0; |
| let canvas, ctx, faceCanvas, faceCtx; |
| let isDrawing = false; |
| let lastX = 0; |
| let lastY = 0; |
| let hue = 0; |
| |
| |
| let gameCanvas, gameCtx; |
| let gameRunning = false; |
| let score = 0; |
| let lives = 3; |
| let impurities = []; |
| let impuritySpeed = 2; |
| let spawnRate = 60; |
| let frameCount = 0; |
| let animationId; |
| |
| |
| const progressBar = document.getElementById('progressBar'); |
| const instructions = document.getElementById('instructions'); |
| const recommendationEl = document.getElementById('recommendations'); |
| const recommendationContent = document.getElementById('recommendationContent'); |
| const startGameBtn = document.getElementById('startGame'); |
| const resetGameBtn = document.getElementById('resetGame'); |
| const scoreEl = document.getElementById('score'); |
| const livesEl = document.getElementById('lives'); |
| |
| |
| document.addEventListener('DOMContentLoaded', function() { |
| |
| faceCanvas = document.getElementById('faceCanvas'); |
| faceCtx = faceCanvas.getContext('2d'); |
| faceCtx.lineJoin = 'round'; |
| faceCtx.lineCap = 'round'; |
| faceCtx.lineWidth = 20; |
| |
| |
| gameCanvas = document.getElementById('gameCanvas'); |
| gameCanvas.width = 400; |
| gameCanvas.height = 400; |
| gameCtx = gameCanvas.getContext('2d'); |
| gameCanvas.addEventListener('click', handleGameClick); |
| |
| |
| document.getElementById('btnOily').addEventListener('click', () => setSkinType('grasa')); |
| document.getElementById('btnDry').addEventListener('click', () => setSkinType('seca')); |
| document.getElementById('btnCombination').addEventListener('click', () => setSkinType('mixta')); |
| document.getElementById('btnSensitive').addEventListener('click', () => setSkinType('sensible')); |
| |
| |
| const toolButtons = document.querySelectorAll('[data-tool]'); |
| toolButtons.forEach(button => { |
| button.addEventListener('click', function() { |
| selectTool(this.getAttribute('data-tool')); |
| }); |
| }); |
| |
| |
| startGameBtn.addEventListener('click', startGame); |
| resetGameBtn.addEventListener('click', resetGame); |
| }); |
| |
| |
| function setSkinType(type) { |
| skinType = type; |
| instructions.classList.add('hidden'); |
| |
| |
| document.querySelectorAll('[id^="btn"]').forEach(btn => { |
| btn.classList.remove('border-purple-600', 'font-bold'); |
| }); |
| |
| document.getElementById(`btn${type.charAt(0).toUpperCase() + type.slice(1)}`).classList.add('border-purple-600', 'font-bold'); |
| |
| |
| showRecommendations(); |
| |
| |
| setupCanvasDrawing(); |
| |
| console.log(`Tipo de piel seleccionado: ${skinType}`); |
| } |
| |
| |
| function selectTool(tool) { |
| selectedTool = tool; |
| |
| |
| document.querySelectorAll('.tool-icon').forEach(icon => { |
| icon.classList.remove('active'); |
| }); |
| |
| document.querySelector(`[data-tool="${tool}"]`).classList.add('active'); |
| |
| |
| switch(tool) { |
| case 'cleanser': |
| faceCtx.strokeStyle = `hsla(210, 80%, 50%, 0.7)`; |
| faceCtx.lineWidth = 25; |
| break; |
| case 'toner': |
| faceCtx.strokeStyle = `hsla(180, 80%, 50%, 0.5)`; |
| faceCtx.lineWidth = 15; |
| break; |
| case 'serum': |
| faceCtx.strokeStyle = `hsla(300, 80%, 50%, 0.4)`; |
| faceCtx.lineWidth = 10; |
| break; |
| case 'moisturizer': |
| faceCtx.strokeStyle = `hsla(60, 80%, 50%, 0.6)`; |
| faceCtx.lineWidth = 20; |
| break; |
| } |
| |
| console.log(`Herramienta seleccionada: ${tool}`); |
| } |
| |
| |
| function setupCanvasDrawing() { |
| faceCanvas.onmousedown = startDrawing; |
| faceCanvas.onmouseup = stopDrawing; |
| faceCanvas.onmouseout = stopDrawing; |
| faceCanvas.onmousemove = draw; |
| |
| |
| faceCanvas.ontouchstart = function(e) { |
| e.preventDefault(); |
| const touch = e.touches[0]; |
| startDrawing({ |
| clientX: touch.clientX, |
| clientY: touch.clientY |
| }); |
| }; |
| |
| faceCanvas.ontouchmove = function(e) { |
| e.preventDefault(); |
| const touch = e.touches[0]; |
| draw({ |
| clientX: touch.clientX, |
| clientY: touch.clientY |
| }); |
| }; |
| |
| faceCanvas.ontouchend = stopDrawing; |
| } |
| |
| function startDrawing(e) { |
| if (!skinType || !selectedTool) return; |
| |
| isDrawing = true; |
| [lastX, lastY] = getMousePos(e); |
| |
| |
| if (progress < 100) { |
| progress += 10; |
| if (progress > 100) progress = 100; |
| progressBar.style.width = `${progress}%`; |
| |
| if (progress === 100) { |
| showCompletionMessage(); |
| } |
| } |
| } |
| |
| function stopDrawing() { |
| isDrawing = false; |
| } |
| |
| function draw(e) { |
| if (!isDrawing) return; |
| |
| const [mouseX, mouseY] = getMousePos(e); |
| |
| faceCtx.beginPath(); |
| faceCtx.moveTo(lastX, lastY); |
| faceCtx.lineTo(mouseX, mouseY); |
| faceCtx.stroke(); |
| |
| [lastX, lastY] = [mouseX, mouseY]; |
| |
| |
| hue = (hue + 1) % 360; |
| faceCtx.strokeStyle = `hsl(${hue}, 80%, 50%)`; |
| } |
| |
| |
| function getMousePos(e) { |
| const rect = faceCanvas.getBoundingClientRect(); |
| return [ |
| e.clientX - rect.left, |
| e.clientY - rect.top |
| ]; |
| } |
| |
| |
| function showRecommendations() { |
| let recommendations = ''; |
| |
| switch(skinType) { |
| case 'grasa': |
| recommendations = ` |
| <p class="mb-2"><strong class="text-pink-600">Recomendaciones para piel grasa:</strong></p> |
| <ul class="list-disc pl-5 space-y-1"> |
| <li>Usa limpiadores con ácido salicílico o arcilla</li> |
| <li>Evita productos cremosos o muy oleosos</li> |
| <li>Prefiere texturas gel o espuma</li> |
| <li>Incluye un tónico astringente para cerrar poros</li> |
| <li>Usa sérums matificantes</li> |
| <li>Hidratantes con efecto mate</li> |
| </ul> |
| `; |
| break; |
| case 'seca': |
| recommendations = ` |
| <p class="mb-2"><strong class="text-blue-600">Recomendaciones para piel seca:</strong></p> |
| <ul class="list-disc pl-5 space-y-1"> |
| <li>Limpiadores cremosos o en aceite</li> |
| <li>Evita productos con alcohol</li> |
| <li>Prefiere fórmulas hidratantes</li> |
| <li>Tónicos hidratantes sin alcohol</li> |
| <li>Sérums con ácido hialurónico</li> |
| <li>Hidratantes ricos en ceramidas</li> |
| </ul> |
| `; |
| break; |
| case 'mixta': |
| recommendations = ` |
| <p class="mb-2"><strong class="text-green-600">Recomendaciones para piel mixta:</strong></p> |
| <ul class="list-disc pl-5 space-y-1"> |
| <li>Limpiadores balanceados ni muy secos ni muy cremosos</li> |
| <li>Trata cada zona según sus necesidades</li> |
| <li>Tónicos equilibrados</li> |
| <li>Sérums multifunción</li> |
| <li>Hidratantes oil-free para la zona T</li> |
| <li>Productos hidratantes para mejillas</li> |
| </ul> |
| `; |
| break; |
| case 'sensible': |
| recommendations = ` |
| <p class="mb-2"><strong class="text-yellow-600">Recomendaciones para piel sensible:</strong></p> |
| <ul class="list-disc pl-5 space-y-1"> |
| <li>Limpiadores sin fragancia y sin sulfatos</li> |
| <li>Evita ingredientes irritantes</li> |
| <li>Productos hipoalergénicos</li> |
| <li>Tónicos calmantes</li> |
| <li>Sérums reparadores</li> |
| <li>Hidratantes con ingredientes calmantes</li> |
| </ul> |
| `; |
| break; |
| } |
| |
| recommendationContent.innerHTML = recommendations; |
| recommendationEl.classList.remove('hidden'); |
| } |
| |
| |
| function showCompletionMessage() { |
| Swal.fire({ |
| title: '¡Rutina completada!', |
| text: 'Has completado correctamente tu rutina de limpieza facial. Recuerda seguir estos pasos diariamente para mantener tu piel saludable.', |
| icon: 'success', |
| confirmButtonText: 'Entendido' |
| }); |
| } |
| |
| |
| function startGame() { |
| if (gameRunning) return; |
| |
| gameRunning = true; |
| score = 0; |
| lives = 3; |
| impurities = []; |
| impuritySpeed = 2; |
| spawnRate = 60; |
| frameCount = 0; |
| |
| scoreEl.textContent = score; |
| livesEl.textContent = lives; |
| |
| startGameBtn.classList.add('hidden'); |
| resetGameBtn.classList.remove('hidden'); |
| |
| gameLoop(); |
| } |
| |
| function resetGame() { |
| cancelAnimationFrame(animationId); |
| gameRunning = false; |
| gameCtx.clearRect(0, 0, gameCanvas.width, gameCanvas.height); |
| |
| startGameBtn.classList.remove('hidden'); |
| resetGameBtn.classList.add('hidden'); |
| } |
| |
| function gameLoop() { |
| if (!gameRunning) return; |
| |
| gameCtx.clearRect(0, 0, gameCanvas.width, gameCanvas.height); |
| |
| |
| drawGameBackground(); |
| |
| |
| if (frameCount % spawnRate === 0) { |
| spawnImpurity(); |
| } |
| |
| |
| updateImpurities(); |
| |
| |
| if (frameCount % 300 === 0) { |
| impuritySpeed = Math.min(impuritySpeed + 0.2, 5); |
| spawnRate = Math.max(20, spawnRate - 5); |
| } |
| |
| frameCount++; |
| animationId = requestAnimationFrame(gameLoop); |
| } |
| |
| function drawGameBackground() { |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(200, 150, 100, 0, Math.PI * 2); |
| gameCtx.strokeStyle = '#d1d5db'; |
| gameCtx.lineWidth = 3; |
| gameCtx.stroke(); |
| |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(160, 120, 15, 0, Math.PI * 2); |
| gameCtx.stroke(); |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(240, 120, 15, 0, Math.PI * 2); |
| gameCtx.stroke(); |
| |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(200, 180, 30, 0, Math.PI); |
| gameCtx.stroke(); |
| } |
| |
| function spawnImpurity() { |
| const radius = Math.random() * 15 + 10; |
| const x = Math.random() * (gameCanvas.width - radius * 2) + radius; |
| |
| impurities.push({ |
| x: x, |
| y: -radius, |
| radius: radius, |
| speed: impuritySpeed, |
| color: getRandomImpurityColor() |
| }); |
| } |
| |
| function getRandomImpurityColor() { |
| const colors = [ |
| '#6b7280', |
| '#ef4444', |
| '#f59e0b', |
| '#10b981', |
| '#8b5cf6' |
| ]; |
| |
| return colors[Math.floor(Math.random() * colors.length)]; |
| } |
| |
| function updateImpurities() { |
| for (let i = impurities.length - 1; i >= 0; i--) { |
| const imp = impurities[i]; |
| |
| |
| imp.y += imp.speed; |
| |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(imp.x, imp.y, imp.radius, 0, Math.PI * 2); |
| gameCtx.fillStyle = imp.color; |
| gameCtx.fill(); |
| gameCtx.strokeStyle = '#000'; |
| gameCtx.lineWidth = 1; |
| gameCtx.stroke(); |
| |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(imp.x - imp.radius/3, imp.y - imp.radius/3, imp.radius/4, 0, Math.PI * 2); |
| gameCtx.fillStyle = 'rgba(255, 255, 255, 0.6)'; |
| gameCtx.fill(); |
| |
| |
| if (imp.y - imp.radius > gameCanvas.height) { |
| impurities.splice(i, 1); |
| loseLife(); |
| } |
| } |
| } |
| |
| function handleGameClick(e) { |
| if (!gameRunning) return; |
| |
| const rect = gameCanvas.getBoundingClientRect(); |
| const x = e.clientX - rect.left; |
| const y = e.clientY - rect.top; |
| |
| |
| for (let i = impurities.length - 1; i >= 0; i--) { |
| const imp = impurities[i]; |
| const distance = Math.sqrt(Math.pow(x - imp.x, 2) + Math.pow(y - imp.y, 2)); |
| |
| if (distance <= imp.radius) { |
| |
| impurities.splice(i, 1); |
| |
| |
| score += Math.floor(30 / imp.radius); |
| scoreEl.textContent = score; |
| |
| |
| gameCtx.beginPath(); |
| gameCtx.arc(imp.x, imp.y, imp.radius * 1.5, 0, Math.PI * 2); |
| gameCtx.fillStyle = 'rgba(255, 255, 255, 0.7)'; |
| gameCtx.fill(); |
| |
| return; |
| } |
| } |
| } |
| |
| function loseLife() { |
| lives--; |
| livesEl.textContent = lives; |
| |
| if (lives <= 0) { |
| gameOver(); |
| } |
| } |
| |
| function gameOver() { |
| gameRunning = false; |
| cancelAnimationFrame(animationId); |
| |
| Swal.fire({ |
| title: '¡Juego terminado!', |
| html: `<p>Tu puntaje final: <strong>${score}</strong></p> |
| <p class="mt-2">Recuerda limpiar tu rostro adecuadamente para mantenerlo libre de impurezas.</p>`, |
| icon: 'info', |
| confirmButtonText: 'Jugar de nuevo' |
| }).then(() => { |
| startGame(); |
| }); |
| } |
| |
| |
| window.Swal = function() { |
| return Promise.resolve({ |
| fire: function(options) { |
| const dialog = document.createElement('div'); |
| dialog.className = 'fixed inset-0 flex items-center justify-center z-50 bg-black bg-opacity-50'; |
| dialog.innerHTML = ` |
| <div class="bg-white rounded-lg shadow-xl p-6 max-w-sm mx-auto"> |
| <h3 class="text-xl font-bold mb-2">${options.title || ''}</h3> |
| <p class="mb-4">${options.text || ''}</p> |
| <button class="bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded"> |
| ${options.confirmButtonText || 'OK'} |
| </button> |
| </div> |
| `; |
| |
| document.body.appendChild(dialog); |
| |
| dialog.querySelector('button').addEventListener('click', function() { |
| document.body.removeChild(dialog); |
| if (options.then) { |
| options.then({ isConfirmed: true }); |
| } |
| }); |
| } |
| }); |
| }; |
| </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=Vale33Ort/simulador" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |