JavaScript Snow
Published: 2023-12-14 11:14:45

Here's how you can add a snow animation with JavaScript to your site just for the festive season :)

See a demo by [watching the tutorial here](https://www.youtube.com/watch?v=JG7B4W9HeOw) and for my thoughts on why it's a bad idea!

{% codepen https://codepen.io/codebubb/pen/LYqovoV %}

## 1. Setup Constants

Let's setup some variables to hold some info on the appearance of our snow animation.

```javascript
const NUMBER_OF_SNOWFLAKES = 300;
const MAX_SNOWFLAKE_SIZE = 5;
const MAX_SNOWFLAKE_SPEED = 2;
const SNOWFLAKE_COLOUR = '#ddd';

const snowflakes = [];
```

We'll also create an empty array called `snowflakes` which is going to keep track of all the individual snowflakes on the page.

## 2. Create a canvas

All our snowflakes are going to be drawn onto a canvas element so let's create that and drop it onto the current document.

```javascript
const canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.pointerEvents = 'none';
canvas.style.top = '0px';
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);

const ctx = canvas.getContext('2d');
```

We're sizing the canvas to fit the entire window and setting the `pointer-event` CSS property to `none` so it makes the canvas invisible and the user can still click things behind it.

Finally, we'll get the 2d canvas context, which we can use to draw our snowflakes on. 

But first, we need a function to generate a snowflake.

## 3. Create a snowflake

```javascript
const createSnowflake = () => ({
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height,
    radius: Math.floor(Math.random() * MAX_SNOWFLAKE_SIZE) + 1,
    color: SNOWFLAKE_COLOUR,
    speed: Math.random() * MAX_SNOWFLAKE_SPEED + 1,
    sway: Math.random() - 0.5
});
```

This function will create and return a snowflake object which is at some random position on the page.  We'll also create a random size (radius) for it, set its colour to the constant we defined and also give it a random speed with a minimum value.

In the second part of the tutorial, we introduce a `sway` property in order to move the snowflake either left or right as it falls down the page.

Now we need a way to draw the snowflake onto the canvas.

## 4. Draw a snowflake

```javascript
const drawSnowflake = snowflake => {
    ctx.beginPath();
    ctx.arc(snowflake.x, snowflake.y, snowflake.radius, 0, Math.PI * 2);
    ctx.fillStyle = snowflake.color;
    ctx.fill();
    ctx.closePath();
};
```

We're just going to draw a circle with a radius as specified by the property on the snowflake object that's passed in.


## 5. Update a snowflake

```javascript
const updateSnowflake = snowflake => {
    snowflake.y += snowflake.speed;
    snowflake.x += snowflake.sway;
    if (snowflake.y > canvas.height) {
        Object.assign(snowflake, createSnowflake());
    }
};
```

Here, we'll take one of our snowflake objects and update its x and y positions on the page.  If it gets to the bottom of the page, we'll re-assign the reference of the snowflake to a new snowflake object.

## 6. Animating snowflakes

```javascript
const animate = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    snowflakes.forEach(snowflake => {
        updateSnowflake(snowflake);
        drawSnowflake(snowflake);
    });

    requestAnimationFrame(animate);
};
```

The `animate` function clears the current canvas and then loops through our array of snowflakes and updates their position, then draws them onto the canvas.

We can make a really smooth animation by simply calling this function repeatedly by passing it to `requestAnimationFrame`.

Of course, we haven't put any snowflake objects into our `snowflakes` array yet so let's populate those now and kick off the animation by calling the `animate` function.

```javascript
for (let i = 0; i < NUMBER_OF_SNOWFLAKES; i++) {
    snowflakes.push(createSnowflake());
}

animate();
``` 

We should have a fully working snowfall animation on our page now!

## 7. Adding Event Listeners

If you try and resize your browser window at this point or scroll down to more content (if it exists on your page) then you'll notice that the snowfall effect is fixed to the top of the page and doesn't resize to fit the browser window.

Let's finish off our beautiful snowfall animation with a couple of event listeners to handle this.

```javascript
window.addEventListener('resize', () => {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
});

window.addEventListener('scroll', () => {
    canvas.style.top = `${window.scrollY}px`;
});
```

Because we've written everything in JavaScript with no extra HTML/CSS required, we can just copy the code and drop it into any site.  For example, here's how it looks on Amazon's site:

![JavaScript snow on Amazon](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts70upghn6t98pkxxi4z.gif)

## Conclusion

As mentioned in the video, this is just a bit of fun and not something you should probably add to your site unless your company is insistent on sending your site back to the 1990s :)

Thanks for reading and be sure to check out the full tutorial here if you want more details:

{% youtube https://www.youtube.com/watch?v=JG7B4W9HeOw %}