tres-vfx 0.3.0 → 0.5.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 CHANGED
@@ -105,37 +105,47 @@ The main particle system component.
105
105
 
106
106
  #### Basic Props
107
107
 
108
- | Prop | Type | Default | Description |
109
- | -------------- | ----------- | ----------- | ------------------------------------------- |
110
- | `name` | `string` | - | Register system for use with VFXEmitter |
111
- | `maxParticles` | `number` | `10000` | Maximum number of particles |
112
- | `autoStart` | `boolean` | `true` | Start emitting automatically |
113
- | `delay` | `number` | `0` | Seconds between emissions (0 = every frame) |
114
- | `emitCount` | `number` | `1` | Particles to emit per burst |
115
- | `position` | `[x, y, z]` | `[0, 0, 0]` | Emitter position |
108
+ | Prop | Type | Default | Description |
109
+ | -------------- | ----------- | ----------- | ----------------------------------------------- |
110
+ | `name` | `string` | - | Register system for use with VFXEmitter |
111
+ | `maxParticles` | `number` | `10000` | Maximum number of particles |
112
+ | `autoStart` | `boolean` | `true` | Start emitting automatically |
113
+ | `delay` | `number` | `0` | Seconds between emissions (0 = every frame) |
114
+ | `emitCount` | `number` | `1` | Particles to emit per burst |
115
+ | `position` | `[x, y, z]` | `[0, 0, 0]` | Emitter position |
116
+ | `debug` | `boolean` | `false` | Show interactive debug panel (lazy-loads debug-vfx) |
116
117
 
117
118
  #### Appearance Props
118
119
 
119
120
  | Prop | Type | Default | Description |
120
121
  | ------------- | ------------------------ | ------------- | ----------------------------------------------------------- |
121
122
  | `size` | `number \| [min, max]` | `[0.1, 0.3]` | Particle size range |
122
- | `colorStart` | `string[]` | `["#ffffff"]` | Starting colors (random pick) |
123
+ | `colorStart` | `string[]` | `["#ffffff"]` | Starting colors (random pick per particle) |
123
124
  | `colorEnd` | `string[] \| null` | `null` | Ending colors (null = no transition) |
124
125
  | `fadeSize` | `number \| [start, end]` | `[1, 0]` | Size multiplier over lifetime |
125
126
  | `fadeOpacity` | `number \| [start, end]` | `[1, 0]` | Opacity over lifetime |
126
127
  | `appearance` | `Appearance` | `GRADIENT` | Shape: `DEFAULT`, `GRADIENT`, `CIRCULAR` |
127
128
  | `intensity` | `number` | `1` | Color intensity multiplier |
128
129
  | `blending` | `Blending` | `NORMAL` | Blend mode: `NORMAL`, `ADDITIVE`, `MULTIPLY`, `SUBTRACTIVE` |
130
+ | `side` | `Side` | `DOUBLE` | Face culling: `FRONT`, `BACK`, `DOUBLE` |
129
131
 
130
132
  #### Physics Props
131
133
 
132
- | Prop | Type | Default | Description |
133
- | ----------- | ----------------------- | ------------------------- | ---------------------------- |
134
- | `lifetime` | `number \| [min, max]` | `[1, 2]` | Particle lifetime in seconds |
135
- | `speed` | `number \| [min, max]` | `[0.1, 0.1]` | Initial speed |
136
- | `direction` | `Range3D \| [min, max]` | `[[-1,1], [0,1], [-1,1]]` | Emission direction per axis |
137
- | `gravity` | `[x, y, z]` | `[0, 0, 0]` | Gravity vector |
138
- | `friction` | `FrictionConfig` | `{ intensity: 0 }` | Velocity damping |
134
+ | Prop | Type | Default | Description |
135
+ | ------------------------- | ----------------------- | ------------------------- | ---------------------------------------------- |
136
+ | `lifetime` | `number \| [min, max]` | `[1, 2]` | Particle lifetime in seconds |
137
+ | `speed` | `number \| [min, max]` | `[0.1, 0.1]` | Initial speed |
138
+ | `direction` | `Range3D \| [min, max]` | `[[-1,1], [0,1], [-1,1]]` | Emission direction per axis |
139
+ | `gravity` | `[x, y, z]` | `[0, 0, 0]` | Gravity vector |
140
+ | `friction` | `FrictionConfig` | `{ intensity: 0 }` | Velocity damping |
141
+ | `startPositionAsDirection`| `boolean` | `false` | Use spawn offset as velocity direction (radial emission) |
142
+
143
+ ```ts
144
+ interface FrictionConfig {
145
+ intensity: number // Drag amount
146
+ easing?: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' // Deceleration curve
147
+ }
148
+ ```
139
149
 
