A browser source overlay for winter vibes for your Live Streams or Videos
1import "./style.css";
2import { CANVAS_HEIGHT, CANVAS_WIDTH, MAX_PARTICAL_COUNT } from "./config";
3import { createSnowflake, drawSnowflake, moveSnowflake } from "./snowflake";
4import {
5 checkCollision,
6 createSnowAccumulator,
7 drawSnowAccumulator,
8} from "./snow_accumulator";
9
10/**
11 * @type{Array.<Snowflake>}
12 */
13const snowFlakes = [];
14
15/**
16 * @type SnowAccumulator
17 */
18const floor = createSnowAccumulator(CANVAS_HEIGHT);
19
20/**
21 * @type {HTMLCanvasElement}
22 */
23let canvas;
24
25/**
26 * @type {CanvasRenderingContext2D}
27 */
28let ctx;
29
30let lastSpawn = 0;
31let lastFrame = 0;
32let fps = 0;
33
34window.onload = init;
35
36function init() {
37 // @ts-ignore -- I dunno how to get ts / jsdoc to be ok with this
38 canvas = document.getElementById("main");
39
40 ctx = canvas.getContext("2d");
41 canvas.width = CANVAS_WIDTH;
42 canvas.height = CANVAS_HEIGHT;
43
44 window.requestAnimationFrame(gameLoop);
45}
46
47/**
48 * @param time {DOMHighResTimeStamp}
49 */
50function gameLoop(time) {
51 const delta = time - lastFrame;
52 fps = Math.round(1 / (delta / 1000));
53
54 ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
55 if (time - lastSpawn > 500 && snowFlakes.length < MAX_PARTICAL_COUNT) {
56 for (let i = 0; i < Math.floor(Math.random() * 2); i++) {
57 snowFlakes.push(createSnowflake());
58 }
59 }
60
61 snowFlakes.forEach((flake, idx) => {
62 moveSnowflake(flake, delta);
63 if (checkCollision(floor, flake)) {
64 snowFlakes[idx] = createSnowflake();
65 }
66 drawSnowflake(flake, ctx);
67 });
68
69 drawSnowAccumulator(ctx, floor);
70 ctx.fillText("FPS: " + fps, 10, 30);
71 lastFrame = time;
72 window.requestAnimationFrame(gameLoop);
73}