repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

2.1 KB · 79 lines · JavaScript Raw History
 1// Drifting points that draw a line to every neighbour within 150px, brighter
 2// the closer they are, so constellations build and dissolve on their own.
 3
 4export const constellations = (cvs, { numStars = 50 } = {}) => {
 5  const ctx = cvs.getContext("2d");
 6  const starDistance = 150;
 7
 8  const resize = () => {
 9    cvs.width = cvs.offsetWidth;
10    cvs.height = cvs.offsetHeight;
11  };
12  resize();
13  window.addEventListener("resize", resize);
14
15  let stars = [];
16  for (let i = 0; i < numStars; i++) {
17    stars.push({
18      loc: [cvs.width * Math.random(), cvs.height * Math.random()],
19      dir: [Math.random() > 0.5 ? 1 : -1, Math.random() > 0.5 ? 1 : -1],
20    });
21  }
22
23  let frame = null;
24  let running = false;
25
26  const draw = () => {
27    ctx.clearRect(0, 0, cvs.width, cvs.height);
28
29    stars.forEach((star) => {
30      ctx.beginPath();
31      ctx.arc(star.loc[0], star.loc[1], 2, 0, 2 * Math.PI);
32      ctx.fillStyle = "rgb(255, 255, 255)";
33      ctx.fill();
34      ctx.closePath();
35
36      stars.forEach((closeStar) => {
37        const distance = Math.hypot(
38          star.loc[0] - closeStar.loc[0],
39          star.loc[1] - closeStar.loc[1]
40        );
41        if (distance >= starDistance) return;
42        ctx.beginPath();
43        ctx.moveTo(star.loc[0], star.loc[1]);
44        ctx.lineTo(closeStar.loc[0], closeStar.loc[1]);
45        ctx.strokeStyle = `rgba(255, 255, 255, ${
46          (starDistance - distance) / starDistance
47        })`;
48        ctx.stroke();
49        ctx.closePath();
50      });
51    });
52
53    stars.forEach((star) => {
54      if (star.loc[0] < 0) star.dir[0] = 1;
55      else if (star.loc[0] > cvs.width) star.dir[0] = -1;
56      if (star.loc[1] < 0) star.dir[1] = 1;
57      else if (star.loc[1] > cvs.height) star.dir[1] = -1;
58
59      star.loc[0] += star.dir[0] * 0.5;
60      star.loc[1] += star.dir[1] * 0.5;
61    });
62
63    if (running) frame = window.requestAnimationFrame(draw);
64  };
65
66  return {
67    start() {
68      if (running) return;
69      running = true;
70      frame = window.requestAnimationFrame(draw);
71    },
72    stop() {
73      running = false;
74      if (frame) window.cancelAnimationFrame(frame);
75      frame = null;
76    },
77  };
78};