Skip to content

Instantly share code, notes, and snippets.

@radfox200289
Created December 31, 2025 11:15
Show Gist options
  • Select an option

  • Save radfox200289/95b6a68b891d1430bb4cf6ceaa0bd1f9 to your computer and use it in GitHub Desktop.

Select an option

Save radfox200289/95b6a68b891d1430bb4cf6ceaa0bd1f9 to your computer and use it in GitHub Desktop.
To my girl vanes
<audio id="music" loop>
<source src="https://cdn.pixabay.com/download/audio/2022/03/15/audio_4c7c3c6b8b.mp3" type="audio/mpeg">
</audio>
<div class="start" onclick="startExperience()">
<div class="bunny">
🐰
<span class="heart">❤️</span>
</div>
<p>Tap the bunny</p>
</div>
<div class="sky hidden" id="sky">
<div class="star you">★</div>
<div class="star her">★</div>
<div class="card">
<h1>Happy New Year</h1>
<h2>Vanessa</h2>
<p id="text"></p>
<p class="signature">Love, Leila ❤️</p>
</div>
</div>
<canvas id="fireworks"></canvas>
const music = document.getElementById("music");
const sky = document.getElementById("sky");
const textEl = document.getElementById("text");
const message = `
To my beautiful wife,
May every New Year’s Eve hold us together.
You are the best thing that happened to me.
May 2026 be the year that brings us together.
Until the day we meet —
shine, my love.
Dance. Eat. Feel joy.
Be everything you want to be.
Happy New Year 💫
`;
let i = 0;
function typeWriter() {
if (i < message.length) {
textEl.innerHTML += message.charAt(i);
i++;
setTimeout(typeWriter, 45);
}
}
function startExperience() {
document.querySelector(".start").style.display = "none";
sky.classList.remove("hidden");
setTimeout(() => sky.classList.add("active"), 500);
music.volume = 0.4;
music.play();
setTimeout(typeWriter, 2000);
startFireworks();
}
/* Fireworks */
const canvas = document.getElementById("fireworks");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function random(min, max) {
return Math.random() * (max - min) + min;
}
function startFireworks() {
setInterval(() => {
const x = random(100, canvas.width - 100);
const y = random(50, canvas.height / 2);
for (let i = 0; i < 40; i++) {
fireworks.push({
x, y,
dx: random(-3, 3),
dy: random(-3, 3),
life: 60
});
}
}, 1200);
}
let fireworks = [];
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
fireworks.forEach((p, index) => {
p.x += p.dx;
p.y += p.dy;
p.life--;
ctx.fillStyle = "rgba(255,182,193,0.8)";
ctx.fillRect(p.x, p.y, 2, 2);
if (p.life <= 0) fireworks.splice(index, 1);
});
requestAnimationFrame(animate);
}
animate();
* {
box-sizing: border-box;
font-family: 'Georgia', serif;
}
body {
margin: 0;
height: 100vh;
background: black;
overflow: hidden;
color: white;
}
.start {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: black;
cursor: pointer;
}
.gift {
font-size: 90px;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.15); }
100% { transform: scale(1); }
}
.sky {
position: fixed;
inset: 0;
background: radial-gradient(circle at top, #1b0036, #000);
}
.hidden {
display: none;
}
/* Stars */
.star {
position: absolute;
top: 30%;
font-size: 30px;
color: #ffd1dc;
transition: all 12s ease;
}
.you {
left: 10%;
}
.her {
right: 10%;
}
.sky.active .you {
left: 45%;
}
.sky.active .her {
right: 45%;
}
/* Message card */
.card {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 340px;
padding: 30px;
border-radius: 25px;
background: rgba(255,255,255,0.08);
backdrop-filter: blur(12px);
text-align: center;
box-shadow: 0 0 40px rgba(255,182,193,0.25);
}
h1 {
color: #ffd1dc;
margin-bottom: 5px;
}
h2 {
color: #ff9eb5;
letter-spacing: 2px;
}
.signature {
margin-top: 20px;
color: #ffd1dc;
font-size: 1.1em;
}
canvas {
position: fixed;
inset: 0;
pointer-events: none;
}.bunny {
font-size: 90px;
position: relative;
animation: hop 1.8s infinite ease-in-out;
}
.bunny .heart {
position: absolute;
top: -10px;
right: -10px;
font-size: 24px;
animation: floatHeart 2s infinite ease-in-out;
}
@keyframes hop {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-18px);
}
}
@keyframes floatHeart {
0% {
opacity: 0;
transform: translateY(0) scale(0.8);
}
50% {
opacity: 1;
transform: translateY(-10px) scale(1);
}
100% {
opacity: 0;
transform: translateY(-20px) scale(1.2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment