@stianlarsen/react-light-beam 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,34 +1,33 @@
1
1
  {
2
2
  "name": "@stianlarsen/react-light-beam",
3
- "version": "3.1.0",
4
- "description": "A customizable React component that creates a light beam effect using conic gradients. Powered by GSAP for maximum performance. Supports dark mode and various customization options.",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/index.d.ts",
3
+ "version": "3.1.1",
4
+ "description": "A customizable React component that creates a light beam effect using conic gradients. Supports dark mode and various customization options.",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
8
9
  "scripts": {
9
- "build": "tsup",
10
- "dev": "tsup --watch",
11
- "typecheck": "tsc --noEmit",
12
- "prepublishOnly": "npm run build"
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "build": "tsup"
13
12
  },
14
13
  "files": [
15
- "dist",
16
- "README.md",
17
- "LICENSE"
14
+ "dist"
18
15
  ],
19
16
  "exports": {
20
17
  ".": {
21
18
  "import": {
22
- "types": "./dist/index.d.mts",
23
- "default": "./dist/index.mjs"
24
- },
25
- "require": {
26
19
  "types": "./dist/index.d.ts",
27
20
  "default": "./dist/index.js"
21
+ },
22
+ "require": {
23
+ "types": "./dist/index.d.cts",
24
+ "default": "./dist/index.cjs"
28
25
  }
29
26
  }
30
27
  },
31
- "sideEffects": false,
28
+ "sideEffects": [
29
+ "*.css"
30
+ ],
32
31
  "repository": {
33
32
  "type": "git",
34
33
  "url": "git+https://github.com/stianalars1/react-light-beam.git"
@@ -38,9 +37,7 @@
38
37
  "light beam",
39
38
  "conic gradient",
40
39
  "dark mode",
41
- "gsap",
42
- "scrolltrigger",
43
- "scroll animation",
40
+ "framer-motion",
44
41
  "animation"
45
42
  ],
46
43
  "author": "Stian Larsen <stian.larsen@mac.com>",
@@ -48,20 +45,24 @@
48
45
  "bugs": {
49
46
  "url": "https://github.com/stianalars1/react-light-beam/issues"
50
47
  },
51
- "homepage": "https://stianlars1.github.io/react-light-beam",
52
- "dependencies": {
53
- "@gsap/react": "^2.1.2",
54
- "gsap": "^3.12.5"
55
- },
48
+ "homepage": "https://github.com/stianalars1/react-light-beam#readme",
56
49
  "peerDependencies": {
57
- "react": "^18.0.0 || ^19.0.0",
58
- "react-dom": "^18.0.0 || ^19.0.0"
50
+ "@emotion/is-prop-valid": "^1.3.1",
51
+ "framer-motion": "^11.11.1",
52
+ "react": "^18 || ^19",
53
+ "react-dom": "^18 || ^19"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "framer-motion": {
57
+ "optional": false
58
+ },
59
+ "@emotion/is-prop-valid": {
60
+ "optional": true
61
+ }
59
62
  },
60
63
  "devDependencies": {
61
- "@types/react": "^19.2.7",
62
- "@types/react-dom": "^19.2.3",
63
- "react": "^19.2.3",
64
- "react-dom": "^19.2.3",
64
+ "@types/react": "^18 || ^19",
65
+ "@types/react-dom": "^18 || ^19",
65
66
  "tsup": "^8.5.1",
66
67
  "typescript": "^5.5.4"
67
68
  }
package/dist/index.d.mts DELETED
@@ -1,138 +0,0 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
-
3
- type DustParticlesConfig = {
4
- /**
5
- * Enable floating dust particles in the beam
6
- * @default false
7
- */
8
- enabled?: boolean;
9
- /**
10
- * Number of dust particles
11
- * @default 30
12
- */
13
- count?: number;
14
- /**
15
- * Animation speed multiplier (1 = normal, 2 = twice as fast)
16
- * @default 1
17
- */
18
- speed?: number;
19
- /**
20
- * Particle size range [min, max] in pixels
21
- * @default [1, 3]
22
- */
23
- sizeRange?: [number, number];
24
- /**
25
- * Particle opacity range [min, max]
26
- * @default [0.2, 0.6]
27
- */
28
- opacityRange?: [number, number];
29
- /**
30
- * Particle color (inherits beam color if not specified)
31
- */
32
- color?: string;
33
- };
34
-
35
- type MistConfig = {
36
- /**
37
- * Enable mist/fog effect
38
- * @default false
39
- */
40
- enabled?: boolean;
41
- /**
42
- * Mist intensity (0-1)
43
- * @default 0.3
44
- */
45
- intensity?: number;
46
- /**
47
- * Animation speed multiplier
48
- * @default 1
49
- */
50
- speed?: number;
51
- /**
52
- * Number of layered mist effects for depth
53
- * @default 2
54
- */
55
- layers?: number;
56
- };
57
-
58
- type PulseConfig = {
59
- /**
60
- * Enable rhythmic pulse effect
61
- * @default false
62
- */
63
- enabled?: boolean;
64
- /**
65
- * Pulse duration in seconds
66
- * @default 2
67
- */
68
- duration?: number;
69
- /**
70
- * Pulse intensity (0-1) - how much brightness varies
71
- * @default 0.2
72
- */
73
- intensity?: number;
74
- /**
75
- * GSAP easing function
76
- * @default "sine.inOut"
77
- */
78
- easing?: string;
79
- };
80
-
81
- type LightBeamProps = {
82
- className?: string;
83
- /**
84
- * Custom styles to merge with or override default styles.
85
- * User styles take priority over defaults.
86
- * @example style={{ height: '800px', width: '80vw' }}
87
- */
88
- style?: React.CSSProperties;
89
- fullWidth?: number;
90
- colorLightmode?: string;
91
- colorDarkmode?: string;
92
- maskLightByProgress?: boolean;
93
- invert?: boolean;
94
- id?: string;
95
- scrollElement?: EventTarget;
96
- onLoaded?: () => void;
97
- /**
98
- * Disable default inline styles. Set to true if you want to provide custom CSS via className only.
99
- * @default false
100
- */
101
- disableDefaultStyles?: boolean;
102
-
103
- /**
104
- * GSAP ScrollTrigger start position
105
- * @default "top bottom"
106
- * @example "top center", "center bottom", "top 80%"
107
- */
108
- scrollStart?: string;
109
-
110
- /**
111
- * GSAP ScrollTrigger end position
112
- * @default "top top"
113
- * @example "top 20%", "center center", "bottom top"
114
- */
115
- scrollEnd?: string;
116
-
117
- /**
118
- * Dust particles configuration
119
- * @example dustParticles={{ enabled: true, count: 50, speed: 1.5 }}
120
- */
121
- dustParticles?: DustParticlesConfig;
122
-
123
- /**
124
- * Mist/fog effect configuration
125
- * @example mist={{ enabled: true, intensity: 0.5, layers: 3 }}
126
- */
127
- mist?: MistConfig;
128
-
129
- /**
130
- * Pulse effect configuration
131
- * @example pulse={{ enabled: true, duration: 3, intensity: 0.3 }}
132
- */
133
- pulse?: PulseConfig;
134
- };
135
-
136
- declare const LightBeam: ({ className, style, colorLightmode, colorDarkmode, maskLightByProgress, fullWidth, invert, id, onLoaded, scrollElement, disableDefaultStyles, scrollStart, scrollEnd, dustParticles, mist, pulse, }: LightBeamProps) => react_jsx_runtime.JSX.Element;
137
-
138
- export { LightBeam };
package/dist/index.mjs DELETED
@@ -1,450 +0,0 @@
1
- "use client";
2
- import gsap3 from 'gsap';
3
- import { ScrollTrigger } from 'gsap/ScrollTrigger';
4
- import { useGSAP } from '@gsap/react';
5
- import { useRef, useEffect, useState, useMemo } from 'react';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
-
8
- var useIsDarkmode = () => {
9
- const [isDarkmode, setIsDarkmodeActive] = useState(false);
10
- useEffect(() => {
11
- const matchMedia = window.matchMedia("(prefers-color-scheme: dark)");
12
- const handleChange = () => {
13
- console.log("Darkmode match?", matchMedia.matches);
14
- setIsDarkmodeActive(matchMedia.matches);
15
- };
16
- setIsDarkmodeActive(matchMedia.matches);
17
- matchMedia.addEventListener("change", handleChange);
18
- handleChange();
19
- return () => {
20
- matchMedia.removeEventListener("change", handleChange);
21
- };
22
- }, []);
23
- return { isDarkmode };
24
- };
25
- var DustParticles = ({ config, beamColor }) => {
26
- const {
27
- enabled = false,
28
- count = 30,
29
- speed = 1,
30
- sizeRange = [1, 3],
31
- opacityRange = [0.2, 0.6],
32
- color
33
- } = config;
34
- const particles = useMemo(() => {
35
- if (!enabled) return [];
36
- return Array.from({ length: count }, (_, i) => {
37
- const x = Math.random() * 100;
38
- const y = Math.random() * 100;
39
- const size = sizeRange[0] + Math.random() * (sizeRange[1] - sizeRange[0]);
40
- const opacity = opacityRange[0] + Math.random() * (opacityRange[1] - opacityRange[0]);
41
- const duration = (3 + Math.random() * 4) / speed;
42
- const delay = Math.random() * duration;
43
- return {
44
- id: `dust-${i}`,
45
- x,
46
- y,
47
- size,
48
- opacity,
49
- duration,
50
- delay
51
- };
52
- });
53
- }, [enabled, count, sizeRange, opacityRange, speed]);
54
- useGSAP(
55
- () => {
56
- if (!enabled || particles.length === 0) return;
57
- const timelines = [];
58
- particles.forEach((particle) => {
59
- const element = document.getElementById(particle.id);
60
- if (!element) return;
61
- const tl = gsap3.timeline({
62
- repeat: -1,
63
- yoyo: true,
64
- delay: particle.delay
65
- });
66
- tl.to(element, {
67
- y: `-=${20 + Math.random() * 30}`,
68
- // Float upward 20-50px
69
- x: `+=${Math.random() * 20 - 10}`,
70
- // Slight horizontal drift ±10px
71
- opacity: particle.opacity * 0.5,
72
- // Fade slightly
73
- duration: particle.duration,
74
- ease: "sine.inOut"
75
- });
76
- timelines.push(tl);
77
- });
78
- return () => {
79
- timelines.forEach((tl) => tl.kill());
80
- };
81
- },
82
- {
83
- dependencies: [particles, enabled]
84
- }
85
- );
86
- if (!enabled) return null;
87
- const particleColor = color || beamColor;
88
- return /* @__PURE__ */ jsx(Fragment, { children: particles.map((particle) => /* @__PURE__ */ jsx(
89
- "div",
90
- {
91
- id: particle.id,
92
- style: {
93
- position: "absolute",
94
- left: `${particle.x}%`,
95
- top: `${particle.y}%`,
96
- width: `${particle.size}px`,
97
- height: `${particle.size}px`,
98
- borderRadius: "50%",
99
- backgroundColor: particleColor,
100
- opacity: particle.opacity,
101
- pointerEvents: "none",
102
- willChange: "transform, opacity"
103
- }
104
- },
105
- particle.id
106
- )) });
107
- };
108
- var MistEffect = ({ config, beamColor }) => {
109
- const {
110
- enabled = false,
111
- intensity = 0.3,
112
- speed = 1,
113
- layers = 2
114
- } = config;
115
- const mistLayers = useMemo(() => {
116
- if (!enabled) return [];
117
- return Array.from({ length: layers }, (_, i) => {
118
- const layerOpacity = intensity * 0.6 / (i + 1);
119
- const duration = (8 + i * 3) / speed;
120
- const delay = i * 1.5 / speed;
121
- const scale = 1 + i * 0.2;
122
- return {
123
- id: `mist-layer-${i}`,
124
- opacity: layerOpacity,
125
- duration,
126
- delay,
127
- scale
128
- };
129
- });
130
- }, [enabled, intensity, speed, layers]);
131
- useGSAP(
132
- () => {
133
- if (!enabled || mistLayers.length === 0) return;
134
- const timelines = [];
135
- mistLayers.forEach((layer) => {
136
- const element = document.getElementById(layer.id);
137
- if (!element) return;
138
- const tl = gsap3.timeline({
139
- repeat: -1,
140
- yoyo: false
141
- });
142
- tl.fromTo(
143
- element,
144
- {
145
- x: "-100%",
146
- opacity: 0
147
- },
148
- {
149
- x: "100%",
150
- opacity: layer.opacity,
151
- duration: layer.duration,
152
- ease: "none",
153
- delay: layer.delay
154
- }
155
- ).to(element, {
156
- opacity: 0,
157
- duration: layer.duration * 0.2,
158
- ease: "power1.in"
159
- });
160
- timelines.push(tl);
161
- });
162
- return () => {
163
- timelines.forEach((tl) => tl.kill());
164
- };
165
- },
166
- {
167
- dependencies: [mistLayers, enabled]
168
- }
169
- );
170
- if (!enabled) return null;
171
- const mistColor = beamColor.replace(/[\d.]+\)$/g, `${intensity})`);
172
- return /* @__PURE__ */ jsx(Fragment, { children: mistLayers.map((layer) => /* @__PURE__ */ jsx(
173
- "div",
174
- {
175
- id: layer.id,
176
- style: {
177
- position: "absolute",
178
- top: 0,
179
- left: 0,
180
- width: "100%",
181
- height: "100%",
182
- background: `radial-gradient(ellipse 120% 80% at 50% 20%, ${mistColor}, transparent 70%)`,
183
- opacity: 0,
184
- pointerEvents: "none",
185
- willChange: "transform, opacity",
186
- transform: `scale(${layer.scale})`,
187
- filter: "blur(40px)"
188
- }
189
- },
190
- layer.id
191
- )) });
192
- };
193
- var PulseEffect = ({ config, containerRef }) => {
194
- const {
195
- enabled = false,
196
- duration = 2,
197
- intensity = 0.2,
198
- easing = "sine.inOut"
199
- } = config;
200
- useGSAP(
201
- () => {
202
- if (!enabled || !containerRef.current) return;
203
- const element = containerRef.current;
204
- const timeline = gsap3.timeline({
205
- repeat: -1,
206
- // Infinite loop
207
- yoyo: true
208
- // Reverse on each iteration
209
- });
210
- const maxMultiplier = Math.min(2, 1 + intensity);
211
- timeline.fromTo(
212
- element,
213
- {
214
- "--pulse-multiplier": 1
215
- },
216
- {
217
- "--pulse-multiplier": maxMultiplier,
218
- duration,
219
- ease: easing
220
- }
221
- );
222
- const updateOpacity = () => {
223
- const baseOpacity = getComputedStyle(element).getPropertyValue("--base-opacity") || "1";
224
- const pulseMultiplier = getComputedStyle(element).getPropertyValue("--pulse-multiplier") || "1";
225
- element.style.opacity = `calc(${baseOpacity} * ${pulseMultiplier})`;
226
- };
227
- const ticker = gsap3.ticker.add(updateOpacity);
228
- return () => {
229
- timeline.kill();
230
- gsap3.ticker.remove(ticker);
231
- };
232
- },
233
- {
234
- dependencies: [enabled, duration, intensity, easing],
235
- scope: containerRef
236
- }
237
- );
238
- return null;
239
- };
240
- gsap3.registerPlugin(ScrollTrigger, useGSAP);
241
- var defaultStyles = {
242
- height: "var(--react-light-beam-height, 500px)",
243
- width: "var(--react-light-beam-width, 100vw)",
244
- // CRITICAL: NO transition on GSAP-controlled properties (background, opacity, mask)
245
- // Transitions would fight with GSAP's instant updates, causing visual glitches
246
- // especially when scroll direction changes
247
- transition: "none",
248
- willChange: "background, opacity",
249
- // Specific properties for better performance
250
- userSelect: "none",
251
- pointerEvents: "none",
252
- contain: "layout style paint",
253
- // CSS containment for better performance
254
- WebkitTransition: "none",
255
- WebkitUserSelect: "none",
256
- MozUserSelect: "none"
257
- };
258
- var LightBeam = ({
259
- className,
260
- style,
261
- colorLightmode = "rgba(0,0,0, 0.5)",
262
- colorDarkmode = "rgba(255, 255, 255, 0.5)",
263
- maskLightByProgress = false,
264
- fullWidth = 1,
265
- // Default to full width range
266
- invert = false,
267
- id = void 0,
268
- onLoaded = void 0,
269
- scrollElement,
270
- disableDefaultStyles = false,
271
- scrollStart = "top bottom",
272
- scrollEnd = "top top",
273
- dustParticles = { enabled: false },
274
- mist = { enabled: false },
275
- pulse = { enabled: false }
276
- }) => {
277
- const elementRef = useRef(null);
278
- const { isDarkmode } = useIsDarkmode();
279
- const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;
280
- const colorRef = useRef(chosenColor);
281
- const invertRef = useRef(invert);
282
- const maskByProgressRef = useRef(maskLightByProgress);
283
- const scrollTriggerRef = useRef(null);
284
- useEffect(() => {
285
- colorRef.current = chosenColor;
286
- if (elementRef.current) {
287
- elementRef.current.style.setProperty("--beam-color", chosenColor);
288
- }
289
- }, [chosenColor, colorLightmode, colorDarkmode]);
290
- useEffect(() => {
291
- const prevInvert = invertRef.current;
292
- invertRef.current = invert;
293
- if (prevInvert !== invert && scrollTriggerRef.current && elementRef.current) {
294
- const st = scrollTriggerRef.current;
295
- elementRef.current;
296
- st.refresh();
297
- }
298
- }, [invert]);
299
- useEffect(() => {
300
- const prevMaskByProgress = maskByProgressRef.current;
301
- maskByProgressRef.current = maskLightByProgress;
302
- if (prevMaskByProgress !== maskLightByProgress && elementRef.current) {
303
- const element = elementRef.current;
304
- if (maskLightByProgress) {
305
- element.style.setProperty("--beam-mask-stop", "50%");
306
- element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
307
- element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
308
- } else {
309
- element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
310
- element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
311
- }
312
- if (scrollTriggerRef.current) {
313
- scrollTriggerRef.current.refresh();
314
- }
315
- }
316
- }, [maskLightByProgress]);
317
- useEffect(() => {
318
- onLoaded && onLoaded();
319
- }, []);
320
- useGSAP(
321
- () => {
322
- const element = elementRef.current;
323
- if (!element || typeof window === "undefined") return;
324
- const opacityMin = 0.839322;
325
- const opacityRange = 0.160678;
326
- const updateColorVar = (color) => {
327
- element.style.setProperty("--beam-color", color);
328
- };
329
- const initGradientStructure = (color) => {
330
- updateColorVar(color);
331
- const baseGradient = `conic-gradient(from 90deg at var(--beam-left-pos) 0%, var(--beam-color), transparent 180deg) 0% 0% / 50% var(--beam-left-size) no-repeat, conic-gradient(from 270deg at var(--beam-right-pos) 0%, transparent 180deg, var(--beam-color)) 100% 0% / 50% 100% no-repeat`;
332
- element.style.background = baseGradient;
333
- if (maskByProgressRef.current) {
334
- element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
335
- element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
336
- } else {
337
- element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
338
- element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
339
- }
340
- };
341
- const adjustedFullWidth = 1 - fullWidth;
342
- const calculateProgress = (rawProgress) => {
343
- const normalizedPosition = Math.max(
344
- adjustedFullWidth,
345
- // Floor value (1 - fullWidth)
346
- Math.min(1, 1 - rawProgress)
347
- // Inverted GSAP progress
348
- );
349
- return invertRef.current ? normalizedPosition : 1 - normalizedPosition;
350
- };
351
- const scroller = scrollElement ? scrollElement : void 0;
352
- const applyProgressState = (progress) => {
353
- const leftPos = 90 - progress * 90;
354
- const rightPos = 10 + progress * 90;
355
- const leftSize = 150 - progress * 50;
356
- const baseOpacity = opacityMin + opacityRange * progress;
357
- const maskStop = maskByProgressRef.current ? 50 + progress * 45 : void 0;
358
- const cssProps = {
359
- "--beam-left-pos": `${leftPos}%`,
360
- "--beam-right-pos": `${rightPos}%`,
361
- "--beam-left-size": `${leftSize}%`,
362
- "--base-opacity": baseOpacity
363
- };
364
- if (maskStop !== void 0) {
365
- cssProps["--beam-mask-stop"] = `${maskStop}%`;
366
- }
367
- if (!pulse.enabled) {
368
- cssProps.opacity = baseOpacity;
369
- }
370
- gsap3.set(element, cssProps);
371
- };
372
- initGradientStructure(colorRef.current);
373
- const st = ScrollTrigger.create({
374
- trigger: element,
375
- start: scrollStart,
376
- // When to start the animation
377
- end: scrollEnd,
378
- // When to end the animation
379
- scroller,
380
- scrub: 0.15,
381
- // Fast catch-up (300ms) for responsive scroll without jitter
382
- onUpdate: (self) => {
383
- const progress = calculateProgress(self.progress);
384
- applyProgressState(progress);
385
- },
386
- onRefresh: (self) => {
387
- const progress = calculateProgress(self.progress);
388
- applyProgressState(progress);
389
- }
390
- });
391
- scrollTriggerRef.current = st;
392
- const initialProgress = calculateProgress(st.progress);
393
- applyProgressState(initialProgress);
394
- const refreshTimeout = setTimeout(() => {
395
- ScrollTrigger.refresh();
396
- }, 100);
397
- return () => {
398
- st.kill();
399
- clearTimeout(refreshTimeout);
400
- };
401
- },
402
- {
403
- // CRITICAL: Use refs for frequently changing values!
404
- // colorRef, invertRef, maskByProgressRef allow updates without recreating ScrollTrigger
405
- // This prevents visual glitches when these values change mid-scroll
406
- // Only include values that affect ScrollTrigger's position/range calculations
407
- dependencies: [
408
- fullWidth,
409
- // Affects progress range calculation
410
- scrollElement,
411
- // Affects which element to watch
412
- scrollStart,
413
- // Affects when animation starts
414
- scrollEnd
415
- // Affects when animation ends
416
- ],
417
- scope: elementRef
418
- }
419
- );
420
- const combinedClassName = `react-light-beam ${className || ""}`.trim();
421
- const finalStyles = disableDefaultStyles ? {
422
- // No default styles, only user styles
423
- willChange: "background, opacity",
424
- contain: "layout style paint",
425
- ...style
426
- // User styles override
427
- } : {
428
- // Merge default styles with user styles
429
- ...defaultStyles,
430
- ...style
431
- // User styles override everything
432
- };
433
- return /* @__PURE__ */ jsxs(
434
- "div",
435
- {
436
- ref: elementRef,
437
- className: combinedClassName,
438
- style: finalStyles,
439
- ...id ? { id } : {},
440
- children: [
441
- dustParticles.enabled && /* @__PURE__ */ jsx(DustParticles, { config: dustParticles, beamColor: chosenColor }),
442
- mist.enabled && /* @__PURE__ */ jsx(MistEffect, { config: mist, beamColor: chosenColor }),
443
- pulse.enabled && /* @__PURE__ */ jsx(PulseEffect, { config: pulse, containerRef: elementRef })
444
- ]
445
- }
446
- );
447
- };
448
-
449
- export { LightBeam };
450
- //# sourceMappingURL=index.mjs.map