/** * Phantom Protocol - Главный JavaScript файл * © NeroWorld AI, 2025 */ (function($) { 'use strict'; // ======================================== // Инициализация при загрузке DOM // ======================================== $(document).ready(function() { initTheme(); initNavbar(); initAOS(); initCopyButtons(); // initHeroBackground(); // ОТКЛЮЧЕНО - используется общий background.js для всех страниц initArchitectureAnimation(); initDemoVisualization(); initComparisonTable(); initSmoothScroll(); }); // ======================================== // Система тем (Dark/Light) // ======================================== function initTheme() { const themeToggle = $('#themeToggle'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; const savedTheme = localStorage.getItem('phantom-theme') || (prefersDark ? 'dark' : 'light'); setTheme(savedTheme); themeToggle.on('click', function() { const currentTheme = $('body').attr('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; setTheme(newTheme); localStorage.setItem('phantom-theme', newTheme); }); } function setTheme(theme) { $('body').attr('data-theme', theme); const icon = theme === 'dark' ? 'fa-sun' : 'fa-moon'; $('#themeToggle i').removeClass('fa-moon fa-sun').addClass(icon); } // ======================================== // Навигация (прозрачность при скролле) // ======================================== function initNavbar() { $(window).on('scroll', function() { const navbar = $('.navbar'); if ($(window).scrollTop() > 100) { navbar.addClass('glass-nav'); } else { navbar.removeClass('glass-nav'); } }); } // ======================================== // Инициализация AOS (Animate On Scroll) // ======================================== function initAOS() { if (typeof AOS !== 'undefined') { AOS.init({ duration: 800, easing: 'ease-out-cubic', once: true, offset: 100, disable: 'mobile' }); } } // ======================================== // Копирование команд в буфер обмена // ======================================== function initCopyButtons() { $('.copy-btn').on('click', function() { const targetId = $(this).data('target'); const codeElement = $('#' + targetId); const text = codeElement.text(); navigator.clipboard.writeText(text).then(function() { showToast(); // Визуальная обратная связь const btn = $(this); const originalText = btn.html(); btn.html(' Скопировано!'); setTimeout(function() { btn.html(originalText); }.bind(this), 2000); }.bind(this), function(err) { console.error('Ошибка копирования: ', err); }); }); } function showToast() { const toast = new bootstrap.Toast($('#copyToast')[0]); toast.show(); } // ======================================== // Hero Background - Анимированная сеть узлов // ======================================== function initHeroBackground() { const container = $('#heroBackground'); if (container.length === 0) return; const canvas = $(''); container.append(canvas); const ctx = canvas[0].getContext('2d'); // Установка размеров canvas function resizeCanvas() { canvas[0].width = container.width(); canvas[0].height = container.height(); } resizeCanvas(); $(window).on('resize', resizeCanvas); // Создание узлов сети const nodes = []; const nodeCount = 50; const connectionDistance = 150; class Node { constructor() { this.x = Math.random() * canvas[0].width; this.y = Math.random() * canvas[0].height; this.vx = (Math.random() - 0.5) * 0.5; this.vy = (Math.random() - 0.5) * 0.5; this.radius = Math.random() * 2 + 1; this.opacity = Math.random() * 0.5 + 0.5; } update() { this.x += this.vx; this.y += this.vy; // Отражение от границ if (this.x < 0 || this.x > canvas[0].width) this.vx *= -1; if (this.y < 0 || this.y > canvas[0].height) this.vy *= -1; } draw() { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fillStyle = `rgba(0, 240, 255, ${this.opacity})`; ctx.fill(); } } // Создание узлов for (let i = 0; i < nodeCount; i++) { nodes.push(new Node()); } // Анимационный цикл function animate() { ctx.clearRect(0, 0, canvas[0].width, canvas[0].height); // Обновление и отрисовка узлов nodes.forEach(node => { node.update(); node.draw(); }); // Рисование соединений между близкими узлами for (let i = 0; i < nodes.length; i++) { for (let j = i + 1; j < nodes.length; j++) { const dx = nodes[i].x - nodes[j].x; const dy = nodes[i].y - nodes[j].y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < connectionDistance) { const opacity = (1 - distance / connectionDistance) * 0.3; ctx.beginPath(); ctx.moveTo(nodes[i].x, nodes[i].y); ctx.lineTo(nodes[j].x, nodes[j].y); ctx.strokeStyle = `rgba(122, 62, 255, ${opacity})`; ctx.lineWidth = 1; ctx.stroke(); } } } requestAnimationFrame(animate); } animate(); } // ======================================== // Анимация архитектурных слоев // ======================================== function initArchitectureAnimation() { const layers = $('.arch-layer'); layers.on('mouseenter', function() { const layer = $(this); layer.css('transform', 'translateX(15px)'); // Пульсация номера слоя const number = layer.find('.layer-number'); number.css('transform', 'scale(1.1)'); }); layers.on('mouseleave', function() { const layer = $(this); layer.css('transform', ''); const number = layer.find('.layer-number'); number.css('transform', ''); }); // Последовательная анимация при загрузке layers.each(function(index) { const layer = $(this); setTimeout(function() { layer.addClass('aos-animate'); }, index * 100); }); } // ======================================== // Таблица сравнения - развернуть/свернуть // ======================================== function initComparisonTable() { $('#expandComparison').on('click', function() { const btn = $(this); const isExpanded = btn.data('expanded'); if (!isExpanded) { // Здесь можно добавить дополнительные строки btn.html(' Свернуть таблицу'); btn.data('expanded', true); } else { btn.html(' Развернуть полное сравнение'); btn.data('expanded', false); } }); } // ======================================== // Демо визуализация - построение анонимного пути // ======================================== function initDemoVisualization() { const canvas = $('#demoCanvas'); if (canvas.length === 0) return; const ctx = canvas[0].getContext('2d'); const width = canvas[0].width; const height = canvas[0].height; let nodes = []; let path = []; let animationFrame = 0; let isAnimating = false; // Создание сети узлов function createNodes() { nodes = []; const nodeCount = 20; for (let i = 0; i < nodeCount; i++) { nodes.push({ id: generatePhantomId(), x: Math.random() * (width - 100) + 50, y: Math.random() * (height - 100) + 50, radius: 8, color: '#9999b8' }); } drawNetwork(); } // Генерация фантомного ID function generatePhantomId() { const chars = 'ABCDEF0123456789'; let id = ''; for (let i = 0; i < 8; i++) { id += chars.charAt(Math.floor(Math.random() * chars.length)); } return id; } // Отрисовка сети function drawNetwork() { ctx.clearRect(0, 0, width, height); // Рисование соединений ctx.strokeStyle = 'rgba(153, 153, 184, 0.1)'; ctx.lineWidth = 1; for (let i = 0; i < nodes.length; i++) { for (let j = i + 1; j < nodes.length; j++) { const dx = nodes[i].x - nodes[j].x; const dy = nodes[i].y - nodes[j].y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { ctx.beginPath(); ctx.moveTo(nodes[i].x, nodes[i].y); ctx.lineTo(nodes[j].x, nodes[j].y); ctx.stroke(); } } } // Рисование узлов nodes.forEach(node => { ctx.beginPath(); ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2); ctx.fillStyle = node.color; ctx.fill(); ctx.strokeStyle = 'rgba(0, 240, 255, 0.3)'; ctx.lineWidth = 2; ctx.stroke(); // ID узла ctx.fillStyle = '#e6e6ff'; ctx.font = '10px JetBrains Mono'; ctx.fillText(node.id, node.x - 25, node.y - 15); }); } // Построение анонимного пути function buildPath() { path = []; const pathLength = Math.floor(Math.random() * 3) + 4; // 4-6 узлов const usedIndices = new Set(); for (let i = 0; i < pathLength; i++) { let index; do { index = Math.floor(Math.random() * nodes.length); } while (usedIndices.has(index)); usedIndices.add(index); path.push(nodes[index]); } } // Анимация пути function animatePath() { if (!isAnimating) return; const currentNode = Math.floor(animationFrame / 20); if (currentNode >= path.length) { isAnimating = false; updateStats('complete', path.length); return; } drawNetwork(); // Подсветка пройденных узлов for (let i = 0; i <= currentNode && i < path.length; i++) { const node = path[i]; // Пульсирующий узел const scale = i === currentNode ? 1 + Math.sin(animationFrame * 0.2) * 0.3 : 1; ctx.beginPath(); ctx.arc(node.x, node.y, node.radius * scale, 0, Math.PI * 2); ctx.fillStyle = i === currentNode ? '#00f0ff' : '#7a3eff'; ctx.fill(); ctx.strokeStyle = '#00f0ff'; ctx.lineWidth = 3; ctx.stroke(); // Соединения пути if (i > 0) { const prevNode = path[i - 1]; ctx.beginPath(); ctx.moveTo(prevNode.x, prevNode.y); ctx.lineTo(node.x, node.y); ctx.strokeStyle = '#00f0ff'; ctx.lineWidth = 2; ctx.stroke(); // Анимация "пакета" if (i === currentNode) { const progress = (animationFrame % 20) / 20; const packetX = prevNode.x + (node.x - prevNode.x) * progress; const packetY = prevNode.y + (node.y - prevNode.y) * progress; ctx.beginPath(); ctx.arc(packetX, packetY, 5, 0, Math.PI * 2); ctx.fillStyle = '#00ff9d'; ctx.fill(); } } } animationFrame++; updateStats('progress', currentNode + 1); requestAnimationFrame(animatePath); } // Обновление статистики function updateStats(status, pathLength) { if (status === 'progress') { $('#pathLength').text(`${pathLength} / ${path.length} узлов`); $('#entropy').text(`${(Math.log2(nodes.length * pathLength)).toFixed(2)} бит`); $('#latency').text(`${(pathLength * 85 + Math.random() * 50).toFixed(0)} мс`); $('#status').text('Передача...'); } else if (status === 'complete') { $('#pathLength').text(`${pathLength} узлов`); $('#entropy').text(`${(Math.log2(nodes.length * pathLength)).toFixed(2)} бит`); $('#latency').text(`${(pathLength * 85).toFixed(0)} мс`); $('#status').text('Доставлено').css('color', '#00ff9d'); } else { $('#pathLength').text('—'); $('#entropy').text('—'); $('#latency').text('—'); $('#status').text('Готов').css('color', ''); } } // Кнопки управления $('#startDemo').on('click', function() { if (isAnimating) return; isAnimating = true; animationFrame = 0; buildPath(); animatePath(); $(this).prop('disabled', true); setTimeout(() => $(this).prop('disabled', false), 6000); }); $('#resetDemo').on('click', function() { isAnimating = false; animationFrame = 0; path = []; createNodes(); updateStats('reset'); }); // Инициализация createNodes(); } // ======================================== // Плавная прокрутка к якорям // ======================================== function initSmoothScroll() { $('a[href^="#"]').on('click', function(e) { const target = $(this.hash); if (target.length) { e.preventDefault(); $('html, body').animate({ scrollTop: target.offset().top - 80 }, 800, 'swing'); // Закрыть мобильное меню $('.navbar-collapse').collapse('hide'); } }); // Scroll indicator $('.scroll-indicator').on('click', function() { $('html, body').animate({ scrollTop: $('#usp').offset().top - 80 }, 800, 'swing'); }); } // ======================================== // Parallax эффект для Hero секции // ======================================== $(window).on('scroll', function() { const scrolled = $(window).scrollTop(); const heroContent = $('.hero-content'); if (scrolled < window.innerHeight) { heroContent.css('transform', `translateY(${scrolled * 0.5}px)`); heroContent.css('opacity', 1 - scrolled / 600); } }); // ======================================== // Ленивая загрузка и оптимизация // ======================================== if ('IntersectionObserver' in window) { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; if (img.dataset.src) { img.src = img.dataset.src; img.removeAttribute('data-src'); } observer.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach(img => { observer.observe(img); }); } // ======================================== // Прелоадер (опционально) // ======================================== $(window).on('load', function() { $('body').addClass('loaded'); // Trigger AOS refresh if (typeof AOS !== 'undefined') { AOS.refresh(); } }); // ======================================== // Отладка: вывод версии // ======================================== console.log('%c🔮 Phantom Protocol v2025', 'color: #00f0ff; font-size: 16px; font-weight: bold;'); console.log('%cДобро пожаловать в анонимную сеть будущего', 'color: #7a3eff; font-size: 12px;'); })(jQuery);