| 1 | (function(){ |
| 2 | window.HPX = window.HPX || {}; |
| 3 | window.HPX['letter-explode'] = function(el){ |
| 4 | const U = window.HPX._u; |
| 5 | if (getComputedStyle(el).position === 'static') el.style.position = 'relative'; |
| 6 | const src = el.querySelector('[data-fx-text]') || el; |
| 7 | const text = (el.getAttribute('data-fx-text-value') || src.textContent || 'EXPLODE').trim(); |
| 8 | // Build a container, hide source text |
| 9 | const wrap = document.createElement('div'); |
| 10 | wrap.style.cssText = 'position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;'; |
| 11 | const inner = document.createElement('div'); |
| 12 | inner.style.cssText = 'font-size:64px;font-weight:900;letter-spacing:0.02em;color:var(--text-1,#fff);white-space:nowrap;'; |
| 13 | wrap.appendChild(inner); |
| 14 | el.appendChild(wrap); |
| 15 | const spans = []; |
| 16 | for (const ch of text){ |
| 17 | const s = document.createElement('span'); |
| 18 | s.textContent = ch === ' ' ? '\u00A0' : ch; |
| 19 | s.style.display='inline-block'; |
| 20 | s.style.transform='translate(0,0)'; |
| 21 | s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms'; |
| 22 | s.style.opacity='0'; |
| 23 | inner.appendChild(s); |
| 24 | spans.push(s); |
| 25 | } |
| 26 | let stopped = false; |
| 27 | const run = () => { |
| 28 | if (stopped) return; |
| 29 | spans.forEach((s,i) => { |
| 30 | const dx = U.rand(-400, 400), dy = U.rand(-300, 300); |
| 31 | s.style.transition='none'; |
| 32 | s.style.transform=`translate(${dx}px,${dy}px) rotate(${U.rand(-180,180)}deg)`; |
| 33 | s.style.opacity='0'; |
| 34 | }); |
| 35 | // force reflow |
| 36 | void inner.offsetWidth; |
| 37 | spans.forEach((s,i) => { |
| 38 | setTimeout(() => { |
| 39 | if (stopped) return; |
| 40 | s.style.transition='transform 900ms cubic-bezier(.2,.9,.3,1), opacity 900ms'; |
| 41 | s.style.transform='translate(0,0) rotate(0deg)'; |
| 42 | s.style.opacity='1'; |
| 43 | }, i*35); |
| 44 | }); |
| 45 | }; |
| 46 | run(); |
| 47 | const iv = setInterval(run, 4500); |
| 48 | return { stop(){ stopped=true; clearInterval(iv); if (wrap.parentNode) wrap.parentNode.removeChild(wrap); } }; |
| 49 | }; |
| 50 | })(); |
| 51 |