lazy-vfx 1.0.0

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/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # ☄️ Lazy VFX
2
+
3
+ _Effortless high-end visual effects for the modern web, built for React & Three.js_
4
+
5
+ Lazy VFX is a minimal, shader-driven VFX engine designed for modern web apps using React and Three.js. It abstracts away all the math and plumbing for emitters, GPU-accelerated particles, and real-time shaders, so you can stay focused on building cinematic, interactive experiences.
6
+
7
+
8
+ [Live demo](#) - [Fireworks demo](#) - [Wizard Game demo](#)
9
+
10
+ ---
11
+
12
+ ## ✨ Features
13
+
14
+ - **Modular Emitters** &mdash; Create and control particle sources with flexible settings using `<VFXEmitter>`.
15
+ - **Custom GLSL Shaders** &mdash; GPU-accelerated with built-in vertex & fragment shaders, easily extensible for custom magic.
16
+ - **Centralized State** &mdash; Driven by a single VFXStore for consistent, live-reloadable scene effects and controls.
17
+ - **Fast Tooling** &mdash; Zero-config Vite setup, instant HMR, rapid production deployments.
18
+ - **Leva Controls** &mdash; Out-of-the-box UI for tuning and exporting effects.
19
+
20
+ ---
21
+
22
+ ## 🚀 Quick Install
23
+
24
+ Use your favorite package manager:
25
+
26
+ ```bash
27
+ # With pnpm
28
+ pnpm add lazy-vfx
29
+
30
+ # Or npm
31
+ npm install lazy-vfx
32
+
33
+ # Or yarn
34
+ yarn add lazy-vfx
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 🛠️ Usage Example
40
+
41
+ **Lazy VFX uses a two-component system:**
42
+
43
+ - **VFXParticles:** Defines the particle system and its rendering properties
44
+ - **VFXEmitter:** Controls how and when particles are emitted into the scene
45
+
46
+
47
+ Add cinematic particles in seconds to any [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) scene:
48
+
49
+ ```jsx
50
+ import { VFXParticals, VFXEmitter } from 'lazy-vfx';
51
+ // Also import your alphaMap or use a texture
52
+
53
+ function Experience() {
54
+ return (
55
+ <>
56
+ {/* Step 1: Define your particle system */}
57
+ <VFXParticles
58
+ name="particles" // A unique identifier for this particle system
59
+ settings={{
60
+ nbParticles: 100000, // Maximum number of particles to allocate
61
+ gravity: [0, -9.8, 0], // Apply gravity (x, y, z)
62
+ fadeSize: [0, 0], // Size fade in/out settings
63
+ fadeAlpha: [0, 0], // Opacity fade in/out settings
64
+ renderMode: "billboard", // "billboard" or "mesh" or "stretchBillboard"
65
+ intensity: 3, // Brightness multiplier
66
+ appearance: AppearanceMode.Circular, // Define the default appearance to be plane (default) or circular
67
+ easeFunction: "easeLinear", // add easing to the particle animations
68
+ }}
69
+ />
70
+
71
+ {/* Step 2: Define your emitter */}
72
+ <VFXEmitter
73
+ debug // Show debug visualization
74
+ emitter="particles" // Target the particle system by name
75
+ settings={{
76
+ loop: true, // Continuously emit particles (only if `spawnMode` is 'time')
77
+ duration: 1, // Emission cycle duration in seconds
78
+ nbParticles: 100, // Number of particles to emit per cycle
79
+ spawnMode: "time", // Emission mode: 'time' or 'burst'
80
+ delay: 0, // Time delay before starting emission
81
+
82
+ // Particle lifetime range [min, max]
83
+ particlesLifetime: [0.1, 1],
84
+
85
+ // Position range (min/max)
86
+ startPositionMin: [-0.1, -0.1, -0.1],
87
+ startPositionMax: [0.1, 0.1, 0.1],
88
+
89
+ // Rotation range (min/max)
90
+ startRotationMin: [0, 0, 0],
91
+ startRotationMax: [0, 0, 0],
92
+ // Rotation speed range (min/max)
93
+ rotationSpeedMin: [0, 0, 0],
94
+ rotationSpeedMax: [0, 0, 0],
95
+
96
+ // Direction range (min/max)
97
+ directionMin: [-1, 0, -1],
98
+ directionMax: [1, 1, 1],
99
+
100
+ // Particle size range [min, max]
101
+ size: [0.01, 0.25],
102
+
103
+ // Particle speed range [min, max]
104
+ speed: [1, 12],
105
+
106
+ // Color at start - an array of strings for random selection
107
+ colorStart: ["white", "skyblue"],
108
+
109
+ // Color at end - an array of strings for random selection
110
+ colorEnd: ["white", "pink"],
111
+
112
+ // When true, the emitter will emit particles using its local axes (transformed by its world rotation)
113
+ useLocalDirection: true,
114
+ }}
115
+ />
116
+ </>
117
+ );
118
+ }
119
+ ```
120
+ ---
121
+
122
+ ## Custom Geometry Example
123
+
124
+ You can use custom geometries for your particles:
125
+
126
+ ```jsx
127
+ import { useGLTF } from '@react-three/drei';
128
+
129
+ const CustomParticles = () => {
130
+ // Load the GLTF model. Make sure the path to your .glb file is correct.
131
+ const { nodes } = useGLTF('/models/sword.glb');
132
+
133
+ return (
134
+ <>
135
+ <VFXParticles
136
+ name="swords"
137
+ geometry={nodes?.Sword?.geometry ? <primitive object={nodes.Sword.geometry} /> : null}
138
+ settings={{
139
+ nbParticles: 1000,
140
+ renderMode: "mesh",
141
+ intensity: 2,
142
+ }}
143
+ />
144
+
145
+ <VFXEmitter
146
+ emitter="swords"
147
+ settings={{
148
+ spawnMode: "burst",
149
+ nbParticles: 100,
150
+ // Add any other emitter settings as needed
151
+ }}
152
+ />
153
+ </>
154
+ );
155
+ };
156
+ ```
157
+
158
+ **Note:**
159
+ - Ensure the GLTF file at `/models/sword.glb` has a node named `Sword`.
160
+ - If your model's node hierarchy is different, adjust `nodes.Sword.geometry` accordingly.
161
+
162
+ ## API Reference
163
+
164
+ ### VFXParticles Component
165
+
166
+ | Property | Type | Description |
167
+ |-------------|-------------------|-----------------------------------------------------|
168
+ | name | string | Unique identifier for this particle system |
169
+ | settings | object | Configuration options for particles |
170
+ | alphaMap | THREE.Texture | Optional texture for particle alpha/transparency |
171
+ | geometry | ReactElement | Optional custom geometry for particles |
172
+
173
+ #### VFXParticles Settings
174
+
175
+ | Setting | Type | Default | Description |
176
+ |-----------------|------------------------------|-----------------|--------------------------------------------------------------------------|
177
+ | nbParticles | number | 1000 | Maximum number of particles |
178
+ | intensity | number | 1 | Brightness multiplier |
179
+ | renderMode | 'billboard' \| 'mesh' \| 'stretchBillboard' | 'mesh' | How particles are rendered |
180
+ | stretchScale | number | 1.0 | Stretch factor for stretchBillboard mode |
181
+ | fadeSize | [number, number] | [0.1, 0.9] | Size fade in/out range (0-1 of lifetime) |
182
+ | fadeAlpha | [number, number] | [0, 1.0] | Opacity fade in/out range |
183
+ | gravity | [number, number, number] | [0, 0, 0] | Gravity force applied to particles |
184
+ | frustumCulled | boolean | true | Whether particles are frustum culled |
185
+ | appearance | AppearanceMode | Square | Particle appearance (Square or Circular) |
186
+ | easeFunction | EaseFunction | 'easeLinear' | Easing function for particle animations |
187
+ | blendingMode | THREE.Blending | AdditiveBlending| How particles blend with the scene |
188
+ | shadingHooks | object | {} | Custom GLSL shader hooks for advanced rendering effects |
189
+
190
+ ---
191
+
192
+ ### VFXEmitter Component
193
+
194
+ | Property | Type | Description |
195
+ |---------------|-----------|-----------------------------------------------------|
196
+ | emitter | string | Name of the target particle system |
197
+ | settings | object | Configuration options for emission behavior |
198
+ | debug | boolean | Show Leva controls to adjust settings |
199
+ | autoStart | boolean | Automatically start emitting |
200
+ | localDirection| boolean | Use emitter's local space for directions |
201
+
202
+ #### VFXEmitter Settings
203
+
204
+ | Setting | Type | Default | Description |
205
+ |---------------------|-----------------------------|---------------------------|-----------------------------------------------------|
206
+ | loop | boolean | true | Continuously emit particles |
207
+ | duration | number | 1 | Emission cycle duration in seconds |
208
+ | nbParticles | number | 100 | Number of particles to emit per cycle |
209
+ | spawnMode | 'time' \| 'burst' | 'time' | How particles are spawned |
210
+ | delay | number | 0 | Time delay before starting emission |
211
+ | particlesLifetime | [number, number] | [0.1, 1] | Particle lifetime range [min, max] |
212
+ | startPositionMin | [number, number, number] | [-0.1, -0.1, -0.1] | Minimum start position |
213
+ | startPositionMax | [number, number, number] | [0.1, 0.1, 0.1] | Maximum start position |
214
+ | startRotationMin | [number, number, number] | [0, 0, 0] | Minimum start rotation |
215
+ | startRotationMax | [number, number, number] | [0, 0, 0] | Maximum start rotation |
216
+ | rotationSpeedMin | [number, number, number] | [0, 0, 0] | Minimum rotation speed |
217
+ | rotationSpeedMax | [number, number, number] | [0, 0, 0] | Maximum rotation speed |
218
+ | directionMin | [number, number, number] | [-1, 0, -1] | Minimum emission direction |
219
+ | directionMax | [number, number, number] | [1, 1, 1] | Maximum emission direction |
220
+ | size | [number, number] | [0.01, 0.25] | Particle size range [min, max] |
221
+ | speed | [number, number] | [1, 12] | Particle speed range [min, max] |
222
+ | colorStart | string[] | ['white'] | Colors at start (randomly selected) |
223
+ | colorEnd | string[] | ['white'] | Colors at end (randomly selected) |
224
+ | useLocalDirection | boolean | false | Use emitter's local space for directions |
225
+
226
+ ---
227
+
228
+
229
+ ## 📄 License
230
+
231
+ MIT © [Dev-Sameerkhan](https://github.com/Dev-Sameer-Khan)
Binary file
@@ -0,0 +1,834 @@
1
+ import ye, { useRef as D, useEffect as ge, forwardRef as Re, useState as Ee, useImperativeHandle as Pe, useCallback as Ae, useMemo as be } from "react";
2
+ import { create as he } from "zustand";
3
+ import { useFrame as Se } from "@react-three/fiber";
4
+ import * as p from "three";
5
+ import { useControls as ae, button as ie, folder as Q } from "leva";
6
+ var Z = { exports: {} }, J = {};
7
+ /**
8
+ * @license React
9
+ * react-jsx-runtime.production.js
10
+ *
11
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
12
+ *
13
+ * This source code is licensed under the MIT license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
16
+ var se;
17
+ function _e() {
18
+ if (se) return J;
19
+ se = 1;
20
+ var n = Symbol.for("react.transitional.element"), g = Symbol.for("react.fragment");
21
+ function l(o, r, a) {
22
+ var E = null;
23
+ if (a !== void 0 && (E = "" + a), r.key !== void 0 && (E = "" + r.key), "key" in r) {
24
+ a = {};
25
+ for (var c in r)
26
+ c !== "key" && (a[c] = r[c]);
27
+ } else a = r;
28
+ return r = a.ref, {
29
+ $$typeof: n,
30
+ type: o,
31
+ key: E,
32
+ ref: r !== void 0 ? r : null,
33
+ props: a
34
+ };
35
+ }
36
+ return J.Fragment = g, J.jsx = l, J.jsxs = l, J;
37
+ }
38
+ var q = {};
39
+ /**
40
+ * @license React
41
+ * react-jsx-runtime.development.js
42
+ *
43
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
44
+ *
45
+ * This source code is licensed under the MIT license found in the
46
+ * LICENSE file in the root directory of this source tree.
47
+ */
48
+ var ce;
49
+ function we() {
50
+ return ce || (ce = 1, process.env.NODE_ENV !== "production" && (function() {
51
+ function n(e) {
52
+ if (e == null) return null;
53
+ if (typeof e == "function")
54
+ return e.$$typeof === C ? null : e.displayName || e.name || null;
55
+ if (typeof e == "string") return e;
56
+ switch (e) {
57
+ case _:
58
+ return "Fragment";
59
+ case z:
60
+ return "Profiler";
61
+ case F:
62
+ return "StrictMode";
63
+ case f:
64
+ return "Suspense";
65
+ case B:
66
+ return "SuspenseList";
67
+ case T:
68
+ return "Activity";
69
+ }
70
+ if (typeof e == "object")
71
+ switch (typeof e.tag == "number" && console.error(
72
+ "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
73
+ ), e.$$typeof) {
74
+ case h:
75
+ return "Portal";
76
+ case w:
77
+ return e.displayName || "Context";
78
+ case N:
79
+ return (e._context.displayName || "Context") + ".Consumer";
80
+ case S:
81
+ var t = e.render;
82
+ return e = e.displayName, e || (e = t.displayName || t.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
83
+ case X:
84
+ return t = e.displayName || null, t !== null ? t : n(e.type) || "Memo";
85
+ case A:
86
+ t = e._payload, e = e._init;
87
+ try {
88
+ return n(e(t));
89
+ } catch {
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ function g(e) {
95
+ return "" + e;
96
+ }
97
+ function l(e) {
98
+ try {
99
+ g(e);
100
+ var t = !1;
101
+ } catch {
102
+ t = !0;
103
+ }
104
+ if (t) {
105
+ t = console;
106
+ var u = t.error, m = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
107
+ return u.call(
108
+ t,
109
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
110
+ m
111
+ ), g(e);
112
+ }
113
+ }
114
+ function o(e) {
115
+ if (e === _) return "<>";
116
+ if (typeof e == "object" && e !== null && e.$$typeof === A)
117
+ return "<...>";
118
+ try {
119
+ var t = n(e);
120
+ return t ? "<" + t + ">" : "<...>";
121
+ } catch {
122
+ return "<...>";
123
+ }
124
+ }
125
+ function r() {
126
+ var e = L.A;
127
+ return e === null ? null : e.getOwner();
128
+ }
129
+ function a() {
130
+ return Error("react-stack-top-frame");
131
+ }
132
+ function E(e) {
133
+ if (I.call(e, "key")) {
134
+ var t = Object.getOwnPropertyDescriptor(e, "key").get;
135
+ if (t && t.isReactWarning) return !1;
136
+ }
137
+ return e.key !== void 0;
138
+ }
139
+ function c(e, t) {
140
+ function u() {
141
+ V || (V = !0, console.error(
142
+ "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
143
+ t
144
+ ));
145
+ }
146
+ u.isReactWarning = !0, Object.defineProperty(e, "key", {
147
+ get: u,
148
+ configurable: !0
149
+ });
150
+ }
151
+ function M() {
152
+ var e = n(this.type);
153
+ return W[e] || (W[e] = !0, console.error(
154
+ "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
155
+ )), e = this.props.ref, e !== void 0 ? e : null;
156
+ }
157
+ function P(e, t, u, m, H, te) {
158
+ var v = u.ref;
159
+ return e = {
160
+ $$typeof: y,
161
+ type: e,
162
+ key: t,
163
+ props: u,
164
+ _owner: m
165
+ }, (v !== void 0 ? v : null) !== null ? Object.defineProperty(e, "ref", {
166
+ enumerable: !1,
167
+ get: M
168
+ }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
169
+ configurable: !1,
170
+ enumerable: !1,
171
+ writable: !0,
172
+ value: 0
173
+ }), Object.defineProperty(e, "_debugInfo", {
174
+ configurable: !1,
175
+ enumerable: !1,
176
+ writable: !0,
177
+ value: null
178
+ }), Object.defineProperty(e, "_debugStack", {
179
+ configurable: !1,
180
+ enumerable: !1,
181
+ writable: !0,
182
+ value: H
183
+ }), Object.defineProperty(e, "_debugTask", {
184
+ configurable: !1,
185
+ enumerable: !1,
186
+ writable: !0,
187
+ value: te
188
+ }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
189
+ }
190
+ function d(e, t, u, m, H, te) {
191
+ var v = t.children;
192
+ if (v !== void 0)
193
+ if (m)
194
+ if (U(v)) {
195
+ for (m = 0; m < v.length; m++)
196
+ i(v[m]);
197
+ Object.freeze && Object.freeze(v);
198
+ } else
199
+ console.error(
200
+ "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
201
+ );
202
+ else i(v);
203
+ if (I.call(t, "key")) {
204
+ v = n(e);
205
+ var $ = Object.keys(t).filter(function(xe) {
206
+ return xe !== "key";
207
+ });
208
+ m = 0 < $.length ? "{key: someKey, " + $.join(": ..., ") + ": ...}" : "{key: someKey}", k[v + m] || ($ = 0 < $.length ? "{" + $.join(": ..., ") + ": ...}" : "{}", console.error(
209
+ `A props object containing a "key" prop is being spread into JSX:
210
+ let props = %s;
211
+ <%s {...props} />
212
+ React keys must be passed directly to JSX without using spread:
213
+ let props = %s;
214
+ <%s key={someKey} {...props} />`,
215
+ m,
216
+ v,
217
+ $,
218
+ v
219
+ ), k[v + m] = !0);
220
+ }
221
+ if (v = null, u !== void 0 && (l(u), v = "" + u), E(t) && (l(t.key), v = "" + t.key), "key" in t) {
222
+ u = {};
223
+ for (var re in t)
224
+ re !== "key" && (u[re] = t[re]);
225
+ } else u = t;
226
+ return v && c(
227
+ u,
228
+ typeof e == "function" ? e.displayName || e.name || "Unknown" : e
229
+ ), P(
230
+ e,
231
+ v,
232
+ u,
233
+ r(),
234
+ H,
235
+ te
236
+ );
237
+ }
238
+ function i(e) {
239
+ x(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === A && (e._payload.status === "fulfilled" ? x(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
240
+ }
241
+ function x(e) {
242
+ return typeof e == "object" && e !== null && e.$$typeof === y;
243
+ }
244
+ var s = ye, y = Symbol.for("react.transitional.element"), h = Symbol.for("react.portal"), _ = Symbol.for("react.fragment"), F = Symbol.for("react.strict_mode"), z = Symbol.for("react.profiler"), N = Symbol.for("react.consumer"), w = Symbol.for("react.context"), S = Symbol.for("react.forward_ref"), f = Symbol.for("react.suspense"), B = Symbol.for("react.suspense_list"), X = Symbol.for("react.memo"), A = Symbol.for("react.lazy"), T = Symbol.for("react.activity"), C = Symbol.for("react.client.reference"), L = s.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, I = Object.prototype.hasOwnProperty, U = Array.isArray, Y = console.createTask ? console.createTask : function() {
245
+ return null;
246
+ };
247
+ s = {
248
+ react_stack_bottom_frame: function(e) {
249
+ return e();
250
+ }
251
+ };
252
+ var V, W = {}, O = s.react_stack_bottom_frame.bind(
253
+ s,
254
+ a
255
+ )(), G = Y(o(a)), k = {};
256
+ q.Fragment = _, q.jsx = function(e, t, u) {
257
+ var m = 1e4 > L.recentlyCreatedOwnerStacks++;
258
+ return d(
259
+ e,
260
+ t,
261
+ u,
262
+ !1,
263
+ m ? Error("react-stack-top-frame") : O,
264
+ m ? Y(o(e)) : G
265
+ );
266
+ }, q.jsxs = function(e, t, u) {
267
+ var m = 1e4 > L.recentlyCreatedOwnerStacks++;
268
+ return d(
269
+ e,
270
+ t,
271
+ u,
272
+ !0,
273
+ m ? Error("react-stack-top-frame") : O,
274
+ m ? Y(o(e)) : G
275
+ );
276
+ };
277
+ })()), q;
278
+ }
279
+ var le;
280
+ function Me() {
281
+ return le || (le = 1, process.env.NODE_ENV === "production" ? Z.exports = _e() : Z.exports = we()), Z.exports;
282
+ }
283
+ var R = Me();
284
+ const oe = he((n, g) => ({
285
+ emitters: {},
286
+ registerEmitter: (l, o) => {
287
+ if (g().emitters[l]) {
288
+ console.warn(`Emitter ${l} already exists`);
289
+ return;
290
+ }
291
+ n((r) => (r.emitters[l] = o, r));
292
+ },
293
+ unregisterEmitter: (l) => {
294
+ n((o) => (delete o.emitters[l], o));
295
+ },
296
+ emit: (l, ...o) => {
297
+ const r = g().emitters[l];
298
+ if (!r) {
299
+ console.warn(`Emitter ${l} not found`);
300
+ return;
301
+ }
302
+ r(...o);
303
+ }
304
+ }));
305
+ function ue(n, g) {
306
+ return n + Math.floor(Math.random() * (g - n + 1));
307
+ }
308
+ function b(n, g) {
309
+ return n + Math.random() * (g - n);
310
+ }
311
+ const Te = ({ settings: n, onChange: g, onRestart: l }) => {
312
+ ae("⚙️ Emitter Settings", {
313
+ Restart: ie(() => l()),
314
+ Export: ie(() => {
315
+ const c = JSON.stringify(E.current);
316
+ console.log("📋 Values saved to clipboard: ", c), navigator.clipboard.writeText(c);
317
+ })
318
+ });
319
+ const [{ ...o }, r] = ae(() => ({
320
+ "🪄 Emitter": Q({
321
+ duration: 4,
322
+ delay: 0,
323
+ nbParticles: 2e3,
324
+ spawnMode: {
325
+ options: ["time", "burst"],
326
+ value: "time"
327
+ },
328
+ loop: !1,
329
+ startPositionMin: {
330
+ value: [-1, -1, -1],
331
+ min: -10,
332
+ max: 10,
333
+ step: 0.1,
334
+ label: "startPositionMin"
335
+ },
336
+ startPositionMax: {
337
+ value: [1, 1, 1],
338
+ min: -10,
339
+ max: 10,
340
+ step: 0.1,
341
+ label: "startPositionMax"
342
+ },
343
+ startRotationMin: {
344
+ value: [0, 0, 0],
345
+ min: -Math.PI * 2,
346
+ max: Math.PI * 2,
347
+ step: 0.1,
348
+ label: "startRotationMin"
349
+ },
350
+ startRotationMax: {
351
+ value: [0, 0, 0],
352
+ min: -Math.PI * 2,
353
+ max: Math.PI * 2,
354
+ step: 0.1,
355
+ label: "startRotationMax"
356
+ }
357
+ }),
358
+ "✨ Particles": Q({
359
+ particlesLifetime: {
360
+ value: [0.1, 1],
361
+ min: 0,
362
+ max: 10,
363
+ step: 0.1,
364
+ label: "lifetime"
365
+ }
366
+ }),
367
+ "🌪 Forces": Q({
368
+ speed: {
369
+ value: [5, 20],
370
+ min: -100,
371
+ max: 100
372
+ },
373
+ directionMin: {
374
+ value: [-1, -1, -1],
375
+ min: -1,
376
+ max: 1,
377
+ step: 0.1
378
+ },
379
+ directionMax: {
380
+ value: [1, 1, 1],
381
+ min: -1,
382
+ max: 1,
383
+ step: 0.1
384
+ },
385
+ rotationSpeedMin: {
386
+ value: [0, 0, 0],
387
+ min: 0,
388
+ max: 10,
389
+ step: 0.1
390
+ },
391
+ rotationSpeedMax: {
392
+ value: [0, 0, 0],
393
+ min: 0,
394
+ max: 10,
395
+ step: 0.1
396
+ }
397
+ }),
398
+ "🎨 Appearance": Q({
399
+ nbColors: {
400
+ options: [1, 2, 3]
401
+ },
402
+ colorStart: "#ffffff",
403
+ colorEnd: "#ffffff",
404
+ colorStart2: {
405
+ value: "#ff0000",
406
+ render: (c) => c("🎨 Appearance.nbColors") > 1
407
+ },
408
+ colorEnd2: {
409
+ value: "#ffffff",
410
+ render: (c) => c("🎨 Appearance.nbColors") > 1
411
+ },
412
+ colorStart3: {
413
+ value: "#ff0000",
414
+ render: (c) => c("🎨 Appearance.nbColors") > 2
415
+ },
416
+ colorEnd3: {
417
+ value: "#ff0000",
418
+ render: (c) => c("🎨 Appearance.nbColors") > 2
419
+ },
420
+ size: {
421
+ value: [0.01, 1],
422
+ min: 0,
423
+ max: 5,
424
+ step: 0.01,
425
+ label: "size"
426
+ }
427
+ })
428
+ })), a = {
429
+ ...o,
430
+ colorStart: [o.colorStart],
431
+ colorEnd: [o.colorEnd]
432
+ };
433
+ delete a.nbColors, delete a.colorStart2, delete a.colorEnd2, delete a.colorStart3, delete a.colorEnd3, o.nbColors > 1 && a.colorStart.push(o.colorStart2), o.nbColors > 1 && a.colorEnd.push(o.colorEnd2), o.nbColors > 2 && a.colorStart.push(o.colorStart3), o.nbColors > 2 && a.colorEnd.push(o.colorEnd3);
434
+ const E = D(a);
435
+ E.current = a, ge(() => {
436
+ var c, M;
437
+ if (n) {
438
+ const P = {
439
+ ...n
440
+ };
441
+ for (let d = 0; d < 2; d++)
442
+ ((c = n.colorStart) == null ? void 0 : c.length) > d && (P[d === 0 ? "colorStart" : `colorStart${d + 1}`] = n.colorStart[d], P.nbColors = d + 1), ((M = n.colorEnd) == null ? void 0 : M.length) > d && (P[d === 0 ? "colorEnd" : `colorEnd${d + 1}`] = n.colorEnd[d]);
443
+ r({
444
+ ...P
445
+ });
446
+ }
447
+ }, [n]), g(a);
448
+ }, K = new p.Vector3(), ne = new p.Quaternion(), Ce = new p.Euler(), ee = new p.Euler(), Oe = new p.Vector3(), Le = Re(
449
+ ({ debug: n = !1, emitter: g, settings: l = {}, ...o }, r) => {
450
+ const [{
451
+ duration: a = 1,
452
+ nParticles: E = 1e3,
453
+ spawnMode: c = "time",
454
+ // time, burst
455
+ loop: M = !1,
456
+ delay: P = 0,
457
+ colorStart: d = ["white", "skyblue"],
458
+ colorEnd: i = [],
459
+ particlesLifetime: x = [0.1, 1],
460
+ speed: s = [5, 20],
461
+ size: y = [0.1, 1],
462
+ startPositionMin: h = [-1, -1, -1],
463
+ startPositionMax: _ = [1, 1, 1],
464
+ startRotationMin: F = [0, 0, 0],
465
+ startRotationMax: z = [0, 0, 0],
466
+ rotationSpeedMin: N = [0, 0, 0],
467
+ rotationSpeedMax: w = [0, 0, 0],
468
+ directionMin: S = [0, 0, 0],
469
+ directionMax: f = [0, 0, 0]
470
+ }, B] = Ee(l), X = oe((U) => U.emit), A = D();
471
+ Pe(r, () => A.current);
472
+ const T = D(0), C = D(0);
473
+ Se(({ clock: U }, Y) => {
474
+ const V = U.elapsedTime;
475
+ if (C.current < E || M) {
476
+ if (!A)
477
+ return;
478
+ const O = (c === "burst" ? E : Math.max(
479
+ 0,
480
+ Math.floor(
481
+ (T.current - P) / a * E
482
+ )
483
+ )) - C.current;
484
+ O > 0 && T.current >= P && (X(g, O, () => {
485
+ A.current.updateWorldMatrix(!0), A.current.matrixWorld.decompose(K, ne, Oe), Ce.setFromQuaternion(ne), ee.setFromQuaternion(ne);
486
+ const k = b(y[0], y[1]), e = d[ue(0, d.length - 1)];
487
+ return {
488
+ position: [
489
+ K.x + b(h[0], _[0]),
490
+ K.y + b(h[1], _[1]),
491
+ K.z + b(h[2], _[2])
492
+ ],
493
+ direction: [
494
+ b(S[0], f[0]),
495
+ b(S[1], f[1]),
496
+ b(S[2], f[2])
497
+ ],
498
+ scale: [k, k, k],
499
+ rotation: [
500
+ ee.x + b(F[0], z[0]),
501
+ ee.y + b(F[1], z[1]),
502
+ ee.z + b(F[2], z[2])
503
+ ],
504
+ rotationSpeed: [
505
+ b(N[0], w[0]),
506
+ b(N[1], w[1]),
507
+ b(N[2], w[2])
508
+ ],
509
+ lifetime: [
510
+ V,
511
+ b(x[0], x[1])
512
+ ],
513
+ colorStart: e,
514
+ colorEnd: i != null && i.length ? i[ue(0, i.length - 1)] : e,
515
+ speed: [b(s[0], s[1])]
516
+ };
517
+ }), C.current += O);
518
+ }
519
+ T.current += Y;
520
+ });
521
+ const L = Ae(() => {
522
+ C.current = 0, T.current = 0;
523
+ }, []), I = be(
524
+ () => n ? /* @__PURE__ */ R.jsx(
525
+ Te,
526
+ {
527
+ settings: l,
528
+ onChange: B,
529
+ onRestart: L
530
+ }
531
+ ) : null,
532
+ [n]
533
+ );
534
+ return /* @__PURE__ */ R.jsxs(R.Fragment, { children: [
535
+ I,
536
+ /* @__PURE__ */ R.jsx("object3D", { ...o, ref: A })
537
+ ] });
538
+ }
539
+ );
540
+ var ke = `varying vec2 vUv;
541
+ varying vec3 vColor;
542
+ varying vec3 vColorEnd;
543
+ varying float vProgress;
544
+
545
+ uniform float uTime;
546
+ uniform vec2 uFadeSize;
547
+ uniform vec3 uGravity;
548
+
549
+ attribute vec3 instanceColor;
550
+ attribute vec3 instanceColorEnd;
551
+ attribute vec3 instanceDirection;
552
+ attribute vec2 instanceLifetime;
553
+ attribute float instanceSpeed;
554
+ attribute vec3 instanceRotationSpeed;
555
+
556
+ mat4 rotationX(float angle) {
557
+ float s = sin(angle);
558
+ float c = cos(angle);
559
+ return mat4(
560
+ 1, 0, 0, 0,
561
+ 0, c, -s, 0,
562
+ 0, s, c, 0,
563
+ 0, 0, 0, 1
564
+ );
565
+ }
566
+
567
+ mat4 rotationY(float angle) {
568
+ float s = sin(angle);
569
+ float c = cos(angle);
570
+ return mat4(
571
+ c, 0, s, 0,
572
+ 0, 1, 0, 0,
573
+ -s, 0, c, 0,
574
+ 0, 0, 0, 1
575
+ );
576
+ }
577
+
578
+ mat4 rotationZ(float angle) {
579
+ float s = sin(angle);
580
+ float c = cos(angle);
581
+ return mat4(
582
+ c, -s, 0, 0,
583
+ s, c, 0, 0,
584
+ 0, 0, 1, 0,
585
+ 0, 0, 0, 1
586
+ );
587
+ }
588
+
589
+ vec3 billboard(vec2 v, mat4 view) {
590
+ vec3 up = vec3(view[0][1], view[1][1], view[2][1]);
591
+ vec3 right = vec3(view[0][0], view[1][0], view[2][0]);
592
+ vec3 p = right * v.x + up * v.y;
593
+ return p;
594
+ }
595
+
596
+
597
+ void main() {
598
+ float startTime = instanceLifetime.x;
599
+ float duration = instanceLifetime.y;
600
+ float age = uTime - startTime;
601
+ vProgress = age / duration;
602
+
603
+ if (vProgress < 0.0 || vProgress > 1.0) {
604
+ gl_Position = vec4(vec3(999.9), 1.0);
605
+ return;
606
+ }
607
+
608
+ float scale = smoothstep(0.0, uFadeSize.x, vProgress) * smoothstep(1.01, uFadeSize.y, vProgress);
609
+ vec3 gravity = 0.5 * uGravity * (age * age);
610
+
611
+ vec3 normalizedDirection = length(instanceDirection) > 0.0 ? normalize(instanceDirection) : vec3(0.0);
612
+ vec3 offset = normalizedDirection * age * instanceSpeed;
613
+ offset += gravity;
614
+
615
+ vec3 rotationSpeed = instanceRotationSpeed * age;
616
+ mat4 rotY = rotationY(rotationSpeed.y);
617
+ mat4 rotX = rotationX(rotationSpeed.x);
618
+ mat4 rotZ = rotationZ(rotationSpeed.z);
619
+ mat4 rotationMatrix = rotZ * rotX * rotX;
620
+
621
+ vec4 mvPosition;
622
+ #ifdef MESH_MODE
623
+ vec4 startPosition = modelMatrix * instanceMatrix * rotationMatrix * vec4(position * scale , 1.0);
624
+
625
+ vec3 instancePosition = startPosition.xyz;
626
+
627
+ vec3 finalPosition = instancePosition + offset;
628
+ mvPosition = modelViewMatrix * vec4(finalPosition, 1.0);
629
+ #endif
630
+
631
+ #ifdef BILLBOARD_MODE
632
+ vec4 localPos = vec4(position, 1.0);
633
+ localPos.xyz = billboard(position.xy, viewMatrix) * scale;
634
+
635
+ vec4 worldPos = modelMatrix * instanceMatrix * rotationMatrix * localPos;
636
+ worldPos.xyz += offset;
637
+ mvPosition = modelViewMatrix * worldPos;
638
+ #endif
639
+
640
+ gl_Position = projectionMatrix * mvPosition;
641
+
642
+ vUv = uv;
643
+ vColor = instanceColor;
644
+ vColorEnd = instanceColorEnd;
645
+ }`, je = `varying vec2 vUv;
646
+ varying vec3 vColor;
647
+ varying vec3 vColorEnd;
648
+ varying float vProgress;
649
+
650
+ uniform float uIntensity;
651
+ uniform vec2 uFadeAlpha;
652
+
653
+ uniform sampler2D uAlphaMap;
654
+
655
+ void main() {
656
+ if (vProgress < 0.0 || vProgress > 1.0) {
657
+ discard;
658
+ }
659
+ vec3 color = mix(vColor, vColorEnd, vProgress);
660
+ color *= uIntensity;
661
+
662
+ float alpha = smoothstep(0.0, uFadeAlpha.x, vProgress) * smoothstep(1.01, uFadeAlpha.y, vProgress);
663
+
664
+ #ifdef ALPHAMAP
665
+ vec4 tex = texture2D(uAlphaMap, vUv);
666
+ gl_FragColor = vec4(color, tex.a * alpha);
667
+ #else
668
+ gl_FragColor = vec4(color, alpha);
669
+ #endif
670
+ }`;
671
+ const fe = new p.Vector3(), de = new p.Euler(), me = new p.Quaternion(), ve = new p.Vector3(1, 1, 1), pe = new p.Matrix4(), j = new p.Color(), Ie = ({ name: n, settings: g = {}, alphaMap: l, geometry: o }) => {
672
+ const { nParticals: r = 1e3, intensity: a = 1, renderMode: E = "mesh", fadeSize: c = [0.1, 0.9], fadeAlpha: M = [0, 1], gravity: P = [0, 0, 0] } = g, d = new p.PlaneGeometry(), i = D(), [x] = Ee({
673
+ instanceColor: new Float32Array(r * 3),
674
+ instanceColorEnd: new Float32Array(r * 3),
675
+ instanceDirection: new Float32Array(r * 3),
676
+ instanceLifetime: new Float32Array(r * 2),
677
+ instanceSpeed: new Float32Array(r * 1),
678
+ instanceRotationSpeed: new Float32Array(r * 3)
679
+ }), s = D(0), y = D(0), h = D(!1), _ = (S, f) => {
680
+ const B = i.current.geometry.getAttribute("instanceColor"), X = i.current.geometry.getAttribute("instanceColorEnd"), A = i.current.geometry.getAttribute("instanceDirection"), T = i.current.geometry.getAttribute("instanceLifetime"), C = i.current.geometry.getAttribute("instanceSpeed"), L = i.current.geometry.getAttribute(
681
+ "instanceRotationSpeed"
682
+ );
683
+ for (let I = 0; I < S; I++) {
684
+ s.current >= r && (s.current = 0);
685
+ const {
686
+ scale: U,
687
+ rotation: Y,
688
+ rotationSpeed: V,
689
+ position: W,
690
+ direction: O,
691
+ lifetime: G,
692
+ colorStart: k,
693
+ colorEnd: e,
694
+ speed: t
695
+ } = f();
696
+ fe.set(...W), de.set(...Y), me.setFromEuler(de), ve.set(...U), pe.compose(fe, me, ve), j.set(k), j.set(e), A.set(O, s.current * 3), T.set(G, s.current * 2), C.set([t], s.current), L.set(V, s.current * 3), B.set(
697
+ [j.r, j.g, j.b],
698
+ s.current * 3
699
+ ), X.set(
700
+ [j.r, j.g, j.b],
701
+ s.current * 3
702
+ ), i.current.setMatrixAt(s.current, pe);
703
+ }
704
+ h.current = !0, s.current++, s.current = s.current % r;
705
+ }, F = () => {
706
+ if (!h.current || !i.current)
707
+ return;
708
+ [
709
+ i.current.instanceMatrix,
710
+ i.current.geometry.getAttribute("instanceColor"),
711
+ i.current.geometry.getAttribute("instanceColorEnd"),
712
+ i.current.geometry.getAttribute("instanceDirection"),
713
+ i.current.geometry.getAttribute("instanceLifetime"),
714
+ i.current.geometry.getAttribute("instanceSpeed"),
715
+ i.current.geometry.getAttribute("instanceRotationSpeed")
716
+ ].forEach((f) => {
717
+ f.clearUpdateRanges(), y.current > s.current ? (f.addUpdateRange(0, s.current * f.itemSize), f.addUpdateRange(
718
+ y.current * f.itemSize,
719
+ r * f.itemSize - y.current * f.itemSize
720
+ )) : f.addUpdateRange(
721
+ y.current * f.itemSize,
722
+ s.current * f.itemSize - y.current * f.itemSize
723
+ ), f.needsUpdate = !0;
724
+ }), y.current = s.current, h.current = !1;
725
+ }, z = oe((S) => S.registerEmitter), N = oe((S) => S.unregisterEmitter);
726
+ ge(() => (z(n, _), () => {
727
+ N(n);
728
+ }), []);
729
+ const w = be(
730
+ () => ({
731
+ uTime: { value: 0 },
732
+ uIntensity: { value: a },
733
+ uFadeSize: { value: c },
734
+ uFadeAlpha: { value: M },
735
+ uGravity: { value: P },
736
+ uAlphaMap: { value: l }
737
+ }),
738
+ []
739
+ );
740
+ return Se(({ clock: S }) => {
741
+ w && (w.uTime.value = S.elapsedTime);
742
+ }), /* @__PURE__ */ R.jsxs(
743
+ "instancedMesh",
744
+ {
745
+ ref: i,
746
+ args: [d, null, r],
747
+ onBeforeRender: F,
748
+ children: [
749
+ o,
750
+ /* @__PURE__ */ R.jsx(
751
+ "shaderMaterial",
752
+ {
753
+ uniforms: w,
754
+ vertexShader: ke,
755
+ fragmentShader: je,
756
+ blending: p.AdditiveBlending,
757
+ depthTest: !1,
758
+ depthWrite: !1,
759
+ transparent: !0,
760
+ defines: {
761
+ BILLBOARD_MODE: E === "billboard",
762
+ MESH_MODE: E === "mesh",
763
+ ALPHAMAP: !!l
764
+ }
765
+ }
766
+ ),
767
+ /* @__PURE__ */ R.jsx(
768
+ "instancedBufferAttribute",
769
+ {
770
+ attach: "geometry-attributes-instanceColor",
771
+ args: [x.instanceColor],
772
+ itemSize: 3,
773
+ count: r,
774
+ usage: p.DynamicDrawUsage
775
+ }
776
+ ),
777
+ /* @__PURE__ */ R.jsx(
778
+ "instancedBufferAttribute",
779
+ {
780
+ attach: "geometry-attributes-instanceColorEnd",
781
+ args: [x.instanceColorEnd],
782
+ itemSize: 3,
783
+ count: r,
784
+ usage: p.DynamicDrawUsage
785
+ }
786
+ ),
787
+ /* @__PURE__ */ R.jsx(
788
+ "instancedBufferAttribute",
789
+ {
790
+ attach: "geometry-attributes-instanceDirection",
791
+ args: [x.instanceDirection],
792
+ itemSize: 3,
793
+ count: r,
794
+ usage: p.DynamicDrawUsage
795
+ }
796
+ ),
797
+ /* @__PURE__ */ R.jsx(
798
+ "instancedBufferAttribute",
799
+ {
800
+ attach: "geometry-attributes-instanceLifetime",
801
+ args: [x.instanceLifetime],
802
+ itemSize: 2,
803
+ count: r,
804
+ usage: p.DynamicDrawUsage
805
+ }
806
+ ),
807
+ /* @__PURE__ */ R.jsx(
808
+ "instancedBufferAttribute",
809
+ {
810
+ attach: "geometry-attributes-instanceSpeed",
811
+ args: [x.instanceSpeed],
812
+ itemSize: 1,
813
+ count: r,
814
+ usage: p.DynamicDrawUsage
815
+ }
816
+ ),
817
+ /* @__PURE__ */ R.jsx(
818
+ "instancedBufferAttribute",
819
+ {
820
+ attach: "geometry-attributes-instanceRotationSpeed",
821
+ args: [x.instanceRotationSpeed],
822
+ itemSize: 3,
823
+ count: r,
824
+ usage: p.DynamicDrawUsage
825
+ }
826
+ )
827
+ ]
828
+ }
829
+ );
830
+ };
831
+ export {
832
+ Le as VFXEmitter,
833
+ Ie as VFXParticles
834
+ };
@@ -0,0 +1,152 @@
1
+ (function(x,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react"),require("zustand"),require("@react-three/fiber"),require("three"),require("leva")):typeof define=="function"&&define.amd?define(["exports","react","zustand","@react-three/fiber","three","leva"],u):(x=typeof globalThis<"u"?globalThis:x||self,u(x.LazyVFX={},x.React,x.zustand,x.Fiber,x.THREE,x.leva))})(this,(function(x,u,ge,ie,Ee,C){"use strict";function be(n){const d=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const a in n)if(a!=="default"){const o=Object.getOwnPropertyDescriptor(n,a);Object.defineProperty(d,a,o.get?o:{enumerable:!0,get:()=>n[a]})}}return d.default=n,Object.freeze(d)}const v=be(Ee);var q={exports:{}},G={};/**
2
+ * @license React
3
+ * react-jsx-runtime.production.js
4
+ *
5
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */var se;function Se(){if(se)return G;se=1;var n=Symbol.for("react.transitional.element"),d=Symbol.for("react.fragment");function a(o,r,i){var S=null;if(i!==void 0&&(S=""+i),r.key!==void 0&&(S=""+r.key),"key"in r){i={};for(var l in r)l!=="key"&&(i[l]=r[l])}else i=r;return r=i.ref,{$$typeof:n,type:o,key:S,ref:r!==void 0?r:null,props:i}}return G.Fragment=d,G.jsx=a,G.jsxs=a,G}var H={};/**
10
+ * @license React
11
+ * react-jsx-runtime.development.js
12
+ *
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ */var ce;function ye(){return ce||(ce=1,process.env.NODE_ENV!=="production"&&(function(){function n(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===D?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case M:return"Fragment";case L:return"Profiler";case N:return"StrictMode";case m:return"Suspense";case J:return"SuspenseList";case k:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case w:return"Portal";case T:return e.displayName||"Context";case I:return(e._context.displayName||"Context")+".Consumer";case y:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Q:return t=e.displayName||null,t!==null?t:n(e.type)||"Memo";case A:t=e._payload,e=e._init;try{return n(e(t))}catch{}}return null}function d(e){return""+e}function a(e){try{d(e);var t=!1}catch{t=!0}if(t){t=console;var f=t.error,g=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return f.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",g),d(e)}}function o(e){if(e===M)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===A)return"<...>";try{var t=n(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function r(){var e=U.A;return e===null?null:e.getOwner()}function i(){return Error("react-stack-top-frame")}function S(e){if(V.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function l(e,t){function f(){B||(B=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}f.isReactWarning=!0,Object.defineProperty(e,"key",{get:f,configurable:!0})}function j(){var e=n(this.type);return Z[e]||(Z[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function _(e,t,f,g,te,oe){var E=f.ref;return e={$$typeof:P,type:e,key:t,props:f,_owner:g},(E!==void 0?E:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:j}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:te}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:oe}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function p(e,t,f,g,te,oe){var E=t.children;if(E!==void 0)if(g)if(Y(E)){for(g=0;g<E.length;g++)s(E[g]);Object.freeze&&Object.freeze(E)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else s(E);if(V.call(t,"key")){E=n(e);var W=Object.keys(t).filter(function(Te){return Te!=="key"});g=0<W.length?"{key: someKey, "+W.join(": ..., ")+": ...}":"{key: someKey}",z[E+g]||(W=0<W.length?"{"+W.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
18
+ let props = %s;
19
+ <%s {...props} />
20
+ React keys must be passed directly to JSX without using spread:
21
+ let props = %s;
22
+ <%s key={someKey} {...props} />`,g,E,W,E),z[E+g]=!0)}if(E=null,f!==void 0&&(a(f),E=""+f),S(t)&&(a(t.key),E=""+t.key),"key"in t){f={};for(var ae in t)ae!=="key"&&(f[ae]=t[ae])}else f=t;return E&&l(f,typeof e=="function"?e.displayName||e.name||"Unknown":e),_(e,E,f,r(),te,oe)}function s(e){h(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===A&&(e._payload.status==="fulfilled"?h(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function h(e){return typeof e=="object"&&e!==null&&e.$$typeof===P}var c=u,P=Symbol.for("react.transitional.element"),w=Symbol.for("react.portal"),M=Symbol.for("react.fragment"),N=Symbol.for("react.strict_mode"),L=Symbol.for("react.profiler"),I=Symbol.for("react.consumer"),T=Symbol.for("react.context"),y=Symbol.for("react.forward_ref"),m=Symbol.for("react.suspense"),J=Symbol.for("react.suspense_list"),Q=Symbol.for("react.memo"),A=Symbol.for("react.lazy"),k=Symbol.for("react.activity"),D=Symbol.for("react.client.reference"),U=c.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,V=Object.prototype.hasOwnProperty,Y=Array.isArray,X=console.createTask?console.createTask:function(){return null};c={react_stack_bottom_frame:function(e){return e()}};var B,Z={},F=c.react_stack_bottom_frame.bind(c,i)(),K=X(o(i)),z={};H.Fragment=M,H.jsx=function(e,t,f){var g=1e4>U.recentlyCreatedOwnerStacks++;return p(e,t,f,!1,g?Error("react-stack-top-frame"):F,g?X(o(e)):K)},H.jsxs=function(e,t,f){var g=1e4>U.recentlyCreatedOwnerStacks++;return p(e,t,f,!0,g?Error("react-stack-top-frame"):F,g?X(o(e)):K)}})()),H}var le;function xe(){return le||(le=1,process.env.NODE_ENV==="production"?q.exports=Se():q.exports=ye()),q.exports}var R=xe();const re=ge.create((n,d)=>({emitters:{},registerEmitter:(a,o)=>{if(d().emitters[a]){console.warn(`Emitter ${a} already exists`);return}n(r=>(r.emitters[a]=o,r))},unregisterEmitter:a=>{n(o=>(delete o.emitters[a],o))},emit:(a,...o)=>{const r=d().emitters[a];if(!r){console.warn(`Emitter ${a} not found`);return}r(...o)}}));function ue(n,d){return n+Math.floor(Math.random()*(d-n+1))}function b(n,d){return n+Math.random()*(d-n)}const Re=({settings:n,onChange:d,onRestart:a})=>{C.useControls("⚙️ Emitter Settings",{Restart:C.button(()=>a()),Export:C.button(()=>{const l=JSON.stringify(S.current);console.log("📋 Values saved to clipboard: ",l),navigator.clipboard.writeText(l)})});const[{...o},r]=C.useControls(()=>({"🪄 Emitter":C.folder({duration:4,delay:0,nbParticles:2e3,spawnMode:{options:["time","burst"],value:"time"},loop:!1,startPositionMin:{value:[-1,-1,-1],min:-10,max:10,step:.1,label:"startPositionMin"},startPositionMax:{value:[1,1,1],min:-10,max:10,step:.1,label:"startPositionMax"},startRotationMin:{value:[0,0,0],min:-Math.PI*2,max:Math.PI*2,step:.1,label:"startRotationMin"},startRotationMax:{value:[0,0,0],min:-Math.PI*2,max:Math.PI*2,step:.1,label:"startRotationMax"}}),"✨ Particles":C.folder({particlesLifetime:{value:[.1,1],min:0,max:10,step:.1,label:"lifetime"}}),"🌪 Forces":C.folder({speed:{value:[5,20],min:-100,max:100},directionMin:{value:[-1,-1,-1],min:-1,max:1,step:.1},directionMax:{value:[1,1,1],min:-1,max:1,step:.1},rotationSpeedMin:{value:[0,0,0],min:0,max:10,step:.1},rotationSpeedMax:{value:[0,0,0],min:0,max:10,step:.1}}),"🎨 Appearance":C.folder({nbColors:{options:[1,2,3]},colorStart:"#ffffff",colorEnd:"#ffffff",colorStart2:{value:"#ff0000",render:l=>l("🎨 Appearance.nbColors")>1},colorEnd2:{value:"#ffffff",render:l=>l("🎨 Appearance.nbColors")>1},colorStart3:{value:"#ff0000",render:l=>l("🎨 Appearance.nbColors")>2},colorEnd3:{value:"#ff0000",render:l=>l("🎨 Appearance.nbColors")>2},size:{value:[.01,1],min:0,max:5,step:.01,label:"size"}})})),i={...o,colorStart:[o.colorStart],colorEnd:[o.colorEnd]};delete i.nbColors,delete i.colorStart2,delete i.colorEnd2,delete i.colorStart3,delete i.colorEnd3,o.nbColors>1&&i.colorStart.push(o.colorStart2),o.nbColors>1&&i.colorEnd.push(o.colorEnd2),o.nbColors>2&&i.colorStart.push(o.colorStart3),o.nbColors>2&&i.colorEnd.push(o.colorEnd3);const S=u.useRef(i);S.current=i,u.useEffect(()=>{var l,j;if(n){const _={...n};for(let p=0;p<2;p++)((l=n.colorStart)==null?void 0:l.length)>p&&(_[p===0?"colorStart":`colorStart${p+1}`]=n.colorStart[p],_.nbColors=p+1),((j=n.colorEnd)==null?void 0:j.length)>p&&(_[p===0?"colorEnd":`colorEnd${p+1}`]=n.colorEnd[p]);r({..._})}},[n]),d(i)},$=new v.Vector3,ne=new v.Quaternion,he=new v.Euler,ee=new v.Euler,Pe=new v.Vector3,_e=u.forwardRef(({debug:n=!1,emitter:d,settings:a={},...o},r)=>{const[{duration:i=1,nParticles:S=1e3,spawnMode:l="time",loop:j=!1,delay:_=0,colorStart:p=["white","skyblue"],colorEnd:s=[],particlesLifetime:h=[.1,1],speed:c=[5,20],size:P=[.1,1],startPositionMin:w=[-1,-1,-1],startPositionMax:M=[1,1,1],startRotationMin:N=[0,0,0],startRotationMax:L=[0,0,0],rotationSpeedMin:I=[0,0,0],rotationSpeedMax:T=[0,0,0],directionMin:y=[0,0,0],directionMax:m=[0,0,0]},J]=u.useState(a),Q=re(Y=>Y.emit),A=u.useRef();u.useImperativeHandle(r,()=>A.current);const k=u.useRef(0),D=u.useRef(0);ie.useFrame(({clock:Y},X)=>{const B=Y.elapsedTime;if(D.current<S||j){if(!A)return;const F=(l==="burst"?S:Math.max(0,Math.floor((k.current-_)/i*S)))-D.current;F>0&&k.current>=_&&(Q(d,F,()=>{A.current.updateWorldMatrix(!0),A.current.matrixWorld.decompose($,ne,Pe),he.setFromQuaternion(ne),ee.setFromQuaternion(ne);const z=b(P[0],P[1]),e=p[ue(0,p.length-1)];return{position:[$.x+b(w[0],M[0]),$.y+b(w[1],M[1]),$.z+b(w[2],M[2])],direction:[b(y[0],m[0]),b(y[1],m[1]),b(y[2],m[2])],scale:[z,z,z],rotation:[ee.x+b(N[0],L[0]),ee.y+b(N[1],L[1]),ee.z+b(N[2],L[2])],rotationSpeed:[b(I[0],T[0]),b(I[1],T[1]),b(I[2],T[2])],lifetime:[B,b(h[0],h[1])],colorStart:e,colorEnd:s!=null&&s.length?s[ue(0,s.length-1)]:e,speed:[b(c[0],c[1])]}}),D.current+=F)}k.current+=X});const U=u.useCallback(()=>{D.current=0,k.current=0},[]),V=u.useMemo(()=>n?R.jsx(Re,{settings:a,onChange:J,onRestart:U}):null,[n]);return R.jsxs(R.Fragment,{children:[V,R.jsx("object3D",{...o,ref:A})]})});var Ae=`varying vec2 vUv;
23
+ varying vec3 vColor;
24
+ varying vec3 vColorEnd;
25
+ varying float vProgress;
26
+
27
+ uniform float uTime;
28
+ uniform vec2 uFadeSize;
29
+ uniform vec3 uGravity;
30
+
31
+ attribute vec3 instanceColor;
32
+ attribute vec3 instanceColorEnd;
33
+ attribute vec3 instanceDirection;
34
+ attribute vec2 instanceLifetime;
35
+ attribute float instanceSpeed;
36
+ attribute vec3 instanceRotationSpeed;
37
+
38
+ mat4 rotationX(float angle) {
39
+ float s = sin(angle);
40
+ float c = cos(angle);
41
+ return mat4(
42
+ 1, 0, 0, 0,
43
+ 0, c, -s, 0,
44
+ 0, s, c, 0,
45
+ 0, 0, 0, 1
46
+ );
47
+ }
48
+
49
+ mat4 rotationY(float angle) {
50
+ float s = sin(angle);
51
+ float c = cos(angle);
52
+ return mat4(
53
+ c, 0, s, 0,
54
+ 0, 1, 0, 0,
55
+ -s, 0, c, 0,
56
+ 0, 0, 0, 1
57
+ );
58
+ }
59
+
60
+ mat4 rotationZ(float angle) {
61
+ float s = sin(angle);
62
+ float c = cos(angle);
63
+ return mat4(
64
+ c, -s, 0, 0,
65
+ s, c, 0, 0,
66
+ 0, 0, 1, 0,
67
+ 0, 0, 0, 1
68
+ );
69
+ }
70
+
71
+ vec3 billboard(vec2 v, mat4 view) {
72
+ vec3 up = vec3(view[0][1], view[1][1], view[2][1]);
73
+ vec3 right = vec3(view[0][0], view[1][0], view[2][0]);
74
+ vec3 p = right * v.x + up * v.y;
75
+ return p;
76
+ }
77
+
78
+
79
+ void main() {
80
+ float startTime = instanceLifetime.x;
81
+ float duration = instanceLifetime.y;
82
+ float age = uTime - startTime;
83
+ vProgress = age / duration;
84
+
85
+ if (vProgress < 0.0 || vProgress > 1.0) {
86
+ gl_Position = vec4(vec3(999.9), 1.0);
87
+ return;
88
+ }
89
+
90
+ float scale = smoothstep(0.0, uFadeSize.x, vProgress) * smoothstep(1.01, uFadeSize.y, vProgress);
91
+ vec3 gravity = 0.5 * uGravity * (age * age);
92
+
93
+ vec3 normalizedDirection = length(instanceDirection) > 0.0 ? normalize(instanceDirection) : vec3(0.0);
94
+ vec3 offset = normalizedDirection * age * instanceSpeed;
95
+ offset += gravity;
96
+
97
+ vec3 rotationSpeed = instanceRotationSpeed * age;
98
+ mat4 rotY = rotationY(rotationSpeed.y);
99
+ mat4 rotX = rotationX(rotationSpeed.x);
100
+ mat4 rotZ = rotationZ(rotationSpeed.z);
101
+ mat4 rotationMatrix = rotZ * rotX * rotX;
102
+
103
+ vec4 mvPosition;
104
+ #ifdef MESH_MODE
105
+ vec4 startPosition = modelMatrix * instanceMatrix * rotationMatrix * vec4(position * scale , 1.0);
106
+
107
+ vec3 instancePosition = startPosition.xyz;
108
+
109
+ vec3 finalPosition = instancePosition + offset;
110
+ mvPosition = modelViewMatrix * vec4(finalPosition, 1.0);
111
+ #endif
112
+
113
+ #ifdef BILLBOARD_MODE
114
+ vec4 localPos = vec4(position, 1.0);
115
+ localPos.xyz = billboard(position.xy, viewMatrix) * scale;
116
+
117
+ vec4 worldPos = modelMatrix * instanceMatrix * rotationMatrix * localPos;
118
+ worldPos.xyz += offset;
119
+ mvPosition = modelViewMatrix * worldPos;
120
+ #endif
121
+
122
+ gl_Position = projectionMatrix * mvPosition;
123
+
124
+ vUv = uv;
125
+ vColor = instanceColor;
126
+ vColorEnd = instanceColorEnd;
127
+ }`,we=`varying vec2 vUv;
128
+ varying vec3 vColor;
129
+ varying vec3 vColorEnd;
130
+ varying float vProgress;
131
+
132
+ uniform float uIntensity;
133
+ uniform vec2 uFadeAlpha;
134
+
135
+ uniform sampler2D uAlphaMap;
136
+
137
+ void main() {
138
+ if (vProgress < 0.0 || vProgress > 1.0) {
139
+ discard;
140
+ }
141
+ vec3 color = mix(vColor, vColorEnd, vProgress);
142
+ color *= uIntensity;
143
+
144
+ float alpha = smoothstep(0.0, uFadeAlpha.x, vProgress) * smoothstep(1.01, uFadeAlpha.y, vProgress);
145
+
146
+ #ifdef ALPHAMAP
147
+ vec4 tex = texture2D(uAlphaMap, vUv);
148
+ gl_FragColor = vec4(color, tex.a * alpha);
149
+ #else
150
+ gl_FragColor = vec4(color, alpha);
151
+ #endif
152
+ }`;const fe=new v.Vector3,de=new v.Euler,me=new v.Quaternion,ve=new v.Vector3(1,1,1),pe=new v.Matrix4,O=new v.Color,Me=({name:n,settings:d={},alphaMap:a,geometry:o})=>{const{nParticals:r=1e3,intensity:i=1,renderMode:S="mesh",fadeSize:l=[.1,.9],fadeAlpha:j=[0,1],gravity:_=[0,0,0]}=d,p=new v.PlaneGeometry,s=u.useRef(),[h]=u.useState({instanceColor:new Float32Array(r*3),instanceColorEnd:new Float32Array(r*3),instanceDirection:new Float32Array(r*3),instanceLifetime:new Float32Array(r*2),instanceSpeed:new Float32Array(r*1),instanceRotationSpeed:new Float32Array(r*3)}),c=u.useRef(0),P=u.useRef(0),w=u.useRef(!1),M=(y,m)=>{const J=s.current.geometry.getAttribute("instanceColor"),Q=s.current.geometry.getAttribute("instanceColorEnd"),A=s.current.geometry.getAttribute("instanceDirection"),k=s.current.geometry.getAttribute("instanceLifetime"),D=s.current.geometry.getAttribute("instanceSpeed"),U=s.current.geometry.getAttribute("instanceRotationSpeed");for(let V=0;V<y;V++){c.current>=r&&(c.current=0);const{scale:Y,rotation:X,rotationSpeed:B,position:Z,direction:F,lifetime:K,colorStart:z,colorEnd:e,speed:t}=m();fe.set(...Z),de.set(...X),me.setFromEuler(de),ve.set(...Y),pe.compose(fe,me,ve),O.set(z),O.set(e),A.set(F,c.current*3),k.set(K,c.current*2),D.set([t],c.current),U.set(B,c.current*3),J.set([O.r,O.g,O.b],c.current*3),Q.set([O.r,O.g,O.b],c.current*3),s.current.setMatrixAt(c.current,pe)}w.current=!0,c.current++,c.current=c.current%r},N=()=>{if(!w.current||!s.current)return;[s.current.instanceMatrix,s.current.geometry.getAttribute("instanceColor"),s.current.geometry.getAttribute("instanceColorEnd"),s.current.geometry.getAttribute("instanceDirection"),s.current.geometry.getAttribute("instanceLifetime"),s.current.geometry.getAttribute("instanceSpeed"),s.current.geometry.getAttribute("instanceRotationSpeed")].forEach(m=>{m.clearUpdateRanges(),P.current>c.current?(m.addUpdateRange(0,c.current*m.itemSize),m.addUpdateRange(P.current*m.itemSize,r*m.itemSize-P.current*m.itemSize)):m.addUpdateRange(P.current*m.itemSize,c.current*m.itemSize-P.current*m.itemSize),m.needsUpdate=!0}),P.current=c.current,w.current=!1},L=re(y=>y.registerEmitter),I=re(y=>y.unregisterEmitter);u.useEffect(()=>(L(n,M),()=>{I(n)}),[]);const T=u.useMemo(()=>({uTime:{value:0},uIntensity:{value:i},uFadeSize:{value:l},uFadeAlpha:{value:j},uGravity:{value:_},uAlphaMap:{value:a}}),[]);return ie.useFrame(({clock:y})=>{T&&(T.uTime.value=y.elapsedTime)}),R.jsxs("instancedMesh",{ref:s,args:[p,null,r],onBeforeRender:N,children:[o,R.jsx("shaderMaterial",{uniforms:T,vertexShader:Ae,fragmentShader:we,blending:v.AdditiveBlending,depthTest:!1,depthWrite:!1,transparent:!0,defines:{BILLBOARD_MODE:S==="billboard",MESH_MODE:S==="mesh",ALPHAMAP:!!a}}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceColor",args:[h.instanceColor],itemSize:3,count:r,usage:v.DynamicDrawUsage}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceColorEnd",args:[h.instanceColorEnd],itemSize:3,count:r,usage:v.DynamicDrawUsage}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceDirection",args:[h.instanceDirection],itemSize:3,count:r,usage:v.DynamicDrawUsage}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceLifetime",args:[h.instanceLifetime],itemSize:2,count:r,usage:v.DynamicDrawUsage}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceSpeed",args:[h.instanceSpeed],itemSize:1,count:r,usage:v.DynamicDrawUsage}),R.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceRotationSpeed",args:[h.instanceRotationSpeed],itemSize:3,count:r,usage:v.DynamicDrawUsage})]})};x.VFXEmitter=_e,x.VFXParticles=Me,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})}));
package/dist/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "lazy-vfx",
3
+ "version": "1.0.0",
4
+ "description": "Effortless high-end visual effects for React and Three.js",
5
+ "keywords": [
6
+ "react",
7
+ "three",
8
+ "react-three-fiber",
9
+ "r3f",
10
+ "vfx",
11
+ "particles",
12
+ "shaders",
13
+ "glsl",
14
+ "motion-design"
15
+ ],
16
+ "type": "module",
17
+ "main": "./dist/lazy-vfx.umd.js",
18
+ "module": "./dist/lazy-vfx.es.js",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./dist/lazy-vfx.es.js",
22
+ "require": "./dist/lazy-vfx.umd.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "dev": "vite",
30
+ "build": "vite build",
31
+ "preview": "vite preview",
32
+ "prepublishOnly": "pnpm build"
33
+ },
34
+ "peerDependencies": {
35
+ "react": ">=18.0.0",
36
+ "react-dom": ">=18.0.0",
37
+ "three": ">=0.150.0",
38
+ "@react-three/fiber": ">=8.0.0",
39
+ "@react-three/drei": ">=9.0.0"
40
+ },
41
+ "dependencies": {
42
+ "@react-three/postprocessing": "^3.0.4",
43
+ "leva": "^0.10.1",
44
+ "zustand": "^5.0.12"
45
+ },
46
+ "devDependencies": {
47
+ "@react-three/drei": "^10.7.7",
48
+ "@react-three/fiber": "^9.5.0",
49
+ "@types/react": "^19.0.10",
50
+ "@types/react-dom": "^19.0.4",
51
+ "@vitejs/plugin-react": "^4.3.4",
52
+ "globals": "^15.15.0",
53
+ "react": "^19.0.0",
54
+ "react-dom": "^19.0.0",
55
+ "three": "^0.183.2",
56
+ "vite": "^6.2.0",
57
+ "vite-plugin-glsl": "^1.5.6",
58
+ "path": "^0.12.7"
59
+ },
60
+ "author": "Sameer Khan",
61
+ "license": "MIT"
62
+ }