About this snippet

Build an interactive galaxy spiral using HTML5 Canvas. We animate hundreds of particles rotating around a central core, so your background mesmerizes.

Size
3.1 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
348
<div class="galaxy-container">
  <canvas id="galaxy-canvas"></canvas>
  <div class="galaxy-text">
    <h2>Infinite Universe</h2>
    <p>Interact with the simulation using your mouse.</p>
  </div>
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  margin: 0;
  background: #020617;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.galaxy-container {
  position: relative;
  width: 100%;
  height: 100vh;
}

#galaxy-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  cursor: crosshair;
}

.galaxy-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  text-align: center;
  color: #ffffff;
  pointer-events: none;
}

.galaxy-text h2 {
  font-size: clamp(3rem, 6vw, 5rem);
  margin: 0 0 10px 0;
  letter-spacing: 2px;
  text-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
}

.galaxy-text p {
  font-size: 1.25rem;
  color: #94a3b8;
  margin: 0;
}
const canvas = document.getElementById("galaxy-canvas");
const ctx = canvas.getContext("2d");

let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;

const particles = new Array();
const particleCount = 800;

const mouse = new Object();
mouse.x = width / 2;
mouse.y = height / 2;

window.addEventListener("mousemove", function(e) {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
});

window.addEventListener("resize", function() {
  width = window.innerWidth;
  height = window.innerHeight;
  canvas.width = width;
  canvas.height = height;
});

// Initialize the particle objects
for (let i = 0; i < particleCount; i++) {
  const p = new Object();
  p.angle = Math.random() * Math.PI * 2;
  p.radius = Math.random() * (width / 1.5);
  p.speed = (Math.random() * 0.005) + 0.001;
  p.size = Math.random() * 2 + 0.5;
  p.color = Math.random() > 0.5 ? "#3b82f6" : "#ec4899";
  particles.push(p);
}

function draw() {
  // Create a slight trailing effect by painting semi-transparent background
  ctx.fillStyle = "rgba(2, 6, 23, 0.1)";
  ctx.fillRect(0, 0, width, height);

  particles.forEach(function(p) {
    p.angle += p.speed;
    
    // Determine target location based on angle and radius
    const targetX = width / 2 + Math.cos(p.angle) * p.radius;
    const targetY = height / 2 + Math.sin(p.angle) * p.radius;
    
    // Check distance to mouse
    const dx = mouse.x - targetX;
    const dy = mouse.y - targetY;
    const dist = Math.sqrt(dx * dx + dy * dy);
    
    let offsetX = 0;
    let offsetY = 0;
    
    // Gently pull particles toward the mouse if they get close
    if (dist < 250) {
      const force = (250 - dist) / 250;
      offsetX = dx * force * 0.1;
      offsetY = dy * force * 0.1;
    }
    
    ctx.beginPath();
    ctx.arc(targetX + offsetX, targetY + offsetY, p.size, 0, Math.PI * 2);
    ctx.fillStyle = p.color;
    ctx.shadowBlur = 10;
    ctx.shadowColor = p.color;
    ctx.fill();
  });

  window.requestAnimationFrame(draw);
}

draw();
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save