File size: 5,395 Bytes
64aa32a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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();
    }
});