// R00TS - Plant the seeds of artificial intelligence // Main application functionality document.addEventListener('DOMContentLoaded', function() { // Initialize particles initParticles(); // Load words from storage loadWords(); // Set up automatic updates setInterval(loadWords, 5000); }); function initParticles() { particlesJS('particles-js', { particles: { number: { value: 80, density: { enable: true, value_area: 800 } }, color: { value: '#00ff9d' }, shape: { type: 'circle' }, opacity: { value: 0.5, random: true, animation: { enable: true, speed: 1, opacity_min: 0.1, sync: false } }, size: { value: 3, random: true, animation: { enable: true, speed: 2, size_min: 0.1, sync: false } }, line_linked: { enable: true, distance: 150, color: '#00ff9d', opacity: 0.2, width: 1 }, move: { enable: true, speed: 1, direction: 'none', random: true, straight: false, out_mode: 'out', bounce: false } }, interactivity: { detect_on: 'canvas', events: { onhover: { enable: true, mode: 'grab' }, resize: true }, modes: { grab: { distance: 140, line_linked: { opacity: 0.5 } } } }, retina_detect: true }); } async function loadWords() { try { // Use the data manager to get words from API let words = await window.dataManager.getCurrentWords(); // Update the visualization updateWordCloud(words); // Update statistics updateStats(words); } catch (error) { console.error('Error loading words:', error); // Fallback to localStorage if API fails let words = JSON.parse(localStorage.getItem('roots-words')) || {}; updateWordCloud(words); updateStats(words); } } function updateStats(words) { const totalSubmissions = Object.values(words).reduce((a, b) => a + b, 0); const uniqueWords = Object.keys(words).length; document.getElementById('submission-count').textContent = totalSubmissions; document.getElementById('unique-count').textContent = uniqueWords; } async function submitWord(word) { word = word.trim().toLowerCase(); if (!word) return false; // Create a particle burst effect if (typeof createParticleBurst === 'function') { createParticleBurst(); } try { // Use the data manager to add word via API await window.dataManager.addWord(word); // Update UI with animation if GSAP is available if (typeof gsap !== 'undefined') { gsap.to('.stat-box', { scale: 1.1, duration: 0.2, yoyo: true, repeat: 1, ease: 'power2.out' }); } loadWords(); return true; } catch (error) { console.error('Error submitting word:', error); // Fallback to localStorage if API fails let words = JSON.parse(localStorage.getItem('roots-words')) || {}; words[word] = (words[word] || 0) + 1; localStorage.setItem('roots-words', JSON.stringify(words)); loadWords(); return true; } } function createParticleBurst() { const container = document.querySelector('.input-area'); const rect = container.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; for (let i = 0; i < 20; i++) { const particle = document.createElement('div'); particle.style.cssText = ` position: fixed; width: 8px; height: 8px; background: #00ff9d; border-radius: 50%; pointer-events: none; z-index: 1000; `; document.body.appendChild(particle); const angle = (i / 20) * Math.PI * 2; const velocity = 2 + Math.random() * 2; const dx = Math.cos(angle) * velocity; const dy = Math.sin(angle) * velocity; gsap.fromTo(particle, { x: centerX, y: centerY, scale: 1, opacity: 1 }, { duration: 1 + Math.random(), x: centerX + dx * 50, y: centerY + dy * 50, scale: 0, opacity: 0, ease: 'power2.out', onComplete: () => particle.remove() } ); } } function updateWordCloud(words) { const container = document.getElementById('word-cloud-container'); if (!container) return; container.innerHTML = ''; const width = container.offsetWidth; const height = container.offsetHeight; const wordData = Object.entries(words).map(([text, value]) => ({ text, value })); // Sort by frequency wordData.sort((a, b) => b.value - a.value); // Take top 100 words const topWords = wordData.slice(0, 100); if (topWords.length === 0) { <<<<<<< HEAD ======= // Show placeholder if no words >>>>>>> 6fcedc69cfea5193a6809e1f2fb705b42479c5bd container.innerHTML = '

Plant some words to see them grow here!

