| class CinematicNumbersApp { |
| constructor() { |
| this.currentNumber = 1; |
| this.currentAnimation = 'zoom'; |
| this.isLooping = true; |
| this.isPlaying = true; |
| this.animationTimeout = null; |
| |
| this.initializeElements(); |
| this.setupEventListeners(); |
| this.startAnimation(); |
| } |
|
|
| initializeElements() { |
| this.numberDisplay = document.getElementById('numberDisplay'); |
| this.currentNumberSpan = document.getElementById('currentNumber'); |
| this.animationTypeSelect = document.getElementById('animationType'); |
| this.loopCheckbox = document.getElementById('loopAnimation'); |
| this.playPauseButton = document.getElementById('playPause'); |
| this.prevButton = document.getElementById('prevNumber'); |
| this.nextButton = document.getElementById('nextNumber'); |
| this.particlesContainer = document.getElementById('particles'); |
| } |
|
|
| setupEventListeners() { |
| this.animationTypeSelect.addEventListener('change', (e) => { |
| this.currentAnimation = e.target.value; |
| this.applyAnimation(); |
| }); |
|
|
| this.loopCheckbox.addEventListener('change', (e) => { |
| this.isLooping = e.target.checked; |
| if (this.isLooping && this.isPlaying) { |
| this.startAnimation(); |
| } |
| }); |
|
|
| this.playPauseButton.addEventListener('click', () => { |
| this.isPlaying = !this.isPlaying; |
| if (this.isPlaying) { |
| this.startAnimation(); |
| } else { |
| this.stopAnimation(); |
| } |
| }); |
|
|
| this.prevButton.addEventListener('click', () => { |
| this.changeNumber(-1); |
| }); |
|
|
| this.nextButton.addEventListener('click', () => { |
| this.changeNumber(1); |
| }); |
|
|
| |
| document.addEventListener('keydown', (e) => { |
| if (e.key === 'ArrowLeft') this.changeNumber(-1); |
| if (e.key === 'ArrowRight') this.changeNumber(1); |
| if (e.key === ' ') { |
| this.isPlaying = !this.isPlaying; |
| if (this.isPlaying) this.startAnimation(); |
| else this.stopAnimation(); |
| } |
| }); |
| } |
|
|
| changeNumber(direction) { |
| this.currentNumber += direction; |
| |
| if (this.currentNumber < 1) this.currentNumber = 10; |
| if (this.currentNumber > 10) this.currentNumber = 1; |
| |
| this.updateDisplay(); |
| this.applyAnimation(); |
| } |
|
|
| updateDisplay() { |
| this.numberDisplay.textContent = this.currentNumber; |
| this.numberDisplay.setAttribute('data-number', this.currentNumber); |
| this.currentNumberSpan.textContent = this.currentNumber; |
| } |
|
|
| applyAnimation() { |
| |
| this.numberDisplay.className = 'cinematic-number text-9xl md:text-[20rem] font-black tracking-tighter'; |
| |
| |
| switch(this.currentAnimation) { |
| case 'zoom': |
| this.numberDisplay.classList.add('zoom-animation'); |
| break; |
| case 'bounce': |
| this.numberDisplay.classList.add('bounce-animation'); |
| break; |
| case 'smoke': |
| this.numberDisplay.classList.add('smoke-animation'); |
| this.createParticles(); |
| break; |
| case 'glitch': |
| this.numberDisplay.classList.add('glitch-animation'); |
| break; |
| case 'pulse': |
| this.numberDisplay.classList.add('pulse-animation'); |
| break; |
| } |
| } |
|
|
| createParticles() { |
| |
| this.particlesContainer.innerHTML = ''; |
| |
| |
| for (let i = 0; i < 30; i++) { |
| const particle = document.createElement('div'); |
| particle.classList.add('particle'); |
| |
| const angle = Math.random() * Math.PI * 2; |
| const distance = 100 + Math.random() * 200; |
| const tx = Math.cos(angle) * distance; |
| const ty = Math.sin(angle) * distance; |
| |
| particle.style.setProperty('--tx', `${tx}px`); |
| particle.style.setProperty('--ty', `${ty}px`); |
| particle.style.left = '50%'; |
| particle.style.top = '50%'; |
| particle.style.animationDelay = `${Math.random() * 0.5}s`; |
| |
| this.particlesContainer.appendChild(particle); |
| } |
| } |
|
|
| startAnimation() { |
| this.stopAnimation(); |
| |
| if (this.isLooping && this.isPlaying) { |
| this.animationTimeout = setTimeout(() => { |
| this.changeNumber(1); |
| this.startAnimation(); |
| }, 3000); |
| } |
| } |
|
|
| stopAnimation() { |
| if (this.animationTimeout) { |
| clearTimeout(this.animationTimeout); |
| this.animationTimeout = null; |
| } |
| } |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| new CinematicNumbersApp(); |
| }); |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| if (typeof feather !== 'undefined') { |
| feather.replace(); |
| } |
| }); |