diff --git a/frogs/frogs.js b/frogs/frogs.js new file mode 100644 index 0000000..810a238 --- /dev/null +++ b/frogs/frogs.js @@ -0,0 +1,153 @@ +const audio = document.getElementById('bg-music'); + +const container = document.getElementById('frog-container'); +const menuHeight = document.querySelector('header').offsetHeight; +const startText = document.getElementById('start-text'); +const startString = "Нажми в любую часть экрана"; + +const particlesContainer = document.querySelector('.particles'); +const particleCount = 60; +for (let i = 0; i < particleCount; i++) { + const particle = document.createElement('div'); + particle.classList.add('particle'); + const size = Math.random() * 8 + 2; + const posX = Math.random() * 100; + const posY = Math.random() * 100; + const duration = Math.random() * 5 + 5; + const baseColor = 200; + const variation = Math.random() * 20 - 10; + particle.style.background = `hsl(${baseColor + variation}, 100%, 50%)`; + particle.style.width = size + 'px'; + particle.style.height = size + 'px'; + particle.style.left = posX + '%'; + particle.style.top = posY + '%'; + particle.style.animationDuration = `${duration}s`; + particlesContainer.appendChild(particle); +} + +const totalFrogs = 33; +const frogs = []; +const occupiedZones = []; +let typingTimers = []; + +function checkOverlap(pos, zones) { + return zones.some(zone => + pos.x < zone.x + zone.w && + pos.x + pos.w > zone.x && + pos.y < zone.y + zone.h && + pos.y + pos.h > zone.y + ); +} + +function getRandomPosition(frog) { + const w = frog.el.offsetWidth; + const h = w; + const x = Math.random() * (window.innerWidth - w); + const y = Math.random() * (window.innerHeight - h - menuHeight) + menuHeight; + return { x, y, w, h }; +} + +function placeFrog(frog) { + let pos, attempts = 0; + do { + pos = getRandomPosition(frog); + attempts++; + if (attempts > 100) break; + } while (checkOverlap(pos, occupiedZones)); + occupiedZones.push(pos); + frog.el.style.left = pos.x + 'px'; + frog.el.style.top = pos.y + 'px'; +} + +function teleportFrogsSync() { + const zones = []; + frogs.forEach(frog => { + let pos, attempts = 0; + do { + pos = getRandomPosition(frog); + attempts++; + if (attempts > 100) break; + } while (checkOverlap(pos, zones)); + zones.push(pos); + frog.el.style.left = pos.x + 'px'; + frog.el.style.top = pos.y + 'px'; + }); +} + +function startTeleportationLoop() { + setInterval(teleportFrogsSync, 1000); +} + +function createFrog() { + const frog = document.createElement('img'); + frog.src = '../assets/frog.gif'; + frog.classList.add('frog'); + if (Math.random() < 0.5) frog.style.transform = 'scaleX(-1)'; + frog.style.opacity = 0; + container.appendChild(frog); + + frog.onload = () => { + const sizePx = window.innerWidth * (0.05 + Math.random() * 0.05); + frog.style.width = sizePx + 'px'; + frog.style.height = 'auto'; + requestAnimationFrame(() => { + placeFrog({ el: frog }); + const delay = Math.random() * 1300 + 200; + setTimeout(() => { frog.style.transition = `opacity ${delay}ms linear`; frog.style.opacity = 1; }, Math.random() * 1500); + }); + }; + return { el: frog }; +} + +function typeWriterEffect(text, container, delay = 50) { + typingTimers.forEach(t => clearTimeout(t)); + typingTimers = []; + container.innerHTML = ''; + [...text].forEach(char => { + const span = document.createElement('span'); + span.textContent = char === ' ' ? '\u00A0' : char; + container.appendChild(span); + }); + const spans = container.querySelectorAll('span'); + spans.forEach((span, i) => { + const timer = setTimeout(() => { span.style.opacity = 1; }, i * delay); + typingTimers.push(timer); + }); +} + +function reverseTypeWriter(container, delay = 50, callback) { + typingTimers.forEach(t => clearTimeout(t)); + typingTimers = []; + const spans = Array.from(container.querySelectorAll('span')).reverse(); + spans.forEach((span, i) => { setTimeout(() => { span.style.opacity = 0; }, i * delay); }); + setTimeout(callback, spans.length * delay + 50); +} + +let started = false; +let typingInProgress = false; + +document.addEventListener('click', () => { + if (started || typingInProgress) return; + + typingInProgress = true; + + reverseTypeWriter(startText, 40, () => { + typingInProgress = false; + started = true; + + audio.play().catch(() => {}); + for (let i = 0; i < totalFrogs; i++) { + frogs.push(createFrog()); + } + startTeleportationLoop(); + }); +}); + +typeWriterEffect(startString, startText, 40); + +window.addEventListener('resize', () => { + frogs.forEach(frog => { + const size = window.innerWidth * (0.05 + Math.random() * 0.05); + frog.el.style.width = size + 'px'; + }); +}); \ No newline at end of file diff --git a/frogs/index.html b/frogs/index.html new file mode 100644 index 0000000..e718662 --- /dev/null +++ b/frogs/index.html @@ -0,0 +1,30 @@ + + +
+ + +