'; return; } // Calculate min/max for scaling const minCount = Math.min(...topWords.map(d => d.value)) || 1; const maxCount = Math.max(...topWords.map(d => d.value)) || 1; // Create SVG const svg = d3.select('#word-cloud-container') .append('svg') .attr('width', width) .attr('height', height) .append('g') <<<<<<< HEAD .attr('transform', `translate(${width/2}, ${height * 0.8})`); // Create tree trunk const trunk = svg.append('path') .attr('d', `M0,0 L0,-${height * 0.6}`) .attr('stroke', '#00ff9d') .attr('stroke-width', 8) .attr('fill', 'none') .style('opacity', 0) .transition() .duration(1000) .style('opacity', 1); // Create branches function function createBranch(startX, startY, length, angle, depth) { if (depth <= 0) return; const endX = startX + length * Math.sin(angle); const endY = startY - length * Math.cos(angle); svg.append('path') .attr('d', `M${startX},${startY} L${endX},${endY}`) .attr('stroke', '#00ff9d') .attr('stroke-width', Math.max(1, depth)) .attr('fill', 'none') .style('opacity', 0) .transition() .delay(1000 + (5 - depth) * 300) .duration(500) .style('opacity', 0.5); createBranch(endX, endY, length * 0.7, angle + 0.5, depth - 1); createBranch(endX, endY, length * 0.7, angle - 0.5, depth - 1); } // Create initial branches createBranch(0, -height * 0.6, height * 0.2, -Math.PI/4, 5); createBranch(0, -height * 0.6, height * 0.2, Math.PI/4, 5); // Create a force simulation for the words const simulation = d3.forceSimulation(topWords) .force('charge', d3.forceManyBody().strength(5)) .force('collide', d3.forceCollide(d => fontSize(d) / 2 + 2)) .force('x', d3.forceX(d => { const angle = (d.index / topWords.length) * Math.PI - Math.PI/2; return Math.cos(angle) * (height * 0.3); })) .force('y', d3.forceY(d => { const angle = (d.index / topWords.length) * Math.PI - Math.PI/2; return Math.sin(angle) * (height * 0.3) - height * 0.4; })); // Create word elements const words = svg.selectAll('.word') .data(topWords) .enter() .append('text') .attr('class', 'word') .style('fill', d => d3.interpolateGreenYellow(d.value / maxCount)) .style('font-size', d => `${fontSize(d)}px`) .style('font-family', '"Space Grotesk", sans-serif') .style('cursor', 'pointer') .text(d => d.text) .style('opacity', 0) .on('mouseover', function(event, d) { d3.select(this) .transition() .duration(200) .style('fill', '#39ff14') .style('font-size', d => `${fontSize(d) * 1.2}px`) .style('text-shadow', '0 0 10px rgba(57, 255, 20, 0.5)'); }) .on('mouseout', function(event, d) { d3.select(this) .transition() .duration(200) .style('fill', d3.interpolateGreenYellow(d.value / maxCount)) .style('font-size', d => `${fontSize(d)}px`) .style('text-shadow', 'none'); }); // Add transition for words appearing words.transition() .delay((d, i) => 2000 + i * 50) .duration(500) .style('opacity', 1); // Update word positions on each tick simulation.on('tick', () => { words .attr('x', d => d.x) .attr('y', d => d.y) .attr('text-anchor', 'middle') .attr('alignment-baseline', 'middle'); }); } // Function to share words function shareResults() { const words = JSON.parse(localStorage.getItem('roots-words')) || {}; const totalWords = Object.values(words).reduce((a, b) => a + b, 0); const uniqueWords = Object.keys(words).length; const topWords = Object.entries(words) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([word, count]) => word) .join(', '); const shareText = `I've planted ${totalWords} words (${uniqueWords} unique) to help grow the future of AI with R00TS! Top contributions: ${topWords}`; // In a real implementation, this would integrate with social sharing APIs // For demo purposes, we'll just copy to clipboard navigator.clipboard.writeText(shareText) .then(() => alert('Share text copied to clipboard!')) .catch(err => console.error('Failed to copy: ', err)); }