/** * The AI-Powered Developer - Presentation Engine * Pure JavaScript - No Dependencies * REVISED with interactive voting */ (function () { 'use strict'; // State let currentSlide = 1; const totalSlides = 13; let isAnimating = false; // Voting state const llmVotes = { anthropic: 0, openai: 0, gemini: 0, grok: 0, mistral: 0, kimi: 0, deepseek: 0, other: 0 }; const editorVotes = { vscode: 0, cursor: 0, antigravity: 0, windsurf: 0, kiro: 0, qoder: 0 }; // DOM Elements const slidesWrapper = document.getElementById('slidesWrapper'); const progressFill = document.getElementById('progressFill'); const currentSlideEl = document.getElementById('currentSlide'); const totalSlidesEl = document.getElementById('totalSlides'); const prevBtn = document.getElementById('prevBtn'); const nextBtn = document.getElementById('nextBtn'); const slides = document.querySelectorAll('.slide'); // Initialize function init() { totalSlidesEl.textContent = totalSlides; updateSlide(1); bindEvents(); initVoting(); addInteractiveFeatures(); } // Bind Events function bindEvents() { // Navigation buttons prevBtn.addEventListener('click', goToPrevSlide); nextBtn.addEventListener('click', goToNextSlide); // Keyboard navigation document.addEventListener('keydown', handleKeyDown); // Touch/Swipe support let touchStartX = 0; let touchEndX = 0; document.addEventListener('touchstart', (e) => { touchStartX = e.changedTouches[0].screenX; }, { passive: true }); document.addEventListener('touchend', (e) => { touchEndX = e.changedTouches[0].screenX; handleSwipe(); }, { passive: true }); function handleSwipe() { const swipeThreshold = 50; const diff = touchStartX - touchEndX; if (Math.abs(diff) > swipeThreshold) { if (diff > 0) { goToNextSlide(); } else { goToPrevSlide(); } } } // Mouse wheel (optional) let wheelTimeout; document.addEventListener('wheel', (e) => { if (wheelTimeout) return; wheelTimeout = setTimeout(() => { wheelTimeout = null; }, 800); if (e.deltaY > 0) { goToNextSlide(); } else if (e.deltaY < 0) { goToPrevSlide(); } }, { passive: true }); } // Keyboard handler function handleKeyDown(e) { switch (e.key) { case 'ArrowRight': case ' ': case 'Enter': e.preventDefault(); goToNextSlide(); break; case 'ArrowLeft': case 'Backspace': e.preventDefault(); goToPrevSlide(); break; case 'Home': e.preventDefault(); goToSlide(1); break; case 'End': e.preventDefault(); goToSlide(totalSlides); break; } // Number keys for quick navigation const num = parseInt(e.key); if (!isNaN(num) && num >= 1 && num <= 9 && num <= totalSlides) { goToSlide(num); } } // Navigation functions function goToNextSlide() { if (currentSlide < totalSlides && !isAnimating) { goToSlide(currentSlide + 1); } } function goToPrevSlide() { if (currentSlide > 1 && !isAnimating) { goToSlide(currentSlide - 1); } } function goToSlide(slideNumber) { if (slideNumber === currentSlide || slideNumber < 1 || slideNumber > totalSlides || isAnimating) { return; } isAnimating = true; currentSlide = slideNumber; // Update slides slides.forEach((slide, index) => { const slideNum = index + 1; slide.classList.remove('active', 'prev'); if (slideNum === currentSlide) { slide.classList.add('active'); triggerSlideAnimations(slide); } else if (slideNum < currentSlide) { slide.classList.add('prev'); } }); updateSlide(currentSlide); setTimeout(() => { isAnimating = false; }, 500); } // Update UI elements function updateSlide(slideNumber) { currentSlideEl.textContent = slideNumber; const progress = (slideNumber / totalSlides) * 100; progressFill.style.width = `${progress}%`; prevBtn.style.opacity = slideNumber === 1 ? '0.3' : '1'; prevBtn.style.pointerEvents = slideNumber === 1 ? 'none' : 'auto'; nextBtn.style.opacity = slideNumber === totalSlides ? '0.3' : '1'; nextBtn.style.pointerEvents = slideNumber === totalSlides ? 'none' : 'auto'; history.replaceState(null, null, `#slide-${slideNumber}`); } // Trigger animations when slide becomes active function triggerSlideAnimations(slide) { const animatedElements = slide.querySelectorAll('.agenda-item, .step-card, [style*="--delay"]'); animatedElements.forEach(el => { el.style.animation = 'none'; el.offsetHeight; el.style.animation = null; }); } // ========== VOTING SYSTEM ========== function initVoting() { // LLM voting cards const llmCards = document.querySelectorAll('.voting-card'); llmCards.forEach(card => { card.addEventListener('click', () => { const llm = card.getAttribute('data-llm'); if (llm && llmVotes.hasOwnProperty(llm)) { llmVotes[llm]++; updateVoteDisplay(card, llmVotes[llm], getTotalVotes(llmVotes)); card.classList.add('voted'); // Animate card.style.transform = 'scale(0.98)'; setTimeout(() => { card.style.transform = ''; }, 150); } }); }); // Editor voting cards const editorCards = document.querySelectorAll('.voting-editor'); editorCards.forEach(card => { card.addEventListener('click', () => { const editor = card.getAttribute('data-editor'); if (editor && editorVotes.hasOwnProperty(editor)) { editorVotes[editor]++; updateVoteDisplay(card, editorVotes[editor], getTotalVotes(editorVotes)); card.classList.add('voted'); // Animate card.style.transform = 'scale(0.98)'; setTimeout(() => { card.style.transform = ''; }, 150); } }); }); } function updateVoteDisplay(card, votes, total) { const voteFill = card.querySelector('.vote-fill'); const voteCount = card.querySelector('.vote-count'); if (voteFill) { const percentage = total > 0 ? (votes / total) * 100 : 0; voteFill.style.width = `${Math.max(percentage, 5)}%`; voteFill.setAttribute('data-votes', votes); } if (voteCount) { voteCount.textContent = `${votes} vote${votes !== 1 ? 's' : ''}`; } // Update all cards in the same group to recalculate percentages setTimeout(() => { updateAllVoteBars(card.closest('.llm-platforms-grid') || card.closest('.editors-poll-grid')); }, 50); } function updateAllVoteBars(container) { if (!container) return; const isLLM = container.classList.contains('llm-platforms-grid'); const votes = isLLM ? llmVotes : editorVotes; const total = getTotalVotes(votes); container.querySelectorAll('.vote-fill').forEach(fill => { const card = fill.closest('[data-llm], [data-editor]'); const key = card.getAttribute('data-llm') || card.getAttribute('data-editor'); if (key && votes[key] !== undefined) { const percentage = total > 0 ? (votes[key] / total) * 100 : 0; fill.style.width = `${Math.max(percentage, votes[key] > 0 ? 5 : 0)}%`; } }); } function getTotalVotes(votesObj) { return Object.values(votesObj).reduce((sum, v) => sum + v, 0); } // Add interactive features function addInteractiveFeatures() { // Approach cards (Slide 3) const approachCards = document.querySelectorAll('.approach-card'); approachCards.forEach(card => { card.addEventListener('click', () => { approachCards.forEach(c => c.classList.remove('selected')); card.classList.add('selected'); }); }); // External links - open in new tab document.querySelectorAll('a[target="_blank"]').forEach(link => { link.addEventListener('click', (e) => { // Allow default behavior for external links }); }); } // Handle URL hash for direct slide access function handleHash() { const hash = window.location.hash; if (hash && hash.startsWith('#slide-')) { const slideNum = parseInt(hash.replace('#slide-', '')); if (slideNum >= 1 && slideNum <= totalSlides) { goToSlide(slideNum); } } } window.addEventListener('hashchange', handleHash); // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { init(); handleHash(); }); } else { init(); handleHash(); } // Expose API window.PresentationAPI = { next: goToNextSlide, prev: goToPrevSlide, goTo: goToSlide, getCurrentSlide: () => currentSlide, getTotalSlides: () => totalSlides, getLLMVotes: () => ({ ...llmVotes }), getEditorVotes: () => ({ ...editorVotes }), resetVotes: () => { Object.keys(llmVotes).forEach(k => llmVotes[k] = 0); Object.keys(editorVotes).forEach(k => editorVotes[k] = 0); document.querySelectorAll('.vote-fill').forEach(f => f.style.width = '0%'); document.querySelectorAll('.vote-count').forEach(c => c.textContent = '0 votes'); document.querySelectorAll('.voted').forEach(c => c.classList.remove('voted')); } }; })();