WEBLEB
Accueil
Éditeur
Connexion
Pro
Français
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Toile : Flux de particules cardiaques
1004
zegarkidawida
Ouvrir dans l'éditeur
Publiez votre code
Recommandé
26 February 2024
Formulaire de connexion HTML CSS
26 December 2024
Un code par securefunction317
26 June 2024
Bouton de médias sociaux multiples
HTML
Copy
Controls
Full Screen
Colors:
Rainbow
Red
Green
Blue
Monochrome
Size:
10
Particles:
32
Speed:
1
Mouse Follow:
50
CSS
Copy
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; } }
JS
Copy
// 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();