140
150
  #### Emitter Shape Props
141
151
 
@@ -153,14 +163,50 @@ The main particle system component.
153
163
 
154
164
  | Prop | Type | Default | Description |
155
165
  | ------------------- | ----------------------- | ---------- | ---------------------------------------------------------- |
156
- | `geometry` | `BufferGeometry` | `null` | Custom particle geometry |
157
- | `lighting` | `Lighting` | `STANDARD` | Material: `BASIC`, `STANDARD`, `PHYSICAL` |
166
+ | `geometry` | `BufferGeometry` | `null` | Custom particle geometry (switches to instanced mesh mode) |
167
+ | `lighting` | `Lighting` | `STANDARD` | Material: `BASIC` (unlit), `STANDARD` (PBR), `PHYSICAL` (full PBR) |
168
+ | `lightingParams` | `LightingParams` | `null` | PBR material parameters (see below) |
158
169
  | `shadow` | `boolean` | `false` | Enable shadow casting/receiving |
159
- | `orientToDirection` | `boolean` | `false` | Orient geometry to velocity |
170
+ | `orientToDirection` | `boolean` | `false` | Orient geometry to velocity direction |
160
171
  | `orientAxis` | `string` | `"z"` | Axis to align: `"x"`, `"y"`, `"z"`, `"-x"`, `"-y"`, `"-z"` |
161
172
  | `rotation` | `Range3D \| [min, max]` | `[0, 0]` | Initial rotation per axis |
162
173
  | `rotationSpeed` | `Range3D \| [min, max]` | `[0, 0]` | Rotation speed rad/s |
163
174
 
175
+ **`lightingParams`** gives full control over PBR material properties when using `lighting: 'standard'` or `'physical'`:
176
+
177
+ ```ts
178
+ interface LightingParams {
179
+ roughness?: number // Surface roughness (0 = mirror, 1 = matte)
180
+ metalness?: number // Metallic factor (0 = dielectric, 1 = metal)
181
+ emissive?: string // Emissive color hex string
182
+ emissiveIntensity?: number // Emissive brightness
183
+ envMapIntensity?: number // Environment map strength
184
+ // Physical mode only:
185
+ clearcoat?: number // Clearcoat layer intensity
186
+ clearcoatRoughness?: number // Clearcoat roughness
187
+ transmission?: number // Glass-like transparency
188
+ thickness?: number // Volume thickness for transmission
189
+ ior?: number // Index of refraction
190
+ iridescence?: number // Iridescence effect intensity
191
+ iridescenceIOR?: number // Iridescence index of refraction
192
+ }
193
+ ```
194
+
195
+ ```tsx
196
+ <VFXParticles
197
+ geometry={gemGeometry}
198
+ lighting="physical"
199
+ lightingParams={{
200
+ roughness: 0.3,
201
+ metalness: 0.8,
202
+ clearcoat: 1,
203
+ clearcoatRoughness: 0.1,
204
+ iridescence: 1,
205
+ iridescenceIOR: 1.5,
206
+ }}
207
+ />
208
+ ```
209
+
164
210
  #### Stretch Props
165
211
 
166
212
  | Prop | Type | Default | Description |
@@ -221,6 +267,79 @@ interface CollisionConfig {
221
267
  }
