BLOG 20: Valentines Madness

Today I made a Valentines website thingy from a tutorial

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Be My Valentine 💘</title>


  <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@500;600;700&family=Poppins:wght@300;400;500&display=swap" rel="stylesheet">


  <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>

This is the main HTML starter code and font and effects.

<style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(-45deg, #ff9a9e, #fad0c4, #fbc2eb, #a18cd1);
      background-size: 400% 400%;
      animation: bgMove 12s ease infinite;
      font-family: "Poppins", sans-serif;
      overflow: hidden;

This is the code for the main site and the body.

    @keyframes bgMove {
      0% { background-position: 0% 50%; }
      50% { background-position: 100% 50%; }
      100% { background-position: 0% 50%; }
    }


    .card {
      width: min(92%, 420px);
      padding: 40px 30px 45px;
      background: rgba(255, 255, 255, 0.75);
      backdrop-filter: blur(18px);
      border-radius: 28px;
      text-align: center;
      box-shadow:
        0 30px 80px rgba(0,0,0,0.25),
        inset 0 0 0 1px rgba(255,255,255,0.4);
      position: relative;
      animation: cardIn 1.1s ease;
    }

This is the code for moving the background and the moving choice.

    @keyframes cardIn {
      from { opacity: 0; transform: translateY(30px) scale(0.95); }
      to { opacity: 1; transform: translateY(0) scale(1); }
    }


    .card::before {
      content: "";
      position: absolute;
      inset: -2px;
      border-radius: 30px;
      background: linear-gradient(120deg, #ff4d6d, #ff9a9e, #fbc2eb);
      z-index: -1;
      filter: blur(20px);
      opacity: 0.7;
    }

This is the code for actually moving the choice and choosing its color and such.

    .emoji {
      font-size: 68px;
      margin-bottom: 12px;
      animation: heartbeat 1.8s infinite;
    }

    @keyframes heartbeat {
      0%,100% { transform: scale(1); }
      25% { transform: scale(1.08); }
      50% { transform: scale(1); }
      75% { transform: scale(1.12); }
    }

This is the code for the emoji animation and such.

    h2 {
      font-family: "Playfair Display", serif;
      font-size: 28px;
      color: #4a1c2f;
      margin-bottom: 30px;
      line-height: 1.35;
    }

    .buttons {
      position: relative;
      height: 78px;
    }

    button {
      position: absolute;
      padding: 14px 36px;
      border-radius: 40px;
      border: none;
      font-size: 16px;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.25s ease;
      box-shadow: 0 10px 25px rgba(0,0,0,0.15);
    }

This is the code for the buttons.

    button:active {
      transform: scale(0.94);
    }

    #yes {
      left: 12%;
      background: linear-gradient(135deg, #ff4d6d, #ff758f);
      color: #fff;
      box-shadow: 0 15px 35px rgba(255,77,109,0.55);
    }

    #yes:hover {
      transform: translateY(-3px);
      box-shadow: 0 20px 40px rgba(255,77,109,0.7);
    }

    #no {
      left: 55%;
      background: rgba(255,255,255,0.9);
      color: #777;
    }

This is the code for the choices.

    .hint {
      margin-top: 28px;
      font-size: 13px;
      color: #6b6b6b;
      font-style: italic;
    }

    .heart {
      position: absolute;
      bottom: -20px;
      animation: floatUp linear forwards;
      pointer-events: none;
      filter: blur(0.3px);
    }

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

This is the code for moving the buttons.

    @media (max-width: 480px) {
      h2 { font-size: 23px; }
      .emoji { font-size: 58px; }
      button { padding: 12px 28px; font-size: 15px; }
      #yes { left: 8%; }
      #no { left: 55%; }
    }
  </style>
</head>

<body>

  <div class="card">
    <div class="emoji">🐱❤️</div>
    <h2>Anon,<br>will you be my Valentine?</h2>

    <div class="buttons">
      <button id="yes">Yes 💖</button>
      <button id="no">No 🙈</button>
    </div>

    <div class="hint">(:✨</div>
  </div>


  <audio id="hoverSound" src="https://assets.mixkit.co/sfx/preview/mixkit-cartoon-voice-laugh-343.mp3"></audio>
  <audio id="yesSound" src="https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3"></audio>

This is the code for the hint text and sounds for hovering over the buttons.

  <script>
    const noBtn = document.getElementById("no");
    const yesBtn = document.getElementById("yes");
    const card = document.querySelector(".card");
    const hoverSound = document.getElementById("hoverSound");
    const yesSound = document.getElementById("yesSound");

    noBtn.addEventListener("mouseenter", () => {
      hoverSound.currentTime = 0;
      hoverSound.play();

      const cardRect = card.getBoundingClientRect();
      const btnRect = noBtn.getBoundingClientRect();

      const maxX = cardRect.width - btnRect.width - 10;
      const maxY = cardRect.height - btnRect.height - 10;

      noBtn.style.left = Math.random() * maxX + "px";
      noBtn.style.top = Math.random() * maxY + "px";
    });

    yesBtn.addEventListener("click", () => {
      yesSound.play();

      confetti({
        particleCount: 260,
        spread: 120,
        origin: { y: 0.65 }
      });

      setTimeout(() => {
        alert("YAY 💕 I can’t wait for Valentine’s Day with you!");
      }, 500);
    });

    function createHeart() {
      const heart = document.createElement("div");
      heart.className = "heart";
      heart.innerHTML = Math.random() > 0.5 ? "❤️" : "💗";
      heart.style.left = Math.random() * 100 + "vw";
      heart.style.fontSize = Math.random() * 22 + 14 + "px";
      heart.style.animationDuration = Math.random() * 3 + 4 + "s";
      heart.style.opacity = Math.random() * 0.5 + 0.4;

      document.body.appendChild(heart);
      setTimeout(() => heart.remove(), 8000);
    }

    setInterval(createHeart, 380);
  </script>

</body>
</html>

This is the code that decides the math for the Animations.

1 thought on “BLOG 20: Valentines Madness”

  1. Very nice blog! I like how you isolate the code and explain it. Next time consider using OBS for screen capture to show off the animations.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top