PageSourceSearch

https://farts.link/scripts/btn-confetti.js

js farts.link collected 2026-10-02 00:37:43 UTC 2,608 bytes, 102 lines download raw bytes

1const canvas = document.getElementById("particleCanvas");
2const ctx = canvas.getContext("2d");
3const button = document.querySelector(".download_btn");
4
5const dpr = window.devicePixelRatio || 1;
6
7function setupCanvas() {
8  const rect = canvas.getBoundingClientRect();
9  canvas.width = rect.width * dpr;
10  canvas.height = rect.height * dpr;
11  ctx.scale(dpr, dpr);
12  canvas.style.width = `${rect.width}px`;
13  canvas.style.height = `${rect.height}px`;
14}
15
16setupCanvas();
17
18const particles = [];
19const emojis = ["💩", "🍑", "💨", "🙈"];
20const maxParticles = 100;
21let lastTriggerTime = 0;
22const triggerCooldown = 200;
23
24class Particle {
25  constructor(x, y) {
26    this.x = x;
27    this.y = y;
28    this.size = 32;
29    this.speedX = (Math.random() - 0.5) * 3;
30    this.speedY = Math.random() * -8;
31    this.gravity = 0.1;
32    this.emoji = emojis[Math.floor(Math.random() * emojis.length)];
33    this.opacity = 1;
34    this.friction = 0.99;
35    this.angle = Math.random() * Math.PI * 2;
36    this.angleSpeed = (Math.random() - 0.5) * 0.1;
37    this.lifetime = 200;
38  }
39
40  update() {
41    this.speedY += this.gravity;
42    this.x += this.speedX;
43    this.y += this.speedY;
44    this.speedX *= this.friction;
45    this.speedY *= this.friction;
46    this.lifetime -= 1;
47    this.opacity = Math.max(0, this.lifetime / 200);
48    this.angle += this.angleSpeed;
49  }
50
51  draw() {
52    ctx.save();
53    ctx.globalAlpha = this.opacity;
54    ctx.font = `${this.size}px Arial`;
55    ctx.translate(this.x, this.y);
56    ctx.rotate(this.angle);
57    ctx.fillText(this.emoji, 0, 0);
58    ctx.restore();
59  }
60}
61
62function createParticles(x, y) {
63  const currentTime = Date.now();
64  if (currentTime - lastTriggerTime < triggerCooldown) return;
65  lastTriggerTime = currentTime;
66
67  const particlesToCreate = Math.min(20, maxParticles - particles.length);
68  for (let i = 0; i < particlesToCreate; i++) {
69    particles.push(new Particle(x, y));
70  }
71}
72
73function animateParticles() {
74  ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);
75
76  for (let i = particles.length - 1; i >= 0; i--) {
77    particles[i].update();
78    particles[i].draw();
79
80    if (particles[i].lifetime <= 0) {
81      particles.splice(i, 1);
82    }
83  }
84
85  requestAnimationFrame(animateParticles);
86}
87
88button.addEventListener("mouseenter", () => {
89  const rect = button.getBoundingClientRect();
90  const canvasRect = canvas.getBoundingClientRect();
91
92  const x = rect.left + rect.width / 2 - canvasRect.left;
93  const y = rect.top + rect.height / 2 - canvasRect.top;
94
95  createParticles(x, y);
96});
97
98animateParticles();
99
100window.addEventListener("resize", () => {
101  setupCanvas();
102});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.