/** * Terminal Effects Module * Handles all the aesthetic terminal animations and effects */ class TerminalEffects { constructor() { this.isGlitching = false; this.scanlineInterval = null; this.init(); } init() { this.createScanlines(); this.initCursorBlink(); this.initRandomGlitches(); this.initTypingEffects(); this.initMatrixRain(); } // Create CRT scanline effect createScanlines() { const scanlines = document.createElement('div'); scanlines.className = 'scanlines'; scanlines.innerHTML = Array(50).fill().map((_, i) => `
` ).join(''); const style = document.createElement('style'); style.textContent = ` .scanlines { position: fixed; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; z-index: 1000; opacity: 0.03; } .scanline { position: absolute; left: 0; right: 0; height: 1px; background: #39ff14; animation: scanline-flicker 0.1s infinite alternate; } @keyframes scanline-flicker { 0% { opacity: 0.8; } 100% { opacity: 0.2; } } `; document.head.appendChild(style); document.body.appendChild(scanlines); } // Enhanced cursor blinking initCursorBlink() { const cursors = document.querySelectorAll('.brand-cursor'); cursors.forEach(cursor => { setInterval(() => { cursor.style.opacity = cursor.style.opacity === '0' ? '1' : '0'; }, 500 + Math.random() * 200); // Slight randomness }); } // Random glitch effects initRandomGlitches() { setInterval(() => { if (Math.random() < 0.02 && !this.isGlitching) { // 2% chance this.triggerGlitch(); } }, 1000); } triggerGlitch() { if (this.isGlitching) return; this.isGlitching = true; const elements = document.querySelectorAll('.terminal-card, .chat-message'); const randomElement = elements[Math.floor(Math.random() * elements.length)]; if (randomElement) { const originalTransform = randomElement.style.transform; const glitchIntensity = Math.random() * 5; // Apply glitch effect randomElement.style.filter = `hue-rotate(${Math.random() * 360}deg) saturate(2)`; randomElement.style.transform = `translateX(${Math.random() * glitchIntensity - glitchIntensity/2}px) skew(${Math.random() * 2}deg)`; // Create text shadow glitch randomElement.style.textShadow = ` ${Math.random() * 10 - 5}px 0 #ff0000, ${Math.random() * 10 - 5}px 0 #00ff00, ${Math.random() * 10 - 5}px 0 #0000ff `; setTimeout(() => { randomElement.style.filter = ''; randomElement.style.transform = originalTransform; randomElement.style.textShadow = ''; this.isGlitching = false; }, 50 + Math.random() * 100); } else { this.isGlitching = false; } } // Typing animation for new elements typeWriter(element, text, speed = 50, callback = null) { let i = 0; element.textContent = ''; const timer = setInterval(() => { if (i < text.length) { element.textContent += text.charAt(i); i++; // Add random typing delays if (Math.random() < 0.1) { clearInterval(timer); setTimeout(() => { this.typeWriter(element, text.substring(i), speed, callback); }, speed * 2); return; } } else { clearInterval(timer); if (callback) callback(); } }, speed); } initTypingEffects() { // Apply to elements that should have typing effect const typeElements = document.querySelectorAll('.typewriter-effect'); typeElements.forEach(element => { const text = element.textContent; this.typeWriter(element, text, 30); }); } // Matrix-style rain effect (subtle) initMatrixRain() { const canvas = document.createElement('canvas'); canvas.style.position = 'fixed'; canvas.style.top = '0'; canvas.style.left = '0'; canvas.style.width = '100%'; canvas.style.height = '100%'; canvas.style.pointerEvents = 'none'; canvas.style.zIndex = '-2'; canvas.style.opacity = '0.03'; const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; const matrix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789@#$%^&*()*&^%+-/~{[|`]}"; const matrixArray = matrix.split(""); const fontSize = 10; const columns = canvas.width / fontSize; const drops = []; for (let x = 0; x < columns; x++) { drops[x] = 1; } function draw() { ctx.fillStyle = 'rgba(13, 17, 23, 0.04)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#39ff14'; ctx.font = fontSize + 'px monospace'; for (let i = 0; i < drops.length; i++) { const text = matrixArray[Math.floor(Math.random() * matrixArray.length)]; ctx.fillText(text, i * fontSize, drops[i] * fontSize); if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) { drops[i] = 0; } drops[i]++; } } document.body.appendChild(canvas); setInterval(draw, 150); // Resize canvas on window resize window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); } // Power-on effect for new elements powerOnEffect(element) { element.style.opacity = '0'; element.style.transform = 'scale(0.8) rotateX(20deg)'; element.style.filter = 'brightness(0)'; setTimeout(() => { element.style.transition = 'all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275)'; element.style.opacity = '1'; element.style.transform = 'scale(1) rotateX(0deg)'; element.style.filter = 'brightness(1)'; // Add a brief glow effect element.style.boxShadow = '0 0 20px var(--terminal-green-glow)'; setTimeout(() => { element.style.boxShadow = ''; }, 500); }, 100); } // Boot sequence effect bootSequence(container, messages, onComplete) { let messageIndex = 0; const bootContainer = document.createElement('div'); bootContainer.className = 'boot-sequence'; bootContainer.innerHTML = `
system_boot.log
`; container.appendChild(bootContainer); const messagesContainer = bootContainer.querySelector('.boot-messages'); function addMessage() { if (messageIndex < messages.length) { const messageDiv = document.createElement('div'); messageDiv.className = 'text-terminal-green'; messageDiv.innerHTML = `> ${messages[messageIndex]}`; messagesContainer.appendChild(messageDiv); // Scroll to bottom messagesContainer.scrollTop = messagesContainer.scrollHeight; messageIndex++; setTimeout(addMessage, 300 + Math.random() * 200); } else { setTimeout(() => { container.removeChild(bootContainer); if (onComplete) onComplete(); }, 1000); } } setTimeout(addMessage, 500); } // Network activity indicator showNetworkActivity() { const indicator = document.querySelector('.status-indicator'); if (indicator) { indicator.style.background = '#ffbd2e'; indicator.style.animation = 'pulse-glow 0.3s infinite'; setTimeout(() => { indicator.style.background = 'var(--terminal-green)'; indicator.style.animation = 'pulse-glow 2s infinite'; }, 1000); } } // Error flash effect errorFlash() { document.body.style.backgroundColor = '#ff5f5610'; setTimeout(() => { document.body.style.backgroundColor = ''; }, 150); } // Success flash effect successFlash() { document.body.style.backgroundColor = '#39ff1410'; setTimeout(() => { document.body.style.backgroundColor = ''; }, 150); } } // Initialize terminal effects when DOM is loaded document.addEventListener('DOMContentLoaded', () => { window.terminalEffects = new TerminalEffects(); }); // Expose for use in other modules window.TerminalEffects = TerminalEffects;