Let it snow with Three.js

With Christmas season at the door and absolutely freezing temperatures outside, clients and developers unite wanting only one thing: snow on their website. If you think that is quite a bit overstated: When three.js asked for feature requests for r160, one respondent replied: “snowflake shader”. So let’s do something fun today and review webgl snow out there. I will also give you my own recipe at the end.

Demo Snow

To create webgl snow, look no further than one of three.js’s own examples. This is snow is rough: It does not even pretend to have anything to do with the fluffy frozen rain in nature. The snowflakes also seem a bit gravitationally challenged, flying mostly from side to side and quite often upwards. The y-axis rotation makes the whole thing look a bit like a snowflake washing machine too.

Different point materials are created for six different, completely artificial snowflake shapes and colours (‘sprites’), which is a very useful technique for animating different particle groups, well, differently. You even get some mouse interaction with the mouse rotating the scene, so you can look around, sort of. This is not GPU snow though. The entire animation runs on the CPU.

I’d say: a solid B.

Boytchev’s Snow

Aaaah, this is beautiful snow. It moves downwards as it should, has variation, and makes one want to look at it forever. If you avoid shaders like the plague, this is your snow. The author generates the snowflake shapes dynamically instead of using cheesy images. Creating a circle in a fragment shaders is three humble lines of code, max, just saying. But if you want to go down the CPU route, this is certainly an efficient approach. Snowflakes also get recycled once they have fallen to the ground, and they are placed at a new random position every cycle. This could be improved by using buffer attributes rather than updating all the vertices at 60fps. But for now I’m saying: A-

Code: https://github.com/boytchev/etudes/blob/master/threejs/snowing.html

Whatever you do, do not actually click the start button on the linked site. Oh no, now you have…

Soledad’s Snow

Only amazing things happen when a “creative browser crashologist” takes a deep dive into snow. Trouble with the website is that none of the examples actually work due to CORS errors. But I assure you, if you follow the concise and well-explained tutorial, you will get proper, GPU-powered snow. The shaders are easy enough and even The Bad Geometrist enjoyed implementing them. The only value ever animated in the loop is time; so the entire scene is very efficient.

Problem with this snow is the lack of randomness. It only takes a couple of seconds to recognise the jiggly movement pattern since the the snow is animated with a wave function. Once you’ve seen the jiggly pattern, it makes you a tiny little bit sick. Particles are also recycled at exactly the point they started, once they have reached the bottom end of the browser. Because this snow has been coded beautifully, runs on the GPU, and comes with a super good tutorial, the verdict is still: A-

Code: https://github.com/sole/three.js-tutorials/blob/master/snow_shader/step10.html (also look at the other steps and the corresponding js-files).

Improving the pattern:

  • Speed and radius do not need to be constants. You could also randomise them on a per-flake basis as buffer attributes. This did not improve my own implementation’s feel much though because the flakes’ path still gets repeated at intervals.
  • Add turbulence.

The Bad Geometrist’s Snow

The Bad Geometrist’s snow is a variation on Soledad’s snow using boring, white circles instead of image textures. I find this does not harm the look at all. But then I am not in the business of animating Ice Age movies. Feel free to pass some textures as uniforms, if you must.

Distance from the camera determines the flakes’ opacity. You could pass a custom colour as a uniform or attribute, if you felt you needed 1980s technicolour snow. The “Demo Snow” example above explains how.

Since I wanted soft, meditative, default-mode network activating1 snow, I only randomised the snowflakes’ x-axis movement by adding Perlin noise (Gustafson, S., 2011) using the formulas found with an article on vertex displacement (Sanchez Elias, J., 2012). This is a tutorial for yet another ugly blob, or “slimy broccoli”, as he calls it. He explains how to apply the noise well to whatever object you plan to put on the screen, despicable or not. You can also play around with Perlin noise to get a feel for it in this code sandbox by Rohan Deshpande.

vec3 pos = position;

// High frequency noise
float noise = 10.0 *  -.10 * turbulence( .5 * normal );
// Low frequency noise
float b = 5.0 * pnoise( 0.05 * position, vec3( 100.0 ) );
// Compose both noises
float displacement = - 10. * noise + b;

    
pos.x += cos((uTime + position.y) * 0.1 * displacement) * uRad.x;
pos.y = mod(pos.y - uTime  * uSpeed.y, uScreenHeight); 
pos.z += sin((uTime + position.x) * 0.25 * uSpeed.x) * uRad.z;

vec4 mvPosition = modelViewMatrix * vec4( pos, 1.0 );

gl_PointSize = uSize * ( uScale / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
vPos = gl_Position.xyz;

So there you have it, a review of popular techniques for generating snow with three.js. If you liked the review and have another three.js snow example to be rated, let me know.

Would it be a bad idea to get in touch?

If you have a project in mind, need wise advice, or just want to say hi: Write on to { click/tap to reveal }

© 2026. Lazy Developer Studio. All rights reserved.