const IMGS = [ "/img/rains/arch.png", "/img/rains/bmo.png", "/img/rains/cat.gif", "/img/rains/demi.png", "/img/rains/dnd.png", "/img/rains/eattherich.png", "/img/rains/gloomhaven.png", "/img/rains/iron_throne.png", "/img/rains/link.png", "/img/rains/meddle.jpeg", "/img/rains/moon.png", "/img/rains/note.png", "/img/rains/obsidian.png", "/img/rains/outerwilds.png", "/img/rains/piano.png", "/img/rains/pirate.svg", "/img/rains/ror.png", "/img/rains/smashball.svg", "/img/rains/ssa.png", "/img/rains/svelte.png", "/img/rains/usu.png", ]; const DROPLETS = 8; const DROPLET_WIDTH_RANGE = [80, 120]; const DROPLET_DY_RANGE = [0.1, 0.4]; const DROPLET_DTHETA_RANGE = [-0.25, 0.25]; const DROPLET_INIT_THETA_RANGE = [-180, 180]; const makeDroplet = (src, width, x, y, theta, dtheta, dy) => { const img = document.createElement("img"); img.style.position = "absolute"; img.style.width = `${width}px`; img.src = src; document.body.appendChild(img); return { img, width, theta, pos: { x, y }, vel: { dy, dtheta }, }; }; const randBetween = (min, max) => Math.random() * (max - min) + min; const update = (droplets, dt, boundedY) => droplets .map((droplet) => { return { ...droplet, pos: { ...droplet.pos, y: droplet.pos.y + droplet.vel.dy * dt }, theta: droplet.theta + droplet.vel.dtheta * dt, }; }) .map((droplet) => { const { pos: { y }, img, } = droplet; if (y >= boundedY) { document.body.removeChild(img); return null; } return droplet; }) .filter((x) => x) .map((droplet) => { const { img, pos: { x, y }, theta, } = droplet; img.style.left = `${x}px`; img.style.top = `${y}px`; img.style.transform = `rotate(${theta}deg)`; return droplet; }); const buildRandomDroplet = () => makeDroplet( IMGS[Math.floor(randBetween(0, IMGS.length))], randBetween(...DROPLET_WIDTH_RANGE), randBetween(0, window.innerWidth - DROPLET_WIDTH_RANGE[1]), randBetween(-50, window.innerHeight / 8), randBetween(...DROPLET_INIT_THETA_RANGE), randBetween(...DROPLET_DTHETA_RANGE), randBetween(...DROPLET_DY_RANGE), ); window.onload = () => { // cache 'em IMGS.forEach((x) => { ((img) => (img.src = x))(new Image()); }); let droplets = Array(DROPLETS).fill().map(buildRandomDroplet); let lastTimestamp = performance.now(); const next = (timestamp) => { const dt = timestamp - lastTimestamp; lastTimestamp = timestamp; droplets = update(droplets, dt, window.innerHeight); if (droplets.length != DROPLETS) { droplets.push(buildRandomDroplet()); } requestAnimationFrame(next); }; requestAnimationFrame(next); };