<main id=app>
  <div class="text">
    <h1>
      Obligatory Holiday Falling Snow
    </h1>
    <p>Using the incredibly light-weight, super-high-performance, bestest canvas particle system in Javascript; Sparticles!</p>
    <a href="https://github.com/simeydotme/sparticles" class="link">Get Sparticles on Github for this holiday season!</a>
  </div>
</main>
* {
  box-sizing: border-box;
}

body, html {
  color: white;
  background: #1e2021;
  padding: 0;
  margin: 0;
  font-family: "Heebo", sans-serif;
  height: 100%;
  width: 100%;
}

main {
  width: 100%;
  height: 100%;
  position: relative;
  display: grid;
  padding-top: 30px;
  z-index: 1;
  background-image: 
    linear-gradient(rgba(165, 196, 211, 0.3), #293743f2), url("https://images.unsplash.com/photo-1552910996-e666ad64695c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80");
  background-size: cover;
  background-position: bottom center;
}

main > .text {
  place-self: center;
  text-align: center;
  max-width: 50vw;
}

.stats {
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 10;
  filter: saturate(0);
}

#app canvas {
  z-index: -1;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  mix-blend-mode: overlay;
}

h1 {
  font-size: 6vw;
  font-weight: 100;
  font-family: "Mountains of Christmas", cursive;
  margin: 0 auto 15px;
}

.dg.ac {
  z-index: 2!important;
}

.link {
  display: block;
  position: absolute;
  left: 0;
  bottom: 20px;
  width: 100%;
  margin: 0 auto;
  text-align: center;
  color: white;
}
View Compiled
//
// I'm hotlinking to some SVG images from flaticon.com
// for use as the snowflakes. I hope that remains possible
// especially with the below attribution;
//
// ❄ Icons made by Freepik from www.flaticon.com
// ❄ https://www.flaticon.com/packs/snowflakes
//

let colorType = {
  type: "multi"
};

let colors = {
  color1: "rgba(255,255,255,1)",
  color2: "rgba(233,239,250,1)",
  color3: "rgba(222,241,250,1)",
  color4: "rgba(178,209,219,1)",
  color5: "rgba(135,143,145,1)"
};

let options = {
  alphaSpeed: 2,
  alphaVariance: 1,
  color: [colors.color1, colors.color2, colors.color3, colors.color4],
  composition: "source-over",
  count: 120,
  direction: 160,
  drift: 2,
  glow: 50,
  imageUrl: [
    "https://assets.codepen.io/13471/snowflake.png",
    "https://assets.codepen.io/13471/snowflake(1).png",
    "https://assets.codepen.io/13471/snowflake(2).png",
    "https://assets.codepen.io/13471/snowflake(3).png",
    "https://assets.codepen.io/13471/snowflake(4).png",
    "https://assets.codepen.io/13471/snowflake(5).png",
    "https://assets.codepen.io/13471/snowflake(6).png",
    "https://assets.codepen.io/13471/snowflake(7).png",
    "https://assets.codepen.io/13471/snowflake(8).png",
  ],
  maxAlpha: 2,
  maxSize: 24,
  minAlpha: -0.2,
  minSize: 3,
  parallax: 6,
  rotation: 0.5,
  shape: ["image"],
  speed: 2.5,
  style: "fill",
  twinkle: false,
  xVariance: 20,
  yVariance: 20,
};

window.onload = function() {
  initStats();
  initSparticles();
  initGui();
}

window.initSparticles = function() {
  var $main = document.querySelector("main");
  window.mySparticles = new Sparticles($main,options);
};

window.initStats = function() {
  var stats = new Stats();
  stats.domElement.classList.add("stats");
  document.body.appendChild(stats.domElement);
  function statsDisplay() {
    stats.begin();
    stats.end();
    requestAnimationFrame(statsDisplay);
  }
  requestAnimationFrame(statsDisplay);
};

