ProjectGenesis's picture
Create animated numbers (1–10) in the style of Netflix’s "Top 10" design.
64aa32a verified
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);
});
// Keyboard navigation
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() {
// Remove all animation classes
this.numberDisplay.className = 'cinematic-number text-9xl md:text-[20rem] font-black tracking-tighter';
// Add current animation class
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() {
// Clear existing particles
this.particlesContainer.innerHTML = '';
// Create new particles
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(); // Clear any existing timeout
if (this.isLooping && this.isPlaying) {
this.animationTimeout = setTimeout(() => {
this.changeNumber(1);
this.startAnimation();
}, 3000); // 3 second delay between numbers
}
}
stopAnimation() {
if (this.animationTimeout) {
clearTimeout(this.animationTimeout);
this.animationTimeout = null;
}
}
}
// Initialize the app when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new CinematicNumbersApp();
});
// Handle feather icons replacement
document.addEventListener('DOMContentLoaded', () => {
if (typeof feather !== 'undefined') {
feather.replace();
}
});