// Version 4: Gaussian Noise Overlay - Perpetual organic motion
const staggerVisualizerEl = document.querySelector('.stagger-visualizer');
const fragment = document.createDocumentFragment();
const grid = [12, 6];
const col = grid[0];
const row = grid[1];
const numberOfElements = col * row;

// Store element data for continuous noise animation
const elementData = [];

for (let i = 0; i < numberOfElements; i++) {
    let div = document.createElement('div');
    div.className = 'part';
    div.dataset.index = i;
    fragment.appendChild(div);
    
    // Store random animation parameters for each element
    elementData.push({
        element: div,
        index: i,
        // Random frequencies for sine wave oscillations
        freqX: anime.utils.random(0.0008, 0.0012),
        freqY: anime.utils.random(0.0006, 0.0010),
        freqRot: anime.utils.random(0.0004, 0.0009),
        freqOpacity: anime.utils.random(0.0005, 0.0008),
        // Random amplitudes for movement
        ampX: anime.utils.random(3, 8),
        ampY: anime.utils.random(3, 8),
        ampRot: anime.utils.random(10, 25),
        // Phase offsets so they don't all move together
        phaseX: anime.utils.random(0, Math.PI * 2),
        phaseY: anime.utils.random(0, Math.PI * 2),
        phaseRot: anime.utils.random(0, Math.PI * 2),
        phaseOpacity: anime.utils.random(0, Math.PI * 2),
    });
}

staggerVisualizerEl.appendChild(fragment);

// Initial burst animation
const staggersAnimation = anime.createTimeline({
    easing: 'easeInOutSine',
    loop: true,
    autoplay: false
});

staggersAnimation
    // Burst outward
    .add('.part', {
        translateX: anime.stagger('-.15rem', { grid: grid, from: 'center', axis: 'x' }),
        translateY: anime.stagger('-.15rem', { grid: grid, from: 'center', axis: 'y' }),
        scale: 0.5,
        duration: 300,
        easing: 'easeOutQuad',
        delay: anime.stagger(60, { grid: grid, from: 'center' })
    }, 0)
    // Spring outward further with randomness
    .add('.part', {
        translateX: (el, i) => anime.utils.random(-8, 8),
        translateY: (el, i) => anime.utils.random(-8, 8),
        scale: (el) => anime.utils.random(0.7, 1.2),
        rotate: (el) => anime.utils.random(-90, 90),
        duration: 600,
        easing: 'easeOutQuad',
        delay: anime.stagger(100, { grid: grid, from: 'center' })
    })
    // Floating phase - long duration
    .add('.part', {
        translateY: (el, i) => anime.utils.random(-4, 4),
        rotate: (el, i) => anime.utils.random(-45, 45),
        duration: 4000,
        easing: 'easeInOutSine',
        delay: (el, i) => i * 25 + anime.utils.random(-150, 150)
    })
    // Gentle convergence
    .add('.part', {
        translateX: 0,
        translateY: 0,
        rotate: (el) => anime.utils.random(0, 360),
        scale: 1,
        duration: 2000,
        easing: 'easeOutQuad',
        delay: anime.stagger(40, { grid: grid, from: 'center' })
    })
    // Rest phase
    .add('.part', {
        opacity: 1,
        duration: 6000,
        delay: 0
    }, '-=1000');

staggersAnimation.play();

// Continuous Gaussian noise animation - using requestAnimationFrame
let startTime = Date.now();

const applyNoise = () => {
    const elapsed = Date.now() - startTime;
    
    elementData.forEach((data) => {
        // Multi-layered sine waves create Gaussian-like noise
        const noiseX = Math.sin(elapsed * data.freqX + data.phaseX) * data.ampX +
                      Math.sin(elapsed * data.freqX * 0.3 + data.phaseX) * data.ampX * 0.3;
        
        const noiseY = Math.sin(elapsed * data.freqY + data.phaseY) * data.ampY +
                      Math.sin(elapsed * data.freqY * 0.4 + data.phaseY) * data.ampY * 0.4;
        
        const noiseRot = Math.sin(elapsed * data.freqRot + data.phaseRot) * data.ampRot +
                        Math.sin(elapsed * data.freqRot * 0.5 + data.phaseRot) * data.ampRot * 0.2;
        
        // Smooth opacity breathing
        const opacityVariation = Math.sin(elapsed * data.freqOpacity + data.phaseOpacity) * 0.12 + 0.88;
        
        // Apply noise to element
        data.element.style.filter = `opacity(${opacityVariation})`;
        
        // Get current computed transform and add noise
        // This is applied on top of anime's transforms
        const currentTransform = window.getComputedStyle(data.element).transform;
        const matrix = currentTransform.match(/matrix.*\((.+)\)/)[1].split(', ');
        const currentX = parseFloat(matrix[4]) || 0;
        const currentY = parseFloat(matrix[5]) || 0;
        
        data.element.style.setProperty('--noise-x', `${noiseX}px`);
        data.element.style.setProperty('--noise-y', `${noiseY}px`);
        data.element.style.setProperty('--noise-rot', `${noiseRot}deg`);
    });
    
    requestAnimationFrame(applyNoise);
};

// Start noise animation after a brief delay to let anime init
setTimeout(() => {
    applyNoise();
}, 100);
