<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Interactive Stars</title>
<style>
/*
Interactive Stars
-----------------
This animation scatters stars across a dark sky and draws faint lines
between those that are close together. The mouse acts as a
constellation generator: as you move, nearby stars connect to the
cursor. Stars drift slowly to add life to the scene.
*/
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: linear-gradient(to bottom, #02021e, #08104d);
cursor: crosshair;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="stars"></canvas>
<script>
(function() {
const canvas = document.getElementById('stars');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Create star objects with random positions and small drift velocities.
const starCount = 150;
const stars = [];
for (let i = 0; i < starCount; i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
r: Math.random() * 2 + 0.5,
vx: (Math.random() - 0.5) * 0.1,
vy: (Math.random() - 0.5) * 0.1
});
}
// Track mouse for constellation effect.
const mouse = { x: null, y: null };
document.addEventListener('mousemove', (e) => {
mouse.x = e.clientX;
mouse.y = e.clientY;
});
document.addEventListener('mouseleave', () => {
mouse.x = mouse.y = null;
});
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw stars
ctx.fillStyle = 'white';
for (const s of stars) {
s.x += s.vx;
s.y += s.vy;
// wrap around edges to create continuous motion
if (s.x < 0) s.x += canvas.width;
if (s.x > canvas.width) s.x -= canvas.width;
if (s.y < 0) s.y += canvas.height;
if (s.y > canvas.height) s.y -= canvas.height;
ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
ctx.fill();
}
// Draw lines between nearby stars
ctx.lineWidth = 0.5;
for (let i = 0; i < starCount; i++) {
for (let j = i + 1; j < starCount; j++) {
const a = stars[i];
const b = stars[j];
const dx = a.x - b.x;
const dy = a.y - b.y;
const distSq = dx * dx + dy * dy;
const threshold = 100 * 100;
if (distSq < threshold) {
const alpha = 1 - distSq / threshold;
ctx.strokeStyle = `rgba(255, 255, 255, ${alpha * 0.3})`;
ctx.beginPath();
ctx.moveTo(a.x, a.y);
ctx.lineTo(b.x, b.y);
ctx.stroke();
}
}
}
// Draw lines to mouse
if (mouse.x !== null) {
for (const s of stars) {
const dx = s.x - mouse.x;
const dy = s.y - mouse.y;
const distSq = dx * dx + dy * dy;
const threshold = 120 * 120;
if (distSq < threshold) {
const alpha = 1 - distSq / threshold;
ctx.strokeStyle = `rgba(255, 255, 255, ${alpha * 0.6})`;
ctx.beginPath();
ctx.moveTo(s.x, s.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
}
}
}
requestAnimationFrame(animate);
}
animate();
})();
</script>
</body>
</html>
<canvas id="stars"></canvas>
/*
Interactive Stars
-----------------
This animation scatters stars across a dark sky and draws faint lines
between those that are close together. The mouse acts as a
constellation generator: as you move, nearby stars connect to the
cursor. Stars drift slowly to add life to the scene.
*/
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: linear-gradient(to bottom, #02021e, #08104d);
cursor: crosshair;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
(function() {
const canvas = document.getElementById('stars');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Create star objects with random positions and small drift velocities.
const starCount = 150;
const stars = [];
for (let i = 0; i < starCount; i++) {
stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
r: Math.random() * 2 + 0.5,
vx: (Math.random() - 0.5) * 0.1,
vy: (Math.random() - 0.5) * 0.1
});
}
// Track mouse for constellation effect.
const mouse = { x: null, y: null };
document.addEventListener('mousemove', (e) => {
mouse.x = e.clientX;
mouse.y = e.clientY;
});
document.addEventListener('mouseleave', () => {
mouse.x = mouse.y = null;
});
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw stars
ctx.fillStyle = 'white';
for (const s of stars) {
s.x += s.vx;
s.y += s.vy;
// wrap around edges to create continuous motion
if (s.x < 0) s.x += canvas.width;
if (s.x > canvas.width) s.x -= canvas.width;
if (s.y < 0) s.y += canvas.height;
if (s.y > canvas.height) s.y -= canvas.height;
ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
ctx.fill();
}
// Draw lines between nearby stars
ctx.lineWidth = 0.5;
for (let i = 0; i < starCount; i++) {
for (let j = i + 1; j < starCount; j++) {
const a = stars[i];
const b = stars[j];
const dx = a.x - b.x;
const dy = a.y - b.y;
const distSq = dx * dx + dy * dy;
const threshold = 100 * 100;
if (distSq < threshold) {
const alpha = 1 - distSq / threshold;
ctx.strokeStyle = `rgba(255, 255, 255, ${alpha * 0.3})`;
ctx.beginPath();
ctx.moveTo(a.x, a.y);
ctx.lineTo(b.x, b.y);
ctx.stroke();
}
}
}
// Draw lines to mouse
if (mouse.x !== null) {
for (const s of stars) {
const dx = s.x - mouse.x;
const dy = s.y - mouse.y;
const distSq = dx * dx + dy * dy;
const threshold = 120 * 120;
if (distSq < threshold) {
const alpha = 1 - distSq / threshold;
ctx.strokeStyle = `rgba(255, 255, 255, ${alpha * 0.6})`;
ctx.beginPath();
ctx.moveTo(s.x, s.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
}
}
}
requestAnimationFrame(animate);
}
animate();
})();