PluginProbe
Extendify / trunk
Extendify vtrunk
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
← All changes | src/Agent/lib/confetti.js +82 -9 3.1.4 → trunk View file →
@@ -1,6 +1,8 @@
1 1 import confetti from 'canvas-confetti';
2 2
3 +export const CANVAS_CONFETTI = 'extendify-agent:canvas-confetti';
4 +
3 5 let confettiInstance = null;
4 6
5 7 const ensureConfettiInstance = () => {
6 8 if (confettiInstance) return confettiInstance;
@@ -22,9 +24,77 @@
22 24 });
23 25 return confettiInstance;
24 26 };
25 27
26 -export const throwSideConfetti = () => {
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) => {
27 97 const LEFT = {
28 98 count: 200,
29 99 defaults: {
30 100 origin: { y: 0.7, x: 0 },
@@ -36,20 +106,23 @@
36 106 { ratio: 0.1, spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 },
37 107 { ratio: 0.1, spread: 120, startVelocity: 45 },
38 108 ],
39 109 };
40 - throwConfetti(LEFT);
41 - throwConfetti({
42 - ...LEFT,
43 - defaults: {
44 - origin: { y: 0.7, x: 1 },
110 + const shooter = shoot ?? ensureConfettiInstance();
111 + throwConfetti(LEFT, shooter);
112 + throwConfetti(
113 + {
114 + ...LEFT,
115 + defaults: {
116 + origin: { y: 0.7, x: 1 },
117 + },
45 118 },
46 - });
119 + shooter,
120 + );
47 121 };
48 122
49 -const throwConfetti = (config) => {
123 +const throwConfetti = (config, shoot) => {
50 124 const { count = 1, defaults, shots } = config;
51 - const shoot = ensureConfettiInstance();
52 125
53 126 shots.forEach(({ ratio = 1, ...opts }) => {
54 127 shoot({
55 128 ...(defaults ?? {}),