<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Particle Heart Illusion</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="heartCanvas"></canvas>
<script>
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('heartCanvas');
const ctx = canvas.getContext('2d');
// Set canvas to full window size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Responsive sizing
const size = Math.min(canvas.width, canvas.height) * 0.8;
// Particle class
class Particle {
constructor(x, y) {
this.originalX = x;
this.originalY = y;
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = Math.random() * 3 + 1;
this.velocityX = Math.random() * 2 - 1;
this.velocityY = Math.random() * 2 - 1;
this.color = `hsl(${340 + Math.random() * 40}, 100%, ${50 + Math.random() * 30}%)`;
this.targetX = x;
this.targetY = y;
}
update() {
const dx = this.targetX - this.x;
const dy = this.targetY - this.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
this.velocityX = dx * 0.03;
this.velocityY = dy * 0.03;
} else {
// Add some random movement when close to target
this.velocityX = (Math.random() * 2 - 1) * 0.3;
this.velocityY = (Math.random() * 2 - 1) * 0.3;
}
this.x += this.velocityX;
this.y += this.velocityY;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
scatter() {
this.targetX = Math.random() * canvas.width;
this.targetY = Math.random() * canvas.height;
}
returnToHeart() {
this.targetX = this.originalX;
this.targetY = this.originalY;
}
}
// Generate particles in a heart shape
const particles = [];
const heartPoints = [];
const particleCount = 1000;
// Create heart shape points
function createHeartPoints() {
heartPoints.length = 0;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const scale = size / 20;
for (let t = 0; t < Math.PI * 2; t += 0.01) {
const x = 16 * Math.pow(Math.sin(t), 3);
const y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);
heartPoints.push({
x: centerX + x * scale,
y: centerY - y * scale
});
}
// Fill in the heart
for (let i = 0; i < 200; i++) {
const randomAngle = Math.random() * Math.PI * 2;
const randomRadius = Math.random() * size / 3;
const x = centerX + Math.cos(randomAngle) * randomRadius;
const y = centerY - Math.sin(randomAngle) * randomRadius;
if (isPointInHeart(x, y, centerX, centerY, scale)) {
heartPoints.push({x, y});
}
}
}
// Check if a point is inside the heart shape
function isPointInHeart(x, y, centerX, centerY, scale) {
const rx = (x - centerX) / scale;
const ry = (centerY - y) / scale;
// Heart equation: (x^2 + y^2 - 1)^3 - x^2*y^3 < 0
const v1 = Math.pow(rx*rx + ry*ry - 1, 3);
const v2 = rx*rx * Math.pow(ry, 3);
return v1 - v2 < 0;
}
// Initialize particles
function initParticles() {
createHeartPoints();
particles.length = 0;
for (let i = 0; i < particleCount; i++) {
const randomIndex = Math.floor(Math.random() * heartPoints.length);
const point = heartPoints[randomIndex];
particles.push(new Particle(point.x, point.y));
}
}
// Animation loop
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const particle of particles) {
particle.update();
particle.draw();
}
requestAnimationFrame(animate);
}
// Event listeners for interactions
canvas.addEventListener('click', function() {
const isScattered = particles[0].targetX !== particles[0].originalX;
if (isScattered) {
for (const particle of particles) {
particle.returnToHeart();
}
} else {
for (const particle of particles) {
particle.scatter();
}
}
});
// Handle window resize
window.addEventListener('resize', function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
initParticles();
});
// Start animation
initParticles();
animate();
});
</script>
</body>
</html>
0 seconds of 0 secondsVolume 90%
Press shift question mark to access a list of keyboard shortcuts
Keyboard Shortcuts
Shortcuts Open/Close/ or ?
Play/PauseSPACE
Increase Volume↑
Decrease Volume↓
Seek Forward→
Seek Backward←
Captions On/Offc
Fullscreen/Exit Fullscreenf
Mute/Unmutem
Decrease Caption Size-
Increase Caption Size+ or =
Seek %0-9
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)