class CinematicNumber extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { this.render(); } static get observedAttributes() { return ['number', 'animation', 'loop']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { this.render(); } } render() { const number = this.getAttribute('number') || '1'; const animation = this.getAttribute('animation') || 'zoom'; const loop = this.getAttribute('loop') === 'true'; this.shadowRoot.innerHTML = `
${number}
`; this.applyAnimation(animation); } applyAnimation(animationType) { const numberElement = this.shadowRoot.querySelector('.cinematic-number'); const particlesContainer = this.shadowRoot.querySelector('.particles'); // Remove existing particles particlesContainer.innerHTML = ''; switch(animationType) { case 'smoke': this.createParticles(particlesContainer); break; } } createParticles(container) { for (let i = 0; i < 20; i++) { const particle = document.createElement('div'); particle.classList.add('particle'); const angle = Math.random() * Math.PI * 2; const distance = 80 + Math.random() * 120; 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.3}s`; container.appendChild(particle); } } } customElements.define('cinematic-number', CinematicNumber);