tres-vfx 0.0.10 → 0.2.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +671 -1
  2. package/dist/index.js +1045 -1
  3. package/package.json +10 -2
package/dist/index.js CHANGED
@@ -1,2 +1,1046 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+
21
+ // src/VFXParticles.ts
22
+ import {
23
+ defineComponent,
24
+ ref,
25
+ watch,
26
+ onMounted,
27
+ onUnmounted,
28
+ h,
29
+ shallowRef
30
+ } from "vue";
31
+ import { useLoop, useTresContext } from "@tresjs/core";
32
+ import { coreStore } from "core-vfx";
33
+ import {
34
+ Appearance,
35
+ Blending,
36
+ EmitterShape,
37
+ Lighting,
38
+ VFXParticleSystem,
39
+ isWebGPUBackend,
40
+ isNonDefaultRotation,
41
+ normalizeProps,
42
+ updateUniforms,
43
+ updateUniformsPartial,
44
+ resolveFeatures
45
+ } from "core-vfx";
46
+ var warnedWebGL = false;
47
+ var VFXParticles = defineComponent({
48
+ name: "VFXParticles",
49
+ props: {
50
+ name: { type: String, default: void 0 },
51
+ debug: { type: Boolean, default: false },
52
+ maxParticles: { type: Number, default: 1e4 },
53
+ size: {
54
+ type: null,
55
+ default: () => [0.1, 0.3]
56
+ },
57
+ colorStart: {
58
+ type: Array,
59
+ default: () => ["#ffffff"]
60
+ },
61
+ colorEnd: {
62
+ type: null,
63
+ default: null
64
+ },
65
+ fadeSize: {
66
+ type: null,
67
+ default: () => [1, 0]
68
+ },
69
+ fadeSizeCurve: { type: null, default: null },
70
+ fadeOpacity: {
71
+ type: null,
72
+ default: () => [1, 0]
73
+ },
74
+ fadeOpacityCurve: { type: null, default: null },
75
+ velocityCurve: { type: null, default: null },
76
+ gravity: {
77
+ type: null,
78
+ default: () => [0, 0, 0]
79
+ },
80
+ lifetime: {
81
+ type: null,
82
+ default: () => [1, 2]
83
+ },
84
+ direction: {
85
+ type: null,
86
+ default: () => [
87
+ [-1, 1],
88
+ [0, 1],
89
+ [-1, 1]
90
+ ]
91
+ },
92
+ startPosition: {
93
+ type: null,
94
+ default: () => [
95
+ [0, 0],
96
+ [0, 0],
97
+ [0, 0]
98
+ ]
99
+ },
100
+ speed: {
101
+ type: null,
102
+ default: () => [0.1, 0.1]
103
+ },
104
+ friction: {
105
+ type: Object,
106
+ default: () => ({ intensity: 0, easing: "linear" })
107
+ },
108
+ appearance: {
109
+ type: null,
110
+ default: Appearance.GRADIENT
111
+ },
112
+ alphaMap: { type: Object, default: null },
113
+ flipbook: { type: Object, default: null },
114
+ rotation: {
115
+ type: null,
116
+ default: () => [0, 0]
117
+ },
118
+ rotationSpeed: {
119
+ type: null,
120
+ default: () => [0, 0]
121
+ },
122
+ rotationSpeedCurve: { type: null, default: null },
123
+ geometry: {
124
+ type: Object,
125
+ default: null
126
+ },
127
+ orientToDirection: { type: Boolean, default: false },
128
+ orientAxis: { type: String, default: "z" },
129
+ stretchBySpeed: {
130
+ type: Object,
131
+ default: null
132
+ },
133
+ lighting: {
134
+ type: null,
135
+ default: Lighting.STANDARD
136
+ },
137
+ shadow: { type: Boolean, default: false },
138
+ blending: {
139
+ type: null,
140
+ default: Blending.NORMAL
141
+ },
142
+ intensity: { type: Number, default: 1 },
143
+ position: {
144
+ type: null,
145
+ default: () => [0, 0, 0]
146
+ },
147
+ autoStart: { type: Boolean, default: true },
148
+ delay: { type: Number, default: 0 },
149
+ backdropNode: { type: null, default: null },
150
+ opacityNode: { type: null, default: null },
151
+ colorNode: { type: null, default: null },
152
+ alphaTestNode: { type: null, default: null },
153
+ castShadowNode: { type: null, default: null },
154
+ emitCount: { type: Number, default: 1 },
155
+ emitterShape: {
156
+ type: null,
157
+ default: EmitterShape.BOX
158
+ },
159
+ emitterRadius: {
160
+ type: null,
161
+ default: () => [0, 1]
162
+ },
163
+ emitterAngle: { type: Number, default: Math.PI / 4 },
164
+ emitterHeight: {
165
+ type: null,
166
+ default: () => [0, 1]
167
+ },
168
+ emitterSurfaceOnly: { type: Boolean, default: false },
169
+ emitterDirection: {
170
+ type: null,
171
+ default: () => [0, 1, 0]
172
+ },
173
+ turbulence: {
174
+ type: Object,
175
+ default: null
176
+ },
177
+ attractors: {
178
+ type: null,
179
+ default: null
180
+ },
181
+ attractToCenter: { type: Boolean, default: false },
182
+ startPositionAsDirection: { type: Boolean, default: false },
183
+ softParticles: { type: Boolean, default: false },
184
+ softDistance: { type: Number, default: 0.5 },
185
+ collision: {
186
+ type: Object,
187
+ default: null
188
+ },
189
+ curveTexturePath: { type: null, default: null },
190
+ depthTest: { type: Boolean, default: true },
191
+ renderOrder: { type: Number, default: 0 }
192
+ },
193
+ setup(props, { expose, slots }) {
194
+ var _a, _b, _c, _d;
195
+ const { renderer: rendererCtx } = useTresContext();
196
+ const { onBeforeRender } = useLoop();
197
+ const systemRef = shallowRef(null);
198
+ const renderObjectRef = shallowRef(null);
199
+ const emitting = ref(props.autoStart);
200
+ const isWebGPU = ref(false);
201
+ const debugValuesRef = ref(null);
202
+ const activeMaxParticles = ref(props.maxParticles);
203
+ const activeLighting = ref(props.lighting);
204
+ const activeAppearance = ref(props.appearance);
205
+ const activeOrientToDirection = ref(props.orientToDirection);
206
+ const activeGeometry = shallowRef(props.geometry);
207
+ const activeShadow = ref(props.shadow);
208
+ const activeFadeSizeCurve = shallowRef(props.fadeSizeCurve);
209
+ const activeFadeOpacityCurve = shallowRef(props.fadeOpacityCurve);
210
+ const activeVelocityCurve = shallowRef(props.velocityCurve);
211
+ const activeRotationSpeedCurve = shallowRef(props.rotationSpeedCurve);
212
+ const activeTurbulence = ref(
213
+ props.turbulence !== null && ((_b = (_a = props.turbulence) == null ? void 0 : _a.intensity) != null ? _b : 0) > 0
214
+ );
215
+ const activeAttractors = ref(
216
+ props.attractors !== null && ((_d = (_c = props.attractors) == null ? void 0 : _c.length) != null ? _d : 0) > 0
217
+ );
218
+ const activeCollision = ref(props.collision !== null);
219
+ const activeNeedsPerParticleColor = ref(
220
+ props.colorStart.length > 1 || props.colorEnd !== null
221
+ );
222
+ const activeNeedsRotation = ref(
223
+ isNonDefaultRotation(props.rotation) || isNonDefaultRotation(props.rotationSpeed)
224
+ );
225
+ const prevGeometryTypeRef = ref(null);
226
+ const prevGeometryArgsRef = ref(null);
227
+ function buildOptions() {
228
+ 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;
229
+ const dbg = props.debug ? debugValuesRef.value : null;
230
+ return {
231
+ maxParticles: activeMaxParticles.value,
232
+ size: (_a2 = dbg == null ? void 0 : dbg.size) != null ? _a2 : props.size,
233
+ colorStart: (_b2 = dbg == null ? void 0 : dbg.colorStart) != null ? _b2 : props.colorStart,
234
+ colorEnd: (dbg == null ? void 0 : dbg.colorEnd) !== void 0 ? dbg.colorEnd : props.colorEnd,
235
+ fadeSize: (_c2 = dbg == null ? void 0 : dbg.fadeSize) != null ? _c2 : props.fadeSize,
236
+ fadeSizeCurve: activeFadeSizeCurve.value,
237
+ fadeOpacity: (_d2 = dbg == null ? void 0 : dbg.fadeOpacity) != null ? _d2 : props.fadeOpacity,
238
+ fadeOpacityCurve: activeFadeOpacityCurve.value,
239
+ velocityCurve: activeVelocityCurve.value,
240
+ gravity: (_e = dbg == null ? void 0 : dbg.gravity) != null ? _e : props.gravity,
241
+ lifetime: (_f = dbg == null ? void 0 : dbg.lifetime) != null ? _f : props.lifetime,
242
+ direction: (_g = dbg == null ? void 0 : dbg.direction) != null ? _g : props.direction,
243
+ startPosition: (_h = dbg == null ? void 0 : dbg.startPosition) != null ? _h : props.startPosition,
244
+ speed: (_i = dbg == null ? void 0 : dbg.speed) != null ? _i : props.speed,
245
+ friction: (_j = dbg == null ? void 0 : dbg.friction) != null ? _j : props.friction,
246
+ appearance: activeAppearance.value,
247
+ alphaMap: props.alphaMap,
248
+ flipbook: props.flipbook,
249
+ rotation: (_k = dbg == null ? void 0 : dbg.rotation) != null ? _k : props.rotation,
250
+ rotationSpeed: (_l = dbg == null ? void 0 : dbg.rotationSpeed) != null ? _l : props.rotationSpeed,
251
+ rotationSpeedCurve: activeRotationSpeedCurve.value,
252
+ geometry: activeGeometry.value,
253
+ orientToDirection: activeOrientToDirection.value,
254
+ orientAxis: (_m = dbg == null ? void 0 : dbg.orientAxis) != null ? _m : props.orientAxis,
255
+ stretchBySpeed: (_n = dbg == null ? void 0 : dbg.stretchBySpeed) != null ? _n : props.stretchBySpeed,
256
+ lighting: activeLighting.value,
257
+ shadow: activeShadow.value,
258
+ blending: (_o = dbg == null ? void 0 : dbg.blending) != null ? _o : props.blending,
259
+ intensity: (_p = dbg == null ? void 0 : dbg.intensity) != null ? _p : props.intensity,
260
+ position: (_q = dbg == null ? void 0 : dbg.position) != null ? _q : props.position,
261
+ autoStart: (_r = dbg == null ? void 0 : dbg.autoStart) != null ? _r : props.autoStart,
262
+ delay: (_s = dbg == null ? void 0 : dbg.delay) != null ? _s : props.delay,
263
+ emitCount: (_t = dbg == null ? void 0 : dbg.emitCount) != null ? _t : props.emitCount,
264
+ emitterShape: (_u = dbg == null ? void 0 : dbg.emitterShape) != null ? _u : props.emitterShape,
265
+ emitterRadius: (_v = dbg == null ? void 0 : dbg.emitterRadius) != null ? _v : props.emitterRadius,
266
+ emitterAngle: (_w = dbg == null ? void 0 : dbg.emitterAngle) != null ? _w : props.emitterAngle,
267
+ emitterHeight: (_x = dbg == null ? void 0 : dbg.emitterHeight) != null ? _x : props.emitterHeight,
268
+ emitterSurfaceOnly: (_y = dbg == null ? void 0 : dbg.emitterSurfaceOnly) != null ? _y : props.emitterSurfaceOnly,
269
+ emitterDirection: (_z = dbg == null ? void 0 : dbg.emitterDirection) != null ? _z : props.emitterDirection,
270
+ turbulence: (_A = dbg == null ? void 0 : dbg.turbulence) != null ? _A : props.turbulence,
271
+ attractors: (_B = dbg == null ? void 0 : dbg.attractors) != null ? _B : props.attractors,
272
+ attractToCenter: (_C = dbg == null ? void 0 : dbg.attractToCenter) != null ? _C : props.attractToCenter,
273
+ startPositionAsDirection: (_D = dbg == null ? void 0 : dbg.startPositionAsDirection) != null ? _D : props.startPositionAsDirection,
274
+ softParticles: (_E = dbg == null ? void 0 : dbg.softParticles) != null ? _E : props.softParticles,
275
+ softDistance: (_F = dbg == null ? void 0 : dbg.softDistance) != null ? _F : props.softDistance,
276
+ collision: (_G = dbg == null ? void 0 : dbg.collision) != null ? _G : props.collision,
277
+ backdropNode: props.backdropNode,
278
+ opacityNode: props.opacityNode,
279
+ colorNode: props.colorNode,
280
+ alphaTestNode: props.alphaTestNode,
281
+ castShadowNode: props.castShadowNode,
282
+ depthTest: (_H = dbg == null ? void 0 : dbg.depthTest) != null ? _H : props.depthTest,
283
+ renderOrder: (_I = dbg == null ? void 0 : dbg.renderOrder) != null ? _I : props.renderOrder,
284
+ curveTexturePath: props.curveTexturePath
285
+ };
286
+ }
287
+ function createSystem() {
288
+ const renderer = rendererCtx.instance;
289
+ if (!renderer) return null;
290
+ const system = new VFXParticleSystem(renderer, buildOptions());
291
+ return system;
292
+ }
293
+ function destroySystem() {
294
+ const system = systemRef.value;
295
+ if (!system) return;
296
+ if (props.name) {
297
+ coreStore.getState().unregisterParticles(props.name);
298
+ }
299
+ system.dispose();
300
+ systemRef.value = null;
301
+ renderObjectRef.value = null;
302
+ }
303
+ function initSystem() {
304
+ const oldSystem = systemRef.value;
305
+ if (oldSystem) {
306
+ oldSystem.initialized = false;
307
+ if (props.name) {
308
+ coreStore.getState().unregisterParticles(props.name);
309
+ }
310
+ }
311
+ systemRef.value = null;
312
+ renderObjectRef.value = null;
313
+ const renderer = rendererCtx.instance;
314
+ if (!renderer) {
315
+ console.warn("tres-vfx: No renderer instance available");
316
+ return;
317
+ }
318
+ if (!isWebGPUBackend(renderer)) {
319
+ if (!warnedWebGL) {
320
+ warnedWebGL = true;
321
+ console.warn(
322
+ "tres-vfx: WebGPU backend not detected. Particle system disabled."
323
+ );
324
+ }
325
+ isWebGPU.value = false;
326
+ return;
327
+ }
328
+ isWebGPU.value = true;
329
+ const system = createSystem();
330
+ if (!system) return;
331
+ systemRef.value = system;
332
+ renderObjectRef.value = system.renderObject;
333
+ system.init();
334
+ if (props.name) {
335
+ coreStore.getState().registerParticles(props.name, {
336
+ spawn: (x = 0, y = 0, z = 0, count = 20, overrides = null) => {
337
+ const [px, py, pz] = system.position;
338
+ system.spawn(px + x, py + y, pz + z, count, overrides);
339
+ },
340
+ start: () => {
341
+ system.start();
342
+ emitting.value = true;
343
+ },
344
+ stop: () => {
345
+ system.stop();
346
+ emitting.value = false;
347
+ },
348
+ get isEmitting() {
349
+ return emitting.value;
350
+ },
351
+ clear: () => system.clear(),
352
+ uniforms: system.uniforms
353
+ });
354
+ }
355
+ if (props.debug) {
356
+ initDebugPanel();
357
+ }
358
+ }
359
+ function handleDebugUpdate(newValues) {
360
+ var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j;
361
+ debugValuesRef.value = __spreadValues(__spreadValues({}, debugValuesRef.value), newValues);
362
+ const system = systemRef.value;
363
+ if (!system) return;
364
+ if ("colorStart" in newValues && newValues.colorStart) {
365
+ const currentColorEnd = (_a2 = debugValuesRef.value) == null ? void 0 : _a2.colorEnd;
366
+ if (!currentColorEnd) {
367
+ newValues = __spreadProps(__spreadValues({}, newValues), { colorEnd: null });
368
+ }
369
+ }
370
+ if ("colorEnd" in newValues && !newValues.colorEnd) {
371
+ newValues = __spreadProps(__spreadValues({}, newValues), {
372
+ colorEnd: null,
373
+ colorStart: (_d2 = (_c2 = newValues.colorStart) != null ? _c2 : (_b2 = debugValuesRef.value) == null ? void 0 : _b2.colorStart) != null ? _d2 : ["#ffffff"]
374
+ });
375
+ }
376
+ updateUniformsPartial(system.uniforms, newValues);
377
+ if ("fadeSizeCurve" in newValues) {
378
+ activeFadeSizeCurve.value = newValues.fadeSizeCurve;
379
+ }
380
+ if ("fadeOpacityCurve" in newValues) {
381
+ activeFadeOpacityCurve.value = newValues.fadeOpacityCurve;
382
+ }
383
+ if ("velocityCurve" in newValues) {
384
+ activeVelocityCurve.value = newValues.velocityCurve;
385
+ }
386
+ if ("rotationSpeedCurve" in newValues) {
387
+ activeRotationSpeedCurve.value = newValues.rotationSpeedCurve;
388
+ }
389
+ if ("turbulence" in newValues) {
390
+ system.setTurbulenceSpeed(
391
+ (_f = (_e = newValues.turbulence) == null ? void 0 : _e.speed) != null ? _f : 1
392
+ );
393
+ }
394
+ const newFeatures = resolveFeatures(
395
+ debugValuesRef.value
396
+ );
397
+ if (newFeatures.needsRotation !== activeNeedsRotation.value) {
398
+ activeNeedsRotation.value = newFeatures.needsRotation;
399
+ }
400
+ if (newFeatures.needsPerParticleColor !== activeNeedsPerParticleColor.value) {
401
+ activeNeedsPerParticleColor.value = newFeatures.needsPerParticleColor;
402
+ }
403
+ if (newFeatures.turbulence !== activeTurbulence.value) {
404
+ activeTurbulence.value = newFeatures.turbulence;
405
+ }
406
+ if (newFeatures.attractors !== activeAttractors.value) {
407
+ activeAttractors.value = newFeatures.attractors;
408
+ }
409
+ if (newFeatures.collision !== activeCollision.value) {
410
+ activeCollision.value = newFeatures.collision;
411
+ }
412
+ if (newValues.position) {
413
+ system.setPosition(newValues.position);
414
+ }
415
+ if ("delay" in newValues) system.setDelay((_g = newValues.delay) != null ? _g : 0);
416
+ if ("emitCount" in newValues)
417
+ system.setEmitCount((_h = newValues.emitCount) != null ? _h : 1);
418
+ if (newValues.autoStart !== void 0) {
419
+ emitting.value = newValues.autoStart;
420
+ }
421
+ if (system.material && newValues.blending !== void 0) {
422
+ ;
423
+ system.material.blending = newValues.blending;
424
+ system.material.needsUpdate = true;
425
+ }
426
+ if (newValues.maxParticles !== void 0 && newValues.maxParticles !== activeMaxParticles.value) {
427
+ activeMaxParticles.value = newValues.maxParticles;
428
+ system.initialized = false;
429
+ system.nextIndex = 0;
430
+ }
431
+ if (newValues.lighting !== void 0 && newValues.lighting !== activeLighting.value) {
432
+ activeLighting.value = newValues.lighting;
433
+ }
434
+ if (newValues.appearance !== void 0 && newValues.appearance !== activeAppearance.value) {
435
+ activeAppearance.value = newValues.appearance;
436
+ }
437
+ if (newValues.orientToDirection !== void 0 && newValues.orientToDirection !== activeOrientToDirection.value) {
438
+ activeOrientToDirection.value = newValues.orientToDirection;
439
+ }
440
+ if (newValues.shadow !== void 0 && newValues.shadow !== activeShadow.value) {
441
+ activeShadow.value = newValues.shadow;
442
+ }
443
+ if ("geometryType" in newValues || "geometryArgs" in newValues) {
444
+ const geoType = (_i = newValues.geometryType) != null ? _i : prevGeometryTypeRef.value;
445
+ const geoArgs = (_j = newValues.geometryArgs) != null ? _j : prevGeometryArgsRef.value;
446
+ const geoTypeChanged = "geometryType" in newValues && geoType !== prevGeometryTypeRef.value;
447
+ const geoArgsChanged = "geometryArgs" in newValues && JSON.stringify(geoArgs) !== JSON.stringify(prevGeometryArgsRef.value);
448
+ if (geoTypeChanged || geoArgsChanged) {
449
+ prevGeometryTypeRef.value = geoType;
450
+ prevGeometryArgsRef.value = geoArgs;
451
+ import("debug-vfx").then((mod) => {
452
+ const { createGeometry, GeometryType } = mod;
453
+ if (geoType === GeometryType.NONE || !geoType) {
454
+ if (activeGeometry.value !== null && !props.geometry) {
455
+ activeGeometry.value.dispose();
456
+ }
457
+ activeGeometry.value = null;
458
+ } else {
459
+ const newGeometry = createGeometry(geoType, geoArgs);
460
+ if (newGeometry) {
461
+ if (activeGeometry.value !== null && activeGeometry.value !== props.geometry) {
462
+ activeGeometry.value.dispose();
463
+ }
464
+ activeGeometry.value = newGeometry;
465
+ }
466
+ }
467
+ });
468
+ }
469
+ }
470
+ }
471
+ function initDebugPanel() {
472
+ import("debug-vfx").then((mod) => {
473
+ const { renderDebugPanel, detectGeometryTypeAndArgs } = mod;
474
+ if (!debugValuesRef.value) {
475
+ const initialValues = __spreadValues({
476
+ name: props.name,
477
+ maxParticles: props.maxParticles,
478
+ size: props.size,
479
+ colorStart: props.colorStart,
480
+ colorEnd: props.colorEnd,
481
+ fadeSize: props.fadeSize,
482
+ fadeSizeCurve: props.fadeSizeCurve || null,
483
+ fadeOpacity: props.fadeOpacity,
484
+ fadeOpacityCurve: props.fadeOpacityCurve || null,
485
+ velocityCurve: props.velocityCurve || null,
486
+ gravity: props.gravity,
487
+ lifetime: props.lifetime,
488
+ direction: props.direction,
489
+ startPosition: props.startPosition,
490
+ startPositionAsDirection: props.startPositionAsDirection,
491
+ speed: props.speed,
492
+ friction: props.friction,
493
+ appearance: props.appearance,
494
+ rotation: props.rotation,
495
+ rotationSpeed: props.rotationSpeed,
496
+ rotationSpeedCurve: props.rotationSpeedCurve || null,
497
+ orientToDirection: props.orientToDirection,
498
+ orientAxis: props.orientAxis,
499
+ stretchBySpeed: props.stretchBySpeed || null,
500
+ lighting: props.lighting,
501
+ shadow: props.shadow,
502
+ blending: props.blending,
503
+ intensity: props.intensity,
504
+ position: props.position,
505
+ autoStart: props.autoStart,
506
+ delay: props.delay,
507
+ emitCount: props.emitCount,
508
+ emitterShape: props.emitterShape,
509
+ emitterRadius: props.emitterRadius,
510
+ emitterAngle: props.emitterAngle,
511
+ emitterHeight: props.emitterHeight,
512
+ emitterSurfaceOnly: props.emitterSurfaceOnly,
513
+ emitterDirection: props.emitterDirection,
514
+ turbulence: props.turbulence,
515
+ attractToCenter: props.attractToCenter,
516
+ softParticles: props.softParticles,
517
+ softDistance: props.softDistance,
518
+ collision: props.collision
519
+ }, detectGeometryTypeAndArgs(props.geometry));
520
+ debugValuesRef.value = initialValues;
521
+ prevGeometryTypeRef.value = initialValues.geometryType;
522
+ prevGeometryArgsRef.value = initialValues.geometryArgs;
523
+ }
524
+ renderDebugPanel(debugValuesRef.value, handleDebugUpdate, "tres");
525
+ });
526
+ }
527
+ watch(
528
+ () => [
529
+ props.maxParticles,
530
+ props.lighting,
531
+ props.appearance,
532
+ props.orientToDirection,
533
+ props.geometry,
534
+ props.shadow,
535
+ props.fadeSizeCurve,
536
+ props.fadeOpacityCurve,
537
+ props.velocityCurve,
538
+ props.rotationSpeedCurve,
539
+ props.colorStart.length,
540
+ props.colorEnd,
541
+ props.rotation,
542
+ props.rotationSpeed,
543
+ props.turbulence,
544
+ props.attractors,
545
+ props.collision
546
+ ],
547
+ () => {
548
+ var _a2, _b2, _c2, _d2;
549
+ if (props.debug) return;
550
+ activeMaxParticles.value = props.maxParticles;
551
+ activeLighting.value = props.lighting;
552
+ activeAppearance.value = props.appearance;
553
+ activeOrientToDirection.value = props.orientToDirection;
554
+ activeGeometry.value = props.geometry;
555
+ activeShadow.value = props.shadow;
556
+ activeFadeSizeCurve.value = props.fadeSizeCurve;
557
+ activeFadeOpacityCurve.value = props.fadeOpacityCurve;
558
+ activeVelocityCurve.value = props.velocityCurve;
559
+ activeRotationSpeedCurve.value = props.rotationSpeedCurve;
560
+ activeNeedsPerParticleColor.value = props.colorStart.length > 1 || props.colorEnd !== null;
561
+ activeNeedsRotation.value = isNonDefaultRotation(props.rotation) || isNonDefaultRotation(props.rotationSpeed);
562
+ activeTurbulence.value = props.turbulence !== null && ((_b2 = (_a2 = props.turbulence) == null ? void 0 : _a2.intensity) != null ? _b2 : 0) > 0;
563
+ activeAttractors.value = props.attractors !== null && ((_d2 = (_c2 = props.attractors) == null ? void 0 : _c2.length) != null ? _d2 : 0) > 0;
564
+ activeCollision.value = props.collision !== null;
565
+ }
566
+ );
567
+ watch(
568
+ [
569
+ activeMaxParticles,
570
+ activeLighting,
571
+ activeAppearance,
572
+ activeOrientToDirection,
573
+ activeGeometry,
574
+ activeShadow,
575
+ activeNeedsPerParticleColor,
576
+ activeNeedsRotation,
577
+ activeTurbulence,
578
+ activeAttractors,
579
+ activeCollision,
580
+ activeFadeSizeCurve,
581
+ activeFadeOpacityCurve,
582
+ activeVelocityCurve,
583
+ activeRotationSpeedCurve
584
+ ],
585
+ () => {
586
+ if (!isWebGPU.value) return;
587
+ initSystem();
588
+ }
589
+ );
590
+ watch(
591
+ () => [
592
+ props.position,
593
+ props.size,
594
+ props.fadeSize,
595
+ props.fadeOpacity,
596
+ props.gravity,
597
+ props.friction,
598
+ props.speed,
599
+ props.lifetime,
600
+ props.direction,
601
+ props.rotation,
602
+ props.rotationSpeed,
603
+ props.intensity,
604
+ props.colorStart,
605
+ props.colorEnd,
606
+ props.collision,
607
+ props.emitterShape,
608
+ props.emitterRadius,
609
+ props.emitterAngle,
610
+ props.emitterHeight,
611
+ props.emitterSurfaceOnly,
612
+ props.emitterDirection,
613
+ props.turbulence,
614
+ props.startPosition,
615
+ props.attractors,
616
+ props.attractToCenter,
617
+ props.startPositionAsDirection,
618
+ props.softParticles,
619
+ props.softDistance,
620
+ props.orientAxis,
621
+ props.stretchBySpeed,
622
+ props.delay,
623
+ props.emitCount
624
+ ],
625
+ () => {
626
+ var _a2, _b2;
627
+ if (props.debug) return;
628
+ const system = systemRef.value;
629
+ if (!system) return;
630
+ system.setPosition(props.position);
631
+ system.setDelay(props.delay);
632
+ system.setEmitCount(props.emitCount);
633
+ system.setTurbulenceSpeed((_b2 = (_a2 = props.turbulence) == null ? void 0 : _a2.speed) != null ? _b2 : 1);
634
+ const normalized = normalizeProps({
635
+ size: props.size,
636
+ speed: props.speed,
637
+ fadeSize: props.fadeSize,
638
+ fadeOpacity: props.fadeOpacity,
639
+ lifetime: props.lifetime,
640
+ gravity: props.gravity,
641
+ direction: props.direction,
642
+ startPosition: props.startPosition,
643
+ rotation: props.rotation,
644
+ rotationSpeed: props.rotationSpeed,
645
+ friction: props.friction,
646
+ intensity: props.intensity,
647
+ colorStart: props.colorStart,
648
+ colorEnd: props.colorEnd,
649
+ emitterShape: props.emitterShape,
650
+ emitterRadius: props.emitterRadius,
651
+ emitterAngle: props.emitterAngle,
652
+ emitterHeight: props.emitterHeight,
653
+ emitterSurfaceOnly: props.emitterSurfaceOnly,
654
+ emitterDirection: props.emitterDirection,
655
+ turbulence: props.turbulence,
656
+ attractors: props.attractors,
657
+ attractToCenter: props.attractToCenter,
658
+ startPositionAsDirection: props.startPositionAsDirection,
659
+ softParticles: props.softParticles,
660
+ softDistance: props.softDistance,
661
+ collision: props.collision,
662
+ orientAxis: props.orientAxis,
663
+ stretchBySpeed: props.stretchBySpeed
664
+ });
665
+ updateUniforms(system.uniforms, normalized);
666
+ },
667
+ { deep: true }
668
+ );
669
+ onBeforeRender(({ delta }) => {
670
+ const system = systemRef.value;
671
+ if (!system || !system.initialized) return;
672
+ system.update(delta);
673
+ if (emitting.value) {
674
+ system.autoEmit(delta);
675
+ }
676
+ });
677
+ onMounted(() => {
678
+ var _a2;
679
+ const mgr = rendererCtx;
680
+ if ((_a2 = mgr.isInitialized) == null ? void 0 : _a2.value) {
681
+ initSystem();
682
+ } else if (mgr.onReady) {
683
+ mgr.onReady(() => {
684
+ initSystem();
685
+ });
686
+ } else {
687
+ initSystem();
688
+ }
689
+ });
690
+ onUnmounted(() => {
691
+ if (props.debug) {
692
+ import("debug-vfx").then((mod) => {
693
+ mod.destroyDebugPanel();
694
+ });
695
+ }
696
+ destroySystem();
697
+ });
698
+ const api = {
699
+ spawn: (x = 0, y = 0, z = 0, count = 20, overrides = null) => {
700
+ const system = systemRef.value;
701
+ if (!system) return;
702
+ const [px, py, pz] = system.position;
703
+ system.spawn(px + x, py + y, pz + z, count, overrides);
704
+ },
705
+ start: () => {
706
+ const system = systemRef.value;
707
+ if (!system) return;
708
+ system.start();
709
+ emitting.value = true;
710
+ },
711
+ stop: () => {
712
+ const system = systemRef.value;
713
+ if (!system) return;
714
+ system.stop();
715
+ emitting.value = false;
716
+ },
717
+ clear: () => {
718
+ var _a2;
719
+ (_a2 = systemRef.value) == null ? void 0 : _a2.clear();
720
+ },
721
+ get isEmitting() {
722
+ return emitting.value;
723
+ },
724
+ get uniforms() {
725
+ var _a2, _b2;
726
+ return (_b2 = (_a2 = systemRef.value) == null ? void 0 : _a2.uniforms) != null ? _b2 : null;
727
+ }
728
+ };
729
+ expose(api);
730
+ return () => {
731
+ if (!isWebGPU.value) {
732
+ return slots.fallback ? slots.fallback() : null;
733
+ }
734
+ const obj = renderObjectRef.value;
735
+ if (!obj) return null;
736
+ return h("primitive", { object: obj });
737
+ };
738
+ }
739
+ });
740
+
741
+ // src/VFXEmitter.ts
742
+ import { defineComponent as defineComponent2, ref as ref2, watch as watch2, onMounted as onMounted2, h as h2 } from "vue";
743
+ import { useLoop as useLoop2, useTresContext as useTresContext2 } from "@tresjs/core";
744
+ import { Vector3, Quaternion } from "three/webgpu";
745
+ import {
746
+ EmitterController,
747
+ isWebGPUBackend as isWebGPUBackend2,
748
+ coreStore as coreStore2
749
+ } from "core-vfx";
750
+ var worldPos = new Vector3();
751
+ var worldQuat = new Quaternion();
752
+ var VFXEmitter = defineComponent2({
753
+ name: "VFXEmitter",
754
+ props: {
755
+ name: { type: String, default: void 0 },
756
+ particlesRef: { type: Object, default: void 0 },
757
+ position: {
758
+ type: null,
759
+ default: () => [0, 0, 0]
760
+ },
761
+ emitCount: { type: Number, default: 10 },
762
+ delay: { type: Number, default: 0 },
763
+ autoStart: { type: Boolean, default: true },
764
+ loop: { type: Boolean, default: true },
765
+ localDirection: { type: Boolean, default: false },
766
+ direction: {
767
+ type: null,
768
+ default: void 0
769
+ },
770
+ overrides: {
771
+ type: Object,
772
+ default: null
773
+ },
774
+ onEmit: {
775
+ type: Function,
776
+ default: void 0
777
+ }
778
+ },
779
+ setup(props, { expose, slots }) {
780
+ const { renderer } = useTresContext2();
781
+ const { onBeforeRender } = useLoop2();
782
+ const groupRef = ref2(null);
783
+ const isWebGPU = ref2(false);
784
+ const controller = new EmitterController({
785
+ emitCount: props.emitCount,
786
+ delay: props.delay,
787
+ autoStart: props.autoStart,
788
+ loop: props.loop,
789
+ localDirection: props.localDirection,
790
+ direction: props.direction,
791
+ overrides: props.overrides,
792
+ onEmit: props.onEmit
793
+ });
794
+ function getParticleSystem() {
795
+ if (props.particlesRef) {
796
+ return props.particlesRef.value || props.particlesRef;
797
+ }
798
+ return props.name ? coreStore2.getState().getParticles(props.name) : void 0;
799
+ }
800
+ watch2(
801
+ () => [
802
+ props.emitCount,
803
+ props.delay,
804
+ props.autoStart,
805
+ props.loop,
806
+ props.localDirection,
807
+ props.direction,
808
+ props.overrides,
809
+ props.onEmit
810
+ ],
811
+ () => {
812
+ controller.updateOptions({
813
+ emitCount: props.emitCount,
814
+ delay: props.delay,
815
+ autoStart: props.autoStart,
816
+ loop: props.loop,
817
+ localDirection: props.localDirection,
818
+ direction: props.direction,
819
+ overrides: props.overrides,
820
+ onEmit: props.onEmit
821
+ });
822
+ }
823
+ );
824
+ function checkWebGPU() {
825
+ const r = renderer.instance;
826
+ if (r && isWebGPUBackend2(r)) {
827
+ isWebGPU.value = true;
828
+ const system = getParticleSystem();
829
+ if (system) controller.setSystem(system);
830
+ }
831
+ }
832
+ onMounted2(() => {
833
+ var _a;
834
+ const mgr = renderer;
835
+ if ((_a = mgr.isInitialized) == null ? void 0 : _a.value) {
836
+ checkWebGPU();
837
+ } else if (mgr.onReady) {
838
+ mgr.onReady(() => {
839
+ checkWebGPU();
840
+ });
841
+ } else {
842
+ checkWebGPU();
843
+ }
844
+ });
845
+ onBeforeRender(({ delta }) => {
846
+ if (!isWebGPU.value) return;
847
+ if (!controller.getSystem()) {
848
+ const system = getParticleSystem();
849
+ if (system) controller.setSystem(system);
850
+ }
851
+ const group = groupRef.value;
852
+ if (!group) return;
853
+ group.getWorldPosition(worldPos);
854
+ group.getWorldQuaternion(worldQuat);
855
+ controller.update(delta, worldPos, worldQuat);
856
+ });
857
+ const emit = (emitOverrides = null) => {
858
+ const group = groupRef.value;
859
+ if (!group) return false;
860
+ if (!controller.getSystem()) {
861
+ const system = getParticleSystem();
862
+ if (system) controller.setSystem(system);
863
+ }
864
+ if (!controller.getSystem()) {
865
+ if (props.name) {
866
+ console.warn(
867
+ `VFXEmitter: No particle system found for name "${props.name}"`
868
+ );
869
+ }
870
+ return false;
871
+ }
872
+ group.getWorldPosition(worldPos);
873
+ group.getWorldQuaternion(worldQuat);
874
+ return controller.emitAtPosition(worldPos, worldQuat, emitOverrides);
875
+ };
876
+ const burst = (count) => {
877
+ const group = groupRef.value;
878
+ if (!group) return false;
879
+ if (!controller.getSystem()) {
880
+ const system = getParticleSystem();
881
+ if (system) controller.setSystem(system);
882
+ }
883
+ if (!controller.getSystem()) return false;
884
+ group.getWorldPosition(worldPos);
885
+ group.getWorldQuaternion(worldQuat);
886
+ return controller.burst(count, worldPos, worldQuat);
887
+ };
888
+ const start = () => controller.start();
889
+ const stop = () => controller.stop();
890
+ expose({
891
+ emit,
892
+ burst,
893
+ start,
894
+ stop,
895
+ get isEmitting() {
896
+ return controller.isEmitting;
897
+ },
898
+ getParticleSystem,
899
+ get group() {
900
+ return groupRef.value;
901
+ }
902
+ });
903
+ return () => {
904
+ return h2(
905
+ "TresGroup",
906
+ {
907
+ ref: (el) => {
908
+ groupRef.value = el;
909
+ },
910
+ position: props.position
911
+ },
912
+ slots.default ? slots.default() : void 0
913
+ );
914
+ };
915
+ }
916
+ });
917
+ function useVFXEmitter(name) {
918
+ const { renderer } = useTresContext2();
919
+ const isWebGPU = ref2(false);
920
+ onMounted2(() => {
921
+ var _a;
922
+ const mgr = renderer;
923
+ if ((_a = mgr.isInitialized) == null ? void 0 : _a.value) {
924
+ const r = renderer.instance;
925
+ if (r && isWebGPUBackend2(r)) {
926
+ isWebGPU.value = true;
927
+ }
928
+ } else if (mgr.onReady) {
929
+ mgr.onReady((r) => {
930
+ if (isWebGPUBackend2(r)) {
931
+ isWebGPU.value = true;
932
+ }
933
+ });
934
+ } else {
935
+ const r = renderer.instance;
936
+ if (r && isWebGPUBackend2(r)) {
937
+ isWebGPU.value = true;
938
+ }
939
+ }
940
+ });
941
+ const getParticles = () => coreStore2.getState().getParticles(name);
942
+ const emit = (position = [0, 0, 0], count = 20, overrides = null) => {
943
+ if (!isWebGPU.value) return false;
944
+ const [x, y, z] = position;
945
+ return coreStore2.getState().emit(name, { x, y, z, count, overrides });
946
+ };
947
+ const burst = (position = [0, 0, 0], count = 50, overrides = null) => {
948
+ if (!isWebGPU.value) return false;
949
+ const [x, y, z] = position;
950
+ return coreStore2.getState().emit(name, { x, y, z, count, overrides });
951
+ };
952
+ const start = () => {
953
+ if (!isWebGPU.value) return false;
954
+ return coreStore2.getState().start(name);
955
+ };
956
+ const stop = () => {
957
+ if (!isWebGPU.value) return false;
958
+ return coreStore2.getState().stop(name);
959
+ };
960
+ const clear = () => {
961
+ if (!isWebGPU.value) return false;
962
+ return coreStore2.getState().clear(name);
963
+ };
964
+ const isEmitting = () => {
965
+ var _a;
966
+ if (!isWebGPU.value) return false;
967
+ const particles = getParticles();
968
+ return (_a = particles == null ? void 0 : particles.isEmitting) != null ? _a : false;
969
+ };
970
+ const getUniforms = () => {
971
+ var _a;
972
+ if (!isWebGPU.value) return null;
973
+ const particles = getParticles();
974
+ return (_a = particles == null ? void 0 : particles.uniforms) != null ? _a : null;
975
+ };
976
+ return {
977
+ emit,
978
+ burst,
979
+ start,
980
+ stop,
981
+ clear,
982
+ isEmitting,
983
+ getUniforms,
984
+ getParticles: () => isWebGPU.value ? getParticles() : null
985
+ };
986
+ }
987
+
988
+ // src/vue-store.ts
989
+ import { ref as ref3, onUnmounted as onUnmounted3 } from "vue";
990
+ import { coreStore as coreStore3 } from "core-vfx";
991
+ function useVFXStore(selector) {
992
+ const pick = selector != null ? selector : ((s) => s);
993
+ const state = ref3(pick(coreStore3.getState()));
994
+ const unsubscribe = coreStore3.subscribe((s) => {
995
+ state.value = pick(s);
996
+ });
997
+ onUnmounted3(unsubscribe);
998
+ return state;
999
+ }
1000
+ useVFXStore.getState = coreStore3.getState;
1001
+ useVFXStore.setState = coreStore3.setState;
1002
+ useVFXStore.subscribe = coreStore3.subscribe;
1003
+
1
1004
  // src/index.ts
