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