3D Aurora Birthday Animation 🎉 (Relaxing Visuals)


 

Youtube link - Click me

In this blog i shared the source code of the video


HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Create Birthday Wish 🎂</title>
  <link rel="stylesheet" href="style.css">
</head>
<body class="form-page">
  <div class="form-box">
    <h2>🎉 Create a Birthday Wish</h2>
    <input id="nameInput" placeholder="Enter name..." maxlength="20" />
    <button onclick="go()">Celebrate 🎂</button>
  </div>

  <script>
    function go() {
      const name = document.getElementById("nameInput").value.trim();
      if (!name) return alert("Please enter a name!");
      window.location.href = `celebrate.html?name=${encodeURIComponent(name)}`;
    }
  </script>
</body>
</html>

CSS

body {
  margin: 0;
  background: radial-gradient(circle at top, #050021, #000);
  overflow: hidden;
  font-family: Arial, sans-serif;
}

canvas {
  position: fixed;
  inset: 0;
}

.overlay {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;
  z-index: 10;
}

h1 {
  color: white;
  font-size: clamp(2.2rem, 6vw, 3.5rem);
  letter-spacing: 6px;
  text-shadow:
    0 0 20px #00f2fe,
    0 0 50px #4facfe,
    0 0 90px #00f2fe;
  opacity: 0;
  transform: scale(0.9);
  animation: fadeIn 1s ease forwards;
}

@keyframes fadeIn {
  to { opacity: 1; transform: scale(1); }
}

.balloon {
  position: fixed;
  bottom: -100px;
  width: 40px;
  height: 55px;
  border-radius: 50%;
  opacity: 0.9;
  animation: floatUp linear forwards;
  z-index: 20;
}

.balloon::after {
  content: "";
  position: absolute;
  width: 2px;
  height: 40px;
  background: rgba(255,255,255,0.5);
  left: 50%;
  top: 55px;
}

@keyframes floatUp {
  to {
    transform: translateY(-120vh);
    opacity: 0;
  }
}

JS

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Resize fix (IMPORTANT)
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

// Aurora particles
const count = 7000;
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(count * 3);

for (let i = 0; i < count; i++) {
  positions[i * 3] = (Math.random() - 0.5) * 40;
  positions[i * 3 + 1] = (Math.random() - 0.5) * 40;
  positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
}

geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));

const material = new THREE.PointsMaterial({
  size: 0.13,
  color: 0x00f2fe,
  transparent: true,
  opacity: 0.9,
  blending: THREE.AdditiveBlending
});

const points = new THREE.Points(geometry, material);
scene.add(points);

camera.position.z = 22;

// 🎆 Firecracker
function firecracker() {
  for (let i = 0; i < 80; i++) {
    const spark = document.createElement("div");
    spark.style.position = "fixed";
    spark.style.left = "50%";
    spark.style.top = "50%";
    spark.style.width = "6px";
    spark.style.height = "6px";
    spark.style.borderRadius = "50%";
    spark.style.background = `hsl(${Math.random() * 360},100%,70%)`;
    spark.style.pointerEvents = "none";
    spark.style.zIndex = 30;
    document.body.appendChild(spark);

    const angle = Math.random() * Math.PI * 2;
    const distance = 100 + Math.random() * 150;

    spark.animate([
      { transform: "translate(-50%, -50%) scale(1)", opacity: 1 },
      { transform: `translate(${Math.cos(angle) * distance}px, ${Math.sin(angle) * distance}px) scale(0)`, opacity: 0 }
    ], { duration: 900, easing: "ease-out" });

    setTimeout(() => spark.remove(), 900);
  }
}

// 🎈 Balloons
function spawnBalloon() {
  const balloon = document.createElement("div");
  balloon.className = "balloon";
  balloon.style.left = Math.random() * 100 + "vw";
  balloon.style.background = `hsl(${Math.random() * 360},80%,60%)`;
  balloon.style.animationDuration = 6 + Math.random() * 4 + "s";
  document.body.appendChild(balloon);
  setTimeout(() => balloon.remove(), 10000);
}

// Trigger effects
setTimeout(() => {
  firecracker();
  for (let i = 0; i < 12; i++) setTimeout(spawnBalloon, i * 300);
}, 1000);

// Aurora animation
function animate() {
  requestAnimationFrame(animate);
  const t = Date.now() * 0.001;
  const pos = geometry.attributes.position.array;

  for (let i = 0; i < count; i++) {
    const x = pos[i * 3];
    const y = pos[i * 3 + 1];
    pos[i * 3 + 2] = Math.sin(x * 0.35 + t) * Math.cos(y * 0.35 + t) * 3;
  }

  geometry.attributes.position.needsUpdate = true;
  points.rotation.z += 0.0012;

  camera.position.x = Math.sin(t * 0.4) * 1.5;
  camera.position.y = Math.cos(t * 0.3) * 1;
  camera.lookAt(scene.position);

  material.color.setHSL((t * 0.08) % 1, 1, 0.6);
  renderer.render(scene, camera);
}

animate();


Comments

Popular posts from this blog

Birthday card in html css js

Create Animated Tooltip Popups in HTML/CSS | No JavaScript Needed!

Built a 3D Morphing Engine with 8,000 Particles! ✨ (Three.js)

Create an Instagram Profile Page Using HTML and CSS | UI Clone Tutorial

JavaScript Voronoi Circles effect |HTML JS| #coding

Digital Clock with animation |HTML|CSS|JS

Coding a 'Smart' Particle System (Text to Dots Tutorial)

MOST EXPENSIVE AND EXTREME GAMING SETUPS EVER