2
- console.log("tres-vfx");
1005
+ import {
1006
+ Appearance as Appearance2,
1007
+ Blending as Blending2,
1008
+ EmitterShape as EmitterShape2,
1009
+ AttractorType,
1010
+ Easing,
1011
+ Lighting as Lighting2,
1012
+ bakeCurveToArray,
1013
+ createCombinedCurveTexture,
1014
+ buildCurveTextureBin,
1015
+ CurveChannel
1016
+ } from "core-vfx";
1017
+ import {
1018
+ VFXParticleSystem as VFXParticleSystem2,
1019
+ EmitterController as EmitterController2,
1020
+ isWebGPUBackend as isWebGPUBackend3,
1021
+ isNonDefaultRotation as isNonDefaultRotation2,
1022
+ normalizeProps as normalizeProps2,
1023
+ resolveCurveTexture
1024
+ } from "core-vfx";
1025
+ export {
1026
+ Appearance2 as Appearance,
1027
+ AttractorType,
1028
+ Blending2 as Blending,
1029
+ CurveChannel,
1030
+ Easing,
1031
+ EmitterController2 as EmitterController,
1032
+ EmitterShape2 as EmitterShape,
1033
+ Lighting2 as Lighting,
1034
+ VFXEmitter,
1035
+ VFXParticleSystem2 as VFXParticleSystem,
1036
+ VFXParticles,
1037
+ bakeCurveToArray,
1038
+ buildCurveTextureBin,
1039
+ createCombinedCurveTexture,
1040
+ isNonDefaultRotation2 as isNonDefaultRotation,
1041
+ isWebGPUBackend3 as isWebGPUBackend,
1042
+ normalizeProps2 as normalizeProps,
1043
+ resolveCurveTexture,
1044
+ useVFXEmitter,
1045
+ useVFXStore
1046
+ };