Armonia animal

            Resonancia para Mascotas             @import url(‘https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&display=swap’);         :root {             –bg-color: #f0fdf4;             /* Very light green hint */             –card-bg: #ffffff;             –text-color: #1e3a8a;             /* Deep blue/slate */             –accent-color: #10b981;             /* Calming emerald green */             –accent-glow: rgba(16, 185, 129, 0.2);             –secondary-color: #64748b;             –danger-color: #f43f5e;             /* Rose instead of harsh red */         }         body {             background-color: var(–bg-color);             color: var(–text-color);             display: flex;             justify-content: center;             align-items: center;             min-height: 100vh;             margin: 0;             padding: 20px;             font-family: ‘Nunito’, sans-serif;         }         .container {             background-color: var(–card-bg);             width: 100%;             max-width: 400px;             padding: 30px;             border-radius: 30px;             /* Softer corners */             box-shadow: 0 20px 40px rgba(0, 0, 0, 0.05);             text-align: center;             border: 1px solid #e2e8f0;         }         h1 {             font-size: 1.8rem;             margin-bottom: 5px;             color: var(–text-color);             margin-top: 0;         }         .subtitle {             font-size: 0.9rem;             color: var(–secondary-color);             margin-bottom: 20px;             margin-top: 0;         }         /* Visualizer Area */         .visualizer-container {             width: 100%;             height: 80px;             background: #f8fafc;             border-radius: 15px;             margin-bottom: 20px;             overflow: hidden;             border: 1px solid #e2e8f0;             position: relative;         }         canvas {             width: 100%;             height: 100%;             display: block;         }         .display-container {             margin-bottom: 30px;             background: #f1f5f9;             padding: 20px;             border-radius: 20px;         }         .large-value {             font-size: 3.5rem;             font-weight: 700;             color: var(–accent-color);         }         .large-value span {             font-size: 1rem;             color: var(–secondary-color);             font-weight: 700;         }         .resonance-label {             font-size: 0.9rem;             color: var(–secondary-color);             margin-top: 5px;         }         .controls {             display: flex;             flex-direction: column;             gap: 25px;         }         .control-group {             display: flex;             flex-direction: column;             gap: 10px;             align-items: stretch;         }         label {             color: var(–secondary-color);             font-size: 0.9rem;             text-align: left;             font-weight: 700;         }         /* Custom Range Slider */         input[type=range] {             -webkit-appearance: none;             width: 100%;             background: transparent;         }         input[type=range]:focus {             outline: none;         }         input[type=range]::-webkit-slider-thumb {             -webkit-appearance: none;             height: 28px;             width: 28px;             border-radius: 50%;             background: var(–accent-color);             cursor: pointer;             margin-top: -12px;             border: 3px solid white;             box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);         }         input[type=range]::-webkit-slider-runnable-track {             width: 100%;             height: 6px;             cursor: pointer;             background: #e2e8f0;             border-radius: 3px;         }         /* Preset Buttons */         .preset-buttons {             display: flex;             gap: 10px;         }         .preset-btn {             flex: 1;             background: var(–bg-color);             border: 2px solid var(–accent-color);             color: var(–accent-color);             padding: 12px;             border-radius: 12px;             font-weight: 700;             cursor: pointer;             transition: all 0.2s;         }         .preset-btn.active {             background: var(–accent-color);             color: white;         }         /* Waveform Setup */         .wave-selector {             display: grid;             grid-template-columns: 1fr 1fr;             gap: 10px;         }         .wave-btn {             background: transparent;             border: 1px solid #cbd5e1;             color: var(–secondary-color);             padding: 10px;             border-radius: 12px;             cursor: pointer;             transition: all 0.2s;         }         .wave-btn.active {             background: #e0f2fe;             color: #0284c7;             border-color: #0284c7;             font-weight: 700;         }         /* Fine controls buttons */         .fine-controls {             display: flex;             justify-content: space-between;             gap: 10px;             margin-top: 5px;         }         .adjust-btn {             flex: 1;             background: #f1f5f9;             border: none;             color: var(–secondary-color);             padding: 8px;             border-radius: 8px;             font-size: 1.2rem;             cursor: pointer;         }         .adjust-btn:active {             background: #e2e8f0;         }         /* Main Action Button */         .main-btn {             margin-top: 10px;             padding: 20px;             font-size: 1.1rem;             font-weight: 800;             border: none;             border-radius: 16px;             background: var(–secondary-color);             color: white;             cursor: pointer;             transition: all 0.3s;             box-shadow: 0 10px 20px -10px rgba(0, 0, 0, 0.2);         }         .main-btn.playing {             background: var(–danger-color);             box-shadow: 0 10px 20px -10px rgba(244, 63, 94, 0.4);         }         .main-btn:not(.playing) {             background: var(–accent-color);             box-shadow: 0 10px 20px -10px var(–accent-glow);         }        
       

🐾 Armonía Animal 🐾

       

Frecuencias de Sanación para Mascotas

       
                   
       
           
7.83 Hz
           
Resonancia Schumann
       
       
                       
                Modos Rápidos                
                                   
           
                       
                Ajuste Manual                                
                                                       
           
                       
                Tipo de Sonido                
                                                       
           
                       
                Volumen                            
                               
   
            // Web Audio API Context         let audioCtx;         let oscillator;         let gainNode;         let analyser;         let isPlaying = false;         let animationId;         // DOM Elements         const playBtn = document.getElementById(‘toggle-btn’);         const freqSlider = document.getElementById(‘freq-slider’);         const freqDisplay = document.getElementById(‘freq-display’);         const volSlider = document.getElementById(‘vol-slider’);         const waveBtns = document.querySelectorAll(‘.wave-btn’);         const freqMinusBtn = document.getElementById(‘freq-minus’);         const freqPlusBtn = document.getElementById(‘freq-plus’);         const presetBtn = document.querySelector(‘.preset-btn’);         const resonanceLabel = document.querySelector(‘.resonance-label’);         const canvas = document.getElementById(‘visualizer’);         const canvasCtx = canvas.getContext(‘2d’);         // State         let currentFreq = 7.83;         let currentVol = 0.5;         let currentWave = ‘sine’;         // Set canvas size (handling DPI)         function resizeCanvas() {             const dpr = window.devicePixelRatio || 1;             const rect = canvas.getBoundingClientRect();             canvas.width = rect.width * dpr;             canvas.height = rect.height * dpr;             canvasCtx.scale(dpr, dpr);         }         window.addEventListener(‘resize’, resizeCanvas);         resizeCanvas();         function initAudio() {             if (!audioCtx) {                 audioCtx = new (window.AudioContext || window.webkitAudioContext)();                 analyser = audioCtx.createAnalyser();                 analyser.fftSize = 2048;             }         }         function startOscillator() {             initAudio();             if (audioCtx.state === ‘suspended’) {                 audioCtx.resume();             }             oscillator = audioCtx.createOscillator();             gainNode = audioCtx.createGain();             oscillator.type = currentWave;             oscillator.frequency.setValueAtTime(currentFreq, audioCtx.currentTime);             gainNode.gain.setValueAtTime(currentVol, audioCtx.currentTime);             // Graph: Oscillator -> Gain -> Analyser -> Destination             oscillator.connect(gainNode);             gainNode.connect(analyser); // Connect to analyser             analyser.connect(audioCtx.destination);             // gainNode.connect(audioCtx.destination); // Redundant if going through analyser, but analyser passes to dest             oscillator.start();             isPlaying = true;             updateUI(null);             drawVisualizer();         }         function stopOscillator() {             if (oscillator) {                 // Ramp down to avoid click sound on stop                 gainNode.gain.setTargetAtTime(0, audioCtx.currentTime, 0.015);                 setTimeout(() => {                     if (oscillator) {                         oscillator.stop();                         oscillator.disconnect();                         oscillator = null;                     }                     isPlaying = false;                     updateUI(null);                     cancelAnimationFrame(animationId);                     // Clear canvas                     canvasCtx.clearRect(0, 0, canvas.width, canvas.height);                 }, 50);             }         }         function drawVisualizer() {             if (!isPlaying) return;             animationId = requestAnimationFrame(drawVisualizer);             const bufferLength = analyser.frequencyBinCount;             const dataArray = new Uint8Array(bufferLength);             analyser.getByteTimeDomainData(dataArray);             // Use getBoundingClientRect for actual display size logic             const width = canvas.width / (window.devicePixelRatio || 1);             const height = canvas.height / (window.devicePixelRatio || 1);             canvasCtx.fillStyle = ‘#f8fafc’; // Background logic handled by CSS, this clears it effectively             canvasCtx.clearRect(0, 0, width, height);             canvasCtx.lineWidth = 2;             canvasCtx.strokeStyle = ‘#10b981’; // Accent color             canvasCtx.beginPath();             const sliceWidth = width * 1.0 / bufferLength;             let x = 0;             for (let i = 0; i < bufferLength; i++) {                 const v = dataArray[i] / 128.0;                 const y = v * height / 2;                 if (i === 0) {                     canvasCtx.moveTo(x, y);                 } else {                     canvasCtx.lineTo(x, y);                 }                 x += sliceWidth;             }             canvasCtx.lineTo(width, height / 2);             canvasCtx.stroke();         }         function updateUI(source) {             if (isPlaying) {                 playBtn.textContent = 'DETENER TERAPIA';                 playBtn.classList.add('playing');             } else {                 playBtn.textContent = 'INICIAR TERAPIA';                 playBtn.classList.remove('playing');             }             // Update Frequency Display Text             freqDisplay.innerHTML = `${Number(currentFreq).toFixed(2)} Hz`;             // Only update slider if the change DID NOT come from the slider itself             if (source !== ‘slider’) {                 freqSlider.value = currentFreq;             }             // Update Preset Button State             if (Math.abs(currentFreq – 7.83) {             if (isPlaying) {                 stopOscillator();             } else {                 startOscillator();             }         });         freqSlider.addEventListener(‘input’, (e) => {             currentFreq = parseFloat(e.target.value);             if (oscillator && isPlaying) {                 oscillator.frequency.setValueAtTime(currentFreq, audioCtx.currentTime);             }             // Pass ‘slider’ as source so we don’t overwrite the user’s drag             updateUI(‘slider’);         });         volSlider.addEventListener(‘input’, (e) => {             currentVol = parseFloat(e.target.value);             if (gainNode && isPlaying) {                 gainNode.gain.setTargetAtTime(currentVol, audioCtx.currentTime, 0.01);             }         });         waveBtns.forEach(btn => {             btn.addEventListener(‘click’, () => {                 waveBtns.forEach(b => b.classList.remove(‘active’));                 btn.classList.add(‘active’);                 currentWave = btn.dataset.type;                 if (oscillator && isPlaying) {                     oscillator.type = currentWave;                 }             });         });         presetBtn.addEventListener(‘click’, () => {             const freq = parseFloat(presetBtn.dataset.freq);             currentFreq = freq;             if (oscillator && isPlaying) {                 oscillator.frequency.setValueAtTime(currentFreq, audioCtx.currentTime);             }             updateUI(‘preset’);         });         freqMinusBtn.addEventListener(‘click’, () => {             if (currentFreq > 1) {                 currentFreq = Math.max(1, currentFreq – 0.1);                 if (oscillator && isPlaying) {                     oscillator.frequency.setValueAtTime(currentFreq, audioCtx.currentTime);                 }                 updateUI(‘button’);             }         });         freqPlusBtn.addEventListener(‘click’, () => {             if (currentFreq < 100) {                 currentFreq = Math.min(100, currentFreq + 0.1);                 if (oscillator && isPlaying) {                     oscillator.frequency.setValueAtTime(currentFreq, audioCtx.currentTime);                 }                 updateUI('button');             }         });