window.initGui = function() {
  const s = window.mySparticles;
  const shapes = ["circle", "square", "triangle", "diamond", "line", "image"];
  const styles = ["fill", "stroke", "both"];
  const colorOptions = ["single", "multi", "rainbow"];
  const composites = [
    "source-over",
    "source-in",
    "source-out",
    "source-atop",
    "destination-over",
    "destination-in",
    "destination-out",
    "destination-atop",
    "lighter",
    "copy",
    "xor",
    "multiply",
    "screen",
    "overlay",
    "darken",
    "color-dodge",
    "color-burn",
    "hard-light",
    "soft-light",
    "difference",
    "exclusion",
    "hue",
    "saturation",
    "color",
    "luminosity"
  ];
  const rerender = () => {
    window.mySparticles.destroy();
    window.initSparticles();
  };
  var rerenderColors = function(v) {
    if (colorType.type === "rainbow") {
      options.color = "rainbow";
    } else if (colorType.type === "single") {
      options.color = colors.color1;
    } else {
      options.color = Object.keys(colors).map(i => {
        return colors[i];
      });
    }
    rerender();
  };

  const gui = new dat.GUI({ load: options });
  const part = gui.addFolder("Particles");
  part.open();
  part.add( options, "count", 1, 1500, 1).onFinishChange(rerender);
  part.add( options, "shape", shapes).onFinishChange(rerender);
  part.add( options, "style", styles).onFinishChange(rerender);
  const image = part.addFolder("Image");
  // image.add( options, "imageUrl").onFinishChange(rerender);
  part.add( options, "minSize", 1, 50, 1).onFinishChange(rerender);
  part.add( options, "maxSize", 1, 50, 1).onFinishChange(rerender);
  const anim = gui.addFolder("Animation");
  anim.add( options, "direction", 0, 360, 1).onFinishChange(rerender);
  anim.add( options, "speed", 0, 100, 0.1).onFinishChange(rerender);
  anim.add( options, "rotation", 0, 100, 0.1).onFinishChange(rerender);
  const move = anim.addFolder("Movement");
  move.add( options, "parallax", 0, 10, 0.1).onFinishChange(rerender);
  move.add( options, "drift", 0, 10, 0.1).onFinishChange(rerender);
  move.add( options, "xVariance", 0, 50, 0.1).onFinishChange(rerender);
  move.add( options, "yVariance", 0, 50, 0.1).onFinishChange(rerender);
  const vis = gui.addFolder("Visual");
  vis.add( options, "glow", 0,50).onFinishChange(rerender);
  vis.add( options, "composition", composites).onFinishChange(rerender);
  const alpha = vis.addFolder("Alpha");
  alpha.add( options, "twinkle").onFinishChange(rerender);
  alpha.add( options, "minAlpha", -2, 2, 0.1).onFinishChange(rerender);
  alpha.add( options, "maxAlpha", -2, 2, 0.1).onFinishChange(rerender);
  alpha.add( options, "alphaSpeed", 0, 50, 1).onFinishChange(rerender);
  alpha.add( options, "alphaVariance", 0, 20, 1).onFinishChange(rerender);
  const color = vis.addFolder("Color");
  color.open();
  color.add(colorType, "type", colorOptions).onFinishChange(rerenderColors);
  color.addColor(colors, "color1").onFinishChange(rerenderColors);
  color.addColor(colors, "color2").onFinishChange(rerenderColors);
  color.addColor(colors, "color3").onFinishChange(rerenderColors);
  color.addColor(colors, "color4").onFinishChange(rerenderColors);
  color.addColor(colors, "color5").onFinishChange(rerenderColors);
};

External CSS

  1. https://fonts.googleapis.com/css?family=Mountains+of+Christmas:400,700|Heebo:100,300,400,500,700,800,900

External JavaScript

  1. https://cdn.jsdelivr.net/npm/sparticles@1.3.0/dist/sparticles.js
  2. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js