lazy-vfx 1.1.0 → 1.1.2
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 +98 -86
- package/dist/lazy-vfx.es.js +1 -1
- package/dist/lazy-vfx.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# ☄️ Lazy VFX
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
*Effortless high-end visual effects for the modern web, built for React & Three.js*
|
|
4
4
|
|
|
5
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
6
|
|
|
7
|
-
|
|
8
|
-
[Live demo](#) - [Fireworks demo](#) - [Wizard Game demo](#)
|
|
7
|
+
[Live demo](https://lazy-vfx.vercel.app/demo) - [Fireworks demo](#) - [Wizard Game demo](#)
|
|
9
8
|
|
|
10
9
|
---
|
|
11
10
|
|
|
@@ -43,80 +42,93 @@ yarn add lazy-vfx
|
|
|
43
42
|
- **VFXParticles:** Defines the particle system and its rendering properties
|
|
44
43
|
- **VFXEmitter:** Controls how and when particles are emitted into the scene
|
|
45
44
|
|
|
46
|
-
|
|
47
45
|
Add cinematic particles in seconds to any [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) scene:
|
|
48
46
|
|
|
49
47
|
```jsx
|
|
50
48
|
import { VFXParticals, VFXEmitter } from 'lazy-vfx';
|
|
49
|
+
import {
|
|
50
|
+
Environment,
|
|
51
|
+
OrbitControls,
|
|
52
|
+
Stats,
|
|
53
|
+
useTexture,
|
|
54
|
+
} from "@react-three/drei";
|
|
55
|
+
|
|
56
|
+
|
|
51
57
|
// Also import your alphaMap or use a texture
|
|
52
58
|
|
|
53
59
|
function Experience() {
|
|
60
|
+
const text = useTexture(
|
|
61
|
+
"https://static.thenounproject.com/png/4312916-200.png",
|
|
62
|
+
);
|
|
63
|
+
|
|
54
64
|
return (
|
|
55
65
|
<>
|
|
66
|
+
<Stats />
|
|
67
|
+
<OrbitControls enablePan={false} />
|
|
68
|
+
<Environment preset="sunset" />
|
|
69
|
+
|
|
56
70
|
{/* Step 1: Define your particle system */}
|
|
57
71
|
<VFXParticles
|
|
58
|
-
name="
|
|
72
|
+
name="sparks" // A unique identifier for this particle system
|
|
59
73
|
settings={{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
fadeSize: [0, 0], // Size fade in/out settings
|
|
63
|
-
fadeAlpha: [0, 0], // Opacity fade in/out settings
|
|
74
|
+
nParticals: 10000, // Maximum number of particles to allocate
|
|
75
|
+
intensity: 2, // Brightness multiplier
|
|
64
76
|
renderMode: "billboard", // "billboard" or "mesh" or "stretchBillboard"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
fadeAlpha: [0.5, 0.5], // Opacity fade in/out settings
|
|
78
|
+
fadeSize: [0, 0], // Size fade in/out settings
|
|
79
|
+
gravity: [0, -20, 0], // Apply gravity (x, y, z)
|
|
68
80
|
}}
|
|
81
|
+
alphaMap={text}
|
|
82
|
+
// geometry={<sphereGeometry />}
|
|
69
83
|
/>
|
|
70
84
|
|
|
71
85
|
{/* Step 2: Define your emitter */}
|
|
72
86
|
<VFXEmitter
|
|
73
87
|
debug // Show debug visualization
|
|
74
|
-
emitter="
|
|
88
|
+
emitter="sparks" // Target the particle system by name
|
|
75
89
|
settings={{
|
|
76
|
-
|
|
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'
|
|
90
|
+
duration: 4, // Emission cycle duration in seconds
|
|
80
91
|
delay: 0, // Time delay before starting emission
|
|
92
|
+
nbParticles: 10000, // Number of particles to emit per cycle
|
|
93
|
+
spawnMode: "time", // Emission mode: 'time' or 'burst'
|
|
94
|
+
loop: true, // Continuously emit particles (only if `spawnMode` is 'time')
|
|
81
95
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// Position range (min/max)
|
|
86
|
-
startPositionMin: [-0.1, -0.1, -0.1],
|
|
87
|
-
startPositionMax: [0.1, 0.1, 0.1],
|
|
96
|
+
// Position range (min/max)
|
|
97
|
+
startPositionMin: [0, 0, 0],
|
|
98
|
+
startPositionMax: [0, 0, 0],
|
|
88
99
|
|
|
89
100
|
// Rotation range (min/max)
|
|
90
101
|
startRotationMin: [0, 0, 0],
|
|
91
102
|
startRotationMax: [0, 0, 0],
|
|
92
|
-
|
|
103
|
+
// Rotation speed range (min/max)
|
|
93
104
|
rotationSpeedMin: [0, 0, 0],
|
|
94
105
|
rotationSpeedMax: [0, 0, 0],
|
|
95
106
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
directionMax: [1, 1, 1],
|
|
99
|
-
|
|
100
|
-
// Particle size range [min, max]
|
|
101
|
-
size: [0.01, 0.25],
|
|
107
|
+
// Particle lifetime range [min, max]
|
|
108
|
+
particlesLifetime: [0.1, 5],
|
|
102
109
|
|
|
103
110
|
// Particle speed range [min, max]
|
|
104
|
-
speed: [1,
|
|
111
|
+
speed: [1, 10],
|
|
105
112
|
|
|
113
|
+
// Direction range (min/max)
|
|
114
|
+
directionMin: [-0.5, 0, -0.5],
|
|
115
|
+
directionMax: [0.5, 1, 0.5],
|
|
116
|
+
|
|
106
117
|
// Color at start - an array of strings for random selection
|
|
107
|
-
colorStart: ["
|
|
118
|
+
colorStart: ["#ffe500", "#ffe500"],
|
|
108
119
|
|
|
109
|
-
|
|
110
|
-
colorEnd: ["
|
|
120
|
+
// Color at end - an array of strings for random selection
|
|
121
|
+
colorEnd: ["#ffe500", "#ffffff"],
|
|
111
122
|
|
|
112
|
-
//
|
|
113
|
-
|
|
123
|
+
// Particle size range [min, max]
|
|
124
|
+
size: [0.1, 0.5],
|
|
114
125
|
}}
|
|
115
126
|
/>
|
|
116
127
|
</>
|
|
117
128
|
);
|
|
118
129
|
}
|
|
119
130
|
```
|
|
131
|
+
|
|
120
132
|
---
|
|
121
133
|
|
|
122
134
|
## Custom Geometry Example
|
|
@@ -156,6 +168,7 @@ const CustomParticles = () => {
|
|
|
156
168
|
```
|
|
157
169
|
|
|
158
170
|
**Note:**
|
|
171
|
+
|
|
159
172
|
- Ensure the GLTF file at `/models/sword.glb` has a node named `Sword`.
|
|
160
173
|
- If your model's node hierarchy is different, adjust `nodes.Sword.geometry` accordingly.
|
|
161
174
|
|
|
@@ -163,69 +176,68 @@ const CustomParticles = () => {
|
|
|
163
176
|
|
|
164
177
|
### VFXParticles Component
|
|
165
178
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
171
|
-
|
|
|
179
|
+
|
|
180
|
+
| Property | Type | Description |
|
|
181
|
+
| -------- | ------------- | ------------------------------------------------ |
|
|
182
|
+
| name | string | Unique identifier for this particle system |
|
|
183
|
+
| settings | object | Configuration options for particles |
|
|
184
|
+
| alphaMap | THREE.Texture | Optional texture for particle alpha/transparency |
|
|
185
|
+
| geometry | ReactElement | Optional custom geometry for particles |
|
|
186
|
+
|
|
172
187
|
|
|
173
188
|
#### VFXParticles Settings
|
|
174
189
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
| fadeSize
|
|
182
|
-
| fadeAlpha
|
|
183
|
-
| gravity
|
|
184
|
-
|
|
|
185
|
-
|
|
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 |
|
|
190
|
+
|
|
191
|
+
| Setting | Type | Default | Description |
|
|
192
|
+
| ------------ | ------------------------ | ---------------- | ---------------------------------------- |
|
|
193
|
+
| nbParticles | number | 1000 | Maximum number of particles |
|
|
194
|
+
| intensity | number | 1 | Brightness multiplier |
|
|
195
|
+
| renderMode | 'billboard' | 'mesh' | 'stretchBillboard' |
|
|
196
|
+
| fadeSize | [number, number] | [0.1, 0.9] | Size fade in/out range (0-1 of lifetime) |
|
|
197
|
+
| fadeAlpha | [number, number] | [0, 1.0] | Opacity fade in/out range |
|
|
198
|
+
| gravity | [number, number, number] | [0, 0, 0] | Gravity force applied to particles |
|
|
199
|
+
| blendingMode | THREE.Blending | AdditiveBlending | How particles blend with the scene |
|
|
200
|
+
|
|
189
201
|
|
|
190
202
|
---
|
|
191
203
|
|
|
192
204
|
### VFXEmitter Component
|
|
193
205
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
199
|
-
|
|
|
200
|
-
|
|
206
|
+
|
|
207
|
+
| Property | Type | Description |
|
|
208
|
+
| -------- | ------- | ------------------------------------------- |
|
|
209
|
+
| emitter | string | Name of the target particle system |
|
|
210
|
+
| settings | object | Configuration options for emission behavior |
|
|
211
|
+
| debug | boolean | Show Leva controls to adjust settings |
|
|
212
|
+
|
|
201
213
|
|
|
202
214
|
#### VFXEmitter Settings
|
|
203
215
|
|
|
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
216
|
|
|
226
|
-
|
|
217
|
+
| Setting | Type | Default | Description |
|
|
218
|
+
| ----------------- | ------------------------ | ------------------ | ------------------------------------- |
|
|
219
|
+
| loop | boolean | true | Continuously emit particles |
|
|
220
|
+
| duration | number | 1 | Emission cycle duration in seconds |
|
|
221
|
+
| nbParticles | number | 100 | Number of particles to emit per cycle |
|
|
222
|
+
| spawnMode | 'time' | 'burst' | 'time' |
|
|
223
|
+
| delay | number | 0 | Time delay before starting emission |
|
|
224
|
+
| particlesLifetime | [number, number] | [0.1, 1] | Particle lifetime range [min, max] |
|
|
225
|
+
| startPositionMin | [number, number, number] | [-0.1, -0.1, -0.1] | Minimum start position |
|
|
226
|
+
| startPositionMax | [number, number, number] | [0.1, 0.1, 0.1] | Maximum start position |
|
|
227
|
+
| startRotationMin | [number, number, number] | [0, 0, 0] | Minimum start rotation |
|
|
228
|
+
| startRotationMax | [number, number, number] | [0, 0, 0] | Maximum start rotation |
|
|
229
|
+
| rotationSpeedMin | [number, number, number] | [0, 0, 0] | Minimum rotation speed |
|
|
230
|
+
| rotationSpeedMax | [number, number, number] | [0, 0, 0] | Maximum rotation speed |
|
|
231
|
+
| directionMin | [number, number, number] | [-1, 0, -1] | Minimum emission direction |
|
|
232
|
+
| directionMax | [number, number, number] | [1, 1, 1] | Maximum emission direction |
|
|
233
|
+
| size | [number, number] | [0.01, 0.25] | Particle size range [min, max] |
|
|
234
|
+
| speed | [number, number] | [1, 12] | Particle speed range [min, max] |
|
|
235
|
+
| colorStart | string[] | ['white'] | Colors at start (randomly selected) |
|
|
236
|
+
| colorEnd | string[] | ['white'] | Colors at end (randomly selected) |
|
|
237
|
+
|
|
227
238
|
|
|
239
|
+
---
|
|
228
240
|
|
|
229
241
|
## 📄 License
|
|
230
242
|
|
|
231
|
-
MIT © [Dev-Sameerkhan](https://github.com/Dev-Sameer-Khan)
|
|
243
|
+
MIT © [Dev-Sameerkhan](https://github.com/Dev-Sameer-Khan)
|
package/dist/lazy-vfx.es.js
CHANGED
|
@@ -673,7 +673,7 @@ var Ue = `varying vec2 vUv;
|
|
|
673
673
|
const ve = new te(), pe = new se(), ge = new Re(), Ee = new te(1, 1, 1), be = new Me(), k = new Te(), Ge = ({ name: o, settings: v = {}, alphaMap: l, geometry: a }) => {
|
|
674
674
|
const {
|
|
675
675
|
nbParticles: r = 1e3,
|
|
676
|
-
intensity: i =
|
|
676
|
+
intensity: i = 2,
|
|
677
677
|
renderMode: p = "mesh",
|
|
678
678
|
fadeSize: c = [0.1, 0.9],
|
|
679
679
|
fadeAlpha: T = [0, 1],
|
package/dist/lazy-vfx.umd.js
CHANGED
|
@@ -149,4 +149,4 @@ React keys must be passed directly to JSX without using spread:
|
|
|
149
149
|
#else
|
|
150
150
|
gl_FragColor = vec4(color, alpha);
|
|
151
151
|
#endif
|
|
152
|
-
}`;const fe=new m.Vector3,de=new m.Euler,me=new m.Quaternion,ve=new m.Vector3(1,1,1),pe=new m.Matrix4,k=new m.Color,we=({name:o,settings:g={},alphaMap:u,geometry:a})=>{const{nbParticles:r=1e3,intensity:i=
|
|
152
|
+
}`;const fe=new m.Vector3,de=new m.Euler,me=new m.Quaternion,ve=new m.Vector3(1,1,1),pe=new m.Matrix4,k=new m.Color,we=({name:o,settings:g={},alphaMap:u,geometry:a})=>{const{nbParticles:r=1e3,intensity:i=2,renderMode:b="mesh",fadeSize:l=[.1,.9],fadeAlpha:F=[0,1],gravity:_=[0,0,0]}=g,n=c.useRef(),w=c.useMemo(()=>new m.PlaneGeometry(.5,.5),[]),N=()=>{if(!M.current||!n.current)return;[n.current.instanceMatrix,n.current.geometry.getAttribute("instanceColor"),n.current.geometry.getAttribute("instanceColorEnd"),n.current.geometry.getAttribute("instanceDirection"),n.current.geometry.getAttribute("instanceLifetime"),n.current.geometry.getAttribute("instanceSpeed"),n.current.geometry.getAttribute("instanceRotationSpeed")].forEach(d=>{d.clearUpdateRanges(),R.current>s.current?(d.addUpdateRange(0,s.current*d.itemSize),d.addUpdateRange(R.current*d.itemSize,r*d.itemSize-R.current*d.itemSize)):d.addUpdateRange(R.current*d.itemSize,s.current*d.itemSize-R.current*d.itemSize),d.needsUpdate=!0}),R.current=s.current,M.current=!1},s=c.useRef(0),R=c.useRef(0),M=c.useRef(!1),h=(x,d)=>{const B=n.current.geometry.getAttribute("instanceColor"),W=n.current.geometry.getAttribute("instanceColorEnd"),A=n.current.geometry.getAttribute("instanceDirection"),C=n.current.geometry.getAttribute("instanceLifetime"),j=n.current.geometry.getAttribute("instanceSpeed"),D=n.current.geometry.getAttribute("instanceRotationSpeed");for(let V=0;V<x;V++){s.current>=r&&(s.current=0);const{scale:Y,rotation:X,rotationSpeed:G,position:Z,direction:z,lifetime:K,colorStart:U,colorEnd:e,speed:t}=d();fe.set(...Z),de.set(...X),me.setFromEuler(de),ve.set(...Y),pe.compose(fe,me,ve),n.current.setMatrixAt(s.current,pe),k.set(U),B.set([k.r,k.g,k.b],s.current*3),k.set(e),W.set([k.r,k.g,k.b],s.current*3),A.set(z,s.current*3),C.set(K,s.current*2),j.set([t],s.current),D.set(G,s.current*3),s.current++,s.current=s.current%r}n.current.instanceMatrix.needsUpdate=!0,B.needsUpdate=!0,W.needsUpdate=!0,A.needsUpdate=!0,C.needsUpdate=!0,j.needsUpdate=!0,D.needsUpdate=!0,M.current=!0},[P]=c.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)}),L=re(x=>x.registerEmitter),I=re(x=>x.unregisterEmitter);c.useEffect(()=>(L(o,h),()=>{I(o)}),[]);const T=c.useMemo(()=>({uTime:{value:0},uIntensity:{value:i},uFadeSize:{value:l},uFadeAlpha:{value:F},uGravity:{value:_},uAlphaMap:{value:u}}),[]);return ie.useFrame(({clock:x})=>{T&&(T.uTime.value=x.elapsedTime)}),S.jsx(S.Fragment,{children:S.jsxs("instancedMesh",{args:[w,null,r],ref:n,onBeforeRender:N,children:[a,S.jsx("shaderMaterial",{uniforms:T,vertexShader:Ae,fragmentShader:_e,blending:m.AdditiveBlending,depthTest:!1,depthWrite:!1,transparent:!0,defines:{BILLBOARD_MODE:b==="billboard",MESH_MODE:b==="mesh",ALPHAMAP:!!u}}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceColor",args:[P.instanceColor],itemSize:3,count:r,usage:m.DynamicDrawUsage}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceColorEnd",args:[P.instanceColorEnd],itemSize:3,count:r,usage:m.DynamicDrawUsage}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceDirection",args:[P.instanceDirection],itemSize:3,count:r,usage:m.DynamicDrawUsage}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceLifetime",args:[P.instanceLifetime],itemSize:2,count:r,usage:m.DynamicDrawUsage}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceSpeed",args:[P.instanceSpeed],itemSize:1,count:r,usage:m.DynamicDrawUsage}),S.jsx("instancedBufferAttribute",{attach:"geometry-attributes-instanceRotationSpeed",args:[P.instanceRotationSpeed],itemSize:3,count:r,usage:m.DynamicDrawUsage})]})})};y.VFXEmitter=Pe,y.VFXParticles=we,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})}));
|