// Scrollytelling functionality class ScrollytellingEngine { constructor() { this.scenes = document.querySelectorAll('.scene'); this.progressBar = document.querySelector('.progress-bar'); this.currentScene = 0; this.init(); } init() { // Set up intersection observer for scene detection this.setupIntersectionObserver(); // Set up scroll progress tracking this.setupScrollProgress(); // Initialize first scene this.activateScene(0); } setupIntersectionObserver() { const options = { root: null, rootMargin: '0px', threshold: this.buildThresholdList() }; this.observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const sceneIndex = parseInt(entry.target.dataset.scene); this.activateScene(sceneIndex); } }); }, options); this.scenes.forEach(scene => { this.observer.observe(scene); }); } buildThresholdList() { const thresholds = []; const numSteps = 20; for (let i = 1.0; i <= numSteps; i++) { const ratio = i / numSteps; thresholds.push(ratio); } thresholds.push(0); return thresholds; } setupScrollProgress() { window.addEventListener('scroll', () => { const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const scrollHeight = document.documentElement.scrollHeight - window.innerHeight; const scrollProgress = (scrollTop / scrollHeight) * 100; if (this.progressBar) { this.progressBar.style.width = `${scrollProgress}%`; } }); } activateScene(index) { // Update all scenes this.scenes.forEach((scene, i) => { if (i === index) { scene.classList.add('active'); } else { scene.classList.remove('active'); } }); this.currentScene = index; this.updateVisualization(index); } updateVisualization(sceneIndex) { const visualizationContainer = document.querySelector('.sticky > div'); if (!visualizationContainer) return; // Update visualization based on current scene switch(sceneIndex) { case 0: visualizationContainer.innerHTML = this.createScene0Visualization(); break; case 1: visualizationContainer.innerHTML = this.createScene1Visualization(); break; case 2: visualizationContainer.innerHTML = this.createScene2Visualization(); break; case 3: visualizationContainer.innerHTML = this.createScene3Visualization(); break; case 4: visualizationContainer.innerHTML = this.createScene4Visualization(); break; case 5: visualizationContainer.innerHTML = this.createScene5Visualization(); break; case 6: visualizationContainer.innerHTML = this.createScene6Visualization(); break; case 7: visualizationContainer.innerHTML = this.createScene7Visualization(); break; case 8: visualizationContainer.innerHTML = this.createScene8Visualization(); break; default: visualizationContainer.innerHTML = this.createDefaultVisualization(); } } createScene0Visualization() { return `