| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| (function () { |
| 'use strict'; |
|
|
| const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; |
|
|
| |
| function initLenis() { |
| if (reduceMotion || typeof Lenis === 'undefined') return null; |
| const lenis = new Lenis({ |
| duration: 1.6, |
| easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), |
| smoothWheel: true, |
| smoothTouch: false, |
| }); |
| function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } |
| requestAnimationFrame(raf); |
|
|
| |
| document.querySelectorAll('a[href^="#"]').forEach((a) => { |
| a.addEventListener('click', (e) => { |
| const id = a.getAttribute('href'); |
| if (!id || id === '#') return; |
| const target = document.querySelector(id); |
| if (!target) return; |
| e.preventDefault(); |
| lenis.scrollTo(target, { offset: -80, duration: 1.8 }); |
| }); |
| }); |
| return lenis; |
| } |
|
|
| |
| function splitWords() { |
| document.querySelectorAll('[data-split]').forEach((el) => { |
| |
| const html = el.innerHTML; |
| |
| const wrapped = html |
| .replace(/(<[^>]+>)/g, '\u0000$1\u0000') |
| .split('\u0000') |
| .map((chunk) => |
| chunk.startsWith('<') ? chunk : chunk.replace(/(\S+)/g, '<span class="word">$1</span>') |
| ) |
| .join(''); |
| el.innerHTML = wrapped; |
| el.classList.add('is-split'); |
| }); |
| } |
|
|
| |
| function initReveals() { |
| const items = document.querySelectorAll('[data-reveal], .reveal'); |
| if (reduceMotion || !('IntersectionObserver' in window)) { |
| items.forEach((el) => el.classList.add('is-in')); |
| document.querySelectorAll('.word').forEach((w) => w.classList.add('is-in')); |
| return; |
| } |
| const io = new IntersectionObserver( |
| (entries) => { |
| entries.forEach((entry) => { |
| if (!entry.isIntersecting) return; |
| const el = entry.target; |
| el.classList.add('is-in'); |
| |
| el.querySelectorAll(':scope > .word, :scope > span.word').forEach((w, i) => { |
| w.style.transitionDelay = `${i * 0.05}s`; |
| w.classList.add('is-in'); |
| }); |
| io.unobserve(el); |
| }); |
| }, |
| { threshold: 0.15, rootMargin: '0px 0px -8% 0px' } |
| ); |
| items.forEach((el) => io.observe(el)); |
|
|
| |
| document.querySelectorAll('[data-split] .word').forEach((w, i) => { |
| w.style.transitionDelay = `${0.1 + i * 0.06}s`; |
| requestAnimationFrame(() => w.classList.add('is-in')); |
| }); |
| } |
|
|
| |
| function boot() { |
| splitWords(); |
| initReveals(); |
| initLenis(); |
| } |
| if (document.readyState === 'loading') { |
| document.addEventListener('DOMContentLoaded', boot); |
| } else { |
| boot(); |
| } |
| })(); |
|
|