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();
.png)
Comments
Post a Comment