// Liquid Bold Lab - Interactive Controls document.addEventListener('DOMContentLoaded', () => { const root = document.documentElement; const text = document.getElementById('grogu-text'); const blocks = document.querySelectorAll('.oil-block'); const panel = document.getElementById('control-panel'); const toggleBtn = document.getElementById('toggle-panel'); const showBtn = document.getElementById('show-panel'); const resetBtn = document.getElementById('reset-all'); // State management const state = { speed: 1, color: 0, boldness: 50, spinSpeed: 0.5, zoom: 1, oilShine: 80, softCorners: 20, depth: 100, letterSpacing: -0.08, blockTwist: 15 }; // Slider elements const sliders = { speed: document.getElementById('speed'), color: document.getElementById('color'), boldness: document.getElementById('boldness'), spinSpeed: document.getElementById('spin-speed'), zoom: document.getElementById('zoom'), oilShine: document.getElementById('oil-shine'), softCorners: document.getElementById('soft-corners'), depth: document.getElementById('depth'), letterSpacing: document.getElementById('letter-spacing'), blockTwist: document.getElementById('block-twist') }; // Value displays const displays = { speed: document.getElementById('val-speed'), color: document.getElementById('val-color'), boldness: document.getElementById('val-bold'), spinSpeed: document.getElementById('val-spin'), zoom: document.getElementById('val-zoom'), oilShine: document.getElementById('val-shine'), softCorners: document.getElementById('val-blur'), depth: document.getElementById('val-depth'), letterSpacing: document.getElementById('val-spacing'), blockTwist: document.getElementById('val-twist') }; // Update CSS variables and displays function updateValue(key, value) { state[key] = parseFloat(value); switch(key) { case 'speed': root.style.setProperty('--anim-speed', state[key]); displays[key].textContent = state[key].toFixed(1) + 'x'; break; case 'color': root.style.setProperty('--base-hue', state[key]); displays[key].textContent = Math.round(state[key]) + '°'; // Update thumb color sliders[key].style.background = `linear-gradient(to right, hsl(${state[key]}, 70%, 50%), hsl(${state[key]}, 70%, 50%))`; break; case 'boldness': root.style.setProperty('--boldness', state[key]); displays[key].textContent = Math.round(state[key]); break; case 'spinSpeed': root.style.setProperty('--spin-speed', Math.abs(state[key])); root.style.setProperty('--direction', state[key] >= 0 ? 1 : -1); displays[key].textContent = state[key].toFixed(1); break; case 'zoom': root.style.setProperty('--zoom', state[key]); displays[key].textContent = state[key].toFixed(2); break; case 'oilShine': root.style.setProperty('--oil-shine', state[key] / 100); displays[key].textContent = Math.round(state[key]) + '%'; document.querySelectorAll('.oil-shine').forEach(el => { el.style.opacity = state[key] / 100; }); break; case 'softCorners': root.style.setProperty('--soft-corners', state[key] + 'px'); displays[key].textContent = Math.round(state[key]) + 'px'; break; case 'depth': root.style.setProperty('--depth', state[key] + 'px'); displays[key].textContent = Math.round(state[key]) + 'px'; break; case 'letterSpacing': root.style.setProperty('--letter-spacing', state[key] + 'em'); displays[key].textContent = state[key].toFixed(2) + 'em'; break; case 'blockTwist': root.style.setProperty('--block-twist', state[key] + 'deg'); displays[key].textContent = Math.round(state[key]) + '°'; break; } } // Event listeners for sliders Object.keys(sliders).forEach(key => { if (sliders[key]) { sliders[key].addEventListener('input', (e) => { updateValue(key, e.target.value); }); } }); // Panel toggle toggleBtn.addEventListener('click', () => { panel.classList.add('translate-x-[120%]'); setTimeout(() => { panel.style.display = 'none'; showBtn.classList.remove('hidden'); }, 300); }); showBtn.addEventListener('click', () => { panel.style.display = 'block'; showBtn.classList.add('hidden'); setTimeout(() => { panel.classList.remove('translate-x-[120%]'); }, 10); }); // Reset functionality const defaults = { speed: 1, color: 0, boldness: 50, spinSpeed: 1, zoom: 1, oilShine: 80, softCorners: 20, depth: 100, letterSpacing: -0.08, blockTwist: 15 }; resetBtn.addEventListener('click', () => { Object.keys(defaults).forEach(key => { if (sliders[key]) { sliders[key].value = defaults[key]; updateValue(key, defaults[key]); } }); }); // Mouse interaction for parallax let mouseX = 0; let mouseY = 0; let currentX = 0; let currentY = 0; document.addEventListener('mousemove', (e) => { mouseX = (e.clientX / window.innerWidth - 0.5) * 2; mouseY = (e.clientY / window.innerHeight - 0.5) * 2; }); // Smooth animation loop function animate() { currentX += (mouseX - currentX) * 0.05; currentY += (mouseY - currentY) * 0.05; // Apply subtle parallax to blocks based on mouse blocks.forEach((block, index) => { const depth = (index + 1) * 20; const rotateX = currentY * 10; const rotateY = currentX * 10; block.style.transform += ` rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; }); // Text follows mouse slightly if (text) { const moveX = currentX * 30; const moveY = currentY * 30; text.style.transform = `translate(${moveX}px, ${moveY}px) scale(var(--zoom))`; } requestAnimationFrame(animate); } animate(); // Prevent scroll on mobile document.body.style.overflow = 'hidden'; document.body.style.touchAction = 'none'; // Keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.key === 'h') { toggleBtn.click(); } if (e.key === ' ') { e.preventDefault(); // Pause/play animation const currentSpeed = parseFloat(sliders.speed.value); if (currentSpeed > 0) { sliders.speed.value = 0; updateValue('speed', 0); } else { sliders.speed.value = 1; updateValue('speed', 1); } } }); // Initial reveal setTimeout(() => { text.style.opacity = '1'; }, 100); });