222
268
  ```
223
269
 
270
+ #### Trail Props
271
+
272
+ | Prop | Type | Default | Description |
273
+ | ------- | ------------- | ------- | --------------------------- |
274
+ | `trail` | `TrailConfig` | `null` | Trail rendering via meshline |
275
+
276
+ Requires `makio-meshline` installed as a peer dependency.
277
+
278
+ ```ts
279
+ interface TrailConfig {
280
+ segments?: number // Trail resolution (default: 32)
281
+ width?: number // Line width (default: 0.1)
282
+ taper?: boolean | ((t: number) => number) // Width taper (default: true)
283
+ opacity?: number | ((data: TrailOpacityData) => Node) // Opacity control (default: 1)
284
+ length?: number // History in seconds (default: 0.5)
285
+ showParticles?: boolean // Show particles alongside trails (default: true)
286
+ fragmentColorFn?: (data: TrailData) => Node // Per-pixel trail coloring
287
+ }
288
+ ```
289
+
290
+ **`taper`** controls how the trail width varies from head to tail:
291
+
292
+ ```tsx
293
+ // Default linear taper (thick at head, thin at tail)
294
+ trail={{ taper: true }}
295
+
296
+ // No tapering (uniform width)
297
+ trail={{ taper: false }}
298
+
299
+ // Custom JS callback: t goes 0 (head) → 1 (tail), return width multiplier
300
+ trail={{ taper: (t) => Math.sin(t * Math.PI) }} // fat middle, thin ends
301
+ trail={{ taper: (t) => Math.abs(Math.sin(t * Math.PI * 4)) }} // wavy
302
+ ```
303
+
304
+ **`opacity`** controls trail transparency. As a number it sets global opacity. As a TSL callback it runs per-vertex in the fragment shader with full access to particle data:
305
+
306
+ ```tsx
307
+ // Global opacity
308
+ trail={{ opacity: 0.5 }}
309
+
310
+ // TSL callback with particle data
311
+ trail={{
312
+ opacity: ({ alpha, trailProgress, progress, lifetime, position, velocity, size }) => {
313
+ // Fade based on trail position and particle lifetime
314
+ return alpha.mul(trailProgress.oneMinus()).mul(lifetime)
315
+ }
316
+ }}
317
+ ```
318
+
319
+ #### Sorting Props
320
+
321
+ | Prop | Type | Default | Description |
322
+ | ------------------- | --------- | ------- | --------------------------------------------------- |
323
+ | `sortParticles` | `boolean` | `false` | Enable back-to-front depth sorting for transparency |
324
+ | `sortFrameInterval` | `number` | `null` | Run sort every N frames (WebGPU only, performance tuning) |
325
+
326
+ When enabled, particles are sorted by distance to camera for correct alpha blending. On WebGPU this uses a GPU bitonic sort; on WebGL fallback it uses a CPU radix sort.
327
+
328
+ ```tsx
329
+ <VFXParticles
330
+ sortParticles
331
+ sortFrameInterval={2} // Sort every other frame for better perf
332
+ blending="normal"
333
+ />
334
+ ```
335
+
336
+ #### Rendering Props
337
+
338
+ | Prop | Type | Default | Description |
339
+ | ------------- | --------- | ------- | ------------------------------------------------ |
340
+ | `depthTest` | `boolean` | `true` | Test against depth buffer |
341
+ | `renderOrder` | `number` | `0` | Three.js render order (higher = renders on top) |
342
+
224
343
  #### Soft Particles Props
225
344
 
226
345
  | Prop | Type | Default | Description |
@@ -242,25 +361,28 @@ interface CurveData {
242
361
  }
243
362
  ```
244
363
 
245
- | Prop | Type | Description |
246
- | -------------------- | ----------- | ---------------------------------------- |
247
- | `fadeSizeCurve` | `CurveData` | Size multiplier over lifetime |
248
- | `fadeOpacityCurve` | `CurveData` | Opacity over lifetime |
249
- | `velocityCurve` | `CurveData` | Velocity multiplier (overrides friction) |
250
- | `rotationSpeedCurve` | `CurveData` | Rotation speed multiplier |
364
+ | Prop | Type | Description |
365
+ | -------------------- | ----------- | ------------------------------------------------- |
366
+ | `fadeSizeCurve` | `CurveData` | Size multiplier over lifetime |
367
+ | `fadeOpacityCurve` | `CurveData` | Opacity over lifetime |
368
+ | `velocityCurve` | `CurveData` | Velocity multiplier (overrides friction) |
369
+ | `rotationSpeedCurve` | `CurveData` | Rotation speed multiplier |
370
+ | `curveTexturePath` | `string` | Path to pre-baked curve texture (faster startup) |
251
371
 
