How to create snow effects for this Christmas with tsParticles
Tags: javascript, webdev, tutorial, html
Published: 2021-12-08 12:34:00


Christmas is coming 🎅 and why don't add a snow effect in your website?

Here's a simple guide to add the snow effect using tsParticles.

{% github matteobruni/tsparticles %}

## Table of Contents

- [Demo](#demo)
- [Configuration](#configuration)
- [Vanilla JS (Standard JavaScript)](#vanilla-js)
- [React JS](#react-js)
- [Vue 2](#vue-2)
- [Vue 3](#vue-3)
- [Angular](#angular)
- [Svelte](#svelte)
- [Solid JS](#solid-js)
- [Riot JS](#riot-js)
- [Preact](#preact)
- [Inferno](#inferno)
- [Web Components](#web-components)
- [jQuery](#jquery)
- [Presets](#presets)
- [Custom Shape](#custom-shape)

## Demo

Here's a small demo of the effect, if you remove the background options it will be transparent so you can put in your website without changing anything.

{% codepen https://codepen.io/matteobruni/pen/PoqmyEy %}

## Configuration

This is one of the easiest configuration for a nice snow effect. It's not interacting with the mouse events, but it can be achieved easily.

For more options and examples checkout the [official website](https://particles.js.org)

*snow.json*

``` json
{
   "background":{
      "color":"#000000"
   },
   "particles":{
      "color":{
         "value":"#fff"
      },
      "move":{
         "direction":"bottom",
         "enable":true,
         "outModes":"out",
         "speed":2
      },
      "number":{
         "density":{
            "enable":true,
            "area":800
         },
         "value":400
      },
      "opacity":{
         "value":0.7
      },
      "shape":{
         "type":"circle"
      },
      "size":{
         "value":10
      },
      "wobble":{
         "enable":true,
         "distance":10,
         "speed":10
      },
      "zIndex":{
         "value":{
            "min":0,
            "max":100
         }
      }
   }
}
```

*file with comments, it can be used only in `.js` files*

``` js
{
   // The background color is for making the particles visible since they're white. Remove this section if not needed
   "background":{
      "color":"#000000"
   },
   // The particles options
   "particles":{
      // The color of the particles/snowflakes
      "color":{
         "value":"#fff"
      },
      // Move the snow flakes to bottom for a realistic effect, "out" in outModes is for making them reappear on top once exited at the bottom of the page, the speed should be slow for a realistic effect
      "move":{
         "direction":"bottom",
         "enable":true,
         "outModes":"out",
         "speed":2
      },
      // How many particles/snowflakes will be created when starting the effect, density is a good option to enable since it calculates the particles number based on the screen size (mobile users will be happy)
      "number":{
         "density":{
            "enable":true,
            "area":800
         },
         "value":400
      },
      // The opacity of the particles/snowflakes
      "opacity":{
         "value":0.7
      },
      // The shape of the particles/snowflakes, also custom shapes can be used, this will be discussed at the end
      "shape":{
         "type":"circle"
      },
      // The size of the particles/snowflakes
      "size":{
         "value":10
      },
      // A nice wobble movement
      "wobble":{
         "enable":true,
         "distance":10,
         "speed":10
      },
      // Some depth to the effect, (the layers count by default is 100, changing max here is not affecting that count)
      // The zIndex will affect speed, size and opacity of the particles/snowflakes, the smaller the zIndex the smaller/more transparent/slower the particles/snowflakes will be
      "zIndex":{
         "value":{
            "min":0,
            "max":100
         }
      }
   }
}
```

## Vanilla JS

For adding this effect in any website using just plain HTML and JavaScript, you just have to add the *snow.json* file above in your folder, and add this HTML below in your page.

```html
<div id="tsparticles"></div>

<script src="https://cdn.jsdelivr.net/npm/tsparticles@1.37.5/tsparticles.min.js"></script>
<script>
  tsParticles.load("tsparticles", "snow.json");
</script>
```

## React JS

For React web sites/applications this is the recommended setup

### Installation

*yarn*

``` shell
$ yarn add react-tsparticles react
```

*npm*

``` shell
$ npm install react-tsparticles react
```

### Component

*snow.jsx*

``` javascript
import Particles from "react-tsparticles";
import snowConfig from "./snow.json";

const Snow = () => (
  <Particles id="tsparticles" options={snowConfig} />
);
```

## Vue 2

For Vue 2.x web sites/applications this is the recommended setup

### Installation

*yarn*

``` shell
$ yarn add particles.vue vue@2 vue-class-component@<8
```

*npm*

``` shell
$ npm install particles.vue vue@2 vue-class-component@<8
```

*main.js*

``` javascript
import Particles from "particles.vue";

Vue.use(Particles);
```

### Component

*snow.vue*

``` html
<template>
    <div id="app">
        <Particles
                id="tsparticles"
                :options="snowConfig"
        />
    </div>
</template>

<script>
import { Vue } from "vue-class-component";
import snowConfig from "./snow.json";

export default class Snow extends Vue {
  snowConfig;

  constructor() {
    super();

    this. snowConfig = snowConfig;
  }
}
</script>
```

## Vue 3

For Vue 3.x web sites/applications this is the recommended setup

### Installation

*yarn*

``` shell
$ yarn add particles.vue3 vue@3 vue-class-component@8
```

*npm*

``` shell
$ npm install particles.vue3 vue@3 vue-class-component@8
```

*main.js*

```javascript
import Particles from "particles.vue3";

createApp(App).use(Particles)
```

### Component

*snow.vue*

```html
<template>
    <div id="app">
        <Particles
                id="tsparticles"
                :options="snowConfig"
        />
    </div>
</template>

<script>
import { Vue } from "vue-class-component";
import snowConfig from "./snow.json";

export default class Snow extends Vue {
  snowConfig;

  constructor() {
    super();

    this. snowConfig = snowConfig;
  }
}
</script>
```

## Angular

For Angular web sites/applications this is the recommended setup

### Installation

*npm*

``` shell
$ npm install ng-particles tsparticles
```

*yarn*

``` shell
$ yarn add ng-particles tsparticles
```

*app.module.ts*

``` typescript
import {NgParticlesModule} from "ng-particles";
import {NgModule} from "@angular/core";

@NgModule({
    declarations: [
        /* AppComponent */
    ],
    imports: [
        /* other imports */ NgParticlesModule /* NgParticlesModule is required*/
    ],
    providers: [],
    bootstrap: [
        /* AppComponent */
    ]
})
export class AppModule {
}
```

### Component

*snow.html*

```html
<ng-particles [id]="id" [options]="snowConfig"></ng-particles>
```

*snow.ts*

```typescript
import snowConfig from "./snow.json";

export class Snow {
    id = "tsparticles";
    
    /* or the classic JavaScript object */
    snowConfig = snowConfig;
}
```

## Svelte

For Svelte web sites/applications this is the recommended setup

### Installation

*npm*

```shell
npm install svelte-particles svelte
```

*yarn*

```shell
yarn add svelte-particles svelte
```

### Component

*snow.svelte*

```html
<script>
  import Particles from "svelte-particles";
  import snowConfig from "./snow.json";
</script>

<Particles
  id="tsparticles"
  options="{snowConfig}"
/>
```

### SSR Component

*snow.svelte*

```html
<script>
  import { onMount } from "svelte";
  import snowConfig from "./snow.json";

  let ParticlesComponent;

  onMount(async () => {
    const module = await import("svelte-particles");

    ParticlesComponent = module.default;
  });

  let onParticlesLoaded = (event) => {
    const particlesContainer = event.detail.particles;

    // you can use particlesContainer to call all the Container class
    // (from the core library) methods like play, pause, refresh, start, stop
  };

  let onParticlesInit = (main) => {
    // you can use main to customize the tsParticles instance adding presets or custom shapes
  };
</script>

<svelte:component
  this="{ParticlesComponent}"
  id="tsparticles"
  options="{snowConfig}"
/>
```

## Solid JS

For Solid.js web sites/applications this is the recommended setup

### Installation

*npm*

```shell
npm install solid-particles solid-js
```

*yarn*

```shell
yarn add solid-particles solid-js
```

### Component

*snow.jsx*
```javascript
import Particles from "solid-particles";
import snowConfig from "./snow.json";

class Snow extends Component {
  snowConfig = snowConfig;

  render() {
    return (
      <Particles
        id="tsparticles"
        options={snowConfig}
      />
    );
  }
}
```

## Riot JS

For Riot.js web sites/applications this is the recommended setup

### Installation

*npm*

``` shell
npm install riot-particles riot
```

*yarn*

``` shell
yarn add riot-particles riot
```

*index.js*

``` javascript
import {register} from 'riot'
import RiotParticles from "riot-particles";

register("riot-particles", RiotParticles);
```

### Component

*snow.riot*

```html
<riot-particles id="tsparticles" options="{snowConfig}" />

<script>
    import RiotParticles from "riot-particles";
    import snowConfig from "./snow.json";

    export default {
        snowConfig,
        components: {
            RiotParticles
        }
    }
</script>
```

## Preact

For Preact web sites/applications this is the recommended setup

### Installation

*yarn*

``` shell
$ yarn add preact-particles preact
```

*npm*

``` shell
$ npm install preact-particles preact
```

### Component

*snow.jsx*

``` javascript
import { Component } from 'preact';
import Particles from "preact-particles";
import snowConfig from "./snow.json";

export default class Snow extends Component {
  render() {
    return (<Particles id="tsparticles" options={snowConfig} />);
  }
}
```

## Inferno

For Riot.js web sites/applications this is the recommended setup

### Installation

*yarn*

``` shell
$ yarn add inferno-particles inferno
```

*npm*

``` shell
$ npm install inferno-particles inferno
```

### Component

*snow.jsx*

``` javascript
import { Component } from 'inferno';
import Particles from "inferno-particles";
import snowConfig from "./snow.json";

export default class Snow extends Component {
  render() {
    return (<Particles id="tsparticles" options={snowConfig} />);
  }
}
```

## Web Components

For adding this effect in any website using Web Components, you just have to add the *snow.json* file above in your folder, and add this HTML below in your page.

*index.html*

``` html
<web-particles
        id="tsparticles"
        url="snow.json"
/>

<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2.6.0/custom-elements-es5-adapter.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2.6.0/webcomponents-loader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/tsparticles@1.37.5/tsparticles.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/web-particles@1.10.5/dist/web-particles.min.js" type="module"></script>
```

## jQuery

For adding this effect in any website using jQuery, you just have to add the *snow.json* file above in your folder, and add this HTML below in your page.

``` html
<div id="tsparticles"></div>

<script src="https://cdn.jsdelivr.net/npm/tsparticles@1.37.5/tsparticles.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-particles@1.37.5/dist/jquery.particles.min.js"></script>
<script>
  $("#tsparticles").particles().ajax("snow.json");
</script>
```

## Presets

For adding this effect in any website using just plain HTML and JavaScript with just a single script and a line of code, a snow preset is also available. Just add this to your website and you'll have a snow effect immediately.

``` html
<div id="snow"></div>

<script src="https://cdn.jsdelivr.net/npm/tsparticles-preset-snow@1.22.5/tsparticles.preset.snow.bundle.min.js"></script>
<script>
  tsParticles.load("snow", { preset: "snow" });
</script>
```

The object `{ preset: "snow" }` is still a complete tsParticles options object, you can still customize everything, just complete the object with your additional configuration, every options added to that object will override the preset default options.

For example:

``` javascript
  tsParticles.load("snow", {
    preset: "snow",
    particles: {
      shape: {
        type: "square"
      }
    }
  });
```

With this sample, you'll have squared particles/snowflakes instead of the default `"circle"` value, falling like snow.

You can read more about the snow preset [here](https://www.npmjs.com/package/tsparticles-preset-snow).
**A typo was made in the README.md file of the package, the `loadFirePreset` should be `loadSnowPreset`.**
It's already fixed in the source code, when the new version will be published everything is going to be fine.

## Custom Shape

It's possible also to create a custom shape, like a generated snowflake. This is not recommended since a snowflake is heavy to be generated on the go, use images instead. But if someone wants to try it I'll leave the link below.

https://codepen.io/matteobruni/pen/yLzeMqB

The preview is not added here since it can be heavy to render.

The custom shape code is this:

``` javascript
const deg = Math.PI / 180;

function snowflake(c, n, len) {
  c.save();
  leg(n);
  c.rotate(-120 * deg);
  leg(n);
  c.rotate(-120 * deg);
  leg(n);
  c.closePath();
  c.restore();

  function leg(n) {
    c.save();
    if (n === 0) {
      c.lineTo(len, 0);
    } else {
      c.scale(1 / 3, 1 / 3);
      leg(n - 1);
      c.rotate(60 * deg);
      leg(n - 1);
      c.rotate(-120 * deg);
      leg(n - 1);
      c.rotate(60 * deg);
      leg(n - 1);
    }
    c.restore();
    c.translate(len, 0);
  }
}

tsParticles.addShape("snowflake", function (context, particle, radius) {
  snowflake(context, Math.floor(Math.random() * 3 + 2), radius);
});
```

And it can be used in any of the configuration above, when used in Vanilla JS, jQuery or Web Components with `<script>` tags you can just add it before calling the `tsParticles.load` function.
In all the other case refer to the documentation for the `particlesInit` or `init` parameter (some component differs in this property) and the parameter of that function is going to replace `tsParticles` object when calling `.addShape` method.

For example, React.js component is going to appear like this:

*snowflake.json*

``` json
{
   "background":{
      "color":"#000000"
   },
   "particles":{
      "color":{
         "value":"#fff"
      },
      "move":{
         "direction":"bottom",
         "enable":true,
         "outModes":"out",
         "speed":2
      },
      "number":{
         "density":{
            "enable":true,
            "area":800
         },
         "value":400
      },
      "opacity":{
         "value":0.7
      },
      "shape":{
         "type":"snowflake"
      },
      "size":{
         "value":10
      },
      "wobble":{
         "enable":true,
         "distance":10,
         "speed":10
      },
      "zIndex":{
         "value":{
            "min":0,
            "max":100
         }
      }
   }
}
```

*snowflakes.jsx*

``` javascript
import { useCallback } from "react";
import Particles from "react-tsparticles";
import snowflakeConfig from "./snowflake.json";

const deg = Math.PI / 180;

function snowflake(c, n, len) {
  c.save();
  leg(n);
  c.rotate(-120 * deg);
  leg(n);
  c.rotate(-120 * deg);
  leg(n);
  c.closePath();
  c.restore();

  function leg(n) {
    c.save();
    if (n === 0) {
      c.lineTo(len, 0);
    } else {
      c.scale(1 / 3, 1 / 3);
      leg(n - 1);
      c.rotate(60 * deg);
      leg(n - 1);
      c.rotate(-120 * deg);
      leg(n - 1);
      c.rotate(60 * deg);
      leg(n - 1);
    }
    c.restore();
    c.translate(len, 0);
  }
}

const Snowflakes = () => {
  const particlesInit = useCallback((main) => {
    main.addShape("snowflake", function (context, particle, radius) {
      snowflake(context, Math.floor(Math.random() * 3 + 2), radius);
    });
  }, []);

  return (<Particles id="tsparticles" options={snowflakeConfig} init={particlesInit} />);
};
```