25% off ProSNIPC25OFF

Seasonal Snowfall / Confetti Effect

Canvas-based festive particle overlay animation (snowflakes or confetti) added to the footer.

Module2 parts · by SnipCraft

PHPLogic

php
<?php
if ( ! function_exists( 'scseed_snowfall_output' ) ) {
    function scseed_snowfall_output() {
        /**
         * Set $mode to 'snow' or 'confetti'.
         * Set $active_months to limit the animation (1=Jan … 12=Dec). Empty array = always on.
         */
        $mode          = 'snow';
        $active_months = array( 12, 1 ); // December and January only

        if ( ! empty( $active_months ) && ! in_array( (int) gmdate( 'n' ), $active_months, true ) ) {
            return;
        }
        ?>
        <canvas id="scseed-snow-canvas" data-mode="<?php echo esc_attr( $mode ); ?>" style="position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:99998" aria-hidden="true"></canvas>
        <?php
    }
    add_action( 'wp_footer', 'scseed_snowfall_output' );
}

JavaScriptScript

js
(function () {
  var canvas = document.getElementById('scseed-snow-canvas');
  if (!canvas) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { canvas.remove(); return; }

  var ctx  = canvas.getContext('2d');
  var mode = canvas.dataset.mode || 'snow';
  var W, H, particles = [];

  var CONFETTI_COLORS = ['#6366f1','#f43f5e','#f59e0b','#10b981','#3b82f6','#ec4899'];

  function resize() {
    W = canvas.width  = window.innerWidth;
    H = canvas.height = window.innerHeight;
  }

  function randBetween(a, b) { return a + Math.random() * (b - a); }

  function createParticle() {
    var p = {
      x: Math.random() * W,
      y: -10,
      r: mode === 'snow' ? randBetween(2, 6) : randBetween(5, 10),
      dx: randBetween(-1, 1),
      dy: randBetween(1, 3.5),
      opacity: randBetween(0.6, 1),
      rot: 0,
      rotSpeed: randBetween(-0.05, 0.05),
      color: mode === 'snow' ? 'rgba(200,220,255,' : null,
      confColor: mode === 'confetti' ? CONFETTI_COLORS[Math.floor(Math.random() * CONFETTI_COLORS.length)] : null,
      w: mode === 'confetti' ? randBetween(6, 12) : 0,
      h: mode === 'confetti' ? randBetween(4, 8) : 0,
    };
    return p;
  }

  function init() {
    particles = [];
    for (var i = 0; i < 120; i++) {
      var p = createParticle();
      p.y = Math.random() * H;
      particles.push(p);
    }
  }

  function draw() {
    ctx.clearRect(0, 0, W, H);
    particles.forEach(function (p) {
      ctx.save();
      ctx.globalAlpha = p.opacity;
      if (mode === 'snow') {
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fillStyle = 'rgba(200,220,255,' + p.opacity + ')';
        ctx.fill();
      } else {
        ctx.translate(p.x, p.y);
        ctx.rotate(p.rot);
        ctx.fillStyle = p.confColor;
        ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
      }
      ctx.restore();
      p.x  += p.dx;
      p.y  += p.dy;
      p.rot += p.rotSpeed;
      if (p.y > H + 20) {
        var np = createParticle();
        p.x = np.x; p.y = -10; p.dx = np.dx; p.dy = np.dy;
      }
    });
    requestAnimationFrame(draw);
  }

  window.addEventListener('resize', function () { resize(); init(); });
  resize();
  init();
  draw();
})();
#animation#snow#confetti#festive#canvas