252
372
  #### Custom Shader Props
253
373
 
254
- | Prop | Type | Description |
255
- | ---------------- | -------------- | ------------------------------ |
256
- | `colorNode` | `NodeFunction` | Custom color shader |
257
- | `opacityNode` | `NodeFunction` | Custom opacity shader |
258
- | `backdropNode` | `NodeFunction` | Backdrop sampling (refraction) |
259
- | `castShadowNode` | `NodeFunction` | Shadow map output |
260
- | `alphaTestNode` | `NodeFunction` | Alpha test/discard |
374
+ | Prop | Type | Description |
375
+ | ---------------- | ---------------------- | -------------------------------------- |
376
+ | `geometryNode` | `GeometryNodeFunction` | Geometry-mode vertex position override |
377
+ | `colorNode` | `NodeFunction` | Custom color shader |
378
+ | `opacityNode` | `NodeFunction` | Custom opacity shader |
379
+ | `backdropNode` | `NodeFunction` | Backdrop sampling (refraction) |
380
+ | `castShadowNode` | `NodeFunction` | Shadow map output |
381
+ | `alphaTestNode` | `NodeFunction` | Alpha test/discard |
261
382
 
262
383
  ```ts
263
384
  type NodeFunction = (data: ParticleData, defaultColor?: Node) => Node
385
+ type GeometryNodeFunction = (data: ParticleData, defaultPosition: Node) => Node
264
386
 
265
387
  interface ParticleData {
266
388
  progress: Node // 0 → 1 over lifetime
@@ -518,6 +640,9 @@ import type {
518
640
  TurbulenceConfig,
519
641
  CollisionConfig,
520
642
  AttractorConfig,
643
+ TrailConfig,
644
+ TrailData,
645
+ TrailOpacityData,
521
646
  } from 'r3f-vfx'
522
647
  ```
523
648
 
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import * as vue from 'vue';
2
- import { PropType, Ref } from 'vue';
3
- import * as THREE from 'three/webgpu';
4
1
  import * as core_vfx from 'core-vfx';
5
2
  import { VFXParticleSystemOptions, FrictionConfig, FlipbookConfig, Rotation3DInput, StretchConfig, TurbulenceConfig, AttractorConfig, CollisionConfig, EmitterControllerOptions, CoreState } from 'core-vfx';
6
3
  export { Appearance, AttractorConfig, AttractorType, BaseParticleProps, Blending, CollisionConfig, CurveChannel, CurveData, CurvePoint, CurveTextureResolved, CurveTextureResult, Easing, EmitterController, EmitterControllerOptions, EmitterShape, FlipbookConfig, FrictionConfig, Lighting, NormalizedParticleProps, ParticleData, Rotation3DInput, StretchConfig, TurbulenceConfig, VFXParticleSystem, VFXParticleSystemOptions, bakeCurveToArray, buildCurveTextureBin, createCombinedCurveTexture, isNonDefaultRotation, isWebGPUBackend, normalizeProps, resolveCurveTexture } from 'core-vfx';
4
+ import * as vue from 'vue';
5
+ import { PropType, Ref } from 'vue';
6
+ import * as THREE from 'three/webgpu';
7
7
 
8
8
  declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
9
9
  name: {
@@ -121,6 +121,10 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
121
121
  type: PropType<string | number>;
122
122
  default: "standard";
123
123
  };
124
+ lightingParams: {
125
+ type: PropType<VFXParticleSystemOptions["lightingParams"]>;
126
+ default: null;
127
+ };
124
128
  shadow: {
125
129
  type: BooleanConstructor;
126
130
  default: boolean;
@@ -149,6 +153,10 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
149
153
  type: PropType<unknown>;
150
154
  default: null;
151
155
  };
156
+ geometryNode: {
157
+ type: PropType<unknown>;
158
+ default: null;
159
+ };
152
160
  opacityNode: {
153
161
  type: PropType<unknown>;
154
162
  default: null;
@@ -221,6 +229,14 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
221
229
  type: PropType<CollisionConfig | null>;
222
230
  default: null;
223
231
  };
