// modules/scroll-loop/index.js import { registerFrameTask } from '../../core/frameloop.js'; export function init(config = {}) { const elements = document.querySelectorAll('[data-scroll-loop]'); elements.forEach(el => { const type = el.dataset.scrollType || 'translate'; if (type === 'translate' && el.children.length === 1) { const clone = el.firstElementChild.cloneNode(true); clone.setAttribute('aria-hidden', 'true'); el.appendChild(clone); } }); registerFrameTask('scroll-loop', () => { const scrollY = window.scrollY; const scrollX = window.scrollX; elements.forEach(el => { const factor = parseFloat(el.dataset.scrollSpeed || config.speed || 0.2); const axis = el.dataset.scrollAxis || 'y'; const type = el.dataset.scrollType || 'translate'; const pause = el.dataset.loopPause === 'true'; const offsetStart = parseFloat(el.dataset.loopOffset || 0); const limit = parseFloat(el.dataset.loopLimit || 0); const input = axis === 'x' ? scrollX : scrollY; if (limit && input > limit) return; if (pause && (el.matches(':hover') || el.matches(':active'))) return; const offset = (input + offsetStart) * factor; switch (type) { case 'translate': { const base = axis === 'x' ? el.offsetWidth : el.offsetHeight; const value = -(offset % base); const transform = axis === 'x' ? `translateX(${value}px)` : `translateY(${value}px)`; el.style.transform = transform; break; } case 'rotate': { const deg = offset % 360; el.style.transform = `rotate(${deg}deg)`; break; } case 'background': { const pos = offset % 100; if (axis === 'x') { el.style.backgroundPosition = `${pos}% center`; } else { el.style.backgroundPosition = `center ${pos}%`; } break; } case 'scale': { const scale = 1 + Math.sin(offset * 0.01) * 0.1; el.style.transform = `scale(${scale.toFixed(3)})`; break; } default: break; } }); }, { autoStart: true }); }