import { useEffect, useRef, useState } from 'react'; import { Box, IconButton } from '@mui/material'; import { Close } from '@mui/icons-material'; import { useThemeStore } from '../stores/themeStore'; interface ScreensaverProps { onClose: () => void; } // Color palette from ColorPicker for complementary color selection const colorPalette = [ '#673ab7', '#9c27b0', '#e1bee7', // Purples '#1976d2', '#03dac6', '#3f51b5', // Blues '#2e7d32', '#4caf50', '#009688', // Greens '#d32f2f', '#ff5722', '#ff9800', // Reds/Oranges '#424242', '#607d8b', '#795548', // Grays ]; // Get complementary colors based on primary color function getComplementaryColors(primaryColor: string): string[] { const primaryIndex = colorPalette.findIndex(color => color === primaryColor); if (primaryIndex === -1) { // If primary color is not in palette, use default complementary colors return ['#ff5722', '#4caf50']; // Orange and Green } // Choose colors that are visually distinct from primary const complementaryIndices = [ (primaryIndex + 6) % colorPalette.length, // Opposite side (primaryIndex + 9) % colorPalette.length, // Further opposite ]; return complementaryIndices.map(index => colorPalette[index]); } // Create gradient pattern function createGradientPattern( ctx: CanvasRenderingContext2D, width: number, height: number, colors: string[], time: number ) { const gradient1 = ctx.createRadialGradient( width * 0.3 + Math.sin(time * 0.001) * 100, height * 0.3 + Math.cos(time * 0.001) * 100, 0, width * 0.3 + Math.sin(time * 0.001) * 100, height * 0.3 + Math.cos(time * 0.001) * 100, width * 0.8 ); gradient1.addColorStop(0, `${colors[0]}80`); gradient1.addColorStop(0.5, `${colors[1]}40`); gradient1.addColorStop(1, `${colors[2]}20`); ctx.fillStyle = gradient1; ctx.fillRect(0, 0, width, height); const gradient2 = ctx.createRadialGradient( width * 0.7 + Math.cos(time * 0.002) * 150, height * 0.7 + Math.sin(time * 0.002) * 150, 0, width * 0.7 + Math.cos(time * 0.002) * 150, height * 0.7 + Math.sin(time * 0.002) * 150, width * 0.6 ); gradient2.addColorStop(0, `${colors[2]}60`); gradient2.addColorStop(0.7, `${colors[0]}30`); gradient2.addColorStop(1, 'transparent'); ctx.fillStyle = gradient2; ctx.fillRect(0, 0, width, height); } // Draw animated shapes function drawShapes( ctx: CanvasRenderingContext2D, width: number, height: number, colors: string[], time: number ) { const numShapes = 8; for (let i = 0; i < numShapes; i++) { const x = width * 0.5 + Math.sin(time * 0.001 + i * 0.8) * (width * 0.3); const y = height * 0.5 + Math.cos(time * 0.001 + i * 0.8) * (height * 0.3); const size = 50 + Math.sin(time * 0.002 + i) * 30; const colorIndex = i % colors.length; const opacity = 0.3 + Math.sin(time * 0.003 + i) * 0.2; ctx.save(); ctx.globalAlpha = opacity; ctx.fillStyle = colors[colorIndex]; if (i % 3 === 0) { // Circles ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fill(); } else if (i % 3 === 1) { // Squares ctx.fillRect(x - size/2, y - size/2, size, size); } else { // Triangles ctx.beginPath(); ctx.moveTo(x, y - size/2); ctx.lineTo(x - size/2, y + size/2); ctx.lineTo(x + size/2, y + size/2); ctx.closePath(); ctx.fill(); } ctx.restore(); } } // Draw line art function drawLineArt( ctx: CanvasRenderingContext2D, width: number, height: number, colors: string[], time: number ) { const numLines = 12; for (let i = 0; i < numLines; i++) { const x1 = Math.sin(time * 0.0005 + i * 0.5) * width; const y1 = Math.cos(time * 0.0005 + i * 0.5) * height; const x2 = Math.sin(time * 0.0005 + i * 0.5 + Math.PI) * width; const y2 = Math.cos(time * 0.0005 + i * 0.5 + Math.PI) * height; const colorIndex = i % colors.length; const opacity = 0.2 + Math.sin(time * 0.001 + i) * 0.1; ctx.save(); ctx.globalAlpha = opacity; ctx.strokeStyle = colors[colorIndex]; ctx.lineWidth = 2 + Math.sin(time * 0.002 + i) * 1; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.restore(); } } export function Screensaver({ onClose }: ScreensaverProps) { const canvasRef = useRef(null); const animationRef = useRef(); const { primaryColor } = useThemeStore(); const [lastClearTime, setLastClearTime] = useState(Date.now()); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; // Set canvas size const resizeCanvas = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; resizeCanvas(); window.addEventListener('resize', resizeCanvas); // Get complementary colors const complementaryColors = getComplementaryColors(primaryColor); const colors = [primaryColor, ...complementaryColors]; let startTime = Date.now(); let clearInterval = 0; const animate = () => { const currentTime = Date.now(); const elapsed = currentTime - startTime; // Clear screen every 3 minutes (180000ms) like Windows 98 if (currentTime - lastClearTime > 180000) { ctx.clearRect(0, 0, canvas.width, canvas.height); setLastClearTime(currentTime); clearInterval = 0; } // Clear screen every few seconds for variety if (clearInterval > 5000) { ctx.clearRect(0, 0, canvas.width, canvas.height); clearInterval = 0; } // Create gradient background createGradientPattern(ctx, canvas.width, canvas.height, colors, elapsed); // Draw shapes drawShapes(ctx, canvas.width, canvas.height, colors, elapsed); // Draw line art drawLineArt(ctx, canvas.width, canvas.height, colors, elapsed); clearInterval += 16; // ~60fps animationRef.current = requestAnimationFrame(animate); }; animate(); return () => { window.removeEventListener('resize', resizeCanvas); if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, [primaryColor, lastClearTime]); // Close on any key press or mouse movement useEffect(() => { const handleInteraction = () => onClose(); window.addEventListener('keydown', handleInteraction); window.addEventListener('mousemove', handleInteraction); window.addEventListener('click', handleInteraction); window.addEventListener('touchstart', handleInteraction); return () => { window.removeEventListener('keydown', handleInteraction); window.removeEventListener('mousemove', handleInteraction); window.removeEventListener('click', handleInteraction); window.removeEventListener('touchstart', handleInteraction); }; }, [onClose]); return ( ); }