WEBLEB
Inicio
Editora de código
Iniciar sesión
Pro
Español
English
Français
Español
Português
Deutsch
Italiano
हिंदी
HTML
CSS
JS
Controls
Full Screen
Colors:
Rainbow
Red
Green
Blue
Monochrome
Size:
10
Particles:
32
Speed:
1
Mouse Follow:
50
body { margin: 0; padding: 0; overflow: hidden; background-color: #000; font-family: "Archivo Black", sans-serif; color: white; } #c { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } #controls-container { position: fixed; top: 20px; left: 20px; z-index: 100; } #toggle-controls { background: rgba(0, 0, 0, 0.7); color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; margin-bottom: 5px; backdrop-filter: blur(5px); } #controls { background: rgba(100, 100, 100, 0.2); padding: 15px; border-radius: 10px; max-width: 300px; backdrop-filter: blur(5px); display: block; } .control-group { margin: 10px 0; display: flex; align-items: center; } .control-group label { width: 100px; font-size: 14px; margin-right: 10px; } .control-group input[type="range"] { flex-grow: 1; margin-right: 10px; } .control-group span { width: 30px; text-align: right; font-size: 14px; } .control-group select { flex-grow: 1; padding: 5px; border-radius: 4px; background: #333; color: white; border: none; } .heart-outline { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 360px; height: 320px; fill: none; stroke: rgba(255, 255, 255, 0.3); stroke-width: 2; pointer-events: none; z-index: 10; } #intro-controls { margin-top: 20px; padding: 20px; border-radius: 10px; background-color: rgba(0, 0, 0, 0.5); } #intro-controls h2 { font-size: 1.5em; margin-bottom: 10px; } #intro-controls ul { list-style-type: none; padding: 0; } #intro-controls li { margin-bottom: 5px; font-size: 1em; } #toggle-fullscreen { position: fixed; top: 20px; right: 20px; background: rgba(0, 0, 0, 0.7); color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; z-index: 100; backdrop-filter: blur(5px); } @media (max-width: 600px) { #controls-container { top: 10px; left: 10px; right: 10px; max-width: none; } .control-group label { width: 80px; font-size: 12px; } }
// Configuration const config = { particleCount: 32, speed: 1, colorScheme: 'rainbow', mouseInfluence: 50, showHeartOutline: true, particleSize: 10 }; // Canvas setup const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); let canvasWidth = canvas.width = window.innerWidth; let canvasHeight = canvas.height = window.innerHeight; // Animation state let trails = []; let heartPath = []; let mouseX = canvasWidth / 2; let mouseY = canvasHeight / 2; let mouseActive = false; let animationRunning = false; // Initialize heart path points (fixed formula) function initHeartPath() { heartPath = []; const PI2 = 6.28318; // 2*PI approximation const steps = Math.max(32, config.particleCount); for (let i = 0; i < steps; i++) { const t = (i / steps) * PI2; heartPath.push([ canvasWidth/2 + 180 * Math.pow(Math.sin(t), 3), canvasHeight/2 + 10 * (-(15 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t))) ]); } } // Initialize particles with proper bounds checking function initParticles() { trails = []; if (heartPath.length === 0) initHeartPath(); for (let i = 0; i < config.particleCount; i++) { const particles = []; const x = Math.random() * canvasWidth; const y = Math.random() * canvasHeight; for (let k = 0; k < config.particleCount; k++) { // Color generation let hue, saturation = Math.random() * 40 + 60; let brightness = Math.random() * 60 + 20; switch(config.colorScheme) { case 'red': hue = Math.random() * 20 + 350; break; case 'blue': hue = Math.random() * 20 + 200; break; case 'green': hue = Math.random() * 20 + 100; break; case 'monochrome': hue = 0; saturation = 0; break; default: hue = i/config.particleCount * 360; // rainbow } particles.push({ x, y, velX: 0, velY: 0, radius: ((1 - k/config.particleCount) + 1) * config.particleSize/2, speed: Math.random() + 1, targetIndex: Math.floor(Math.random() * heartPath.length), direction: i % 2 * 2 - 1, friction: Math.random() * 0.2 + 0.7, color: `hsla(${hue},${saturation}%,${brightness}%,0.1)` }); } trails.push(particles); } } // Render a single particle function renderParticle(particle) { ctx.fillStyle = particle.color; ctx.beginPath(); ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2); ctx.fill(); } // Main animation loop with robust error handling function animationLoop() { if (!animationRunning) return; // Stop the animation if not running try { // Clear with trail effect ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; ctx.fillRect(0, 0, canvasWidth, canvasHeight); trails.forEach(trail => { if (!trail || !trail.length) return; const leader = trail[0]; const target = heartPath[leader.targetIndex % heartPath.length]; if (!target) return; // Mouse influence if (mouseActive && config.mouseInfluence > 0) { const dx = mouseX - leader.x; const dy = mouseY - leader.y; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < 300) { const force = (1 - dist/300) * (config.mouseInfluence/20); leader.velX += dx/dist * force; leader.velY += dy/dist * force; } } // Move toward target const dx = leader.x - target[0]; const dy = leader.y - target[1]; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < 10) { if (Math.random() > 0.95) { leader.targetIndex = Math.floor(Math.random() * heartPath.length); } else { if (Math.random() > 0.99) leader.direction *= -1; leader.targetIndex += leader.direction; leader.targetIndex = (leader.targetIndex + heartPath.length) % heartPath.length; } } // Update physics leader.velX += -dx/dist * leader.speed * config.speed; leader.velY += -dy/dist * leader.speed * config.speed; leader.x += leader.velX; leader.y += leader.velY; leader.velX *= leader.friction; leader.velY *= leader.friction; // Render trail renderParticle(leader); for (let k = 1; k < trail.length; k++) { trail[k].x -= (trail[k].x - trail[k-1].x) * 0.7; trail[k].y -= (trail[k].y - trail[k-1].y) * 0.7; renderParticle(trail[k]); } }); } catch (error) { console.error("Animation error:", error); } requestAnimationFrame(animationLoop); } // Control handlers function setupControls() { const controls = document.getElementById('controls'); let controlsVisible = true; document.getElementById('toggle-controls').addEventListener('click', () => { controlsVisible = !controlsVisible; controls.style.display = controlsVisible ? 'block' : 'none'; }); document.getElementById('toggle-fullscreen').addEventListener('click', () => { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } else { if (document.exitFullscreen) { document.exitFullscreen(); } } }); const updateParticles = () => { config.particleCount = Math.min(100, Math.max(10, parseInt(document.getElementById('particleCount').value))); document.getElementById('particleCountValue').textContent = config.particleCount; initHeartPath(); initParticles(); }; document.getElementById('particleCount').addEventListener('input', updateParticles); document.getElementById('speed').addEventListener('input', (e) => { config.speed = parseFloat(e.target.value); document.getElementById('speedValue').textContent = config.speed; }); document.getElementById('colorScheme').addEventListener('change', (e) => { config.colorScheme = e.target.value; initParticles(); }); document.getElementById('mouseInfluence').addEventListener('input', (e) => { config.mouseInfluence = parseInt(e.target.value); document.getElementById('mouseInfluenceValue').textContent = config.mouseInfluence; }); document.getElementById('particleSize').addEventListener('input', (e) => { config.particleSize = parseInt(e.target.value); document.getElementById('particleSizeValue').textContent = config.particleSize; initParticles(); }); // Mouse tracking document.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; mouseActive = true; }); document.addEventListener('mouseleave', () => mouseActive = false); // Window resize window.addEventListener('resize', () => { canvasWidth = canvas.width = window.innerWidth; canvasHeight = canvas.height = window.innerHeight; initHeartPath(); }); } // Initialize everything function init() { const controls = document.getElementById('controls'); const canvas = document.getElementById('c'); controls.style.display = 'block'; canvas.style.display = 'block'; animationRunning = true; setupControls(); animationLoop(); // Start the animation loop // Initialize everything initHeartPath(); initParticles(); } // Start the animation init();
Validating your code, please wait...
HTML
CSS
JS
Controls
Full Screen
Colors:
Rainbow
Red
Green
Blue
Monochrome
Size:
10
Particles:
32
Speed:
1
Mouse Follow:
50
body { margin: 0; padding: 0; overflow: hidden; background-color: #000; font-family: "Archivo Black", sans-serif; color: white; } #c { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } #controls-container { position: fixed; top: 20px; left: 20px; z-index: 100; } #toggle-controls { background: rgba(0, 0, 0, 0.7); color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; margin-bottom: 5px; backdrop-filter: blur(5px); } #controls { background: rgba(100, 100, 100, 0.2); padding: 15px; border-radius: 10px; max-width: 300px; backdrop-filter: blur(5px); display: block; } .control-group { margin: 10px 0; display: flex; align-items: center; } .control-group label { width: 100px; font-size: 14px; margin-right: 10px; } .control-group input[type="range"] { flex-grow: 1; margin-right: 10px; } .control-group span { width: 30px; text-align: right; font-size: 14px; } .control-group select { flex-grow: 1; padding: 5px; border-radius: 4px; background: #333; color: white; border: none; } .heart-outline { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 360px; height: 320px; fill: none; stroke: rgba(255, 255, 255, 0.3); stroke-width: 2; pointer-events: none; z-index: 10; } #intro-controls { margin-top: 20px; padding: 20px; border-radius: 10px; background-color: rgba(0, 0, 0, 0.5); } #intro-controls h2 { font-size: 1.5em; margin-bottom: 10px; } #intro-controls ul { list-style-type: none; padding: 0; } #intro-controls li { margin-bottom: 5px; font-size: 1em; } #toggle-fullscreen { position: fixed; top: 20px; right: 20px; background: rgba(0, 0, 0, 0.7); color: white; border: none; padding: 10px; border-radius: 5px; cursor: pointer; z-index: 100; backdrop-filter: blur(5px); } @media (max-width: 600px) { #controls-container { top: 10px; left: 10px; right: 10px; max-width: none; } .control-group label { width: 80px; font-size: 12px; } }
// Configuration const config = { particleCount: 32, speed: 1, colorScheme: 'rainbow', mouseInfluence: 50, showHeartOutline: true, particleSize: 10 }; // Canvas setup const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d'); let canvasWidth = canvas.width = window.innerWidth; let canvasHeight = canvas.height = window.innerHeight; // Animation state let trails = []; let heartPath = []; let mouseX = canvasWidth / 2; let mouseY = canvasHeight / 2; let mouseActive = false; let animationRunning = false; // Initialize heart path points (fixed formula) function initHeartPath() { heartPath = []; const PI2 = 6.28318; // 2*PI approximation const steps = Math.max(32, config.particleCount); for (let i = 0; i < steps; i++) { const t = (i / steps) * PI2; heartPath.push([ canvasWidth/2 + 180 * Math.pow(Math.sin(t), 3), canvasHeight/2 + 10 * (-(15 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t))) ]); } } // Initialize particles with proper bounds checking function initParticles() { trails = []; if (heartPath.length === 0) initHeartPath(); for (let i = 0; i < config.particleCount; i++) { const particles = []; const x = Math.random() * canvasWidth; const y = Math.random() * canvasHeight; for (let k = 0; k < config.particleCount; k++) { // Color generation let hue, saturation = Math.random() * 40 + 60; let brightness = Math.random() * 60 + 20; switch(config.colorScheme) { case 'red': hue = Math.random() * 20 + 350; break; case 'blue': hue = Math.random() * 20 + 200; break; case 'green': hue = Math.random() * 20 + 100; break; case 'monochrome': hue = 0; saturation = 0; break; default: hue = i/config.particleCount * 360; // rainbow } particles.push({ x, y, velX: 0, velY: 0, radius: ((1 - k/config.particleCount) + 1) * config.particleSize/2, speed: Math.random() + 1, targetIndex: Math.floor(Math.random() * heartPath.length), direction: i % 2 * 2 - 1, friction: Math.random() * 0.2 + 0.7, color: `hsla(${hue},${saturation}%,${brightness}%,0.1)` }); } trails.push(particles); } } // Render a single particle function renderParticle(particle) { ctx.fillStyle = particle.color; ctx.beginPath(); ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2); ctx.fill(); } // Main animation loop with robust error handling function animationLoop() { if (!animationRunning) return; // Stop the animation if not running try { // Clear with trail effect ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; ctx.fillRect(0, 0, canvasWidth, canvasHeight); trails.forEach(trail => { if (!trail || !trail.length) return; const leader = trail[0]; const target = heartPath[leader.targetIndex % heartPath.length]; if (!target) return; // Mouse influence if (mouseActive && config.mouseInfluence > 0) { const dx = mouseX - leader.x; const dy = mouseY - leader.y; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < 300) { const force = (1 - dist/300) * (config.mouseInfluence/20); leader.velX += dx/dist * force; leader.velY += dy/dist * force; } } // Move toward target const dx = leader.x - target[0]; const dy = leader.y - target[1]; const dist = Math.sqrt(dx*dx + dy*dy); if (dist < 10) { if (Math.random() > 0.95) { leader.targetIndex = Math.floor(Math.random() * heartPath.length); } else { if (Math.random() > 0.99) leader.direction *= -1; leader.targetIndex += leader.direction; leader.targetIndex = (leader.targetIndex + heartPath.length) % heartPath.length; } } // Update physics leader.velX += -dx/dist * leader.speed * config.speed; leader.velY += -dy/dist * leader.speed * config.speed; leader.x += leader.velX; leader.y += leader.velY; leader.velX *= leader.friction; leader.velY *= leader.friction; // Render trail renderParticle(leader); for (let k = 1; k < trail.length; k++) { trail[k].x -= (trail[k].x - trail[k-1].x) * 0.7; trail[k].y -= (trail[k].y - trail[k-1].y) * 0.7; renderParticle(trail[k]); } }); } catch (error) { console.error("Animation error:", error); } requestAnimationFrame(animationLoop); } // Control handlers function setupControls() { const controls = document.getElementById('controls'); let controlsVisible = true; document.getElementById('toggle-controls').addEventListener('click', () => { controlsVisible = !controlsVisible; controls.style.display = controlsVisible ? 'block' : 'none'; }); document.getElementById('toggle-fullscreen').addEventListener('click', () => { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } else { if (document.exitFullscreen) { document.exitFullscreen(); } } }); const updateParticles = () => { config.particleCount = Math.min(100, Math.max(10, parseInt(document.getElementById('particleCount').value))); document.getElementById('particleCountValue').textContent = config.particleCount; initHeartPath(); initParticles(); }; document.getElementById('particleCount').addEventListener('input', updateParticles); document.getElementById('speed').addEventListener('input', (e) => { config.speed = parseFloat(e.target.value); document.getElementById('speedValue').textContent = config.speed; }); document.getElementById('colorScheme').addEventListener('change', (e) => { config.colorScheme = e.target.value; initParticles(); }); document.getElementById('mouseInfluence').addEventListener('input', (e) => { config.mouseInfluence = parseInt(e.target.value); document.getElementById('mouseInfluenceValue').textContent = config.mouseInfluence; }); document.getElementById('particleSize').addEventListener('input', (e) => { config.particleSize = parseInt(e.target.value); document.getElementById('particleSizeValue').textContent = config.particleSize; initParticles(); }); // Mouse tracking document.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; mouseActive = true; }); document.addEventListener('mouseleave', () => mouseActive = false); // Window resize window.addEventListener('resize', () => { canvasWidth = canvas.width = window.innerWidth; canvasHeight = canvas.height = window.innerHeight; initHeartPath(); }); } // Initialize everything function init() { const controls = document.getElementById('controls'); const canvas = document.getElementById('c'); controls.style.display = 'block'; canvas.style.display = 'block'; animationRunning = true; setupControls(); animationLoop(); // Start the animation loop // Initialize everything initHeartPath(); initParticles(); } // Start the animation init();