Spaces:
Running
Running
| // Optical Illusions Data | |
| const illusions = [ | |
| { | |
| title: "Spinning Vortex", | |
| description: "A mesmerizing spiral that appears to spin infinitely", | |
| type: "spiral", | |
| colors: ["#ff00ff", "#00ffff", "#ffff00"] | |
| }, | |
| { | |
| title: "Floating Grid", | |
| description: "Grid patterns that seem to float and transform", | |
| type: "grid", | |
| colors: ["#ff0066", "#6600ff", "#00ff99"] | |
| }, | |
| { | |
| title: "Morphing Circles", | |
| description: "Circles that continuously change shape and size", | |
| type: "circles", | |
| colors: ["#ff5500", "#55ff00", "#0055ff"] | |
| }, | |
| { | |
| title: "Pulsating Waves", | |
| description: "Waves that create a breathing, living pattern", | |
| type: "waves", | |
| colors: ["#ff00aa", "#aa00ff", "#00aaff"] | |
| }, | |
| { | |
| title: "Kaleidoscope", | |
| description: "Symmetrical patterns that shift and transform", | |
| type: "kaleidoscope", | |
| colors: ["#ffff00", "#ff00ff", "#00ffff"] | |
| }, | |
| { | |
| title: "Infinity Tunnel", | |
| description: "A tunnel that appears to extend into infinity", | |
| type: "tunnel", | |
| colors: ["#ff0000", "#00ff00", "#0000ff"] | |
| } | |
| ]; | |
| // Canvas Variables | |
| let canvas, ctx; | |
| let isAnimating = false; | |
| let animationId; | |
| // Initialize when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', function() { | |
| initializeIllusions(); | |
| initializeCanvas(); | |
| startBackgroundAnimations(); | |
| }); | |
| // Initialize Optical Illusions Gallery | |
| function initializeIllusions() { | |
| const grid = document.getElementById('illusions-grid'); | |
| illusions.forEach((illusion, index) => { | |
| const card = document.createElement('div'); | |
| card.className = 'illusion-card p-6'; | |
| card.innerHTML = ` | |
| <div class="w-full h-48 mb-4 rounded-lg ${illusion.type} ${index % 2 === 0 ? 'floating' : 'breathing'}" | |
| style="background: conic-gradient(from 0deg, ${illusion.colors.join(', ')});"></div> | |
| <h3 class="text-xl font-bold mb-2 psychedelic-text">${illusion.title}</h3> | |
| <p class="text-white/70">${illusion.description}</p> | |
| `; | |
| grid.appendChild(card); | |
| }); | |
| } | |
| // Initialize Interactive Canvas | |
| function initializeCanvas() { | |
| canvas = document.getElementById('psychedelic-canvas'); | |
| ctx = canvas.getContext('2d'); | |
| // Set canvas size | |
| canvas.width = canvas.offsetWidth; | |
| canvas.height = canvas.offsetHeight; | |
| // Add drawing functionality | |
| let isDrawing = false; | |
| let lastX = 0; | |
| let lastY = 0; | |
| let hue = 0; | |
| canvas.addEventListener('mousedown', startDrawing); | |
| canvas.addEventListener('mousemove', draw); | |
| canvas.addEventListener('mouseup', stopDrawing); | |
| canvas.addEventListener('mouseout', stopDrawing); | |
| function startDrawing(e) { | |
| isDrawing = true; | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| } | |
| function draw(e) { | |
| if (!isDrawing) return; | |
| ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`; | |
| ctx.lineWidth = 3; | |
| ctx.lineJoin = 'round'; | |
| ctx.lineCap = 'round'; | |
| ctx.beginPath(); | |
| ctx.moveTo(lastX, lastY); | |
| ctx.lineTo(e.offsetX, e.offsetY); | |
| ctx.stroke(); | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| hue = (hue + 1) % 360; | |
| } | |
| function stopDrawing() { | |
| isDrawing = false; | |
| } | |
| } | |
| // Canvas Functions | |
| function clearCanvas() { | |
| ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| } | |
| function toggleAnimation() { | |
| isAnimating = !isAnimating; | |
| if (isAnimating) { | |
| animateCanvas(); | |
| } else { | |
| cancelAnimationFrame(animationId); | |
| } | |
| } | |
| function animateCanvas() { | |
| if (!isAnimating) return; | |
| // Create psychedelic animation | |
| ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| const time = Date.now() * 0.001; | |
| for (let i = 0; i < 5; i++) { | |
| const x = Math.sin(time * 0.5 + i) * canvas.width * 0.3 + canvas.width * 0.5; | |
| const y = Math.cos(time * 0.7 + i) * canvas.height * 0.3 + canvas.height * 0.5; | |
| const radius = Math.sin(time + i) * 50 + 70; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, radius, 0, Math.PI * 2); | |
| ctx.strokeStyle = `hsl(${(time * 50 + i * 72) % 360}, 100%, 50%)`; | |
| ctx.lineWidth = 3; | |
| ctx.stroke(); | |
| } | |
| animationId = requestAnimationFrame(animateCanvas); | |
| } | |
| // Background Animations | |
| function startBackgroundAnimations() { | |
| // Add floating particles | |
| createFloatingParticles(); | |
| // Add occasional color shifts | |
| setInterval(() => { | |
| document.documentElement.style.setProperty('--hue-rotate', `${Math.random() * 360}deg`); | |
| }, 3000); | |
| } | |
| function createFloatingParticles() { | |
| const particlesContainer = document.createElement('div'); | |
| particlesContainer.className = 'fixed inset-0 pointer-events-none'; | |
| document.body.appendChild(particlesContainer); | |
| for (let i = 0; i < 20; i++) { | |
| const particle = document.createElement('div'); | |
| particle.className = 'absolute w-2 h-2 rounded-full'; | |
| particle.style.background = `hsl(${Math.random() * 360}, 100%, 50%)`; | |
| particle.style.left = `${Math.random() * 100}%`; | |
| particle.style.top = `${Math.random() * 100}%`; | |
| particle.style.animation = `floating ${6 + Math.random() * 4}s ease-in-out infinite`; | |
| particle.style.animationDelay = `${Math.random() * 5}s`; | |
| particlesContainer.appendChild(particle); | |
| } | |
| } | |
| // Handle window resize | |
| window.addEventListener('resize', function() { | |
| if (canvas) { | |
| canvas.width = canvas.offsetWidth; | |
| canvas.height = canvas.offsetHeight; | |
| } | |
| }); |