232
+ sortParticles: {
233
+ type: BooleanConstructor;
234
+ default: boolean;
235
+ };
236
+ sortFrameInterval: {
237
+ type: PropType<number | null>;
238
+ default: null;
239
+ };
224
240
  curveTexturePath: {
225
241
  type: PropType<string | null>;
226
242
  default: null;
@@ -351,6 +367,10 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
351
367
  type: PropType<string | number>;
352
368
  default: "standard";
353
369
  };
370
+ lightingParams: {
371
+ type: PropType<VFXParticleSystemOptions["lightingParams"]>;
372
+ default: null;
373
+ };
354
374
  shadow: {
355
375
  type: BooleanConstructor;
356
376
  default: boolean;
@@ -379,6 +399,10 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
379
399
  type: PropType<unknown>;
380
400
  default: null;
381
401
  };
402
+ geometryNode: {
403
+ type: PropType<unknown>;
404
+ default: null;
405
+ };
382
406
  opacityNode: {
383
407
  type: PropType<unknown>;
384
408
  default: null;
@@ -451,6 +475,14 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
451
475
  type: PropType<CollisionConfig | null>;
452
476
  default: null;
453
477
  };
478
+ sortParticles: {
479
+ type: BooleanConstructor;
480
+ default: boolean;
481
+ };
482
+ sortFrameInterval: {
483
+ type: PropType<number | null>;
484
+ default: null;
485
+ };
454
486
  curveTexturePath: {
455
487
  type: PropType<string | null>;
456
488
  default: null;
@@ -466,6 +498,7 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
466
498
  }>> & Readonly<{}>, {
467
499
  direction: Rotation3DInput;
468
500
  startPosition: Rotation3DInput;
501
+ lightingParams: core_vfx.LightingParams | undefined;
469
502
  name: string;
470
503
  debug: boolean;
471
504
  maxParticles: number;
@@ -499,6 +532,7 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
499
532
  autoStart: boolean;
500
533
  delay: number;
501
534
  backdropNode: null;
535
+ geometryNode: null;
502
536
  opacityNode: null;
503
537
  colorNode: null;
504
538
  alphaTestNode: null;
@@ -517,6 +551,8 @@ declare const VFXParticles: vue.DefineComponent<vue.ExtractPropTypes<{
517
551
  softParticles: boolean;
518
552
  softDistance: number;
519
553
  collision: CollisionConfig;
554
+ sortParticles: boolean;
555
+ sortFrameInterval: number | null;
520
556
  curveTexturePath: string | null;
521
557
  depthTest: boolean;
522
558
  renderOrder: number;
package/dist/index.js CHANGED
@@ -147,6 +147,10 @@ var VFXParticles = defineComponent({
147
147
  type: null,
148
148
  default: Lighting.STANDARD
149
149
  },
150
+ lightingParams: {
151
+ type: Object,
152
+ default: null
153
+ },
150
154
  shadow: { type: Boolean, default: false },
151
155
  blending: {
152
156
  type: null,
@@ -160,6 +164,7 @@ var VFXParticles = defineComponent({
160
164
  autoStart: { type: Boolean, default: true },
161
165
  delay: { type: Number, default: 0 },
162
166
  backdropNode: { type: null, default: null },
167
+ geometryNode: { type: null, default: null },
163
168
  opacityNode: { type: null, default: null },
164
169
  colorNode: { type: null, default: null },
165
170
  alphaTestNode: {
@@ -205,6 +210,11 @@ var VFXParticles = defineComponent({
205
210
  type: Object,
206
211
  default: null
207
212
  },
213
+ sortParticles: { type: Boolean, default: false },
214
+ sortFrameInterval: {
215
+ type: null,
216
+ default: null
217
+ },
208
218
  curveTexturePath: {
209
219
  type: null,
210
220
  default: null
@@ -213,8 +223,9 @@ var VFXParticles = defineComponent({
213
223
  renderOrder: { type: Number, default: 0 }
214
224
  },
215
225
  setup(props, { expose }) {
216
- var _a, _b, _c, _d;
217
- const { renderer: rendererCtx } = useTresContext();
226
+ var _a, _b, _c, _d, _e;
227
+ const tresCtx = useTresContext();
228
+ const rendererCtx = tresCtx.renderer;
218
229
  const { onBeforeRender } = useLoop();
219
230
  const systemRef = shallowRef(null);
220
231
  const renderObjectRef = shallowRef(null);
@@ -237,6 +248,7 @@ var VFXParticles = defineComponent({
237
248
  props.attractors !== null && ((_d = (_c = props.attractors) == null ? void 0 : _c.length) != null ? _d : 0) > 0
238
249
  );
239
250
  const activeCollision = ref(props.collision !== null);
251
+ const activeLightingParamsKey = ref(JSON.stringify((_e = props.lightingParams) != null ? _e : null));
240
252
  const activeNeedsPerParticleColor = ref(
241
253
  props.colorStart.length > 1 || props.colorEnd !== null
242
254
  );
@@ -246,7 +258,7 @@ var VFXParticles = defineComponent({
246
258
  const prevGeometryTypeRef = ref(null);
247
259
  const prevGeometryArgsRef = ref(null);
248
260
  function buildOptions() {
249
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;
261
+ var _a2, _b2, _c2, _d2, _e2, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
250
262
  const dbg = props.debug ? debugValuesRef.value : null;
251
263
  return {
252
264
  maxParticles: activeMaxParticles.value,
@@ -258,7 +270,7 @@ var VFXParticles = defineComponent({
258
270
  fadeOpacity: (_d2 = dbg == null ? void 0 : dbg.fadeOpacity) != null ? _d2 : props.fadeOpacity,
259
271
  fadeOpacityCurve: activeFadeOpacityCurve.value,
260
272
  velocityCurve: activeVelocityCurve.value,
261
- gravity: (_e = dbg == null ? void 0 : dbg.gravity) != null ? _e : props.gravity,
273
+ gravity: (_e2 = dbg == null ? void 0 : dbg.gravity) != null ? _e2 : props.gravity,
262
274
  lifetime: (_f = dbg == null ? void 0 : dbg.lifetime) != null ? _f : props.lifetime,
263
275
  direction: (_g = dbg == null ? void 0 : dbg.direction) != null ? _g : props.direction,
264
276
  startPosition: (_h = dbg == null ? void 0 : dbg.startPosition) != null ? _h : props.startPosition,
@@ -275,6 +287,7 @@ var VFXParticles = defineComponent({
275
287
  orientAxis: (_m = dbg == null ? void 0 : dbg.orientAxis) != null ? _m : props.orientAxis,
276
288
  stretchBySpeed: (_n = dbg == null ? void 0 : dbg.stretchBySpeed) != null ? _n : props.stretchBySpeed,
277
289
  lighting: activeLighting.value,
290
+ lightingParams: props.lightingParams,
278
291
  shadow: activeShadow.value,
279
292
  blending: (_o = dbg == null ? void 0 : dbg.blending) != null ? _o : props.blending,
280
293
  intensity: (_p = dbg == null ? void 0 : dbg.intensity) != null ? _p : props.intensity,
@@ -295,13 +308,16 @@ var VFXParticles = defineComponent({
295
308
  softParticles: (_E = dbg == null ? void 0 : dbg.softParticles) != null ? _E : props.softParticles,
296
309
  softDistance: (_F = dbg == null ? void 0 : dbg.softDistance) != null ? _F : props.softDistance,
297
310
  collision: (_G = dbg == null ? void 0 : dbg.collision) != null ? _G : props.collision,
311
+ sortParticles: (_H = dbg == null ? void 0 : dbg.sortParticles) != null ? _H : props.sortParticles,
312
+ sortFrameInterval: (dbg == null ? void 0 : dbg.sortFrameInterval) !== void 0 ? dbg.sortFrameInterval : props.sortFrameInterval,
298
313
  backdropNode: props.backdropNode,
314
+ geometryNode: props.geometryNode,
299
315
  opacityNode: props.opacityNode,
300
316
  colorNode: props.colorNode,
301
317
  alphaTestNode: props.alphaTestNode,
302
318
  castShadowNode: props.castShadowNode,
303
- depthTest: (_H = dbg == null ? void 0 : dbg.depthTest) != null ? _H : props.depthTest,
304
- renderOrder: (_I = dbg == null ? void 0 : dbg.renderOrder) != null ? _I : props.renderOrder,
319
+ depthTest: (_I = dbg == null ? void 0 : dbg.depthTest) != null ? _I : props.depthTest,
320
+ renderOrder: (_J = dbg == null ? void 0 : dbg.renderOrder) != null ? _J : props.renderOrder,
305
321
  curveTexturePath: props.curveTexturePath
306
322
  };
307
323
  }
@@ -367,7 +383,7 @@ var VFXParticles = defineComponent({
367
383
  }
368
384
  }
369
385
  function handleDebugUpdate(newValues) {
370
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j;
386
+ var _a2, _b2, _c2, _d2, _e2, _f, _g, _h, _i, _j, _k;
371
387
  debugValuesRef.value = __spreadValues(__spreadValues({}, debugValuesRef.value), newValues);
372
388
  const system = systemRef.value;
373
389
  if (!system) return;
@@ -398,7 +414,7 @@ var VFXParticles = defineComponent({
398
414
  }
399
415
  if ("turbulence" in newValues) {
400
416
  system.setTurbulenceSpeed(
401
- (_f = (_e = newValues.turbulence) == null ? void 0 : _e.speed) != null ? _f : 1
417
+ (_f = (_e2 = newValues.turbulence) == null ? void 0 : _e2.speed) != null ? _f : 1
402
418
  );
403
419
  }
404
420
  const newFeatures = resolveFeatures(
@@ -426,6 +442,12 @@ var VFXParticles = defineComponent({
426
442
  system.setDelay((_g = newValues.delay) != null ? _g : 0);
427
443
  if ("emitCount" in newValues)
428
444
  system.setEmitCount((_h = newValues.emitCount) != null ? _h : 1);
445
+ if ("sortParticles" in newValues)
446
+ system.setSortEnabled(!!newValues.sortParticles);
447
+ if ("sortFrameInterval" in newValues)
448
+ system.setSortFrameInterval(
449
+ (_i = newValues.sortFrameInterval) != null ? _i : null
450
+ );
429
451
  if (newValues.autoStart !== void 0) {
430
452
  emitting.value = newValues.autoStart;
431
453
  }
@@ -452,8 +474,8 @@ var VFXParticles = defineComponent({
452
474
  activeShadow.value = newValues.shadow;
453
475
  }
454
476
  if ("geometryType" in newValues || "geometryArgs" in newValues) {
455
- const geoType = (_i = newValues.geometryType) != null ? _i : prevGeometryTypeRef.value;
456
- const geoArgs = (_j = newValues.geometryArgs) != null ? _j : prevGeometryArgsRef.value;
477
+ const geoType = (_j = newValues.geometryType) != null ? _j : prevGeometryTypeRef.value;
478
+ const geoArgs = (_k = newValues.geometryArgs) != null ? _k : prevGeometryArgsRef.value;
457
479
  const geoTypeChanged = "geometryType" in newValues && geoType !== prevGeometryTypeRef.value;
458
480
  const geoArgsChanged = "geometryArgs" in newValues && JSON.stringify(geoArgs) !== JSON.stringify(prevGeometryArgsRef.value);
459
481
  if (geoTypeChanged || geoArgsChanged) {
@@ -529,7 +551,9 @@ var VFXParticles = defineComponent({
529
551
  attractToCenter: props.attractToCenter,
530
552
  softParticles: props.softParticles,
531
553
  softDistance: props.softDistance,
532
- collision: props.collision
554
+ collision: props.collision,
555
+ sortParticles: props.sortParticles,
556
+ sortFrameInterval: props.sortFrameInterval
533
557
  }, detectGeometryTypeAndArgs(props.geometry));
534
558
  debugValuesRef.value = initialValues;
535
559
  prevGeometryTypeRef.value = initialValues.geometryType;
@@ -556,10 +580,11 @@ var VFXParticles = defineComponent({
556
580
  props.rotationSpeed,
557
581
  props.turbulence,
558
582
  props.attractors,
559
- props.collision
583
+ props.collision,
584
+ props.lightingParams
560
585
  ],
561
586
  () => {
562
- var _a2, _b2, _c2, _d2;
587
+ var _a2, _b2, _c2, _d2, _e2;
563
588
  if (props.debug) return;
564
589
  activeMaxParticles.value = props.maxParticles;
565
590
  activeLighting.value = props.lighting;
@@ -576,6 +601,7 @@ var VFXParticles = defineComponent({
576
601
  activeTurbulence.value = props.turbulence !== null && ((_b2 = (_a2 = props.turbulence) == null ? void 0 : _a2.intensity) != null ? _b2 : 0) > 0;
577
602
  activeAttractors.value = props.attractors !== null && ((_d2 = (_c2 = props.attractors) == null ? void 0 : _c2.length) != null ? _d2 : 0) > 0;
578
603
  activeCollision.value = props.collision !== null;
604
+ activeLightingParamsKey.value = JSON.stringify((_e2 = props.lightingParams) != null ? _e2 : null);
579
605
  }
580
606
  );
581
607
  watch(
@@ -594,7 +620,8 @@ var VFXParticles = defineComponent({
594
620
  activeFadeSizeCurve,
595
621
  activeFadeOpacityCurve,
596
622
  activeVelocityCurve,
597
- activeRotationSpeedCurve
623
+ activeRotationSpeedCurve,
624
+ activeLightingParamsKey
598
625
  ],
599
626
  () => {
600
627
  initSystem();
@@ -633,7 +660,9 @@ var VFXParticles = defineComponent({
633
660
  props.orientAxis,
634
661
  props.stretchBySpeed,
635
662
  props.delay,
636
- props.emitCount
663
+ props.emitCount,
664
+ props.sortParticles,
665
+ props.sortFrameInterval
637
666
  ],
638
667
  () => {
639
668
  var _a2, _b2;
@@ -644,6 +673,8 @@ var VFXParticles = defineComponent({
644
673
  system.setDelay(props.delay);
645
674
  system.setEmitCount(props.emitCount);
646
675
  system.setTurbulenceSpeed((_b2 = (_a2 = props.turbulence) == null ? void 0 : _a2.speed) != null ? _b2 : 1);
676
+ system.setSortFrameInterval(props.sortFrameInterval);
677
+ system.setSortEnabled(props.sortParticles);
647
678
  const normalized = normalizeProps({
648
679
  size: props.size,
649
680
  speed: props.speed,
@@ -679,10 +710,17 @@ var VFXParticles = defineComponent({
679
710
  },
680
711
  { deep: true }
681
712
  );
682
- onBeforeRender(({ delta }) => {
713
+ onBeforeRender((frame) => {
714
+ var _a2, _b2, _c2, _d2, _e2;
683
715
  const system = systemRef.value;
684
716
  if (!system || !system.initialized) return;
685
- system.update(delta);
717
+ const delta = (_a2 = frame == null ? void 0 : frame.delta) != null ? _a2 : 0;
718
+ const cam = (_e2 = (_d2 = (_c2 = frame == null ? void 0 : frame.camera) != null ? _c2 : (_b2 = tresCtx.camera) == null ? void 0 : _b2.value) != null ? _d2 : tresCtx.camera) != null ? _e2 : null;
719
+ const pos = cam == null ? void 0 : cam.position;
720
+ if (pos) {
721
+ system.setCameraPosition([pos.x, pos.y, pos.z]);
722
+ }
723
+ void system.update(delta);
686
724
  if (emitting.value) {
687
725
  system.autoEmit(delta);
688
726
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tres-vfx",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -24,8 +24,8 @@
24
24
  "prepublishOnly": "bun run typecheck && bun run build && bun run copy-readme"
25
25
  },
26
26
  "dependencies": {
27
- "core-vfx": "0.2.0",
28
- "debug-vfx": "0.1.2"
27
+ "core-vfx": "0.4.0",
28
+ "debug-vfx": "0.4.0"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@tresjs/core": ">=5.0.0",