PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / lib / confetti.js

confetti.js in Extendify 3.2.1, at src/Agent/lib/confetti.js

135 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import confetti from 'canvas-confetti';
2
3 export const CANVAS_CONFETTI = 'extendify-agent:canvas-confetti';
4
5 let confettiInstance = null;
6
7 const ensureConfettiInstance = () => {
8 if (confettiInstance) return confettiInstance;
9
10 // Custom canvas to account for height issues
11 const canvas = document.createElement('canvas');
12 canvas.style.position = 'fixed';
13 canvas.style.top = '0';
14 canvas.style.left = '0';
15 canvas.style.width = '100%';
16 canvas.style.height = '100%';
17 canvas.style.pointerEvents = 'none';
18 canvas.style.zIndex = Number.MAX_SAFE_INTEGER;
19 document.body.appendChild(canvas);
20
21 confettiInstance = confetti.create(canvas, {
22 disableForReducedMotion: true,
23 resize: true,
24 });
25 return confettiInstance;
26 };
27
28 // Its own canvas is what confines a burst to the element that asked.
29 export const confettiIn = (canvas) =>
30 confetti.create(canvas, { disableForReducedMotion: true, resize: true });
31
32 const TOP = () => ({ x: Math.random(), y: 0 });
33
34 // A zero start velocity is what makes it fall rather than be thrown.
35 export const FALLING = {
36 interval: 55,
37 perDrop: 2,
38 drift: 0.5,
39 origin: TOP,
40 colors: [
41 '#26ccff',
42 '#a25afd',
43 '#ff5e7e',
44 '#88ff5a',
45 '#fcff42',
46 '#ffa62d',
47 '#ff36ff',
48 ],
49 shot: {
50 particleCount: 1,
51 startVelocity: 0,
52 gravity: 0.9,
53 ticks: 300,
54 scalar: 0.85,
55 },
56 };
57
58 // An absent interval is what makes it fire once instead of repeating.
59 export const THROW = {
60 perDrop: 2,
61 origin: (i) => ({ x: i, y: 0.75 }),
62 shot: {
63 particleCount: 70,
64 startVelocity: 50,
65 spread: 75,
66 decay: 0.91,
67 ticks: 220,
68 scalar: 0.95,
69 },
70 };
71
72 const pick = (list) => list[Math.floor(Math.random() * list.length)];
73
74 // A multi-particle shot cannot spread at zero velocity, so it lands as one clump.
75 // A one-particle shot takes only the first colour of the palette.
76 export const dropConfetti = (
77 shoot,
78 { interval, shot, drift = 0, perDrop = 1, colors, origin = TOP },
79 ) => {
80 const drop = () => {
81 for (let i = 0; i < perDrop; i++) {
82 shoot({
83 ...shot,
84 origin: origin(i),
85 ...(drift && { drift: (Math.random() * 2 - 1) * drift }),
86 ...(colors && { colors: [pick(colors)] }),
87 });
88 }
89 };
90 drop();
91 if (!interval) return () => {};
92 const timer = setInterval(drop, interval);
93 return () => clearInterval(timer);
94 };
95
96 export const throwSideConfetti = (shoot) => {
97 const LEFT = {
98 count: 200,
99 defaults: {
100 origin: { y: 0.7, x: 0 },
101 },
102 shots: [
103 { ratio: 0.25, spread: 26, startVelocity: 55 },
104 { ratio: 0.2, spread: 60 },
105 { ratio: 0.35, spread: 100, decay: 0.91, scalar: 0.8 },
106 { ratio: 0.1, spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 },
107 { ratio: 0.1, spread: 120, startVelocity: 45 },
108 ],
109 };
110 const shooter = shoot ?? ensureConfettiInstance();
111 throwConfetti(LEFT, shooter);
112 throwConfetti(
113 {
114 ...LEFT,
115 defaults: {
116 origin: { y: 0.7, x: 1 },
117 },
118 },
119 shooter,
120 );
121 };
122
123 const throwConfetti = (config, shoot) => {
124 const { count = 1, defaults, shots } = config;
125
126 shots.forEach(({ ratio = 1, ...opts }) => {
127 shoot({
128 ...(defaults ?? {}),
129 ...(opts ?? {}),
130 particleCount: Math.floor(count * ratio),
131 zIndex: Number.MAX_SAFE_INTEGER,
132 });
133 });
134 };
135