### Initialize EmailJS with Public Key Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Initializes the EmailJS library with a public key. Ensure this key is correctly set for email sending functionality. ```javascript emailjs.init({ publicKey: "tS0Y50AWUTT8FRopj" }); ``` -------------------------------- ### Load User Data and Initialize State Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Loads user's score and pet adoption status from local storage. Initializes module completion flags and UI elements. ```javascript let puntos = parseInt(localStorage.getItem("cyberkids_score")) || 0; let esAdoptado = localStorage.getItem("mascota_adoptada") === "true"; let accesorioActual = localStorage.getItem("mascota_accesorio") || ""; // Estado de los módulos leídos let m1Completado = false; let m2Completado = false; const txtPoints = document.getElementById("user-points"); const robotMesh = document.getElementById("robot-mesh"); const statusText = document.getElementById("mascot-status"); const btnAdopt = document.getElementById("btn-adopt"); const interactionZone = document.getElementById("interaction-zone"); const consoleBox = document.getElementById("pet-log-console"); const elementShields = document.getElementById("gear-shields"); const elementHelmet = document.getElementById("gear-helmet"); const btnCert = document.getElementById("btn-open-cert"); ``` -------------------------------- ### Pet Adoption Functionality Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Handles the logic for adopting the pet, deducting points, and updating local storage. Ensures the player has enough points before adoption. ```javascript function adoptarMascota() { if (puntos >= 20) { puntos -= 20; esAdoptado = true; localStorage.setItem("cyberkids_score", puntos); localStorage.setItem("mascota_adoptada", "true"); enviarLogConsola("BYTE.EXE initialized correctly.", "ok"); actualizarInterfazMascota(); } } ``` -------------------------------- ### Accessory Purchase Logic Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Manages the purchase of accessories for the pet, deducting costs and updating the current accessory. Logs the action or an error if credits are insufficient. ```javascript function comprarAccesorio(tipo, coste) { if (puntos >= coste) { puntos -= coste; accesorioActual = tipo; localStorage.setItem("cyberkids_score", puntos); localStorage.setItem("mascota_accesorio", tipo); enviarLogConsola(`Módulo ${tipo} acoplado a la estructura.`, "ok"); actualizarInterfazMascota(); } else { enviarLogConsola("Créditos insuficientes.", "err"); } } ``` -------------------------------- ### Download Certificate as PNG Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Converts the diploma element into a PNG image and initiates a download. Includes error handling for missing student names and canvas rendering failures. ```javascript function descargarCertificadoImagen() { const nombreAlumno = document.getElementById("student-name").value.trim(); const statusMsg = document.getElementById("email-status-msg"); if (!nombreAlumno || nombreAlumno === "[ ESCRIBE TU NOMBRE AQUÍ ]") { statusMsg.innerText = "❌ ERROR: Por favor escribe tu nombre en el diploma antes de tomarle la foto."; statusMsg.style.color = "var(--cyber-red)"; return; } statusMsg.innerText = "📸 Capturando tu diploma táctico..."; statusMsg.style.color = "var(--cyber-blue)"; const certificadoTarget = document.getElementById("printable-certificate"); html2canvas(certificadoTarget, { backgroundColor: null, scale: 2, logging: false, useCORS: true }).then(canvas => { const link = document.createElement('a'); link.download = `Certificado_CyberKids_${nombreAlumno.replace(/\s+/g, '_')}.png`; link.href = canvas.toDataURL('image/png'); link.click(); statusMsg.innerText = "🟩 ¡Imagen descargada con éxito! Ya puedes imprimirla. 🖨️"; statusMsg.style.color = "var(--cyber-green)"; enviarLogConsola("Captura de credencial de egreso exportada al sistema local.", "ok"); }).catch(err => { statusMsg.innerText = "❌ ERROR: Falló la renderización del archivo gráfico."; statusMsg.style.color = "var(--cyber-red)"; console.error("Error de html2canvas:", err); }); } ``` -------------------------------- ### Mostrar Puntaje Acumulado del Usuario Source: https://github.com/dorianabv/cyberkids/blob/main/familia.html Sincroniza y muestra el puntaje acumulado de los niños en el hogar utilizando localStorage. Se asegura de que siempre haya un valor, incluso si no se ha guardado ninguno previamente. ```javascript let puntosGlobales = localStorage.getItem("cyberkids_score") || 0; document.getElementById("user-points").innerText = puntosGlobales; ``` -------------------------------- ### Update Module Completion and Points Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Updates the visual progress and user points upon module completion. Enables the certificate button if all modules are finished. ```javascript function actualizarModulo(idNum, recompensa) { const check = document.getElementById("chk-m" + idNum); if (idNum === 1) { m1Completado = check.checked; document.getElementById("fill-m1").style.width = m1Completado ? "100%" : "0%"; if(m1Completado) { puntos += recompensa; enviarLogConsola("Módulo 01 descifrado. +15 estrellas.", "ok"); } } else { m2Completado = check.checked; document.getElementById("fill-m2").style.width = m2Completado ? "100%" : "0%"; // <-- Corregido para que afecte a fill-m2 if(m2Completado) { puntos += recompensa; enviarLogConsola("Módulo 02 descifrado. +15 estrellas.", "ok"); } } localStorage.setItem("cyberkids_score", puntos); txtPoints.innerText = puntos; // Si completa todos los módulos, se desbloquea el generador de certificados if (m1Completado && m2Completado) { btnCert.disabled = false; enviarLogConsola("¡RUTA COMPLETADA! Credencial de egreso liberada.", "warn"); } else { btnCert.disabled = true; } } ``` -------------------------------- ### Pet Interface Update Logic Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Updates the pet's interface based on its status, such as points and adoption state. Handles displaying adoption buttons and interaction zones. ```javascript function actualizarInterfazMascota() { txtPoints.innerText = puntos; if (esAdoptado) { robotMesh.classList.add("robot-active"); statusText.innerText = "[ESTADO]: BYTE_IA activo."; statusText.style.color = "var(--cyber-green)"; btnAdopt.style.display = "none"; interactionZone.style.display = "block"; elementShields.style.display = accesorioActual === "FIREWALL" ? "block" : "none"; elementHelmet.style.display = accesorioActual === "KERNEL" ? "block" : "none"; } else { robotMesh.classList.remove("robot-active"); btnAdopt.disabled = puntos < 20; } } ``` -------------------------------- ### Logo Icon Styling with Blink Animation Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Styles a logo icon with a specific margin and applies a 'blink' keyframe animation for a pulsating effect. The animation alternates opacity and scale for a blinking visual. ```css .logo-icon { margin-right: 8px; font-size: 24px; animation: blink 1.5s infinite; } @keyframes blink { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.95); } } ``` -------------------------------- ### Feedback and Logo Styles Source: https://github.com/dorianabv/cyberkids/blob/main/juego2.html Styles the feedback area for game messages and the cyber logo, including animation for the logo icon. ```css #j2-feedback { margin-top: 25px; font-size: 1.1rem; font-weight: bold; min-height: 50px; } .cyber-logo-container { display: flex; align-items: center; font-family: 'Courier New', Courier, monospace; /* Vibra hacker/consola */ font-weight: bold; font-size: 26px; letter-spacing: 1px; cursor: pointer; text-decoration: none; } .logo-icon { margin-right: 8px; font-size: 24px; animation: blink 1.5s infinite; } .logo-text-1 { color: var(--cyber-green, #00ff66); /* Verde Hacker brillante */ text-shadow: 0 0 10px rgba(0, 255, 102, 0.6); } .logo-text-2 { color: #ffffff; text-shadow: 0 0 5px rgba(255, 255, 255, 0.3); } .logo-badge { background-color: var(--cyber-red, #ff0055); /* Rojo Neón */ color: white; font-size: 11px; font-family: 'Arial', sans-serif; padding: 2px 6px; border-radius: 4px; margin-left: 10px; font-weight: 900; letter-spacing: 0.5px; box-shadow: 0 0 8px var(--cyber-red, #ff0055); } @keyframes blink { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.95); } } ``` -------------------------------- ### Send Certificate via EmailJS Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Generates a compressed JPEG image of the certificate, then sends it via EmailJS. Includes validation for student name and email, and provides status updates. ```javascript function enviarCertificadoPorCorreo() { const nombre = document.getElementById("student-name").value.trim(); const correo = document.getElementById("student-email").value.trim(); const statusMsg = document.getElementById("email-status-msg"); if (!nombre || nombre === "\[ ESCRIBE TU NOMBRE AQUÍ \]" || !correo) { statusMsg.innerText = "❌ ERROR: Debe completar los campos de identidad y correo."; statusMsg.style.color = "var(--cyber-red)"; return; } statusMsg.innerText = "📸 Procesando y comprimiendo diploma táctico..."; statusMsg.style.color = "var(--cyber-yellow)"; const certificadoTarget = document.getElementById("printable-certificate"); // Optimizamos las opciones de captura para reducir drásticamente el peso de la variable html2canvas(certificadoTarget, { backgroundColor: "#0e1726", scale: 0.8, // Escala menor para optimizar los Kilobytes generados logging: false, useCORS: true }).then(canvas => { // CAMBIO CLAVE: Convertimos a JPEG con una compresión de calidad del 60% (0.6) // Esto hace que la foto pese un 80% menos que un PNG y pase sin problemas la API. const imagenBase64Comprimida = canvas.toDataURL('image/jpeg', 0.6); statusMsg.innerText = "🚀 Transmitiendo paquete optimizado (<50Kb) a EmailJS..."; statusMsg.style.color = "var(--cyber-blue)"; const templateParams = { to_name: nombre, to_email: correo, cert_image_base64: imagenBase64Comprimida }; emailjs.send('service_duzfk43', 'template_d6cuxn8', templateParams) .then(function(response) { statusMsg.innerText = "🟩 ¡DIPLOMA GRÁFICO ENVIADO! Revisa tu bandeja de entrada. 📬🎉"; statusMsg.style.color = "var(--cyber-green)"; enviarLogConsola(`Certificado multimedia enviado a: ${correo}`, "ok"); }, function(error) { statusMsg.innerText = "❌ ERROR API ("; enviarLogConsola(`Error al enviar certificado: ${error}`, "err"); }); }); } ``` -------------------------------- ### Shop Item Styling Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Styles individual shop items with a dark background, padding, rounded corners, and a flex layout for space-between alignment. Suitable for list items in a shop or inventory. ```css .shop-item { background: #161b22; padding: 8px; border-radius: 6px; margin-top: 8px; font-size: 0.85rem; display: flex; justify-content: space-between; align-items: center; } ``` -------------------------------- ### Display Certificate Modal Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Sets the display style of the certificate modal to 'flex' to make it visible on the page. ```javascript function mostrarModalCertificado() { document.getElementById("cert-modal").style.display = "flex"; } ``` -------------------------------- ### Password Display and Button Styles Source: https://github.com/dorianabv/cyberkids/blob/main/juego2.html Styles the area where the password is displayed and the buttons for interacting with password strength. Includes styles for button hover and active states. ```css /* Área donde aparece la contraseña a evaluar */ .password-display { background-color: #2c3e50; color: #ffd166; font-family: 'Courier New', Courier, monospace; font-size: 1.8rem; font-weight: bold; padding: 25px; border-radius: 12px; margin: 30px 0; letter-spacing: 1px; box-shadow: inset 0 0 10px rgba(0,0,0,0.5); } .btn-j2 { border: none; padding: 15px 30px; font-size: 1.1rem; font-weight: bold; border-radius: 12px; cursor: pointer; transition: transform 0.1s; margin: 0 15px; color: white; } .btn-j2:active { transform: scale(0.95); } .btn-weak { background-color: #ef476f; } .btn-strong { background-color: #06d6a0; } ``` -------------------------------- ### Log Message to Console Source: https://github.com/dorianabv/cyberkids/blob/main/teoria.html Appends a message to the console log, with styling based on message type (ok, warn, err). Used for displaying system feedback. ```javascript function enviarLogConsola(texto, tipo) { let cl = "console-line"; if(tipo === "ok") cl += " text-success"; if(tipo === "warn") cl += " text-alert"; if(tipo === "err") cl += " text-error"; consoleBox.innerHTML = `