Skip to content

Instantly share code, notes, and snippets.

@PechenkiUA
Last active December 28, 2023 06:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PechenkiUA/05cd66bdc9c28e28b0bbb67c36bb8e92 to your computer and use it in GitHub Desktop.
Save PechenkiUA/05cd66bdc9c28e28b0bbb67c36bb8e92 to your computer and use it in GitHub Desktop.
Snow
(function (){
document.querySelector('body').insertAdjacentHTML('afterbegin',`<canvas id="particle_canvas" style="position: fixed; left: 0; top: 0; width: 100%; height: 100%;"></canvas>`);
const canvas = document.querySelector('#particle_canvas')
const ctx = canvas.getContext('2d')
let width, height, lastNow
let snowflakes
const maxSnowflakes = 100
function init() {
snowflakes = []
resize()
render(lastNow = performance.now())
}
function render(now) {
requestAnimationFrame(render)
const elapsed = now - lastNow
lastNow = now
ctx.clearRect(0, 0, width, height)
if (snowflakes.length < maxSnowflakes)
snowflakes.push(new Snowflake())
ctx.fillStyle = ctx.strokeStyle = '#fff'
snowflakes.forEach(snowflake => snowflake.update(elapsed, now))
}
function pause() {
cancelAnimationFrame(render)
}
function resume() {
lastNow = performance.now()
requestAnimationFrame(render)
}
class Snowflake {
constructor() {
this.spawn()
}
spawn(anyY = false) {
this.x = rand(0, width)
this.y = anyY === true
? rand(-50, height + 50)
: rand(-50, -10)
this.xVel = rand(-.05, .05)
this.yVel = rand(.02, .1)
this.angle = rand(0, Math.PI * 2)
this.angleVel = rand(-.001, .001)
this.size = rand(7, 12)
this.sizeOsc = rand(.01, .5)
}
update(elapsed, now) {
const xForce = rand(-.001, .001);
if (Math.abs(this.xVel + xForce) < .075) {
this.xVel += xForce
}
this.x += this.xVel * elapsed
this.y += this.yVel * elapsed
this.angle += this.xVel * 0.05 * elapsed //this.angleVel * elapsed
if (
this.y - this.size > height ||
this.x + this.size < 0 ||
this.x - this.size > width
) {
this.spawn()
}
this.render()
}
render() {
ctx.save()
const { x, y, angle, size } = this
ctx.beginPath()
ctx.arc(x, y, size * 0.2, 0, Math.PI * 2, false)
ctx.fill()
ctx.restore()
}
}
// Utils
const rand = (min, max) => min + Math.random() * (max - min)
function resize() {
width = canvas.width = window.innerWidth
height = canvas.height = window.innerHeight
}
window.addEventListener('resize', resize)
window.addEventListener('blur', pause)
window.addEventListener('focus', resume)
init()
})();
.snowflake {
position: absolute;
width: 10px;
height: 10px;
background: white;
border-radius: 50%;
filter: drop-shadow(0 0 10px white);
}
(function (){
document.querySelector('body').insertAdjacentHTML('afterbegin',`<div id="snow" style="position: fixed; left: 0; top: 0; width: 100%; height: 100%;"></div>`);
let snowflakes_count = 200;
// let base_css = ``; // Put your custom base css here
if (typeof total !== 'undefined'){
snowflakes_count = total;
}
// This function allows you to turn on and off the snow
function toggle_snow() {
let check_box = document.getElementById("toggle_snow");
if (check_box.checked == true) {
document.getElementById('snow').style.display = "block";
}
else {
document.getElementById('snow').style.display = "none";
}
}
// Creating snowflakes
function spawn_snow(snow_density = 200) {
snow_density -= 1;
for (let x = 0; x < snow_density; x++) {
let board = document.createElement('div');
board.className = "snowflake";
document.getElementById('snow').appendChild(board);
}
}
// Append style for each snowflake to the head
function add_css(rule) {
let css = document.createElement('style');
css.type = 'text/css';
css.appendChild(document.createTextNode(rule)); // Support for the rest
document.getElementsByTagName("head")[0].appendChild(css);
}
// Math
function random_int(value = 100){
return Math.floor(Math.random() * value) + 1;
}
function random_range(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Create style for snowflake
function spawnSnowCSS(snow_density = 200){
let snowflake_name = "snowflake";
let rule = ``;
if (typeof base_css !== 'undefined'){
rule = base_css;
}
for(let i = 1; i < snow_density; i++){
let random_x = Math.random() * 100; // vw
let random_offset = random_range(-100000, 100000) * 0.0001; // vw;
let random_x_end = random_x + random_offset;
let random_x_end_yoyo = random_x + (random_offset / 2);
let random_yoyo_time = random_range(30000, 80000) / 100000;
let random_yoyo_y = random_yoyo_time * 100; // vh
let random_scale = Math.random();
let fall_duration = random_range(10, 30) * 1; // s
let fall_delay = random_int(30) * -1; // s
let opacity_ = Math.random();
rule += `
.${snowflake_name}:nth-child(${i}) {
opacity: ${opacity_};
transform: translate(${random_x}vw, -10px) scale(${random_scale});
animation: fall-${i} ${fall_duration}s ${fall_delay}s linear infinite;
}
@keyframes fall-${i} {
${random_yoyo_time*100}% {
transform: translate(${random_x_end}vw, ${random_yoyo_y}vh) scale(${random_scale});
}
to {
transform: translate(${random_x_end_yoyo}vw, 100vh) scale(${random_scale});
}
}
`
}
add_css(rule);
}
// Load the rules and execute after the DOM loads
window.onload = function() {
spawnSnowCSS(snowflakes_count);
spawn_snow(snowflakes_count);
};
// TODO add progress bar for slower clients
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment