aradhyapavan's picture
multi-personality-bot
540412a verified
/**
* 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) =>
`<div class="scanline" style="top: ${i * 2}%"></div>`
).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 = `
<div class="terminal-window">
<div class="terminal-header">
<div class="terminal-dots">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
</div>
<h6 class="terminal-title">system_boot.log</h6>
</div>
<div class="boot-content bg-dark p-3" style="font-family: var(--terminal-font); min-height: 200px;">
<div class="boot-messages"></div>
</div>
</div>
`;
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 = `<span class="text-muted">></span> ${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;