r3f-vfx 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -18,6 +18,18 @@ var __spreadValues = (a, b) => {
18
18
  return a;
19
19
  };
20
20
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
21
33
  var __esm = (fn, res) => function __init() {
22
34
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
23
35
  };
@@ -45,6 +57,117 @@ var init_react_store = __esm({
45
57
  }
46
58
  });
47
59
 
60
+ // src/useCurveTextureAsync.ts
61
+ import { useRef, useEffect } from "react";
62
+ import {
63
+ createDefaultCurveTexture,
64
+ loadCurveTextureFromPath
65
+ } from "core-vfx";
66
+ var import_meta, curveWorker, curveWorkerCallbacks, curveWorkerIdCounter, getCurveWorker, bakeCurvesAsync, useCurveTextureAsync;
67
+ var init_useCurveTextureAsync = __esm({
68
+ "src/useCurveTextureAsync.ts"() {
69
+ "use strict";
70
+ import_meta = {};
71
+ curveWorker = null;
72
+ curveWorkerCallbacks = /* @__PURE__ */ new Map();
73
+ curveWorkerIdCounter = 0;
74
+ getCurveWorker = () => {
75
+ if (!curveWorker) {
76
+ curveWorker = new Worker(new URL("./curveWorker.js", import_meta.url), {
77
+ type: "module"
78
+ });
79
+ curveWorker.onmessage = (e) => {
80
+ const { id, rgba } = e.data;
81
+ const callback = curveWorkerCallbacks.get(id);
82
+ if (callback) {
83
+ callback(rgba);
84
+ curveWorkerCallbacks.delete(id);
85
+ }
86
+ };
87
+ }
88
+ return curveWorker;
89
+ };
90
+ bakeCurvesAsync = (sizeCurve, opacityCurve, velocityCurve, rotationSpeedCurve) => {
91
+ return new Promise((resolve) => {
92
+ const worker = getCurveWorker();
93
+ const id = curveWorkerIdCounter++;
94
+ curveWorkerCallbacks.set(id, resolve);
95
+ worker.postMessage({
96
+ id,
97
+ sizeCurve,
98
+ opacityCurve,
99
+ velocityCurve,
100
+ rotationSpeedCurve
101
+ });
102
+ });
103
+ };
104
+ useCurveTextureAsync = (sizeCurve, opacityCurve, velocityCurve, rotationSpeedCurve, curveTexturePath = null) => {
105
+ const textureRef = useRef(null);
106
+ const pendingRef = useRef(null);
107
+ if (!textureRef.current) {
108
+ textureRef.current = createDefaultCurveTexture();
109
+ }
110
+ useEffect(() => {
111
+ const requestId = {};
112
+ pendingRef.current = requestId;
113
+ const hasAnyCurve = sizeCurve || opacityCurve || velocityCurve || rotationSpeedCurve;
114
+ if (curveTexturePath) {
115
+ loadCurveTextureFromPath(curveTexturePath, textureRef.current).catch(
116
+ (err) => {
117
+ console.warn(
118
+ `Failed to load curve texture: ${curveTexturePath}, falling back to baking`,
119
+ err
120
+ );
121
+ return bakeCurvesAsync(
122
+ sizeCurve,
123
+ opacityCurve,
124
+ velocityCurve,
125
+ rotationSpeedCurve
126
+ ).then((rgba) => {
127
+ var _a;
128
+ if (pendingRef.current === requestId && ((_a = textureRef.current) == null ? void 0 : _a.image.data)) {
129
+ textureRef.current.image.data.set(rgba);
130
+ textureRef.current.needsUpdate = true;
131
+ }
132
+ });
133
+ }
134
+ );
135
+ } else if (hasAnyCurve) {
136
+ bakeCurvesAsync(
137
+ sizeCurve,
138
+ opacityCurve,
139
+ velocityCurve,
140
+ rotationSpeedCurve
141
+ ).then((rgba) => {
142
+ var _a;
143
+ if (pendingRef.current === requestId && ((_a = textureRef.current) == null ? void 0 : _a.image.data)) {
144
+ textureRef.current.image.data.set(rgba);
145
+ textureRef.current.needsUpdate = true;
146
+ }
147
+ });
148
+ }
149
+ return () => {
150
+ pendingRef.current = null;
151
+ };
152
+ }, [
153
+ sizeCurve,
154
+ opacityCurve,
155
+ velocityCurve,
156
+ rotationSpeedCurve,
157
+ curveTexturePath
158
+ ]);
159
+ useEffect(() => {
160
+ return () => {
161
+ var _a;
162
+ (_a = textureRef.current) == null ? void 0 : _a.dispose();
163
+ textureRef.current = null;
164
+ };
165
+ }, []);
166
+ return textureRef.current;
167
+ };
168
+ }
169
+ });
170
+
48
171
  // src/VFXParticlesDebugPanel.jsx
49
172
  var VFXParticlesDebugPanel_exports = {};
50
173
  __export(VFXParticlesDebugPanel_exports, {
@@ -57,7 +180,7 @@ __export(VFXParticlesDebugPanel_exports, {
57
180
  updateDebugPanel: () => updateDebugPanel
58
181
  });
59
182
  import { createRoot } from "react-dom/client";
60
- import { useState, useCallback, useRef, useEffect } from "react";
183
+ import { useState, useCallback, useRef as useRef2, useEffect as useEffect2 } from "react";
61
184
  import * as THREE from "three";
62
185
  import { create } from "zustand";
63
186
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -74,7 +197,7 @@ function renderDebugPanel(values, onChange) {
74
197
  style.id = styleId;
75
198
  style.textContent = `
76
199
  @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
77
-
200
+
78
201
  @keyframes dotPulse {
79
202
  0%, 100% {
80
203
  box-shadow: 0 0 4px rgba(249, 115, 22, 0.4), 0 0 8px rgba(249, 115, 22, 0.2);
@@ -85,12 +208,12 @@ function renderDebugPanel(values, onChange) {
85
208
  transform: scale(1.1);
86
209
  }
87
210
  }
88
-
211
+
89
212
  @keyframes spin {
90
213
  from { transform: rotate(0deg); }
91
214
  to { transform: rotate(360deg); }
92
215
  }
93
-
216
+
94
217
  #vfx-debug-panel-root *::-webkit-scrollbar {
95
218
  width: 6px;
96
219
  height: 6px;
@@ -225,7 +348,7 @@ function destroyDebugPanel() {
225
348
  currentValues = null;
226
349
  currentOnChange = null;
227
350
  }
228
- var useDebugPanelStore, getFlushChanges, setFlushChanges, GeometryType, geometryDefaults, DEFAULT_VALUES, createGeometry, debugRoot, debugContainer, currentValues, currentOnChange, wrapped, formatJSXValue, geometryTypeToJSX, generateVFXParticlesJSX, styles, parseRange, parse3D, Section, useScrubber, ScrubInput, NumberInput, RangeInput, Vec3Input, Range3DInput, SelectInput, CheckboxInput, CustomColorPicker, ColorArrayInput, EasingCurveEditor, LoadingSpinner, DebugPanelContent, VFXParticlesDebugPanel_default;
351
+ var useDebugPanelStore, getFlushChanges, setFlushChanges, GeometryType, geometryDefaults, DEFAULT_VALUES, createGeometry, debugRoot, debugContainer, currentValues, currentOnChange, wrapped, formatJSXValue, geometryTypeToJSX, arraysEqual, isDefaultFriction, isDefaultTurbulence, generateVFXParticlesJSX, styles, parseRange, parse3D, Section, useScrubber, ScrubInput, NumberInput, RangeInput, Vec3Input, Range3DInput, SelectInput, CheckboxInput, CustomColorPicker, ColorArrayInput, EasingCurveEditor, LoadingSpinner, DebugPanelContent, VFXParticlesDebugPanel_default;
229
352
  var init_VFXParticlesDebugPanel = __esm({
230
353
  "src/VFXParticlesDebugPanel.jsx"() {
231
354
  "use strict";
@@ -432,17 +555,11 @@ var init_VFXParticlesDebugPanel = __esm({
432
555
  mergedArgs.detail
433
556
  );
434
557
  case GeometryType.ICOSAHEDRON:
435
- return new THREE.IcosahedronGeometry(
436
- mergedArgs.radius,
437
- mergedArgs.detail
438
- );
558
+ return new THREE.IcosahedronGeometry(mergedArgs.radius, mergedArgs.detail);
439
559
  case GeometryType.OCTAHEDRON:
440
560
  return new THREE.OctahedronGeometry(mergedArgs.radius, mergedArgs.detail);
441
561
  case GeometryType.TETRAHEDRON:
442
- return new THREE.TetrahedronGeometry(
443
- mergedArgs.radius,
444
- mergedArgs.detail
445
- );
562
+ return new THREE.TetrahedronGeometry(mergedArgs.radius, mergedArgs.detail);
446
563
  case GeometryType.CAPSULE:
447
564
  return new THREE.CapsuleGeometry(
448
565
  mergedArgs.radius,
@@ -584,9 +701,31 @@ ${" ".repeat(indent - 2)}}`;
584
701
  return null;
585
702
  }
586
703
  };
704
+ arraysEqual = (a, b) => {
705
+ if (!Array.isArray(a) || !Array.isArray(b)) return false;
706
+ if (a.length !== b.length) return false;
707
+ return a.every((v, i) => {
708
+ if (Array.isArray(v) && Array.isArray(b[i])) return arraysEqual(v, b[i]);
709
+ return v === b[i];
710
+ });
711
+ };
712
+ isDefaultFriction = (f) => {
713
+ if (!f) return true;
714
+ const intensity = f.intensity;
715
+ if (Array.isArray(intensity)) {
716
+ return intensity[0] === 0 && intensity[1] === 0;
717
+ }
718
+ return intensity === 0 || intensity === void 0;
719
+ };
720
+ isDefaultTurbulence = (t) => {
721
+ if (!t) return true;
722
+ return t.intensity === 0 || t.intensity === void 0;
723
+ };
587
724
  generateVFXParticlesJSX = (values) => {
588
725
  const props = [];
589
726
  const propOrder = [
727
+ "name",
728
+ "curveTexturePath",
590
729
  "maxParticles",
591
730
  "position",
592
731
  "autoStart",
@@ -639,24 +778,61 @@ ${" ".repeat(indent - 2)}}`;
639
778
  for (const key of propOrder) {
640
779
  const value = values[key];
641
780
  if (value === void 0 || value === null) continue;
781
+ if (key === "name" && !value) continue;
782
+ if (key === "curveTexturePath" && !value) continue;
642
783
  if (key === "maxParticles" && value === 1e4) continue;
784
+ if (key === "position" && arraysEqual(value, [0, 0, 0])) continue;
643
785
  if (key === "autoStart" && value === true) continue;
644
786
  if (key === "emitCount" && value === 1) continue;
645
787
  if (key === "delay" && value === 0) continue;
646
788
  if (key === "intensity" && value === 1) continue;
789
+ if (key === "size" && arraysEqual(value, [0.1, 0.3])) continue;
790
+ if (key === "speed" && arraysEqual(value, [0.1, 0.1])) continue;
791
+ if (key === "lifetime" && arraysEqual(value, [1, 2])) continue;
792
+ if (key === "fadeSize" && arraysEqual(value, [1, 0])) continue;
793
+ if (key === "fadeOpacity" && arraysEqual(value, [1, 0])) continue;
794
+ if (key === "colorStart" && arraysEqual(value, ["#ffffff"])) continue;
795
+ if (key === "gravity" && arraysEqual(value, [0, 0, 0])) continue;
796
+ if (key === "friction" && isDefaultFriction(value)) continue;
797
+ if (key === "friction" && values.velocityCurve) continue;
798
+ if (key === "direction" && arraysEqual(value, [
799
+ [-1, 1],
800
+ [0, 1],
801
+ [-1, 1]
802
+ ]))
803
+ continue;
804
+ if (key === "direction" && values.startPositionAsDirection) continue;
805
+ if (key === "startPosition" && arraysEqual(value, [
806
+ [0, 0],
807
+ [0, 0],
808
+ [0, 0]
809
+ ]))
810
+ continue;
811
+ if (key === "startPositionAsDirection" && value === false) continue;
812
+ if (key === "rotation" && arraysEqual(value, [0, 0])) continue;
813
+ if (key === "rotationSpeed" && arraysEqual(value, [0, 0])) continue;
814
+ if (key === "appearance" && value === 0) continue;
815
+ if (key === "blending" && value === 1) continue;
816
+ if (key === "lighting" && value === 1) continue;
647
817
  if (key === "shadow" && value === false) continue;
648
818
  if (key === "orientToDirection" && value === false) continue;
649
819
  if (key === "orientAxis") {
650
820
  const axisNeeded = values.orientToDirection || values.stretchBySpeed;
651
821
  if (!axisNeeded || value === "z" || value === "+z") continue;
652
822
  }
653
- if (key === "softParticles" && value === false) continue;
654
- if (key === "attractToCenter" && value === false) continue;
655
- if (key === "startPositionAsDirection" && value === false) continue;
656
- if (key === "direction" && values.startPositionAsDirection) continue;
823
+ if (key === "stretchBySpeed" && !value) continue;
824
+ if (key === "emitterShape" && value === 0) continue;
825
+ if (key === "emitterRadius" && arraysEqual(value, [0, 1])) continue;
826
+ if (key === "emitterAngle" && Math.abs(value - Math.PI / 4) < 1e-3)
827
+ continue;
828
+ if (key === "emitterHeight" && arraysEqual(value, [0, 1])) continue;
829
+ if (key === "emitterDirection" && arraysEqual(value, [0, 1, 0])) continue;
657
830
  if (key === "emitterSurfaceOnly" && value === false) continue;
831
+ if (key === "turbulence" && isDefaultTurbulence(value)) continue;
832
+ if (key === "collision" && !value) continue;
833
+ if (key === "softParticles" && value === false) continue;
658
834
  if (key === "softDistance" && !values.softParticles) continue;
659
- if (key === "friction" && values.velocityCurve) continue;
835
+ if (key === "attractToCenter" && value === false) continue;
660
836
  const formatted = formatJSXValue(key, value);
661
837
  if (formatted) props.push(formatted);
662
838
  }
@@ -1070,9 +1246,9 @@ ${" ".repeat(indent - 2)}}`;
1070
1246
  }) => {
1071
1247
  const [isOpen, setIsOpen] = useState(defaultOpen);
1072
1248
  const [isHovered, setIsHovered] = useState(false);
1073
- const contentRef = useRef(null);
1249
+ const contentRef = useRef2(null);
1074
1250
  const [contentHeight, setContentHeight] = useState(defaultOpen ? "auto" : 0);
1075
- useEffect(() => {
1251
+ useEffect2(() => {
1076
1252
  if (contentRef.current) {
1077
1253
  if (isOpen) {
1078
1254
  const height = contentRef.current.scrollHeight;
@@ -1149,10 +1325,10 @@ ${" ".repeat(indent - 2)}}`;
1149
1325
  );
1150
1326
  };
1151
1327
  useScrubber = (value, onChange, step = 0.01, min, max) => {
1152
- const isDraggingRef = useRef(false);
1153
- const hasMoved = useRef(false);
1154
- const startX = useRef(0);
1155
- const startValue = useRef(0);
1328
+ const isDraggingRef = useRef2(false);
1329
+ const hasMoved = useRef2(false);
1330
+ const startX = useRef2(0);
1331
+ const startValue = useRef2(0);
1156
1332
  const [isDragging, setIsDragging] = useState(false);
1157
1333
  const handleMouseDown = useCallback(
1158
1334
  (e) => {
@@ -1210,7 +1386,7 @@ ${" ".repeat(indent - 2)}}`;
1210
1386
  style,
1211
1387
  placeholder
1212
1388
  }) => {
1213
- const inputRef = useRef(null);
1389
+ const inputRef = useRef2(null);
1214
1390
  const [localValue, setLocalValue] = useState(String(value));
1215
1391
  const [isFocused, setIsFocused] = useState(false);
1216
1392
  const { handleMouseDown, hasMoved, isDragging } = useScrubber(
@@ -1220,7 +1396,7 @@ ${" ".repeat(indent - 2)}}`;
1220
1396
  min,
1221
1397
  max
1222
1398
  );
1223
- useEffect(() => {
1399
+ useEffect2(() => {
1224
1400
  if (!isFocused) {
1225
1401
  setLocalValue(String(value));
1226
1402
  }
@@ -1592,10 +1768,10 @@ ${" ".repeat(indent - 2)}}`;
1592
1768
  CustomColorPicker = ({ color, onChange }) => {
1593
1769
  const [isOpen, setIsOpen] = useState(false);
1594
1770
  const [hexInput, setHexInput] = useState(color);
1595
- const pickerRef = useRef(null);
1596
- const gradientRef = useRef(null);
1597
- const isDraggingGradient = useRef(false);
1598
- const isDraggingHue = useRef(false);
1771
+ const pickerRef = useRef2(null);
1772
+ const gradientRef = useRef2(null);
1773
+ const isDraggingGradient = useRef2(false);
1774
+ const isDraggingHue = useRef2(false);
1599
1775
  const presets = [
1600
1776
  "#ffffff",
1601
1777
  "#f97316",
@@ -1688,13 +1864,13 @@ ${" ".repeat(indent - 2)}}`;
1688
1864
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1689
1865
  };
1690
1866
  const [hsv, setHsv] = useState(() => hexToHsv(color));
1691
- useEffect(() => {
1867
+ useEffect2(() => {
1692
1868
  if (!isOpen) {
1693
1869
  setHsv(hexToHsv(color));
1694
1870
  setHexInput(color);
1695
1871
  }
1696
1872
  }, [color, isOpen]);
1697
- useEffect(() => {
1873
+ useEffect2(() => {
1698
1874
  if (!isOpen) return;
1699
1875
  const handleClickOutside = (e) => {
1700
1876
  if (pickerRef.current && !pickerRef.current.contains(e.target)) {
@@ -2024,21 +2200,21 @@ ${" ".repeat(indent - 2)}}`;
2024
2200
  { pos: [1, 0], handleIn: [-0.3, 0] }
2025
2201
  ]
2026
2202
  };
2027
- const canvasRef = useRef(null);
2028
- const containerRef = useRef(null);
2029
- const draggingRef = useRef(null);
2030
- const localDataRef = useRef((value == null ? void 0 : value.points) || defaultValue.points);
2203
+ const canvasRef = useRef2(null);
2204
+ const containerRef = useRef2(null);
2205
+ const draggingRef = useRef2(null);
2206
+ const localDataRef = useRef2((value == null ? void 0 : value.points) || defaultValue.points);
2031
2207
  const [, forceUpdate] = useState(0);
2032
2208
  const [hoverItem, setHoverItem] = useState(null);
2033
2209
  const [selectedPoint, setSelectedPoint] = useState(null);
2034
2210
  const [isScaling, setIsScaling] = useState(false);
2035
- const scaleStartRef = useRef(null);
2211
+ const scaleStartRef = useRef2(null);
2036
2212
  const [isRotating, setIsRotating] = useState(false);
2037
- const rotateStartRef = useRef(null);
2213
+ const rotateStartRef = useRef2(null);
2038
2214
  const SIZE = 260;
2039
2215
  const PADDING = 30;
2040
2216
  const GRAPH_SIZE = SIZE - 2 * PADDING;
2041
- useEffect(() => {
2217
+ useEffect2(() => {
2042
2218
  if (value == null ? void 0 : value.points) {
2043
2219
  localDataRef.current = value.points;
2044
2220
  forceUpdate((n) => n + 1);
@@ -2229,7 +2405,7 @@ ${" ".repeat(indent - 2)}}`;
2229
2405
  ctx.fillText("value \u2192", 0, 0);
2230
2406
  ctx.restore();
2231
2407
  }, [toCanvas, hoverItem, GRAPH_SIZE, selectedPoint, isScaling, isRotating]);
2232
- useEffect(() => {
2408
+ useEffect2(() => {
2233
2409
  draw();
2234
2410
  }, [draw]);
2235
2411
  const hitTest = useCallback(
@@ -2266,7 +2442,7 @@ ${" ".repeat(indent - 2)}}`;
2266
2442
  },
2267
2443
  [toCanvas]
2268
2444
  );
2269
- useEffect(() => {
2445
+ useEffect2(() => {
2270
2446
  const handleMouseMove = (e) => {
2271
2447
  if (!canvasRef.current) return;
2272
2448
  const rect = canvasRef.current.getBoundingClientRect();
@@ -3376,22 +3552,23 @@ ${" ".repeat(indent - 2)}}`;
3376
3552
  const [isMinimized, setIsMinimized] = useState(false);
3377
3553
  const [panelSize, setPanelSize] = useState({ width: 380, height: null });
3378
3554
  const [copySuccess, setCopySuccess] = useState(false);
3555
+ const [bakeSuccess, setBakeSuccess] = useState(false);
3379
3556
  const [hasPendingChanges, setHasPendingChanges] = useState(false);
3380
- const valuesRef = useRef(initialValues);
3381
- const dirtyKeysRef = useRef(/* @__PURE__ */ new Set());
3557
+ const valuesRef = useRef2(initialValues);
3558
+ const dirtyKeysRef = useRef2(/* @__PURE__ */ new Set());
3382
3559
  const [, forceUpdate] = useState(0);
3383
- const isResizing = useRef(false);
3384
- const resizeType = useRef(null);
3385
- const debounceTimerRef = useRef(null);
3560
+ const isResizing = useRef2(false);
3561
+ const resizeType = useRef2(null);
3562
+ const debounceTimerRef = useRef2(null);
3386
3563
  const DEBOUNCE_DELAY = 500;
3387
3564
  const [searchQuery, setSearchQuery] = useState("");
3388
- const historyRef = useRef([JSON.parse(JSON.stringify(initialValues))]);
3565
+ const historyRef = useRef2([JSON.parse(JSON.stringify(initialValues))]);
3389
3566
  const [historyIndex, setHistoryIndex] = useState(0);
3390
3567
  const [historyLength, setHistoryLength] = useState(1);
3391
3568
  const MAX_HISTORY = 50;
3392
- const isUndoingRef = useRef(false);
3393
- const prevInitialValuesRef = useRef(initialValues);
3394
- useEffect(() => {
3569
+ const isUndoingRef = useRef2(false);
3570
+ const prevInitialValuesRef = useRef2(initialValues);
3571
+ useEffect2(() => {
3395
3572
  if (initialValues !== prevInitialValuesRef.current) {
3396
3573
  const merged = __spreadValues({}, valuesRef.current);
3397
3574
  for (const key in initialValues) {
@@ -3428,7 +3605,7 @@ ${" ".repeat(indent - 2)}}`;
3428
3605
  flushChanges();
3429
3606
  }, DEBOUNCE_DELAY);
3430
3607
  }, [flushChanges]);
3431
- useEffect(() => {
3608
+ useEffect2(() => {
3432
3609
  return () => {
3433
3610
  if (debounceTimerRef.current) {
3434
3611
  clearTimeout(debounceTimerRef.current);
@@ -3448,7 +3625,118 @@ ${" ".repeat(indent - 2)}}`;
3448
3625
  console.error("Failed to copy:", err);
3449
3626
  }
3450
3627
  }, [hasPendingChanges, flushChanges]);
3451
- const recordHistoryTimeoutRef = useRef(null);
3628
+ const handleBakeCurves = useCallback(async () => {
3629
+ if (hasPendingChanges) {
3630
+ flushChanges();
3631
+ }
3632
+ const values2 = valuesRef.current;
3633
+ const CURVE_RESOLUTION2 = 256;
3634
+ const evaluateBezierSegment = (t, p0, p1, h0Out, h1In) => {
3635
+ const cp0 = p0;
3636
+ const cp1 = [p0[0] + ((h0Out == null ? void 0 : h0Out[0]) || 0), p0[1] + ((h0Out == null ? void 0 : h0Out[1]) || 0)];
3637
+ const cp2 = [p1[0] + ((h1In == null ? void 0 : h1In[0]) || 0), p1[1] + ((h1In == null ? void 0 : h1In[1]) || 0)];
3638
+ const cp3 = p1;
3639
+ const mt = 1 - t;
3640
+ const mt2 = mt * mt;
3641
+ const mt3 = mt2 * mt;
3642
+ const t2 = t * t;
3643
+ const t3 = t2 * t;
3644
+ return [
3645
+ mt3 * cp0[0] + 3 * mt2 * t * cp1[0] + 3 * mt * t2 * cp2[0] + t3 * cp3[0],
3646
+ mt3 * cp0[1] + 3 * mt2 * t * cp1[1] + 3 * mt * t2 * cp2[1] + t3 * cp3[1]
3647
+ ];
3648
+ };
3649
+ const sampleCurveAtX = (x, points) => {
3650
+ var _a2, _b2, _c2, _d2;
3651
+ if (!points || points.length < 2) return x;
3652
+ if (!((_a2 = points[0]) == null ? void 0 : _a2.pos) || !((_b2 = points[points.length - 1]) == null ? void 0 : _b2.pos)) return x;
3653
+ let segmentIdx = 0;
3654
+ for (let i = 0; i < points.length - 1; i++) {
3655
+ if (((_c2 = points[i]) == null ? void 0 : _c2.pos) && ((_d2 = points[i + 1]) == null ? void 0 : _d2.pos) && x >= points[i].pos[0] && x <= points[i + 1].pos[0]) {
3656
+ segmentIdx = i;
3657
+ break;
3658
+ }
3659
+ }
3660
+ const p0 = points[segmentIdx];
3661
+ const p1 = points[segmentIdx + 1];
3662
+ if (!(p0 == null ? void 0 : p0.pos) || !(p1 == null ? void 0 : p1.pos)) return x;
3663
+ let tLow = 0, tHigh = 1, t = 0.5;
3664
+ for (let iter = 0; iter < 20; iter++) {
3665
+ const [px] = evaluateBezierSegment(
3666
+ t,
3667
+ p0.pos,
3668
+ p1.pos,
3669
+ p0.handleOut,
3670
+ p1.handleIn
3671
+ );
3672
+ if (Math.abs(px - x) < 1e-4) break;
3673
+ if (px < x) {
3674
+ tLow = t;
3675
+ } else {
3676
+ tHigh = t;
3677
+ }
3678
+ t = (tLow + tHigh) / 2;
3679
+ }
3680
+ const [, py] = evaluateBezierSegment(
3681
+ t,
3682
+ p0.pos,
3683
+ p1.pos,
3684
+ p0.handleOut,
3685
+ p1.handleIn
3686
+ );
3687
+ return Math.max(-0.5, Math.min(1.5, py));
3688
+ };
3689
+ const bakeCurveToArray2 = (curveData) => {
3690
+ const data = new Float32Array(CURVE_RESOLUTION2);
3691
+ if (!(curveData == null ? void 0 : curveData.points) || !Array.isArray(curveData.points) || curveData.points.length < 2) {
3692
+ for (let i = 0; i < CURVE_RESOLUTION2; i++) {
3693
+ data[i] = 1 - i / (CURVE_RESOLUTION2 - 1);
3694
+ }
3695
+ return data;
3696
+ }
3697
+ const firstPoint = curveData.points[0];
3698
+ const lastPoint = curveData.points[curveData.points.length - 1];
3699
+ if (!(firstPoint == null ? void 0 : firstPoint.pos) || !(lastPoint == null ? void 0 : lastPoint.pos) || !Array.isArray(firstPoint.pos) || !Array.isArray(lastPoint.pos)) {
3700
+ for (let i = 0; i < CURVE_RESOLUTION2; i++) {
3701
+ data[i] = 1 - i / (CURVE_RESOLUTION2 - 1);
3702
+ }
3703
+ return data;
3704
+ }
3705
+ for (let i = 0; i < CURVE_RESOLUTION2; i++) {
3706
+ const x = i / (CURVE_RESOLUTION2 - 1);
3707
+ data[i] = sampleCurveAtX(x, curveData.points);
3708
+ }
3709
+ return data;
3710
+ };
3711
+ const sizeData = bakeCurveToArray2(values2.fadeSizeCurve);
3712
+ const opacityData = bakeCurveToArray2(values2.fadeOpacityCurve);
3713
+ const velocityData = bakeCurveToArray2(values2.velocityCurve);
3714
+ const rotationSpeedData = bakeCurveToArray2(values2.rotationSpeedCurve);
3715
+ const rgba = new Float32Array(CURVE_RESOLUTION2 * 4);
3716
+ for (let i = 0; i < CURVE_RESOLUTION2; i++) {
3717
+ rgba[i * 4] = sizeData[i];
3718
+ rgba[i * 4 + 1] = opacityData[i];
3719
+ rgba[i * 4 + 2] = velocityData[i];
3720
+ rgba[i * 4 + 3] = rotationSpeedData[i];
3721
+ }
3722
+ const vfxName = values2.name || `vfx-curves-${Date.now()}`;
3723
+ const filename = `${vfxName.replace(/[^a-zA-Z0-9-_]/g, "-")}.bin`;
3724
+ const blob = new Blob([rgba.buffer], { type: "application/octet-stream" });
3725
+ const link = document.createElement("a");
3726
+ link.download = filename;
3727
+ link.href = URL.createObjectURL(blob);
3728
+ link.click();
3729
+ URL.revokeObjectURL(link.href);
3730
+ setBakeSuccess(true);
3731
+ setTimeout(() => setBakeSuccess(false), 2e3);
3732
+ const texturePath = `/vfx/curves/${filename}`;
3733
+ try {
3734
+ await navigator.clipboard.writeText(`curveTexturePath="${texturePath}"`);
3735
+ } catch (err) {
3736
+ console.error("Failed to copy texture path:", err);
3737
+ }
3738
+ }, [hasPendingChanges, flushChanges]);
3739
+ const recordHistoryTimeoutRef = useRef2(null);
3452
3740
  const recordHistory = useCallback(() => {
3453
3741
  if (isUndoingRef.current) return;
3454
3742
  if (recordHistoryTimeoutRef.current) {
@@ -3497,9 +3785,7 @@ ${" ".repeat(indent - 2)}}`;
3497
3785
  isUndoingRef.current = true;
3498
3786
  const newIndex = historyIndex + 1;
3499
3787
  setHistoryIndex(newIndex);
3500
- const nextState = JSON.parse(
3501
- JSON.stringify(historyRef.current[newIndex])
3502
- );
3788
+ const nextState = JSON.parse(JSON.stringify(historyRef.current[newIndex]));
3503
3789
  valuesRef.current = nextState;
3504
3790
  for (const key in nextState) {
3505
3791
  dirtyKeysRef.current.add(key);
@@ -3538,7 +3824,7 @@ ${" ".repeat(indent - 2)}}`;
3538
3824
  isUndoingRef.current = false;
3539
3825
  }, 50);
3540
3826
  }, [flushChanges, historyIndex]);
3541
- useEffect(() => {
3827
+ useEffect2(() => {
3542
3828
  const handleKeyDown = (e) => {
3543
3829
  if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")
3544
3830
  return;
@@ -3593,7 +3879,7 @@ ${" ".repeat(indent - 2)}}`;
3593
3879
  },
3594
3880
  [scheduleUpdate, recordHistory]
3595
3881
  );
3596
- useEffect(() => {
3882
+ useEffect2(() => {
3597
3883
  setFlushChanges(flushChanges);
3598
3884
  return () => setFlushChanges(null);
3599
3885
  }, [flushChanges]);
@@ -3835,6 +4121,16 @@ ${" ".repeat(indent - 2)}}`;
3835
4121
  children: copySuccess ? "\u2713 copied" : "copy jsx"
3836
4122
  }
3837
4123
  ),
4124
+ /* @__PURE__ */ jsx(
4125
+ "button",
4126
+ {
4127
+ style: __spreadProps(__spreadValues(__spreadValues({}, styles.copyBtn), bakeSuccess ? styles.copyBtnSuccess : {}), {
4128
+ marginLeft: "4px"
4129
+ }),
4130
+ onClick: handleBakeCurves,
4131
+ children: bakeSuccess ? "\u2713 exported" : "bake curves"
4132
+ }
4133
+ ),
3838
4134
  /* @__PURE__ */ jsx(
3839
4135
  "button",
3840
4136
  {
@@ -5128,8 +5424,8 @@ ${" ".repeat(indent - 2)}}`;
5128
5424
  import {
5129
5425
  forwardRef,
5130
5426
  useImperativeHandle,
5131
- useEffect as useEffect2,
5132
- useRef as useRef2,
5427
+ useEffect as useEffect3,
5428
+ useRef as useRef3,
5133
5429
  useMemo,
5134
5430
  useCallback as useCallback2,
5135
5431
  useState as useState2
@@ -5149,7 +5445,6 @@ import {
5149
5445
  axisToNumber,
5150
5446
  toRotation3D,
5151
5447
  lifetimeToFadeRate,
5152
- createCombinedCurveTexture,
5153
5448
  createInitCompute,
5154
5449
  createSpawnCompute,
5155
5450
  createUpdateCompute,
@@ -5171,1286 +5466,1433 @@ var init_VFXParticles = __esm({
5171
5466
  "src/VFXParticles.tsx"() {
5172
5467
  "use strict";
5173
5468
  init_react_store();
5174
- VFXParticles = forwardRef(function VFXParticles2({
5175
- name,
5176
- // Optional name for registering with useVFXStore (enables VFXEmitter linking)
5177
- maxParticles = 1e4,
5178
- size = [0.1, 0.3],
5179
- colorStart = ["#ffffff"],
5180
- colorEnd = null,
5181
- // If null, uses colorStart (no color transition)
5182
- fadeSize = [1, 0],
5183
- fadeSizeCurve = null,
5184
- // Curve data { points: [...] } - controls fadeSize over lifetime (overrides fadeSize if set)
5185
- fadeOpacity = [1, 0],
5186
- fadeOpacityCurve = null,
5187
- // Curve data { points: [...] } - controls fadeOpacity over lifetime (overrides fadeOpacity if set)
5188
- velocityCurve = null,
5189
- // Curve data { points: [...] } - controls velocity/speed over lifetime (overrides friction if set)
5190
- gravity = [0, 0, 0],
5191
- lifetime = [1, 2],
5192
- direction = [
5193
- [-1, 1],
5194
- [0, 1],
5195
- [-1, 1]
5196
- ],
5197
- // [[minX, maxX], [minY, maxY], [minZ, maxZ]] or [min, max] for all axes
5198
- startPosition = [
5199
- [0, 0],
5200
- [0, 0],
5201
- [0, 0]
5202
- ],
5203
- // [[minX, maxX], [minY, maxY], [minZ, maxZ]] offset from spawn position
5204
- speed = [0.1, 0.1],
5205
- friction = { intensity: 0, easing: "linear" },
5206
- // { intensity: [start, end] or single value, easing: string }
5207
- // intensity: 1 = max friction (almost stopped), 0 = no friction (normal), negative = boost/acceleration
5208
- appearance = Appearance2.GRADIENT,
5209
- alphaMap = null,
5210
- flipbook = null,
5211
- // { rows: 4, columns: 8 }
5212
- rotation = [0, 0],
5213
- // [min, max] in radians
5214
- rotationSpeed = [0, 0],
5215
- // [min, max] rotation speed in radians/second
5216
- rotationSpeedCurve = null,
5217
- // Curve data { points: [...] } - controls rotation speed over lifetime
5218
- geometry = null,
5219
- // Custom geometry (e.g. new THREE.SphereGeometry(0.5, 8, 8))
5220
- orientToDirection = false,
5221
- // Rotate geometry to face velocity direction (geometry mode only)
5222
- orientAxis = "z",
5223
- // Which local axis aligns with velocity: "x", "y", "z", "-x", "-y", "-z"
5224
- stretchBySpeed = null,
5225
- // { factor: 2, maxStretch: 5 } - stretch particles in velocity direction based on effective speed
5226
- lighting = Lighting2.STANDARD,
5227
- // 'basic' | 'standard' | 'physical' - material type for geometry mode
5228
- shadow = false,
5229
- // Enable both castShadow and receiveShadow on geometry instances
5230
- blending = Blending2.NORMAL,
5231
- intensity = 1,
5232
- position = [0, 0, 0],
5233
- autoStart = true,
5234
- delay = 0,
5235
- backdropNode = null,
5236
- // TSL node or function for backdrop sampling
5237
- opacityNode = null,
5238
- // TSL node or function for custom opacity control
5239
- colorNode = null,
5240
- // TSL node or function to override color (receives particleData, should return vec4)
5241
- alphaTestNode = null,
5242
- // TSL node or function for custom alpha test/discard (return true to discard fragment)
5243
- castShadowNode = null,
5244
- // TSL node or function for shadow map output (what shadow the particle casts)
5245
- emitCount = 1,
5246
- // Emitter shape props
5247
- emitterShape = EmitterShape2.BOX,
5248
- // Emission shape type
5249
- emitterRadius = [0, 1],
5250
- // [inner, outer] radius for sphere/cone/disk (inner=0 for solid)
5251
- emitterAngle = Math.PI / 4,
5252
- // Cone angle in radians (0 = line, PI/2 = hemisphere)
5253
- emitterHeight = [0, 1],
5254
- // [min, max] height for cone
5255
- emitterSurfaceOnly = false,
5256
- // Emit from surface only (sphere/disk)
5257
- emitterDirection = [0, 1, 0],
5258
- // Direction for cone/disk normal
5259
- // Turbulence (curl noise)
5260
- turbulence = null,
5261
- // { intensity: 0.5, frequency: 1, speed: 1 }
5262
- // Attractors - array of up to 4 attractors
5263
- // { position: [x,y,z], strength: 1, radius: 3, type: 'point'|'vortex', axis?: [x,y,z] }
5264
- attractors = null,
5265
- // Simple attract to center - particles move from spawn position to center over lifetime
5266
- // Overrides speed/direction - lifetime controls how long it takes to reach center
5267
- attractToCenter = false,
5268
- // Use start position offset as direction - particles move in the direction of their spawn offset
5269
- startPositionAsDirection = false,
5270
- // Soft particles - fade when intersecting scene geometry
5271
- softParticles = false,
5272
- softDistance = 0.5,
5273
- // Distance in world units over which to fade
5274
- // Plane collision - particles bounce or die when hitting a plane
5275
- // { plane: { y: 0 }, bounce: 0.3, friction: 0.8, die: false, sizeBasedGravity: 0 }
5276
- collision = null,
5277
- // Debug mode - shows tweakable control panel
5278
- debug = false
5279
- }, ref) {
5280
- const { gl: renderer } = useThree();
5281
- const spriteRef = useRef2(null);
5282
- const initialized = useRef2(false);
5283
- const nextIndex = useRef2(0);
5284
- const [emitting, setEmitting] = useState2(autoStart);
5285
- const emitAccumulator = useRef2(0);
5286
- const delayRef = useRef2(delay);
5287
- const emitCountRef = useRef2(emitCount);
5288
- const turbulenceRef = useRef2(turbulence);
5289
- const [activeMaxParticles, setActiveMaxParticles] = useState2(maxParticles);
5290
- const [activeLighting, setActiveLighting] = useState2(lighting);
5291
- const [activeAppearance, setActiveAppearance] = useState2(appearance);
5292
- const [activeOrientToDirection, setActiveOrientToDirection] = useState2(orientToDirection);
5293
- const [activeGeometry, setActiveGeometry] = useState2(geometry);
5294
- const [activeShadow, setActiveShadow] = useState2(shadow);
5295
- const [activeFadeSizeCurve, setActiveFadeSizeCurve] = useState2(fadeSizeCurve);
5296
- const [activeFadeOpacityCurve, setActiveFadeOpacityCurve] = useState2(fadeOpacityCurve);
5297
- const [activeVelocityCurve, setActiveVelocityCurve] = useState2(velocityCurve);
5298
- const [activeRotationSpeedCurve, setActiveRotationSpeedCurve] = useState2(rotationSpeedCurve);
5299
- useEffect2(() => {
5300
- delayRef.current = delay;
5301
- emitCountRef.current = emitCount;
5302
- turbulenceRef.current = turbulence;
5303
- }, [delay, emitCount, turbulence]);
5304
- useEffect2(() => {
5305
- if (!debug) {
5306
- setActiveMaxParticles(maxParticles);
5307
- setActiveLighting(lighting);
5308
- setActiveAppearance(appearance);
5309
- setActiveOrientToDirection(orientToDirection);
5310
- setActiveGeometry(geometry);
5311
- setActiveShadow(shadow);
5312
- setActiveFadeSizeCurve(fadeSizeCurve);
5313
- setActiveFadeOpacityCurve(fadeOpacityCurve);
5314
- setActiveVelocityCurve(velocityCurve);
5315
- setActiveRotationSpeedCurve(rotationSpeedCurve);
5316
- }
5317
- }, [
5318
- debug,
5319
- maxParticles,
5320
- lighting,
5321
- appearance,
5322
- orientToDirection,
5323
- geometry,
5324
- shadow,
5325
- fadeSizeCurve,
5326
- fadeOpacityCurve,
5327
- velocityCurve,
5328
- rotationSpeedCurve
5329
- ]);
5330
- const sizeRange = useMemo(() => toRange(size, [0.1, 0.3]), [size]);
5331
- const speedRange = useMemo(() => toRange(speed, [0.1, 0.1]), [speed]);
5332
- const fadeSizeRange = useMemo(() => toRange(fadeSize, [1, 0]), [fadeSize]);
5333
- const fadeOpacityRange = useMemo(
5334
- () => toRange(fadeOpacity, [1, 0]),
5335
- [fadeOpacity]
5336
- );
5337
- const curveTexture = useMemo(() => {
5338
- return createCombinedCurveTexture(
5469
+ init_useCurveTextureAsync();
5470
+ VFXParticles = forwardRef(
5471
+ function VFXParticles2({
5472
+ name,
5473
+ // Optional name for registering with useVFXStore (enables VFXEmitter linking)
5474
+ maxParticles = 1e4,
5475
+ size = [0.1, 0.3],
5476
+ colorStart = ["#ffffff"],
5477
+ colorEnd = null,
5478
+ // If null, uses colorStart (no color transition)
5479
+ fadeSize = [1, 0],
5480
+ fadeSizeCurve = null,
5481
+ // Curve data { points: [...] } - controls fadeSize over lifetime (overrides fadeSize if set)
5482
+ fadeOpacity = [1, 0],
5483
+ fadeOpacityCurve = null,
5484
+ // Curve data { points: [...] } - controls fadeOpacity over lifetime (overrides fadeOpacity if set)
5485
+ velocityCurve = null,
5486
+ // Curve data { points: [...] } - controls velocity/speed over lifetime (overrides friction if set)
5487
+ gravity = [0, 0, 0],
5488
+ lifetime = [1, 2],
5489
+ direction = [
5490
+ [-1, 1],
5491
+ [0, 1],
5492
+ [-1, 1]
5493
+ ],
5494
+ // [[minX, maxX], [minY, maxY], [minZ, maxZ]] or [min, max] for all axes
5495
+ startPosition = [
5496
+ [0, 0],
5497
+ [0, 0],
5498
+ [0, 0]
5499
+ ],
5500
+ // [[minX, maxX], [minY, maxY], [minZ, maxZ]] offset from spawn position
5501
+ speed = [0.1, 0.1],
5502
+ friction = { intensity: 0, easing: "linear" },
5503
+ // { intensity: [start, end] or single value, easing: string }
5504
+ // intensity: 1 = max friction (almost stopped), 0 = no friction (normal), negative = boost/acceleration
5505
+ appearance = Appearance2.GRADIENT,
5506
+ alphaMap = null,
5507
+ flipbook = null,
5508
+ // { rows: 4, columns: 8 }
5509
+ rotation = [0, 0],
5510
+ // [min, max] in radians
5511
+ rotationSpeed = [0, 0],
5512
+ // [min, max] rotation speed in radians/second
5513
+ rotationSpeedCurve = null,
5514
+ // Curve data { points: [...] } - controls rotation speed over lifetime
5515
+ geometry = null,
5516
+ // Custom geometry (e.g. new THREE.SphereGeometry(0.5, 8, 8))
5517
+ orientToDirection = false,
5518
+ // Rotate geometry to face velocity direction (geometry mode only)
5519
+ orientAxis = "z",
5520
+ // Which local axis aligns with velocity: "x", "y", "z", "-x", "-y", "-z"
5521
+ stretchBySpeed = null,
5522
+ // { factor: 2, maxStretch: 5 } - stretch particles in velocity direction based on effective speed
5523
+ lighting = Lighting2.STANDARD,
5524
+ // 'basic' | 'standard' | 'physical' - material type for geometry mode
5525
+ shadow = false,
5526
+ // Enable both castShadow and receiveShadow on geometry instances
5527
+ blending = Blending2.NORMAL,
5528
+ intensity = 1,
5529
+ position = [0, 0, 0],
5530
+ autoStart = true,
5531
+ delay = 0,
5532
+ backdropNode = null,
5533
+ // TSL node or function for backdrop sampling
5534
+ opacityNode = null,
5535
+ // TSL node or function for custom opacity control
5536
+ colorNode = null,
5537
+ // TSL node or function to override color (receives particleData, should return vec4)
5538
+ alphaTestNode = null,
5539
+ // TSL node or function for custom alpha test/discard (return true to discard fragment)
5540
+ castShadowNode = null,
5541
+ // TSL node or function for shadow map output (what shadow the particle casts)
5542
+ emitCount = 1,
5543
+ // Emitter shape props
5544
+ emitterShape = EmitterShape2.BOX,
5545
+ // Emission shape type
5546
+ emitterRadius = [0, 1],
5547
+ // [inner, outer] radius for sphere/cone/disk (inner=0 for solid)
5548
+ emitterAngle = Math.PI / 4,
5549
+ // Cone angle in radians (0 = line, PI/2 = hemisphere)
5550
+ emitterHeight = [0, 1],
5551
+ // [min, max] height for cone
5552
+ emitterSurfaceOnly = false,
5553
+ // Emit from surface only (sphere/disk)
5554
+ emitterDirection = [0, 1, 0],
5555
+ // Direction for cone/disk normal
5556
+ // Turbulence (curl noise)
5557
+ turbulence = null,
5558
+ // { intensity: 0.5, frequency: 1, speed: 1 }
5559
+ // Attractors - array of up to 4 attractors
5560
+ // { position: [x,y,z], strength: 1, radius: 3, type: 'point'|'vortex', axis?: [x,y,z] }
5561
+ attractors = null,
5562
+ // Simple attract to center - particles move from spawn position to center over lifetime
5563
+ // Overrides speed/direction - lifetime controls how long it takes to reach center
5564
+ attractToCenter = false,
5565
+ // Use start position offset as direction - particles move in the direction of their spawn offset
5566
+ startPositionAsDirection = false,
5567
+ // Soft particles - fade when intersecting scene geometry
5568
+ softParticles = false,
5569
+ softDistance = 0.5,
5570
+ // Distance in world units over which to fade
5571
+ // Plane collision - particles bounce or die when hitting a plane
5572
+ // { plane: { y: 0 }, bounce: 0.3, friction: 0.8, die: false, sizeBasedGravity: 0 }
5573
+ collision = null,
5574
+ // Debug mode - shows tweakable control panel
5575
+ debug = false,
5576
+ // Path to pre-baked curve texture (skips runtime baking for faster load)
5577
+ curveTexturePath = null,
5578
+ // Depth test
5579
+ depthTest = true,
5580
+ // Render order
5581
+ renderOrder = 0
5582
+ }, ref) {
5583
+ var _a;
5584
+ const { gl: renderer } = useThree();
5585
+ const spriteRef = useRef3(null);
5586
+ const initialized = useRef3(false);
5587
+ const nextIndex = useRef3(0);
5588
+ const [emitting, setEmitting] = useState2(autoStart);
5589
+ const emitAccumulator = useRef3(0);
5590
+ const delayRef = useRef3(delay);
5591
+ const emitCountRef = useRef3(emitCount);
5592
+ const turbulenceRef = useRef3(turbulence);
5593
+ const [activeMaxParticles, setActiveMaxParticles] = useState2(maxParticles);
5594
+ const [activeLighting, setActiveLighting] = useState2(lighting);
5595
+ const [activeAppearance, setActiveAppearance] = useState2(appearance);
5596
+ const [activeOrientToDirection, setActiveOrientToDirection] = useState2(orientToDirection);
5597
+ const [activeGeometry, setActiveGeometry] = useState2(geometry);
5598
+ const [activeShadow, setActiveShadow] = useState2(shadow);
5599
+ const [activeFadeSizeCurve, setActiveFadeSizeCurve] = useState2(fadeSizeCurve);
5600
+ const [activeFadeOpacityCurve, setActiveFadeOpacityCurve] = useState2(fadeOpacityCurve);
5601
+ const [activeVelocityCurve, setActiveVelocityCurve] = useState2(velocityCurve);
5602
+ const [activeRotationSpeedCurve, setActiveRotationSpeedCurve] = useState2(rotationSpeedCurve);
5603
+ const [activeTurbulence, setActiveTurbulence] = useState2(
5604
+ turbulence !== null && ((_a = turbulence == null ? void 0 : turbulence.intensity) != null ? _a : 0) > 0
5605
+ );
5606
+ const [activeAttractors, setActiveAttractors] = useState2(
5607
+ attractors !== null && attractors.length > 0
5608
+ );
5609
+ const [activeCollision, setActiveCollision] = useState2(collision !== null);
5610
+ const [activeNeedsPerParticleColor, setActiveNeedsPerParticleColor] = useState2(colorStart.length > 1 || colorEnd !== null);
5611
+ const isNonDefaultRotation = (r) => {
5612
+ if (typeof r === "number") return r !== 0;
5613
+ if (Array.isArray(r) && r.length === 2 && typeof r[0] === "number") {
5614
+ return r[0] !== 0 || r[1] !== 0;
5615
+ }
5616
+ if (Array.isArray(r)) {
5617
+ return r.some(
5618
+ (axis) => Array.isArray(axis) && (axis[0] !== 0 || axis[1] !== 0)
5619
+ );
5620
+ }
5621
+ return false;
5622
+ };
5623
+ const [activeNeedsRotation, setActiveNeedsRotation] = useState2(
5624
+ isNonDefaultRotation(rotation) || isNonDefaultRotation(rotationSpeed)
5625
+ );
5626
+ useEffect3(() => {
5627
+ delayRef.current = delay;
5628
+ emitCountRef.current = emitCount;
5629
+ turbulenceRef.current = turbulence;
5630
+ }, [delay, emitCount, turbulence]);
5631
+ useEffect3(() => {
5632
+ var _a2;
5633
+ if (!debug) {
5634
+ setActiveMaxParticles(maxParticles);
5635
+ setActiveLighting(lighting);
5636
+ setActiveAppearance(appearance);
5637
+ setActiveOrientToDirection(orientToDirection);
5638
+ setActiveGeometry(geometry);
5639
+ setActiveShadow(shadow);
5640
+ setActiveFadeSizeCurve(fadeSizeCurve);
5641
+ setActiveFadeOpacityCurve(fadeOpacityCurve);
5642
+ setActiveVelocityCurve(velocityCurve);
5643
+ setActiveRotationSpeedCurve(rotationSpeedCurve);
5644
+ setActiveNeedsPerParticleColor(
5645
+ colorStart.length > 1 || colorEnd !== null
5646
+ );
5647
+ setActiveNeedsRotation(
5648
+ isNonDefaultRotation(rotation) || isNonDefaultRotation(rotationSpeed)
5649
+ );
5650
+ setActiveTurbulence(
5651
+ turbulence !== null && ((_a2 = turbulence == null ? void 0 : turbulence.intensity) != null ? _a2 : 0) > 0
5652
+ );
5653
+ setActiveAttractors(attractors !== null && attractors.length > 0);
5654
+ setActiveCollision(collision !== null);
5655
+ }
5656
+ }, [
5657
+ debug,
5658
+ maxParticles,
5659
+ lighting,
5660
+ appearance,
5661
+ orientToDirection,
5662
+ geometry,
5663
+ colorStart.length,
5664
+ colorEnd,
5665
+ shadow,
5666
+ fadeSizeCurve,
5667
+ fadeOpacityCurve,
5668
+ velocityCurve,
5669
+ rotationSpeedCurve,
5670
+ rotation,
5671
+ rotationSpeed,
5672
+ turbulence,
5673
+ attractors,
5674
+ collision
5675
+ ]);
5676
+ const sizeRange = useMemo(() => toRange(size, [0.1, 0.3]), [size]);
5677
+ const speedRange = useMemo(() => toRange(speed, [0.1, 0.1]), [speed]);
5678
+ const fadeSizeRange = useMemo(() => toRange(fadeSize, [1, 0]), [fadeSize]);
5679
+ const fadeOpacityRange = useMemo(
5680
+ () => toRange(fadeOpacity, [1, 0]),
5681
+ [fadeOpacity]
5682
+ );
5683
+ const curveTexture = useCurveTextureAsync(
5339
5684
  activeFadeSizeCurve,
5340
5685
  activeFadeOpacityCurve,
5341
5686
  activeVelocityCurve,
5342
- activeRotationSpeedCurve
5687
+ activeRotationSpeedCurve,
5688
+ curveTexturePath
5343
5689
  );
5344
- }, [
5345
- activeFadeSizeCurve,
5346
- activeFadeOpacityCurve,
5347
- activeVelocityCurve,
5348
- activeRotationSpeedCurve
5349
- ]);
5350
- const prevCurveTextureRef = useRef2(null);
5351
- useEffect2(() => {
5352
- if (prevCurveTextureRef.current && prevCurveTextureRef.current !== curveTexture) {
5353
- prevCurveTextureRef.current.dispose();
5354
- }
5355
- prevCurveTextureRef.current = curveTexture;
5356
- return () => {
5357
- if (curveTexture) {
5358
- curveTexture.dispose();
5359
- }
5360
- };
5361
- }, [curveTexture]);
5362
- const lifetimeRange = useMemo(() => toRange(lifetime, [1, 2]), [lifetime]);
5363
- const rotation3D = useMemo(() => toRotation3D(rotation), [rotation]);
5364
- const rotationSpeed3D = useMemo(
5365
- () => toRotation3D(rotationSpeed),
5366
- [rotationSpeed]
5367
- );
5368
- const direction3D = useMemo(() => toRotation3D(direction), [direction]);
5369
- const startPosition3D = useMemo(
5370
- () => toRotation3D(startPosition),
5371
- [startPosition]
5372
- );
5373
- const emitterRadiusRange = useMemo(
5374
- () => toRange(emitterRadius, [0, 1]),
5375
- [emitterRadius]
5376
- );
5377
- const emitterHeightRange = useMemo(
5378
- () => toRange(emitterHeight, [0, 1]),
5379
- [emitterHeight]
5380
- );
5381
- const frictionIntensityRange = useMemo(() => {
5382
- if (typeof friction === "object" && friction !== null && "intensity" in friction) {
5383
- return toRange(friction.intensity, [0, 0]);
5384
- }
5385
- return [0, 0];
5386
- }, [friction]);
5387
- const frictionEasingType = useMemo(() => {
5388
- var _a;
5389
- if (typeof friction === "object" && friction !== null && "easing" in friction) {
5390
- return easingToType((_a = friction.easing) != null ? _a : "linear");
5391
- }
5392
- return 0;
5393
- }, [friction]);
5394
- const startColors = useMemo(() => {
5395
- const colors = colorStart.slice(0, 8).map(hexToRgb);
5396
- while (colors.length < 8)
5397
- colors.push(colors[colors.length - 1] || [1, 1, 1]);
5398
- return colors;
5399
- }, [colorStart]);
5400
- const effectiveColorEnd = colorEnd != null ? colorEnd : colorStart;
5401
- const endColors = useMemo(() => {
5402
- const colors = effectiveColorEnd.slice(0, 8).map(hexToRgb);
5403
- while (colors.length < 8)
5404
- colors.push(colors[colors.length - 1] || [1, 1, 1]);
5405
- return colors;
5406
- }, [effectiveColorEnd]);
5407
- const uniforms = useMemo(
5408
- () => {
5409
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5410
- return {
5411
- sizeMin: uniform(sizeRange[0]),
5412
- sizeMax: uniform(sizeRange[1]),
5413
- fadeSizeStart: uniform(fadeSizeRange[0]),
5414
- fadeSizeEnd: uniform(fadeSizeRange[1]),
5415
- fadeOpacityStart: uniform(fadeOpacityRange[0]),
5416
- fadeOpacityEnd: uniform(fadeOpacityRange[1]),
5417
- gravity: uniform(new THREE2.Vector3(...gravity)),
5418
- frictionIntensityStart: uniform(frictionIntensityRange[0]),
5419
- frictionIntensityEnd: uniform(frictionIntensityRange[1]),
5420
- frictionEasingType: uniform(frictionEasingType),
5421
- speedMin: uniform(speedRange[0]),
5422
- speedMax: uniform(speedRange[1]),
5423
- lifetimeMin: uniform(lifetimeToFadeRate(lifetimeRange[1])),
5424
- lifetimeMax: uniform(lifetimeToFadeRate(lifetimeRange[0])),
5425
- deltaTime: uniform(0.016),
5426
- // Will be updated each frame
5427
- // 3D direction ranges
5428
- dirMinX: uniform(direction3D[0][0]),
5429
- dirMaxX: uniform(direction3D[0][1]),
5430
- dirMinY: uniform(direction3D[1][0]),
5431
- dirMaxY: uniform(direction3D[1][1]),
5432
- dirMinZ: uniform(direction3D[2][0]),
5433
- dirMaxZ: uniform(direction3D[2][1]),
5434
- // 3D start position offset ranges
5435
- startPosMinX: uniform(startPosition3D[0][0]),
5436
- startPosMaxX: uniform(startPosition3D[0][1]),
5437
- startPosMinY: uniform(startPosition3D[1][0]),
5438
- startPosMaxY: uniform(startPosition3D[1][1]),
5439
- startPosMinZ: uniform(startPosition3D[2][0]),
5440
- startPosMaxZ: uniform(startPosition3D[2][1]),
5441
- spawnPosition: uniform(new THREE2.Vector3(...position)),
5442
- spawnIndexStart: uniform(0),
5443
- spawnIndexEnd: uniform(0),
5444
- spawnSeed: uniform(0),
5445
- intensity: uniform(intensity),
5446
- // 3D rotation ranges
5447
- rotationMinX: uniform(rotation3D[0][0]),
5448
- rotationMaxX: uniform(rotation3D[0][1]),
5449
- rotationMinY: uniform(rotation3D[1][0]),
5450
- rotationMaxY: uniform(rotation3D[1][1]),
5451
- rotationMinZ: uniform(rotation3D[2][0]),
5452
- rotationMaxZ: uniform(rotation3D[2][1]),
5453
- // 3D rotation speed ranges (radians/second)
5454
- rotationSpeedMinX: uniform(rotationSpeed3D[0][0]),
5455
- rotationSpeedMaxX: uniform(rotationSpeed3D[0][1]),
5456
- rotationSpeedMinY: uniform(rotationSpeed3D[1][0]),
5457
- rotationSpeedMaxY: uniform(rotationSpeed3D[1][1]),
5458
- rotationSpeedMinZ: uniform(rotationSpeed3D[2][0]),
5459
- rotationSpeedMaxZ: uniform(rotationSpeed3D[2][1]),
5460
- // Color arrays (8 colors max each)
5461
- colorStartCount: uniform(colorStart.length),
5462
- colorEndCount: uniform(effectiveColorEnd.length),
5463
- colorStart0: uniform(new THREE2.Color(...startColors[0])),
5464
- colorStart1: uniform(new THREE2.Color(...startColors[1])),
5465
- colorStart2: uniform(new THREE2.Color(...startColors[2])),
5466
- colorStart3: uniform(new THREE2.Color(...startColors[3])),
5467
- colorStart4: uniform(new THREE2.Color(...startColors[4])),
5468
- colorStart5: uniform(new THREE2.Color(...startColors[5])),
5469
- colorStart6: uniform(new THREE2.Color(...startColors[6])),
5470
- colorStart7: uniform(new THREE2.Color(...startColors[7])),
5471
- colorEnd0: uniform(new THREE2.Color(...endColors[0])),
5472
- colorEnd1: uniform(new THREE2.Color(...endColors[1])),
5473
- colorEnd2: uniform(new THREE2.Color(...endColors[2])),
5474
- colorEnd3: uniform(new THREE2.Color(...endColors[3])),
5475
- colorEnd4: uniform(new THREE2.Color(...endColors[4])),
5476
- colorEnd5: uniform(new THREE2.Color(...endColors[5])),
5477
- colorEnd6: uniform(new THREE2.Color(...endColors[6])),
5478
- colorEnd7: uniform(new THREE2.Color(...endColors[7])),
5479
- // Emitter shape uniforms
5480
- emitterShapeType: uniform(emitterShape),
5481
- emitterRadiusInner: uniform(emitterRadiusRange[0]),
5482
- emitterRadiusOuter: uniform(emitterRadiusRange[1]),
5483
- emitterAngle: uniform(emitterAngle),
5484
- emitterHeightMin: uniform(emitterHeightRange[0]),
5485
- emitterHeightMax: uniform(emitterHeightRange[1]),
5486
- emitterSurfaceOnly: uniform(emitterSurfaceOnly ? 1 : 0),
5487
- emitterDir: uniform(new THREE2.Vector3(...emitterDirection).normalize()),
5488
- // Turbulence uniforms
5489
- turbulenceIntensity: uniform((_a = turbulence == null ? void 0 : turbulence.intensity) != null ? _a : 0),
5490
- turbulenceFrequency: uniform((_b = turbulence == null ? void 0 : turbulence.frequency) != null ? _b : 1),
5491
- turbulenceSpeed: uniform((_c = turbulence == null ? void 0 : turbulence.speed) != null ? _c : 1),
5492
- turbulenceTime: uniform(0),
5493
- // Updated each frame
5494
- // Attractor uniforms (up to 4)
5495
- attractorCount: uniform(0),
5496
- attractor0Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5497
- attractor0Strength: uniform(0),
5498
- attractor0Radius: uniform(1),
5499
- attractor0Type: uniform(0),
5500
- attractor0Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5501
- attractor1Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5502
- attractor1Strength: uniform(0),
5503
- attractor1Radius: uniform(1),
5504
- attractor1Type: uniform(0),
5505
- attractor1Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5506
- attractor2Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5507
- attractor2Strength: uniform(0),
5508
- attractor2Radius: uniform(1),
5509
- attractor2Type: uniform(0),
5510
- attractor2Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5511
- attractor3Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5512
- attractor3Strength: uniform(0),
5513
- attractor3Radius: uniform(1),
5514
- attractor3Type: uniform(0),
5515
- attractor3Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5516
- // Simple attract to center
5517
- attractToCenter: uniform(attractToCenter ? 1 : 0),
5518
- // Use start position as direction
5519
- startPositionAsDirection: uniform(startPositionAsDirection ? 1 : 0),
5520
- // Soft particles
5521
- softParticlesEnabled: uniform(softParticles ? 1 : 0),
5522
- softDistance: uniform(softDistance),
5523
- // Velocity curve (replaces friction when enabled)
5524
- velocityCurveEnabled: uniform(velocityCurve ? 1 : 0),
5525
- // Rotation speed curve (modulates rotation speed over lifetime)
5526
- rotationSpeedCurveEnabled: uniform(rotationSpeedCurve ? 1 : 0),
5527
- // Fade size curve (when disabled, uses fadeSize prop interpolation)
5528
- fadeSizeCurveEnabled: uniform(fadeSizeCurve ? 1 : 0),
5529
- // Fade opacity curve (when disabled, uses fadeOpacity prop interpolation)
5530
- fadeOpacityCurveEnabled: uniform(fadeOpacityCurve ? 1 : 0),
5531
- // Orient axis: 0=+X, 1=+Y, 2=+Z, 3=-X, 4=-Y, 5=-Z
5532
- orientAxisType: uniform(axisToNumber(orientAxis)),
5533
- // Stretch by speed (uses effective velocity after curve modifier)
5534
- stretchEnabled: uniform(stretchBySpeed ? 1 : 0),
5535
- stretchFactor: uniform((_d = stretchBySpeed == null ? void 0 : stretchBySpeed.factor) != null ? _d : 1),
5536
- stretchMax: uniform((_e = stretchBySpeed == null ? void 0 : stretchBySpeed.maxStretch) != null ? _e : 5),
5537
- // Collision uniforms
5538
- collisionEnabled: uniform(collision ? 1 : 0),
5539
- collisionPlaneY: uniform((_g = (_f = collision == null ? void 0 : collision.plane) == null ? void 0 : _f.y) != null ? _g : 0),
5540
- collisionBounce: uniform((_h = collision == null ? void 0 : collision.bounce) != null ? _h : 0.3),
5541
- collisionFriction: uniform((_i = collision == null ? void 0 : collision.friction) != null ? _i : 0.8),
5542
- collisionDie: uniform((collision == null ? void 0 : collision.die) ? 1 : 0),
5543
- // Size-based gravity (inside collision object)
5544
- sizeBasedGravity: uniform((_j = collision == null ? void 0 : collision.sizeBasedGravity) != null ? _j : 0)
5690
+ const prevCurveTextureRef = useRef3(null);
5691
+ useEffect3(() => {
5692
+ prevCurveTextureRef.current = curveTexture;
5693
+ return () => {
5694
+ if (curveTexture) {
5695
+ curveTexture.dispose();
5696
+ }
5545
5697
  };
5546
- },
5547
- []
5548
- );
5549
- const positionRef = useRef2(position);
5550
- useEffect2(() => {
5551
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
5552
- if (debug) return;
5553
- positionRef.current = position;
5554
- uniforms.sizeMin.value = sizeRange[0];
5555
- uniforms.sizeMax.value = sizeRange[1];
5556
- uniforms.fadeSizeStart.value = fadeSizeRange[0];
5557
- uniforms.fadeSizeEnd.value = fadeSizeRange[1];
5558
- uniforms.fadeOpacityStart.value = fadeOpacityRange[0];
5559
- uniforms.fadeOpacityEnd.value = fadeOpacityRange[1];
5560
- uniforms.gravity.value.set(...gravity);
5561
- uniforms.frictionIntensityStart.value = frictionIntensityRange[0];
5562
- uniforms.frictionIntensityEnd.value = frictionIntensityRange[1];
5563
- uniforms.frictionEasingType.value = frictionEasingType;
5564
- uniforms.speedMin.value = speedRange[0];
5565
- uniforms.speedMax.value = speedRange[1];
5566
- uniforms.lifetimeMin.value = lifetimeToFadeRate(lifetimeRange[1]);
5567
- uniforms.lifetimeMax.value = lifetimeToFadeRate(lifetimeRange[0]);
5568
- uniforms.dirMinX.value = direction3D[0][0];
5569
- uniforms.dirMaxX.value = direction3D[0][1];
5570
- uniforms.dirMinY.value = direction3D[1][0];
5571
- uniforms.dirMaxY.value = direction3D[1][1];
5572
- uniforms.dirMinZ.value = direction3D[2][0];
5573
- uniforms.dirMaxZ.value = direction3D[2][1];
5574
- uniforms.startPosMinX.value = startPosition3D[0][0];
5575
- uniforms.startPosMaxX.value = startPosition3D[0][1];
5576
- uniforms.startPosMinY.value = startPosition3D[1][0];
5577
- uniforms.startPosMaxY.value = startPosition3D[1][1];
5578
- uniforms.startPosMinZ.value = startPosition3D[2][0];
5579
- uniforms.startPosMaxZ.value = startPosition3D[2][1];
5580
- uniforms.rotationMinX.value = rotation3D[0][0];
5581
- uniforms.rotationMaxX.value = rotation3D[0][1];
5582
- uniforms.rotationMinY.value = rotation3D[1][0];
5583
- uniforms.rotationMaxY.value = rotation3D[1][1];
5584
- uniforms.rotationMinZ.value = rotation3D[2][0];
5585
- uniforms.rotationMaxZ.value = rotation3D[2][1];
5586
- uniforms.rotationSpeedMinX.value = rotationSpeed3D[0][0];
5587
- uniforms.rotationSpeedMaxX.value = rotationSpeed3D[0][1];
5588
- uniforms.rotationSpeedMinY.value = rotationSpeed3D[1][0];
5589
- uniforms.rotationSpeedMaxY.value = rotationSpeed3D[1][1];
5590
- uniforms.rotationSpeedMinZ.value = rotationSpeed3D[2][0];
5591
- uniforms.rotationSpeedMaxZ.value = rotationSpeed3D[2][1];
5592
- uniforms.intensity.value = intensity;
5593
- uniforms.colorStartCount.value = colorStart.length;
5594
- uniforms.colorEndCount.value = effectiveColorEnd.length;
5595
- startColors.forEach((c, i) => {
5596
- var _a2;
5597
- (_a2 = uniforms[`colorStart${i}`]) == null ? void 0 : _a2.value.setRGB(...c);
5598
- });
5599
- endColors.forEach((c, i) => {
5698
+ }, [curveTexture]);
5699
+ const lifetimeRange = useMemo(() => toRange(lifetime, [1, 2]), [lifetime]);
5700
+ const rotation3D = useMemo(() => toRotation3D(rotation), [rotation]);
5701
+ const rotationSpeed3D = useMemo(
5702
+ () => toRotation3D(rotationSpeed),
5703
+ [rotationSpeed]
5704
+ );
5705
+ const direction3D = useMemo(() => toRotation3D(direction), [direction]);
5706
+ const startPosition3D = useMemo(
5707
+ () => toRotation3D(startPosition),
5708
+ [startPosition]
5709
+ );
5710
+ const emitterRadiusRange = useMemo(
5711
+ () => toRange(emitterRadius, [0, 1]),
5712
+ [emitterRadius]
5713
+ );
5714
+ const emitterHeightRange = useMemo(
5715
+ () => toRange(emitterHeight, [0, 1]),
5716
+ [emitterHeight]
5717
+ );
5718
+ const activeFeatures = useMemo(
5719
+ () => ({
5720
+ // Storage array features
5721
+ needsPerParticleColor: activeNeedsPerParticleColor,
5722
+ needsRotation: activeNeedsRotation,
5723
+ // Shader features (skip code entirely when disabled)
5724
+ turbulence: activeTurbulence,
5725
+ attractors: activeAttractors,
5726
+ collision: activeCollision,
5727
+ rotation: activeNeedsRotation,
5728
+ perParticleColor: activeNeedsPerParticleColor
5729
+ }),
5730
+ [
5731
+ activeNeedsPerParticleColor,
5732
+ activeNeedsRotation,
5733
+ activeTurbulence,
5734
+ activeAttractors,
5735
+ activeCollision
5736
+ ]
5737
+ );
5738
+ const frictionIntensityRange = useMemo(() => {
5739
+ if (typeof friction === "object" && friction !== null && "intensity" in friction) {
5740
+ return toRange(friction.intensity, [0, 0]);
5741
+ }
5742
+ return [0, 0];
5743
+ }, [friction]);
5744
+ const frictionEasingType = useMemo(() => {
5600
5745
  var _a2;
5601
- (_a2 = uniforms[`colorEnd${i}`]) == null ? void 0 : _a2.value.setRGB(...c);
5602
- });
5603
- uniforms.emitterShapeType.value = emitterShape;
5604
- uniforms.emitterRadiusInner.value = emitterRadiusRange[0];
5605
- uniforms.emitterRadiusOuter.value = emitterRadiusRange[1];
5606
- uniforms.emitterAngle.value = emitterAngle;
5607
- uniforms.emitterHeightMin.value = emitterHeightRange[0];
5608
- uniforms.emitterHeightMax.value = emitterHeightRange[1];
5609
- uniforms.emitterSurfaceOnly.value = emitterSurfaceOnly ? 1 : 0;
5610
- uniforms.emitterDir.value.set(...emitterDirection).normalize();
5611
- uniforms.turbulenceIntensity.value = (_a = turbulence == null ? void 0 : turbulence.intensity) != null ? _a : 0;
5612
- uniforms.turbulenceFrequency.value = (_b = turbulence == null ? void 0 : turbulence.frequency) != null ? _b : 1;
5613
- uniforms.turbulenceSpeed.value = (_c = turbulence == null ? void 0 : turbulence.speed) != null ? _c : 1;
5614
- const attractorList = attractors != null ? attractors : [];
5615
- uniforms.attractorCount.value = Math.min(
5616
- attractorList.length,
5617
- MAX_ATTRACTORS
5746
+ if (typeof friction === "object" && friction !== null && "easing" in friction) {
5747
+ return easingToType((_a2 = friction.easing) != null ? _a2 : "linear");
5748
+ }
5749
+ return 0;
5750
+ }, [friction]);
5751
+ const startColors = useMemo(() => {
5752
+ const colors = colorStart.slice(0, 8).map(hexToRgb);
5753
+ while (colors.length < 8)
5754
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
5755
+ return colors;
5756
+ }, [colorStart]);
5757
+ const effectiveColorEnd = colorEnd != null ? colorEnd : colorStart;
5758
+ const endColors = useMemo(() => {
5759
+ const colors = effectiveColorEnd.slice(0, 8).map(hexToRgb);
5760
+ while (colors.length < 8)
5761
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
5762
+ return colors;
5763
+ }, [effectiveColorEnd]);
5764
+ const uniforms = useMemo(
5765
+ () => {
5766
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5767
+ return {
5768
+ sizeMin: uniform(sizeRange[0]),
5769
+ sizeMax: uniform(sizeRange[1]),
5770
+ fadeSizeStart: uniform(fadeSizeRange[0]),
5771
+ fadeSizeEnd: uniform(fadeSizeRange[1]),
5772
+ fadeOpacityStart: uniform(fadeOpacityRange[0]),
5773
+ fadeOpacityEnd: uniform(fadeOpacityRange[1]),
5774
+ gravity: uniform(new THREE2.Vector3(...gravity)),
5775
+ frictionIntensityStart: uniform(frictionIntensityRange[0]),
5776
+ frictionIntensityEnd: uniform(frictionIntensityRange[1]),
5777
+ frictionEasingType: uniform(frictionEasingType),
5778
+ speedMin: uniform(speedRange[0]),
5779
+ speedMax: uniform(speedRange[1]),
5780
+ lifetimeMin: uniform(lifetimeToFadeRate(lifetimeRange[1])),
5781
+ lifetimeMax: uniform(lifetimeToFadeRate(lifetimeRange[0])),
5782
+ deltaTime: uniform(0.016),
5783
+ // Will be updated each frame
5784
+ // 3D direction ranges
5785
+ dirMinX: uniform(direction3D[0][0]),
5786
+ dirMaxX: uniform(direction3D[0][1]),
5787
+ dirMinY: uniform(direction3D[1][0]),
5788
+ dirMaxY: uniform(direction3D[1][1]),
5789
+ dirMinZ: uniform(direction3D[2][0]),
5790
+ dirMaxZ: uniform(direction3D[2][1]),
5791
+ // 3D start position offset ranges
5792
+ startPosMinX: uniform(startPosition3D[0][0]),
5793
+ startPosMaxX: uniform(startPosition3D[0][1]),
5794
+ startPosMinY: uniform(startPosition3D[1][0]),
5795
+ startPosMaxY: uniform(startPosition3D[1][1]),
5796
+ startPosMinZ: uniform(startPosition3D[2][0]),
5797
+ startPosMaxZ: uniform(startPosition3D[2][1]),
5798
+ spawnPosition: uniform(new THREE2.Vector3(...position)),
5799
+ spawnIndexStart: uniform(0),
5800
+ spawnIndexEnd: uniform(0),
5801
+ spawnSeed: uniform(0),
5802
+ intensity: uniform(intensity),
5803
+ // 3D rotation ranges
5804
+ rotationMinX: uniform(rotation3D[0][0]),
5805
+ rotationMaxX: uniform(rotation3D[0][1]),
5806
+ rotationMinY: uniform(rotation3D[1][0]),
5807
+ rotationMaxY: uniform(rotation3D[1][1]),
5808
+ rotationMinZ: uniform(rotation3D[2][0]),
5809
+ rotationMaxZ: uniform(rotation3D[2][1]),
5810
+ // 3D rotation speed ranges (radians/second)
5811
+ rotationSpeedMinX: uniform(rotationSpeed3D[0][0]),
5812
+ rotationSpeedMaxX: uniform(rotationSpeed3D[0][1]),
5813
+ rotationSpeedMinY: uniform(rotationSpeed3D[1][0]),
5814
+ rotationSpeedMaxY: uniform(rotationSpeed3D[1][1]),
5815
+ rotationSpeedMinZ: uniform(rotationSpeed3D[2][0]),
5816
+ rotationSpeedMaxZ: uniform(rotationSpeed3D[2][1]),
5817
+ // Color arrays (8 colors max each)
5818
+ colorStartCount: uniform(colorStart.length),
5819
+ colorEndCount: uniform(effectiveColorEnd.length),
5820
+ colorStart0: uniform(new THREE2.Color(...startColors[0])),
5821
+ colorStart1: uniform(new THREE2.Color(...startColors[1])),
5822
+ colorStart2: uniform(new THREE2.Color(...startColors[2])),
5823
+ colorStart3: uniform(new THREE2.Color(...startColors[3])),
5824
+ colorStart4: uniform(new THREE2.Color(...startColors[4])),
5825
+ colorStart5: uniform(new THREE2.Color(...startColors[5])),
5826
+ colorStart6: uniform(new THREE2.Color(...startColors[6])),
5827
+ colorStart7: uniform(new THREE2.Color(...startColors[7])),
5828
+ colorEnd0: uniform(new THREE2.Color(...endColors[0])),
5829
+ colorEnd1: uniform(new THREE2.Color(...endColors[1])),
5830
+ colorEnd2: uniform(new THREE2.Color(...endColors[2])),
5831
+ colorEnd3: uniform(new THREE2.Color(...endColors[3])),
5832
+ colorEnd4: uniform(new THREE2.Color(...endColors[4])),
5833
+ colorEnd5: uniform(new THREE2.Color(...endColors[5])),
5834
+ colorEnd6: uniform(new THREE2.Color(...endColors[6])),
5835
+ colorEnd7: uniform(new THREE2.Color(...endColors[7])),
5836
+ // Emitter shape uniforms
5837
+ emitterShapeType: uniform(emitterShape),
5838
+ emitterRadiusInner: uniform(emitterRadiusRange[0]),
5839
+ emitterRadiusOuter: uniform(emitterRadiusRange[1]),
5840
+ emitterAngle: uniform(emitterAngle),
5841
+ emitterHeightMin: uniform(emitterHeightRange[0]),
5842
+ emitterHeightMax: uniform(emitterHeightRange[1]),
5843
+ emitterSurfaceOnly: uniform(emitterSurfaceOnly ? 1 : 0),
5844
+ emitterDir: uniform(new THREE2.Vector3(...emitterDirection).normalize()),
5845
+ // Turbulence uniforms
5846
+ turbulenceIntensity: uniform((_a2 = turbulence == null ? void 0 : turbulence.intensity) != null ? _a2 : 0),
5847
+ turbulenceFrequency: uniform((_b = turbulence == null ? void 0 : turbulence.frequency) != null ? _b : 1),
5848
+ turbulenceSpeed: uniform((_c = turbulence == null ? void 0 : turbulence.speed) != null ? _c : 1),
5849
+ turbulenceTime: uniform(0),
5850
+ // Updated each frame
5851
+ // Attractor uniforms (up to 4)
5852
+ attractorCount: uniform(0),
5853
+ attractor0Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5854
+ attractor0Strength: uniform(0),
5855
+ attractor0Radius: uniform(1),
5856
+ attractor0Type: uniform(0),
5857
+ attractor0Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5858
+ attractor1Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5859
+ attractor1Strength: uniform(0),
5860
+ attractor1Radius: uniform(1),
5861
+ attractor1Type: uniform(0),
5862
+ attractor1Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5863
+ attractor2Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5864
+ attractor2Strength: uniform(0),
5865
+ attractor2Radius: uniform(1),
5866
+ attractor2Type: uniform(0),
5867
+ attractor2Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5868
+ attractor3Pos: uniform(new THREE2.Vector3(0, 0, 0)),
5869
+ attractor3Strength: uniform(0),
5870
+ attractor3Radius: uniform(1),
5871
+ attractor3Type: uniform(0),
5872
+ attractor3Axis: uniform(new THREE2.Vector3(0, 1, 0)),
5873
+ // Simple attract to center
5874
+ attractToCenter: uniform(attractToCenter ? 1 : 0),
5875
+ // Use start position as direction
5876
+ startPositionAsDirection: uniform(startPositionAsDirection ? 1 : 0),
5877
+ // Soft particles
5878
+ softParticlesEnabled: uniform(softParticles ? 1 : 0),
5879
+ softDistance: uniform(softDistance),
5880
+ // Velocity curve (replaces friction when enabled)
5881
+ // Enable if velocityCurve prop is set OR curveTexturePath is provided
5882
+ velocityCurveEnabled: uniform(
5883
+ velocityCurve || curveTexturePath ? 1 : 0
5884
+ ),
5885
+ // Rotation speed curve (modulates rotation speed over lifetime)
5886
+ rotationSpeedCurveEnabled: uniform(
5887
+ rotationSpeedCurve || curveTexturePath ? 1 : 0
5888
+ ),
5889
+ // Fade size curve (when disabled, uses fadeSize prop interpolation)
5890
+ fadeSizeCurveEnabled: uniform(
5891
+ fadeSizeCurve || curveTexturePath ? 1 : 0
5892
+ ),
5893
+ // Fade opacity curve (when disabled, uses fadeOpacity prop interpolation)
5894
+ fadeOpacityCurveEnabled: uniform(
5895
+ fadeOpacityCurve || curveTexturePath ? 1 : 0
5896
+ ),
5897
+ // Orient axis: 0=+X, 1=+Y, 2=+Z, 3=-X, 4=-Y, 5=-Z
5898
+ orientAxisType: uniform(axisToNumber(orientAxis)),
5899
+ // Stretch by speed (uses effective velocity after curve modifier)
5900
+ stretchEnabled: uniform(stretchBySpeed ? 1 : 0),
5901
+ stretchFactor: uniform((_d = stretchBySpeed == null ? void 0 : stretchBySpeed.factor) != null ? _d : 1),
5902
+ stretchMax: uniform((_e = stretchBySpeed == null ? void 0 : stretchBySpeed.maxStretch) != null ? _e : 5),
5903
+ // Collision uniforms
5904
+ collisionEnabled: uniform(collision ? 1 : 0),
5905
+ collisionPlaneY: uniform((_g = (_f = collision == null ? void 0 : collision.plane) == null ? void 0 : _f.y) != null ? _g : 0),
5906
+ collisionBounce: uniform((_h = collision == null ? void 0 : collision.bounce) != null ? _h : 0.3),
5907
+ collisionFriction: uniform((_i = collision == null ? void 0 : collision.friction) != null ? _i : 0.8),
5908
+ collisionDie: uniform((collision == null ? void 0 : collision.die) ? 1 : 0),
5909
+ // Size-based gravity (inside collision object)
5910
+ sizeBasedGravity: uniform((_j = collision == null ? void 0 : collision.sizeBasedGravity) != null ? _j : 0)
5911
+ };
5912
+ },
5913
+ []
5618
5914
  );
5619
- for (let i = 0; i < MAX_ATTRACTORS; i++) {
5620
- const a = attractorList[i];
5621
- const u = uniforms;
5622
- if (a) {
5623
- u[`attractor${i}Pos`].value.set(...(_d = a.position) != null ? _d : [0, 0, 0]);
5624
- u[`attractor${i}Strength`].value = (_e = a.strength) != null ? _e : 1;
5625
- u[`attractor${i}Radius`].value = (_f = a.radius) != null ? _f : 0;
5626
- u[`attractor${i}Type`].value = a.type === "vortex" ? 1 : 0;
5627
- u[`attractor${i}Axis`].value.set(...(_g = a.axis) != null ? _g : [0, 1, 0]).normalize();
5628
- } else {
5629
- u[`attractor${i}Strength`].value = 0;
5915
+ const positionRef = useRef3(position);
5916
+ useEffect3(() => {
5917
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
5918
+ if (debug) return;
5919
+ positionRef.current = position;
5920
+ uniforms.sizeMin.value = sizeRange[0];
5921
+ uniforms.sizeMax.value = sizeRange[1];
5922
+ uniforms.fadeSizeStart.value = fadeSizeRange[0];
5923
+ uniforms.fadeSizeEnd.value = fadeSizeRange[1];
5924
+ uniforms.fadeOpacityStart.value = fadeOpacityRange[0];
5925
+ uniforms.fadeOpacityEnd.value = fadeOpacityRange[1];
5926
+ uniforms.gravity.value.set(...gravity);
5927
+ uniforms.frictionIntensityStart.value = frictionIntensityRange[0];
5928
+ uniforms.frictionIntensityEnd.value = frictionIntensityRange[1];
5929
+ uniforms.frictionEasingType.value = frictionEasingType;
5930
+ uniforms.speedMin.value = speedRange[0];
5931
+ uniforms.speedMax.value = speedRange[1];
5932
+ uniforms.lifetimeMin.value = lifetimeToFadeRate(lifetimeRange[1]);
5933
+ uniforms.lifetimeMax.value = lifetimeToFadeRate(lifetimeRange[0]);
5934
+ uniforms.dirMinX.value = direction3D[0][0];
5935
+ uniforms.dirMaxX.value = direction3D[0][1];
5936
+ uniforms.dirMinY.value = direction3D[1][0];
5937
+ uniforms.dirMaxY.value = direction3D[1][1];
5938
+ uniforms.dirMinZ.value = direction3D[2][0];
5939
+ uniforms.dirMaxZ.value = direction3D[2][1];
5940
+ uniforms.startPosMinX.value = startPosition3D[0][0];
5941
+ uniforms.startPosMaxX.value = startPosition3D[0][1];
5942
+ uniforms.startPosMinY.value = startPosition3D[1][0];
5943
+ uniforms.startPosMaxY.value = startPosition3D[1][1];
5944
+ uniforms.startPosMinZ.value = startPosition3D[2][0];
5945
+ uniforms.startPosMaxZ.value = startPosition3D[2][1];
5946
+ uniforms.rotationMinX.value = rotation3D[0][0];
5947
+ uniforms.rotationMaxX.value = rotation3D[0][1];
5948
+ uniforms.rotationMinY.value = rotation3D[1][0];
5949
+ uniforms.rotationMaxY.value = rotation3D[1][1];
5950
+ uniforms.rotationMinZ.value = rotation3D[2][0];
5951
+ uniforms.rotationMaxZ.value = rotation3D[2][1];
5952
+ uniforms.rotationSpeedMinX.value = rotationSpeed3D[0][0];
5953
+ uniforms.rotationSpeedMaxX.value = rotationSpeed3D[0][1];
5954
+ uniforms.rotationSpeedMinY.value = rotationSpeed3D[1][0];
5955
+ uniforms.rotationSpeedMaxY.value = rotationSpeed3D[1][1];
5956
+ uniforms.rotationSpeedMinZ.value = rotationSpeed3D[2][0];
5957
+ uniforms.rotationSpeedMaxZ.value = rotationSpeed3D[2][1];
5958
+ uniforms.intensity.value = intensity;
5959
+ uniforms.colorStartCount.value = colorStart.length;
5960
+ uniforms.colorEndCount.value = effectiveColorEnd.length;
5961
+ startColors.forEach((c, i) => {
5962
+ var _a3;
5963
+ ;
5964
+ (_a3 = uniforms[`colorStart${i}`]) == null ? void 0 : _a3.value.setRGB(...c);
5965
+ });
5966
+ endColors.forEach((c, i) => {
5967
+ var _a3;
5968
+ ;
5969
+ (_a3 = uniforms[`colorEnd${i}`]) == null ? void 0 : _a3.value.setRGB(...c);
5970
+ });
5971
+ uniforms.emitterShapeType.value = emitterShape;
5972
+ uniforms.emitterRadiusInner.value = emitterRadiusRange[0];
5973
+ uniforms.emitterRadiusOuter.value = emitterRadiusRange[1];
5974
+ uniforms.emitterAngle.value = emitterAngle;
5975
+ uniforms.emitterHeightMin.value = emitterHeightRange[0];
5976
+ uniforms.emitterHeightMax.value = emitterHeightRange[1];
5977
+ uniforms.emitterSurfaceOnly.value = emitterSurfaceOnly ? 1 : 0;
5978
+ uniforms.emitterDir.value.set(...emitterDirection).normalize();
5979
+ uniforms.turbulenceIntensity.value = (_a2 = turbulence == null ? void 0 : turbulence.intensity) != null ? _a2 : 0;
5980
+ uniforms.turbulenceFrequency.value = (_b = turbulence == null ? void 0 : turbulence.frequency) != null ? _b : 1;
5981
+ uniforms.turbulenceSpeed.value = (_c = turbulence == null ? void 0 : turbulence.speed) != null ? _c : 1;
5982
+ const attractorList = attractors != null ? attractors : [];
5983
+ uniforms.attractorCount.value = Math.min(
5984
+ attractorList.length,
5985
+ MAX_ATTRACTORS
5986
+ );
5987
+ for (let i = 0; i < MAX_ATTRACTORS; i++) {
5988
+ const a = attractorList[i];
5989
+ const u = uniforms;
5990
+ if (a) {
5991
+ ;
5992
+ u[`attractor${i}Pos`].value.set(
5993
+ ...(_d = a.position) != null ? _d : [0, 0, 0]
5994
+ );
5995
+ u[`attractor${i}Strength`].value = (_e = a.strength) != null ? _e : 1;
5996
+ u[`attractor${i}Radius`].value = (_f = a.radius) != null ? _f : 0;
5997
+ u[`attractor${i}Type`].value = a.type === "vortex" ? 1 : 0;
5998
+ u[`attractor${i}Axis`].value.set(...(_g = a.axis) != null ? _g : [0, 1, 0]).normalize();
5999
+ } else {
6000
+ u[`attractor${i}Strength`].value = 0;
6001
+ }
5630
6002
  }
5631
- }
5632
- uniforms.attractToCenter.value = attractToCenter ? 1 : 0;
5633
- uniforms.startPositionAsDirection.value = startPositionAsDirection ? 1 : 0;
5634
- uniforms.softParticlesEnabled.value = softParticles ? 1 : 0;
5635
- uniforms.softDistance.value = softDistance;
5636
- uniforms.velocityCurveEnabled.value = velocityCurve ? 1 : 0;
5637
- uniforms.rotationSpeedCurveEnabled.value = rotationSpeedCurve ? 1 : 0;
5638
- uniforms.fadeSizeCurveEnabled.value = fadeSizeCurve ? 1 : 0;
5639
- uniforms.fadeOpacityCurveEnabled.value = fadeOpacityCurve ? 1 : 0;
5640
- uniforms.orientAxisType.value = axisToNumber(orientAxis);
5641
- uniforms.stretchEnabled.value = stretchBySpeed ? 1 : 0;
5642
- uniforms.stretchFactor.value = (_h = stretchBySpeed == null ? void 0 : stretchBySpeed.factor) != null ? _h : 1;
5643
- uniforms.stretchMax.value = (_i = stretchBySpeed == null ? void 0 : stretchBySpeed.maxStretch) != null ? _i : 5;
5644
- uniforms.collisionEnabled.value = collision ? 1 : 0;
5645
- uniforms.collisionPlaneY.value = (_k = (_j = collision == null ? void 0 : collision.plane) == null ? void 0 : _j.y) != null ? _k : 0;
5646
- uniforms.collisionBounce.value = (_l = collision == null ? void 0 : collision.bounce) != null ? _l : 0.3;
5647
- uniforms.collisionFriction.value = (_m = collision == null ? void 0 : collision.friction) != null ? _m : 0.8;
5648
- uniforms.collisionDie.value = (collision == null ? void 0 : collision.die) ? 1 : 0;
5649
- uniforms.sizeBasedGravity.value = (_n = collision == null ? void 0 : collision.sizeBasedGravity) != null ? _n : 0;
5650
- }, [
5651
- debug,
5652
- position,
5653
- sizeRange,
5654
- fadeSizeRange,
5655
- fadeOpacityRange,
5656
- gravity,
5657
- frictionIntensityRange,
5658
- frictionEasingType,
5659
- speedRange,
5660
- lifetimeRange,
5661
- direction3D,
5662
- rotation3D,
5663
- rotationSpeed3D,
5664
- intensity,
5665
- colorStart,
5666
- effectiveColorEnd,
5667
- startColors,
5668
- endColors,
5669
- uniforms,
5670
- collision,
5671
- emitterShape,
5672
- emitterRadiusRange,
5673
- emitterAngle,
5674
- emitterHeightRange,
5675
- emitterSurfaceOnly,
5676
- emitterDirection,
5677
- turbulence,
5678
- startPosition3D,
5679
- attractors,
5680
- attractToCenter,
5681
- startPositionAsDirection,
5682
- softParticles,
5683
- softDistance,
5684
- velocityCurve,
5685
- rotationSpeedCurve,
5686
- fadeSizeCurve,
5687
- fadeOpacityCurve,
5688
- orientAxis,
5689
- stretchBySpeed
5690
- ]);
5691
- const storage = useMemo(
5692
- () => ({
5693
- positions: instancedArray(activeMaxParticles, "vec3"),
5694
- velocities: instancedArray(activeMaxParticles, "vec3"),
5695
- lifetimes: instancedArray(activeMaxParticles, "float"),
5696
- fadeRates: instancedArray(activeMaxParticles, "float"),
5697
- particleSizes: instancedArray(activeMaxParticles, "float"),
5698
- particleRotations: instancedArray(activeMaxParticles, "vec3"),
5699
- particleColorStarts: instancedArray(activeMaxParticles, "vec3"),
5700
- particleColorEnds: instancedArray(activeMaxParticles, "vec3")
5701
- }),
5702
- [activeMaxParticles]
5703
- );
5704
- const computeInit = useMemo(
5705
- () => createInitCompute(storage, activeMaxParticles),
5706
- [storage, activeMaxParticles]
5707
- );
5708
- const computeSpawn = useMemo(
5709
- () => createSpawnCompute(storage, uniforms, activeMaxParticles),
5710
- [storage, uniforms, activeMaxParticles]
5711
- );
5712
- const computeUpdate = useMemo(
5713
- () => createUpdateCompute(storage, uniforms, curveTexture, activeMaxParticles),
5714
- [storage, uniforms, curveTexture, activeMaxParticles]
5715
- );
5716
- const material = useMemo(
5717
- () => createParticleMaterial(storage, uniforms, curveTexture, {
5718
- alphaMap,
5719
- flipbook,
5720
- appearance: activeAppearance,
5721
- lighting: activeLighting,
5722
- softParticles,
5723
- geometry: activeGeometry,
5724
- orientToDirection: activeOrientToDirection,
5725
- shadow: activeShadow,
5726
- blending,
5727
- opacityNode,
5728
- colorNode,
5729
- backdropNode,
5730
- alphaTestNode,
5731
- castShadowNode
5732
- }),
5733
- [
5734
- storage,
6003
+ uniforms.attractToCenter.value = attractToCenter ? 1 : 0;
6004
+ uniforms.startPositionAsDirection.value = startPositionAsDirection ? 1 : 0;
6005
+ uniforms.softParticlesEnabled.value = softParticles ? 1 : 0;
6006
+ uniforms.softDistance.value = softDistance;
6007
+ uniforms.velocityCurveEnabled.value = velocityCurve || curveTexturePath ? 1 : 0;
6008
+ uniforms.rotationSpeedCurveEnabled.value = rotationSpeedCurve || curveTexturePath ? 1 : 0;
6009
+ uniforms.fadeSizeCurveEnabled.value = fadeSizeCurve || curveTexturePath ? 1 : 0;
6010
+ uniforms.fadeOpacityCurveEnabled.value = fadeOpacityCurve || curveTexturePath ? 1 : 0;
6011
+ uniforms.orientAxisType.value = axisToNumber(orientAxis);
6012
+ uniforms.stretchEnabled.value = stretchBySpeed ? 1 : 0;
6013
+ uniforms.stretchFactor.value = (_h = stretchBySpeed == null ? void 0 : stretchBySpeed.factor) != null ? _h : 1;
6014
+ uniforms.stretchMax.value = (_i = stretchBySpeed == null ? void 0 : stretchBySpeed.maxStretch) != null ? _i : 5;
6015
+ uniforms.collisionEnabled.value = collision ? 1 : 0;
6016
+ uniforms.collisionPlaneY.value = (_k = (_j = collision == null ? void 0 : collision.plane) == null ? void 0 : _j.y) != null ? _k : 0;
6017
+ uniforms.collisionBounce.value = (_l = collision == null ? void 0 : collision.bounce) != null ? _l : 0.3;
6018
+ uniforms.collisionFriction.value = (_m = collision == null ? void 0 : collision.friction) != null ? _m : 0.8;
6019
+ uniforms.collisionDie.value = (collision == null ? void 0 : collision.die) ? 1 : 0;
6020
+ uniforms.sizeBasedGravity.value = (_n = collision == null ? void 0 : collision.sizeBasedGravity) != null ? _n : 0;
6021
+ }, [
6022
+ debug,
6023
+ position,
6024
+ sizeRange,
6025
+ fadeSizeRange,
6026
+ fadeOpacityRange,
6027
+ gravity,
6028
+ frictionIntensityRange,
6029
+ frictionEasingType,
6030
+ speedRange,
6031
+ lifetimeRange,
6032
+ direction3D,
6033
+ rotation3D,
6034
+ rotationSpeed3D,
6035
+ intensity,
6036
+ colorStart,
6037
+ effectiveColorEnd,
6038
+ startColors,
6039
+ endColors,
5735
6040
  uniforms,
5736
- curveTexture,
5737
- activeAppearance,
5738
- alphaMap,
5739
- flipbook,
5740
- blending,
5741
- activeGeometry,
5742
- activeOrientToDirection,
5743
- activeLighting,
5744
- backdropNode,
5745
- opacityNode,
5746
- colorNode,
5747
- alphaTestNode,
5748
- castShadowNode,
6041
+ collision,
6042
+ emitterShape,
6043
+ emitterRadiusRange,
6044
+ emitterAngle,
6045
+ emitterHeightRange,
6046
+ emitterSurfaceOnly,
6047
+ emitterDirection,
6048
+ turbulence,
6049
+ startPosition3D,
6050
+ attractors,
6051
+ attractToCenter,
6052
+ startPositionAsDirection,
5749
6053
  softParticles,
5750
- activeShadow
5751
- ]
5752
- );
5753
- const renderObject = useMemo(() => {
5754
- if (activeGeometry) {
5755
- const mesh = new THREE2.InstancedMesh(
5756
- activeGeometry,
5757
- material,
5758
- activeMaxParticles
5759
- );
5760
- mesh.frustumCulled = false;
5761
- mesh.castShadow = activeShadow;
5762
- mesh.receiveShadow = activeShadow;
5763
- return mesh;
5764
- } else {
5765
- const s = new THREE2.Sprite(material);
5766
- s.count = activeMaxParticles;
5767
- s.frustumCulled = false;
5768
- return s;
5769
- }
5770
- }, [material, activeMaxParticles, activeGeometry, activeShadow]);
5771
- useEffect2(() => {
5772
- if (!renderer || initialized.current) return;
5773
- renderer.computeAsync(computeInit).then(() => {
5774
- initialized.current = true;
5775
- });
5776
- }, [renderer, computeInit]);
5777
- const applySpawnOverrides = useCallback2(
5778
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5779
- (overrides) => {
5780
- if (!overrides) return null;
5781
- const saved = {};
5782
- const setUniform = (key, value) => {
5783
- if (uniforms[key]) {
5784
- saved[key] = uniforms[key].value;
5785
- uniforms[key].value = value;
5786
- }
6054
+ softDistance,
6055
+ velocityCurve,
6056
+ rotationSpeedCurve,
6057
+ fadeSizeCurve,
6058
+ fadeOpacityCurve,
6059
+ curveTexturePath,
6060
+ orientAxis,
6061
+ stretchBySpeed
6062
+ ]);
6063
+ const storage = useMemo(() => {
6064
+ const arrays = {
6065
+ positions: instancedArray(activeMaxParticles, "vec3"),
6066
+ velocities: instancedArray(activeMaxParticles, "vec3"),
6067
+ lifetimes: instancedArray(activeMaxParticles, "float"),
6068
+ fadeRates: instancedArray(activeMaxParticles, "float"),
6069
+ particleSizes: instancedArray(activeMaxParticles, "float"),
6070
+ // Optional arrays - null when feature unused (saves GPU memory)
6071
+ particleRotations: null,
6072
+ particleColorStarts: null,
6073
+ particleColorEnds: null
5787
6074
  };
5788
- if (overrides.size !== void 0) {
5789
- const range = toRange(overrides.size, [0.1, 0.3]);
5790
- setUniform("sizeMin", range[0]);
5791
- setUniform("sizeMax", range[1]);
5792
- }
5793
- if (overrides.speed !== void 0) {
5794
- const range = toRange(overrides.speed, [0.1, 0.1]);
5795
- setUniform("speedMin", range[0]);
5796
- setUniform("speedMax", range[1]);
6075
+ if (activeFeatures.needsRotation) {
6076
+ arrays.particleRotations = instancedArray(activeMaxParticles, "vec3");
5797
6077
  }
5798
- if (overrides.lifetime !== void 0) {
5799
- const range = toRange(overrides.lifetime, [1, 2]);
5800
- setUniform("lifetimeMin", 1 / range[1]);
5801
- setUniform("lifetimeMax", 1 / range[0]);
6078
+ if (activeFeatures.needsPerParticleColor) {
6079
+ arrays.particleColorStarts = instancedArray(activeMaxParticles, "vec3");
6080
+ arrays.particleColorEnds = instancedArray(activeMaxParticles, "vec3");
5802
6081
  }
5803
- if (overrides.direction !== void 0) {
5804
- const dir3D = toRotation3D(overrides.direction);
5805
- setUniform("dirMinX", dir3D[0][0]);
5806
- setUniform("dirMaxX", dir3D[0][1]);
5807
- setUniform("dirMinY", dir3D[1][0]);
5808
- setUniform("dirMaxY", dir3D[1][1]);
5809
- setUniform("dirMinZ", dir3D[2][0]);
5810
- setUniform("dirMaxZ", dir3D[2][1]);
5811
- }
5812
- if (overrides.startPosition !== void 0) {
5813
- const pos3D = toRotation3D(overrides.startPosition);
5814
- setUniform("startPosMinX", pos3D[0][0]);
5815
- setUniform("startPosMaxX", pos3D[0][1]);
5816
- setUniform("startPosMinY", pos3D[1][0]);
5817
- setUniform("startPosMaxY", pos3D[1][1]);
5818
- setUniform("startPosMinZ", pos3D[2][0]);
5819
- setUniform("startPosMaxZ", pos3D[2][1]);
5820
- }
5821
- if (overrides.gravity !== void 0) {
5822
- saved.gravity = uniforms.gravity.value.clone();
5823
- uniforms.gravity.value.set(...overrides.gravity);
5824
- }
5825
- const u = uniforms;
5826
- if (overrides.colorStart !== void 0) {
5827
- const colors = overrides.colorStart.slice(0, 8).map(hexToRgb);
5828
- while (colors.length < 8)
5829
- colors.push(colors[colors.length - 1] || [1, 1, 1]);
5830
- setUniform("colorStartCount", overrides.colorStart.length);
5831
- colors.forEach((c, i) => {
5832
- if (u[`colorStart${i}`]) {
5833
- saved[`colorStart${i}`] = u[`colorStart${i}`].value.clone();
5834
- u[`colorStart${i}`].value.setRGB(...c);
5835
- }
5836
- });
5837
- }
5838
- if (overrides.colorEnd !== void 0) {
5839
- const colors = overrides.colorEnd.slice(0, 8).map(hexToRgb);
5840
- while (colors.length < 8)
5841
- colors.push(colors[colors.length - 1] || [1, 1, 1]);
5842
- setUniform("colorEndCount", overrides.colorEnd.length);
5843
- colors.forEach((c, i) => {
5844
- if (u[`colorEnd${i}`]) {
5845
- saved[`colorEnd${i}`] = u[`colorEnd${i}`].value.clone();
5846
- u[`colorEnd${i}`].value.setRGB(...c);
5847
- }
5848
- });
5849
- }
5850
- if (overrides.rotation !== void 0) {
5851
- const rot3D = toRotation3D(overrides.rotation);
5852
- setUniform("rotationMinX", rot3D[0][0]);
5853
- setUniform("rotationMaxX", rot3D[0][1]);
5854
- setUniform("rotationMinY", rot3D[1][0]);
5855
- setUniform("rotationMaxY", rot3D[1][1]);
5856
- setUniform("rotationMinZ", rot3D[2][0]);
5857
- setUniform("rotationMaxZ", rot3D[2][1]);
6082
+ return arrays;
6083
+ }, [
6084
+ activeMaxParticles,
6085
+ activeFeatures.needsRotation,
6086
+ activeFeatures.needsPerParticleColor
6087
+ ]);
6088
+ const computeInit = useMemo(
6089
+ () => createInitCompute(storage, activeMaxParticles),
6090
+ [storage, activeMaxParticles]
6091
+ );
6092
+ const computeSpawn = useMemo(
6093
+ () => createSpawnCompute(storage, uniforms, activeMaxParticles),
6094
+ [storage, uniforms, activeMaxParticles]
6095
+ );
6096
+ const computeUpdate = useMemo(
6097
+ () => createUpdateCompute(
6098
+ storage,
6099
+ uniforms,
6100
+ curveTexture,
6101
+ activeMaxParticles,
6102
+ {
6103
+ turbulence: activeFeatures.turbulence,
6104
+ attractors: activeFeatures.attractors,
6105
+ collision: activeFeatures.collision,
6106
+ rotation: activeFeatures.rotation,
6107
+ perParticleColor: activeFeatures.perParticleColor
6108
+ }
6109
+ ),
6110
+ [storage, uniforms, curveTexture, activeMaxParticles, activeFeatures]
6111
+ );
6112
+ const material = useMemo(
6113
+ () => createParticleMaterial(storage, uniforms, curveTexture, {
6114
+ alphaMap,
6115
+ flipbook,
6116
+ appearance: activeAppearance,
6117
+ lighting: activeLighting,
6118
+ softParticles,
6119
+ geometry: activeGeometry,
6120
+ orientToDirection: activeOrientToDirection,
6121
+ shadow: activeShadow,
6122
+ blending,
6123
+ opacityNode,
6124
+ colorNode,
6125
+ backdropNode,
6126
+ alphaTestNode,
6127
+ castShadowNode
6128
+ }),
6129
+ [
6130
+ storage,
6131
+ uniforms,
6132
+ curveTexture,
6133
+ activeAppearance,
6134
+ alphaMap,
6135
+ flipbook,
6136
+ blending,
6137
+ activeGeometry,
6138
+ activeOrientToDirection,
6139
+ activeLighting,
6140
+ backdropNode,
6141
+ opacityNode,
6142
+ colorNode,
6143
+ alphaTestNode,
6144
+ castShadowNode,
6145
+ softParticles,
6146
+ activeShadow
6147
+ ]
6148
+ );
6149
+ const renderObject = useMemo(() => {
6150
+ if (activeGeometry) {
6151
+ const mesh = new THREE2.InstancedMesh(
6152
+ activeGeometry,
6153
+ material,
6154
+ activeMaxParticles
6155
+ );
6156
+ mesh.frustumCulled = false;
6157
+ mesh.castShadow = activeShadow;
6158
+ mesh.receiveShadow = activeShadow;
6159
+ return mesh;
6160
+ } else {
6161
+ const s = new THREE2.Sprite(material);
6162
+ s.count = activeMaxParticles;
6163
+ s.frustumCulled = false;
6164
+ return s;
5858
6165
  }
5859
- return () => {
5860
- Object.entries(saved).forEach(([key, value]) => {
6166
+ }, [material, activeMaxParticles, activeGeometry, activeShadow]);
6167
+ useEffect3(() => {
6168
+ if (!renderer || initialized.current) return;
6169
+ renderer.computeAsync(computeInit).then(() => {
6170
+ initialized.current = true;
6171
+ });
6172
+ }, [renderer, computeInit]);
6173
+ const applySpawnOverrides = useCallback2(
6174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6175
+ (overrides) => {
6176
+ if (!overrides) return null;
6177
+ const saved = {};
6178
+ const setUniform = (key, value) => {
5861
6179
  if (uniforms[key]) {
6180
+ saved[key] = uniforms[key].value;
5862
6181
  uniforms[key].value = value;
5863
6182
  }
5864
- });
5865
- };
5866
- },
5867
- [uniforms]
5868
- );
5869
- const spawnInternal = useCallback2(
5870
- (x, y, z, count = 20, overrides = null) => {
6183
+ };
6184
+ if (overrides.size !== void 0) {
6185
+ const range = toRange(overrides.size, [0.1, 0.3]);
6186
+ setUniform("sizeMin", range[0]);
6187
+ setUniform("sizeMax", range[1]);
6188
+ }
6189
+ if (overrides.speed !== void 0) {
6190
+ const range = toRange(overrides.speed, [0.1, 0.1]);
6191
+ setUniform("speedMin", range[0]);
6192
+ setUniform("speedMax", range[1]);
6193
+ }
6194
+ if (overrides.lifetime !== void 0) {
6195
+ const range = toRange(overrides.lifetime, [1, 2]);
6196
+ setUniform("lifetimeMin", 1 / range[1]);
6197
+ setUniform("lifetimeMax", 1 / range[0]);
6198
+ }
6199
+ if (overrides.direction !== void 0) {
6200
+ const dir3D = toRotation3D(overrides.direction);
6201
+ setUniform("dirMinX", dir3D[0][0]);
6202
+ setUniform("dirMaxX", dir3D[0][1]);
6203
+ setUniform("dirMinY", dir3D[1][0]);
6204
+ setUniform("dirMaxY", dir3D[1][1]);
6205
+ setUniform("dirMinZ", dir3D[2][0]);
6206
+ setUniform("dirMaxZ", dir3D[2][1]);
6207
+ }
6208
+ if (overrides.startPosition !== void 0) {
6209
+ const pos3D = toRotation3D(overrides.startPosition);
6210
+ setUniform("startPosMinX", pos3D[0][0]);
6211
+ setUniform("startPosMaxX", pos3D[0][1]);
6212
+ setUniform("startPosMinY", pos3D[1][0]);
6213
+ setUniform("startPosMaxY", pos3D[1][1]);
6214
+ setUniform("startPosMinZ", pos3D[2][0]);
6215
+ setUniform("startPosMaxZ", pos3D[2][1]);
6216
+ }
6217
+ if (overrides.gravity !== void 0) {
6218
+ saved.gravity = uniforms.gravity.value.clone();
6219
+ uniforms.gravity.value.set(
6220
+ ...overrides.gravity
6221
+ );
6222
+ }
6223
+ const u = uniforms;
6224
+ if (overrides.colorStart !== void 0) {
6225
+ const colors = overrides.colorStart.slice(0, 8).map(hexToRgb);
6226
+ while (colors.length < 8)
6227
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
6228
+ setUniform("colorStartCount", overrides.colorStart.length);
6229
+ colors.forEach((c, i) => {
6230
+ if (u[`colorStart${i}`]) {
6231
+ saved[`colorStart${i}`] = u[`colorStart${i}`].value.clone();
6232
+ u[`colorStart${i}`].value.setRGB(...c);
6233
+ }
6234
+ });
6235
+ }
6236
+ if (overrides.colorEnd !== void 0) {
6237
+ const colors = overrides.colorEnd.slice(0, 8).map(hexToRgb);
6238
+ while (colors.length < 8)
6239
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
6240
+ setUniform("colorEndCount", overrides.colorEnd.length);
6241
+ colors.forEach((c, i) => {
6242
+ if (u[`colorEnd${i}`]) {
6243
+ saved[`colorEnd${i}`] = u[`colorEnd${i}`].value.clone();
6244
+ u[`colorEnd${i}`].value.setRGB(...c);
6245
+ }
6246
+ });
6247
+ }
6248
+ if (overrides.rotation !== void 0) {
6249
+ const rot3D = toRotation3D(overrides.rotation);
6250
+ setUniform("rotationMinX", rot3D[0][0]);
6251
+ setUniform("rotationMaxX", rot3D[0][1]);
6252
+ setUniform("rotationMinY", rot3D[1][0]);
6253
+ setUniform("rotationMaxY", rot3D[1][1]);
6254
+ setUniform("rotationMinZ", rot3D[2][0]);
6255
+ setUniform("rotationMaxZ", rot3D[2][1]);
6256
+ }
6257
+ return () => {
6258
+ Object.entries(saved).forEach(([key, value]) => {
6259
+ if (uniforms[key]) {
6260
+ uniforms[key].value = value;
6261
+ }
6262
+ });
6263
+ };
6264
+ },
6265
+ [uniforms]
6266
+ );
6267
+ const spawnInternal = useCallback2(
6268
+ (x, y, z, count = 20, overrides = null) => {
6269
+ if (!initialized.current || !renderer) return;
6270
+ const restore = applySpawnOverrides(overrides);
6271
+ const startIdx = nextIndex.current;
6272
+ const endIdx = (startIdx + count) % activeMaxParticles;
6273
+ uniforms.spawnPosition.value.set(x, y, z);
6274
+ uniforms.spawnIndexStart.value = startIdx;
6275
+ uniforms.spawnIndexEnd.value = endIdx;
6276
+ uniforms.spawnSeed.value = Math.random() * 1e4;
6277
+ nextIndex.current = endIdx;
6278
+ renderer.computeAsync(computeSpawn);
6279
+ if (restore) restore();
6280
+ },
6281
+ [
6282
+ renderer,
6283
+ computeSpawn,
6284
+ uniforms,
6285
+ activeMaxParticles,
6286
+ applySpawnOverrides
6287
+ ]
6288
+ );
6289
+ const spawn = useCallback2(
6290
+ (x = 0, y = 0, z = 0, count = 20, overrides = null) => {
6291
+ var _a2;
6292
+ const [px, py, pz] = (_a2 = positionRef.current) != null ? _a2 : [0, 0, 0];
6293
+ spawnInternal(px + x, py + y, pz + z, count, overrides);
6294
+ },
6295
+ [spawnInternal]
6296
+ );
6297
+ const computeUpdateRef = useRef3(computeUpdate);
6298
+ useEffect3(() => {
6299
+ computeUpdateRef.current = computeUpdate;
6300
+ }, [computeUpdate]);
6301
+ useFrame(async (state, delta) => {
6302
+ var _a2, _b;
5871
6303
  if (!initialized.current || !renderer) return;
5872
- const restore = applySpawnOverrides(overrides);
5873
- const startIdx = nextIndex.current;
5874
- const endIdx = (startIdx + count) % activeMaxParticles;
5875
- uniforms.spawnPosition.value.set(x, y, z);
5876
- uniforms.spawnIndexStart.value = startIdx;
5877
- uniforms.spawnIndexEnd.value = endIdx;
5878
- uniforms.spawnSeed.value = Math.random() * 1e4;
5879
- nextIndex.current = endIdx;
5880
- renderer.computeAsync(computeSpawn);
5881
- if (restore) restore();
5882
- },
5883
- [renderer, computeSpawn, uniforms, activeMaxParticles, applySpawnOverrides]
5884
- );
5885
- const spawn = useCallback2(
5886
- (x = 0, y = 0, z = 0, count = 20, overrides = null) => {
5887
- var _a;
5888
- const [px, py, pz] = (_a = positionRef.current) != null ? _a : [0, 0, 0];
5889
- spawnInternal(px + x, py + y, pz + z, count, overrides);
5890
- },
5891
- [spawnInternal]
5892
- );
5893
- const computeUpdateRef = useRef2(computeUpdate);
5894
- useEffect2(() => {
5895
- computeUpdateRef.current = computeUpdate;
5896
- }, [computeUpdate]);
5897
- useFrame(async (state, delta) => {
5898
- var _a, _b;
5899
- if (!initialized.current || !renderer) return;
5900
- uniforms.deltaTime.value = delta;
5901
- const turbSpeed = (_b = (_a = turbulenceRef.current) == null ? void 0 : _a.speed) != null ? _b : 1;
5902
- uniforms.turbulenceTime.value += delta * turbSpeed;
5903
- await renderer.computeAsync(computeUpdateRef.current);
5904
- if (emitting) {
5905
- const [px, py, pz] = positionRef.current;
5906
- const currentDelay = delayRef.current;
5907
- const currentEmitCount = emitCountRef.current;
5908
- if (!currentDelay) {
5909
- spawnInternal(px, py, pz, currentEmitCount);
5910
- } else {
5911
- emitAccumulator.current += delta;
5912
- if (emitAccumulator.current >= currentDelay) {
5913
- emitAccumulator.current -= currentDelay;
6304
+ uniforms.deltaTime.value = delta;
6305
+ const turbSpeed = (_b = (_a2 = turbulenceRef.current) == null ? void 0 : _a2.speed) != null ? _b : 1;
6306
+ uniforms.turbulenceTime.value += delta * turbSpeed;
6307
+ await renderer.computeAsync(computeUpdateRef.current);
6308
+ if (emitting) {
6309
+ const [px, py, pz] = positionRef.current;
6310
+ const currentDelay = delayRef.current;
6311
+ const currentEmitCount = emitCountRef.current;
6312
+ if (!currentDelay) {
5914
6313
  spawnInternal(px, py, pz, currentEmitCount);
6314
+ } else {
6315
+ emitAccumulator.current += delta;
6316
+ if (emitAccumulator.current >= currentDelay) {
6317
+ emitAccumulator.current -= currentDelay;
6318
+ spawnInternal(px, py, pz, currentEmitCount);
6319
+ }
5915
6320
  }
5916
6321
  }
5917
- }
5918
- });
5919
- const start = useCallback2(() => {
5920
- setEmitting(true);
5921
- emitAccumulator.current = 0;
5922
- }, []);
5923
- const stop = useCallback2(() => {
5924
- setEmitting(false);
5925
- }, []);
5926
- const prevMaterialRef = useRef2(null);
5927
- const prevRenderObjectRef = useRef2(null);
5928
- useEffect2(() => {
5929
- if (prevMaterialRef.current && prevMaterialRef.current !== material) {
5930
- prevMaterialRef.current.dispose();
5931
- }
5932
- prevMaterialRef.current = material;
5933
- if (prevRenderObjectRef.current && prevRenderObjectRef.current !== renderObject) {
5934
- if (prevRenderObjectRef.current.material) {
5935
- prevRenderObjectRef.current.material.dispose();
6322
+ });
6323
+ const start = useCallback2(() => {
6324
+ setEmitting(true);
6325
+ emitAccumulator.current = 0;
6326
+ }, []);
6327
+ const stop = useCallback2(() => {
6328
+ setEmitting(false);
6329
+ }, []);
6330
+ const prevMaterialRef = useRef3(null);
6331
+ const prevRenderObjectRef = useRef3(null);
6332
+ useEffect3(() => {
6333
+ if (prevMaterialRef.current && prevMaterialRef.current !== material) {
6334
+ prevMaterialRef.current.dispose();
5936
6335
  }
5937
- }
5938
- prevRenderObjectRef.current = renderObject;
5939
- }, [material, renderObject]);
5940
- useEffect2(() => {
5941
- return () => {
5942
- if (material) {
5943
- material.dispose();
6336
+ prevMaterialRef.current = material;
6337
+ if (prevRenderObjectRef.current && prevRenderObjectRef.current !== renderObject) {
6338
+ if (prevRenderObjectRef.current.material) {
6339
+ prevRenderObjectRef.current.material.dispose();
6340
+ }
5944
6341
  }
5945
- if (renderObject) {
5946
- if (renderObject.geometry && !geometry) {
5947
- renderObject.geometry.dispose();
6342
+ prevRenderObjectRef.current = renderObject;
6343
+ }, [material, renderObject]);
6344
+ useEffect3(() => {
6345
+ return () => {
6346
+ if (material) {
6347
+ material.dispose();
5948
6348
  }
5949
- if (renderObject.material) {
5950
- renderObject.material.dispose();
6349
+ if (renderObject) {
6350
+ if (renderObject.geometry && !geometry) {
6351
+ renderObject.geometry.dispose();
6352
+ }
6353
+ if (renderObject.material) {
6354
+ renderObject.material.dispose();
6355
+ }
5951
6356
  }
5952
- }
5953
- initialized.current = false;
5954
- nextIndex.current = 0;
5955
- };
5956
- }, []);
5957
- const particleAPI = useMemo(
5958
- () => ({
5959
- spawn,
5960
- start,
5961
- stop,
5962
- get isEmitting() {
5963
- return emitting;
5964
- },
5965
- clear() {
5966
- renderer.computeAsync(computeInit);
6357
+ initialized.current = false;
5967
6358
  nextIndex.current = 0;
5968
- },
5969
- uniforms
5970
- }),
5971
- [spawn, start, stop, emitting, renderer, computeInit, uniforms]
5972
- );
5973
- useImperativeHandle(ref, () => particleAPI, [particleAPI]);
5974
- const registerParticles = useVFXStore((s) => s.registerParticles);
5975
- const unregisterParticles = useVFXStore((s) => s.unregisterParticles);
5976
- useEffect2(() => {
5977
- if (!name) return;
5978
- registerParticles(name, particleAPI);
5979
- return () => {
5980
- unregisterParticles(name);
5981
- };
5982
- }, [name, particleAPI, registerParticles, unregisterParticles]);
5983
- const debugValuesRef = useRef2(null);
5984
- const prevGeometryTypeRef = useRef2(null);
5985
- const prevGeometryArgsRef = useRef2(null);
5986
- const handleDebugUpdate = useCallback2(
5987
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5988
- (newValues) => {
5989
- var _a, _b, _c, _d, _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;
5990
- debugValuesRef.current = __spreadValues(__spreadValues({}, debugValuesRef.current), newValues);
5991
- if ("size" in newValues) {
5992
- const sizeR = toRange(newValues.size, [0.1, 0.3]);
5993
- uniforms.sizeMin.value = sizeR[0];
5994
- uniforms.sizeMax.value = sizeR[1];
5995
- }
5996
- if ("fadeSize" in newValues) {
5997
- const fadeSizeR = toRange(newValues.fadeSize, [1, 0]);
5998
- uniforms.fadeSizeStart.value = fadeSizeR[0];
5999
- uniforms.fadeSizeEnd.value = fadeSizeR[1];
6000
- }
6001
- if ("fadeOpacity" in newValues) {
6002
- const fadeOpacityR = toRange(newValues.fadeOpacity, [1, 0]);
6003
- uniforms.fadeOpacityStart.value = fadeOpacityR[0];
6004
- uniforms.fadeOpacityEnd.value = fadeOpacityR[1];
6005
- }
6006
- if ("fadeSizeCurve" in newValues) {
6007
- setActiveFadeSizeCurve(newValues.fadeSizeCurve);
6008
- uniforms.fadeSizeCurveEnabled.value = newValues.fadeSizeCurve ? 1 : 0;
6009
- }
6010
- if ("fadeOpacityCurve" in newValues) {
6011
- setActiveFadeOpacityCurve(newValues.fadeOpacityCurve);
6012
- uniforms.fadeOpacityCurveEnabled.value = newValues.fadeOpacityCurve ? 1 : 0;
6013
- }
6014
- if ("velocityCurve" in newValues) {
6015
- setActiveVelocityCurve(newValues.velocityCurve);
6016
- uniforms.velocityCurveEnabled.value = newValues.velocityCurve ? 1 : 0;
6017
- }
6018
- if ("rotationSpeedCurve" in newValues) {
6019
- setActiveRotationSpeedCurve(newValues.rotationSpeedCurve);
6020
- uniforms.rotationSpeedCurveEnabled.value = newValues.rotationSpeedCurve ? 1 : 0;
6021
- }
6022
- if ("orientAxis" in newValues) {
6023
- uniforms.orientAxisType.value = axisToNumber(newValues.orientAxis);
6024
- }
6025
- if ("stretchBySpeed" in newValues) {
6026
- uniforms.stretchEnabled.value = newValues.stretchBySpeed ? 1 : 0;
6027
- uniforms.stretchFactor.value = (_b = (_a = newValues.stretchBySpeed) == null ? void 0 : _a.factor) != null ? _b : 1;
6028
- uniforms.stretchMax.value = (_d = (_c = newValues.stretchBySpeed) == null ? void 0 : _c.maxStretch) != null ? _d : 5;
6029
- }
6030
- if (newValues.gravity && Array.isArray(newValues.gravity)) {
6031
- uniforms.gravity.value.x = newValues.gravity[0];
6032
- uniforms.gravity.value.y = newValues.gravity[1];
6033
- uniforms.gravity.value.z = newValues.gravity[2];
6034
- }
6035
- if ("speed" in newValues) {
6036
- const speedR = toRange(newValues.speed, [0.1, 0.1]);
6037
- uniforms.speedMin.value = speedR[0];
6038
- uniforms.speedMax.value = speedR[1];
6039
- }
6040
- if ("lifetime" in newValues) {
6041
- const lifetimeR = toRange(newValues.lifetime, [1, 2]);
6042
- uniforms.lifetimeMin.value = 1 / lifetimeR[1];
6043
- uniforms.lifetimeMax.value = 1 / lifetimeR[0];
6044
- }
6045
- if ("friction" in newValues && newValues.friction) {
6046
- const frictionR = toRange(newValues.friction.intensity, [0, 0]);
6047
- uniforms.frictionIntensityStart.value = frictionR[0];
6048
- uniforms.frictionIntensityEnd.value = frictionR[1];
6049
- uniforms.frictionEasingType.value = easingToType(
6050
- newValues.friction.easing
6051
- );
6052
- }
6053
- if ("direction" in newValues) {
6054
- const dir3D = toRotation3D(newValues.direction);
6055
- uniforms.dirMinX.value = dir3D[0][0];
6056
- uniforms.dirMaxX.value = dir3D[0][1];
6057
- uniforms.dirMinY.value = dir3D[1][0];
6058
- uniforms.dirMaxY.value = dir3D[1][1];
6059
- uniforms.dirMinZ.value = dir3D[2][0];
6060
- uniforms.dirMaxZ.value = dir3D[2][1];
6061
- }
6062
- if ("startPosition" in newValues) {
6063
- const startPos3D = toRotation3D(newValues.startPosition);
6064
- uniforms.startPosMinX.value = startPos3D[0][0];
6065
- uniforms.startPosMaxX.value = startPos3D[0][1];
6066
- uniforms.startPosMinY.value = startPos3D[1][0];
6067
- uniforms.startPosMaxY.value = startPos3D[1][1];
6068
- uniforms.startPosMinZ.value = startPos3D[2][0];
6069
- uniforms.startPosMaxZ.value = startPos3D[2][1];
6070
- }
6071
- if ("rotation" in newValues) {
6072
- const rot3D = toRotation3D(newValues.rotation);
6073
- uniforms.rotationMinX.value = rot3D[0][0];
6074
- uniforms.rotationMaxX.value = rot3D[0][1];
6075
- uniforms.rotationMinY.value = rot3D[1][0];
6076
- uniforms.rotationMaxY.value = rot3D[1][1];
6077
- uniforms.rotationMinZ.value = rot3D[2][0];
6078
- uniforms.rotationMaxZ.value = rot3D[2][1];
6079
- }
6080
- if ("rotationSpeed" in newValues) {
6081
- const rotSpeed3D = toRotation3D(newValues.rotationSpeed);
6082
- uniforms.rotationSpeedMinX.value = rotSpeed3D[0][0];
6083
- uniforms.rotationSpeedMaxX.value = rotSpeed3D[0][1];
6084
- uniforms.rotationSpeedMinY.value = rotSpeed3D[1][0];
6085
- uniforms.rotationSpeedMaxY.value = rotSpeed3D[1][1];
6086
- uniforms.rotationSpeedMinZ.value = rotSpeed3D[2][0];
6087
- uniforms.rotationSpeedMaxZ.value = rotSpeed3D[2][1];
6088
- }
6089
- if ("intensity" in newValues) {
6090
- uniforms.intensity.value = newValues.intensity || 1;
6091
- }
6092
- if ("colorStart" in newValues && newValues.colorStart) {
6093
- const startColors2 = newValues.colorStart.slice(0, 8).map(hexToRgb);
6094
- while (startColors2.length < 8)
6095
- startColors2.push(startColors2[startColors2.length - 1] || [1, 1, 1]);
6096
- uniforms.colorStartCount.value = newValues.colorStart.length;
6097
- startColors2.forEach((c, i) => {
6098
- if (uniforms[`colorStart${i}`]) {
6099
- uniforms[`colorStart${i}`].value.setRGB(...c);
6359
+ };
6360
+ }, []);
6361
+ const particleAPI = useMemo(
6362
+ () => ({
6363
+ spawn,
6364
+ start,
6365
+ stop,
6366
+ get isEmitting() {
6367
+ return emitting;
6368
+ },
6369
+ clear() {
6370
+ renderer.computeAsync(computeInit);
6371
+ nextIndex.current = 0;
6372
+ },
6373
+ uniforms
6374
+ }),
6375
+ [spawn, start, stop, emitting, renderer, computeInit, uniforms]
6376
+ );
6377
+ useImperativeHandle(ref, () => particleAPI, [particleAPI]);
6378
+ const registerParticles = useVFXStore((s) => s.registerParticles);
6379
+ const unregisterParticles = useVFXStore((s) => s.unregisterParticles);
6380
+ useEffect3(() => {
6381
+ if (!name) return;
6382
+ registerParticles(name, particleAPI);
6383
+ return () => {
6384
+ unregisterParticles(name);
6385
+ };
6386
+ }, [name, particleAPI, registerParticles, unregisterParticles]);
6387
+ const debugValuesRef = useRef3(null);
6388
+ const prevGeometryTypeRef = useRef3(null);
6389
+ const prevGeometryArgsRef = useRef3(null);
6390
+ const handleDebugUpdate = useCallback2(
6391
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6392
+ (newValues) => {
6393
+ var _a2, _b, _c, _d, _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, _J, _K, _L, _M, _N, _O, _P, _Q, _R;
6394
+ debugValuesRef.current = __spreadValues(__spreadValues({}, debugValuesRef.current), newValues);
6395
+ if ("size" in newValues) {
6396
+ const sizeR = toRange(newValues.size, [0.1, 0.3]);
6397
+ uniforms.sizeMin.value = sizeR[0];
6398
+ uniforms.sizeMax.value = sizeR[1];
6399
+ }
6400
+ if ("fadeSize" in newValues) {
6401
+ const fadeSizeR = toRange(newValues.fadeSize, [1, 0]);
6402
+ uniforms.fadeSizeStart.value = fadeSizeR[0];
6403
+ uniforms.fadeSizeEnd.value = fadeSizeR[1];
6404
+ }
6405
+ if ("fadeOpacity" in newValues) {
6406
+ const fadeOpacityR = toRange(newValues.fadeOpacity, [1, 0]);
6407
+ uniforms.fadeOpacityStart.value = fadeOpacityR[0];
6408
+ uniforms.fadeOpacityEnd.value = fadeOpacityR[1];
6409
+ }
6410
+ if ("fadeSizeCurve" in newValues) {
6411
+ setActiveFadeSizeCurve(newValues.fadeSizeCurve);
6412
+ uniforms.fadeSizeCurveEnabled.value = newValues.fadeSizeCurve ? 1 : 0;
6413
+ }
6414
+ if ("fadeOpacityCurve" in newValues) {
6415
+ setActiveFadeOpacityCurve(newValues.fadeOpacityCurve);
6416
+ uniforms.fadeOpacityCurveEnabled.value = newValues.fadeOpacityCurve ? 1 : 0;
6417
+ }
6418
+ if ("velocityCurve" in newValues) {
6419
+ setActiveVelocityCurve(newValues.velocityCurve);
6420
+ uniforms.velocityCurveEnabled.value = newValues.velocityCurve ? 1 : 0;
6421
+ }
6422
+ if ("rotationSpeedCurve" in newValues) {
6423
+ setActiveRotationSpeedCurve(newValues.rotationSpeedCurve);
6424
+ uniforms.rotationSpeedCurveEnabled.value = newValues.rotationSpeedCurve ? 1 : 0;
6425
+ }
6426
+ if ("orientAxis" in newValues) {
6427
+ uniforms.orientAxisType.value = axisToNumber(newValues.orientAxis);
6428
+ }
6429
+ if ("stretchBySpeed" in newValues) {
6430
+ uniforms.stretchEnabled.value = newValues.stretchBySpeed ? 1 : 0;
6431
+ uniforms.stretchFactor.value = (_b = (_a2 = newValues.stretchBySpeed) == null ? void 0 : _a2.factor) != null ? _b : 1;
6432
+ uniforms.stretchMax.value = (_d = (_c = newValues.stretchBySpeed) == null ? void 0 : _c.maxStretch) != null ? _d : 5;
6433
+ }
6434
+ if (newValues.gravity && Array.isArray(newValues.gravity)) {
6435
+ uniforms.gravity.value.x = newValues.gravity[0];
6436
+ uniforms.gravity.value.y = newValues.gravity[1];
6437
+ uniforms.gravity.value.z = newValues.gravity[2];
6438
+ }
6439
+ if ("speed" in newValues) {
6440
+ const speedR = toRange(newValues.speed, [0.1, 0.1]);
6441
+ uniforms.speedMin.value = speedR[0];
6442
+ uniforms.speedMax.value = speedR[1];
6443
+ }
6444
+ if ("lifetime" in newValues) {
6445
+ const lifetimeR = toRange(newValues.lifetime, [1, 2]);
6446
+ uniforms.lifetimeMin.value = 1 / lifetimeR[1];
6447
+ uniforms.lifetimeMax.value = 1 / lifetimeR[0];
6448
+ }
6449
+ if ("friction" in newValues && newValues.friction) {
6450
+ const frictionR = toRange(newValues.friction.intensity, [0, 0]);
6451
+ uniforms.frictionIntensityStart.value = frictionR[0];
6452
+ uniforms.frictionIntensityEnd.value = frictionR[1];
6453
+ uniforms.frictionEasingType.value = easingToType(
6454
+ newValues.friction.easing
6455
+ );
6456
+ }
6457
+ if ("direction" in newValues) {
6458
+ const dir3D = toRotation3D(newValues.direction);
6459
+ uniforms.dirMinX.value = dir3D[0][0];
6460
+ uniforms.dirMaxX.value = dir3D[0][1];
6461
+ uniforms.dirMinY.value = dir3D[1][0];
6462
+ uniforms.dirMaxY.value = dir3D[1][1];
6463
+ uniforms.dirMinZ.value = dir3D[2][0];
6464
+ uniforms.dirMaxZ.value = dir3D[2][1];
6465
+ }
6466
+ if ("startPosition" in newValues) {
6467
+ const startPos3D = toRotation3D(newValues.startPosition);
6468
+ uniforms.startPosMinX.value = startPos3D[0][0];
6469
+ uniforms.startPosMaxX.value = startPos3D[0][1];
6470
+ uniforms.startPosMinY.value = startPos3D[1][0];
6471
+ uniforms.startPosMaxY.value = startPos3D[1][1];
6472
+ uniforms.startPosMinZ.value = startPos3D[2][0];
6473
+ uniforms.startPosMaxZ.value = startPos3D[2][1];
6474
+ }
6475
+ if ("rotation" in newValues) {
6476
+ const rot3D = toRotation3D(newValues.rotation);
6477
+ uniforms.rotationMinX.value = rot3D[0][0];
6478
+ uniforms.rotationMaxX.value = rot3D[0][1];
6479
+ uniforms.rotationMinY.value = rot3D[1][0];
6480
+ uniforms.rotationMaxY.value = rot3D[1][1];
6481
+ uniforms.rotationMinZ.value = rot3D[2][0];
6482
+ uniforms.rotationMaxZ.value = rot3D[2][1];
6483
+ }
6484
+ if ("rotationSpeed" in newValues) {
6485
+ const rotSpeed3D = toRotation3D(newValues.rotationSpeed);
6486
+ uniforms.rotationSpeedMinX.value = rotSpeed3D[0][0];
6487
+ uniforms.rotationSpeedMaxX.value = rotSpeed3D[0][1];
6488
+ uniforms.rotationSpeedMinY.value = rotSpeed3D[1][0];
6489
+ uniforms.rotationSpeedMaxY.value = rotSpeed3D[1][1];
6490
+ uniforms.rotationSpeedMinZ.value = rotSpeed3D[2][0];
6491
+ uniforms.rotationSpeedMaxZ.value = rotSpeed3D[2][1];
6492
+ }
6493
+ if ("rotation" in newValues || "rotationSpeed" in newValues) {
6494
+ const rot = (_g = (_f = newValues.rotation) != null ? _f : (_e = debugValuesRef.current) == null ? void 0 : _e.rotation) != null ? _g : [0, 0];
6495
+ const rotSpeed = (_j = (_i = newValues.rotationSpeed) != null ? _i : (_h = debugValuesRef.current) == null ? void 0 : _h.rotationSpeed) != null ? _j : [0, 0];
6496
+ const needsRotation = isNonDefaultRotation(rot) || isNonDefaultRotation(rotSpeed);
6497
+ if (needsRotation !== activeNeedsRotation) {
6498
+ setActiveNeedsRotation(needsRotation);
6100
6499
  }
6101
- });
6102
- const currentColorEnd = (_e = debugValuesRef.current) == null ? void 0 : _e.colorEnd;
6103
- if (!currentColorEnd) {
6104
- uniforms.colorEndCount.value = newValues.colorStart.length;
6500
+ }
6501
+ if ("intensity" in newValues) {
6502
+ uniforms.intensity.value = newValues.intensity || 1;
6503
+ }
6504
+ if ("colorStart" in newValues && newValues.colorStart) {
6505
+ const startColors2 = newValues.colorStart.slice(0, 8).map(hexToRgb);
6506
+ while (startColors2.length < 8)
6507
+ startColors2.push(startColors2[startColors2.length - 1] || [1, 1, 1]);
6508
+ uniforms.colorStartCount.value = newValues.colorStart.length;
6105
6509
  startColors2.forEach((c, i) => {
6106
- if (uniforms[`colorEnd${i}`]) {
6107
- uniforms[`colorEnd${i}`].value.setRGB(...c);
6510
+ if (uniforms[`colorStart${i}`]) {
6511
+ uniforms[`colorStart${i}`].value.setRGB(...c);
6108
6512
  }
6109
6513
  });
6514
+ const currentColorEnd = (_k = debugValuesRef.current) == null ? void 0 : _k.colorEnd;
6515
+ if (!currentColorEnd) {
6516
+ uniforms.colorEndCount.value = newValues.colorStart.length;
6517
+ startColors2.forEach((c, i) => {
6518
+ if (uniforms[`colorEnd${i}`]) {
6519
+ uniforms[`colorEnd${i}`].value.setRGB(...c);
6520
+ }
6521
+ });
6522
+ }
6110
6523
  }
6111
- }
6112
- if ("colorEnd" in newValues) {
6113
- const effectiveEndColors = newValues.colorEnd || newValues.colorStart || ((_f = debugValuesRef.current) == null ? void 0 : _f.colorStart) || ["#ffffff"];
6114
- if (effectiveEndColors) {
6115
- const endColors2 = effectiveEndColors.slice(0, 8).map(hexToRgb);
6116
- while (endColors2.length < 8)
6117
- endColors2.push(endColors2[endColors2.length - 1] || [1, 1, 1]);
6118
- uniforms.colorEndCount.value = effectiveEndColors.length;
6119
- endColors2.forEach((c, i) => {
6120
- if (uniforms[`colorEnd${i}`]) {
6121
- uniforms[`colorEnd${i}`].value.setRGB(...c);
6122
- }
6123
- });
6524
+ if ("colorEnd" in newValues) {
6525
+ const effectiveEndColors = newValues.colorEnd || newValues.colorStart || ((_l = debugValuesRef.current) == null ? void 0 : _l.colorStart) || ["#ffffff"];
6526
+ if (effectiveEndColors) {
6527
+ const endColors2 = effectiveEndColors.slice(0, 8).map(hexToRgb);
6528
+ while (endColors2.length < 8)
6529
+ endColors2.push(endColors2[endColors2.length - 1] || [1, 1, 1]);
6530
+ uniforms.colorEndCount.value = effectiveEndColors.length;
6531
+ endColors2.forEach((c, i) => {
6532
+ if (uniforms[`colorEnd${i}`]) {
6533
+ uniforms[`colorEnd${i}`].value.setRGB(...c);
6534
+ }
6535
+ });
6536
+ }
6124
6537
  }
6125
- }
6126
- if ("emitterShape" in newValues) {
6127
- uniforms.emitterShapeType.value = (_g = newValues.emitterShape) != null ? _g : EmitterShape2.BOX;
6128
- }
6129
- if ("emitterRadius" in newValues) {
6130
- const emitterRadiusR = toRange(newValues.emitterRadius, [0, 1]);
6131
- uniforms.emitterRadiusInner.value = emitterRadiusR[0];
6132
- uniforms.emitterRadiusOuter.value = emitterRadiusR[1];
6133
- }
6134
- if ("emitterAngle" in newValues) {
6135
- uniforms.emitterAngle.value = (_h = newValues.emitterAngle) != null ? _h : Math.PI / 4;
6136
- }
6137
- if ("emitterHeight" in newValues) {
6138
- const emitterHeightR = toRange(newValues.emitterHeight, [0, 1]);
6139
- uniforms.emitterHeightMin.value = emitterHeightR[0];
6140
- uniforms.emitterHeightMax.value = emitterHeightR[1];
6141
- }
6142
- if ("emitterSurfaceOnly" in newValues) {
6143
- uniforms.emitterSurfaceOnly.value = newValues.emitterSurfaceOnly ? 1 : 0;
6144
- }
6145
- if ("emitterDirection" in newValues && newValues.emitterDirection && Array.isArray(newValues.emitterDirection)) {
6146
- const dir = new THREE2.Vector3(
6147
- ...newValues.emitterDirection
6148
- ).normalize();
6149
- uniforms.emitterDir.value.x = dir.x;
6150
- uniforms.emitterDir.value.y = dir.y;
6151
- uniforms.emitterDir.value.z = dir.z;
6152
- }
6153
- if ("turbulence" in newValues) {
6154
- uniforms.turbulenceIntensity.value = (_j = (_i = newValues.turbulence) == null ? void 0 : _i.intensity) != null ? _j : 0;
6155
- uniforms.turbulenceFrequency.value = (_l = (_k = newValues.turbulence) == null ? void 0 : _k.frequency) != null ? _l : 1;
6156
- uniforms.turbulenceSpeed.value = (_n = (_m = newValues.turbulence) == null ? void 0 : _m.speed) != null ? _n : 1;
6157
- turbulenceRef.current = newValues.turbulence;
6158
- }
6159
- if ("attractToCenter" in newValues) {
6160
- uniforms.attractToCenter.value = newValues.attractToCenter ? 1 : 0;
6161
- }
6162
- if ("startPositionAsDirection" in newValues) {
6163
- uniforms.startPositionAsDirection.value = newValues.startPositionAsDirection ? 1 : 0;
6164
- }
6165
- if ("softParticles" in newValues) {
6166
- uniforms.softParticlesEnabled.value = newValues.softParticles ? 1 : 0;
6167
- }
6168
- if ("softDistance" in newValues) {
6169
- uniforms.softDistance.value = (_o = newValues.softDistance) != null ? _o : 0.5;
6170
- }
6171
- if ("collision" in newValues) {
6172
- uniforms.collisionEnabled.value = newValues.collision ? 1 : 0;
6173
- uniforms.collisionPlaneY.value = (_r = (_q = (_p = newValues.collision) == null ? void 0 : _p.plane) == null ? void 0 : _q.y) != null ? _r : 0;
6174
- uniforms.collisionBounce.value = (_t = (_s = newValues.collision) == null ? void 0 : _s.bounce) != null ? _t : 0.3;
6175
- uniforms.collisionFriction.value = (_v = (_u = newValues.collision) == null ? void 0 : _u.friction) != null ? _v : 0.8;
6176
- uniforms.collisionDie.value = ((_w = newValues.collision) == null ? void 0 : _w.die) ? 1 : 0;
6177
- uniforms.sizeBasedGravity.value = (_y = (_x = newValues.collision) == null ? void 0 : _x.sizeBasedGravity) != null ? _y : 0;
6178
- }
6179
- if (newValues.position) {
6180
- positionRef.current = newValues.position;
6181
- }
6182
- if ("delay" in newValues) delayRef.current = (_z = newValues.delay) != null ? _z : 0;
6183
- if ("emitCount" in newValues)
6184
- emitCountRef.current = (_A = newValues.emitCount) != null ? _A : 1;
6185
- if (newValues.autoStart !== void 0) {
6186
- setEmitting(newValues.autoStart);
6187
- }
6188
- if (material && newValues.blending !== void 0) {
6189
- material.blending = newValues.blending;
6190
- material.needsUpdate = true;
6191
- }
6192
- if (newValues.maxParticles !== void 0 && newValues.maxParticles !== activeMaxParticles) {
6193
- setActiveMaxParticles(newValues.maxParticles);
6194
- initialized.current = false;
6195
- nextIndex.current = 0;
6196
- }
6197
- if (newValues.lighting !== void 0 && newValues.lighting !== activeLighting) {
6198
- setActiveLighting(newValues.lighting);
6199
- }
6200
- if (newValues.appearance !== void 0 && newValues.appearance !== activeAppearance) {
6201
- setActiveAppearance(newValues.appearance);
6202
- }
6203
- if (newValues.orientToDirection !== void 0 && newValues.orientToDirection !== activeOrientToDirection) {
6204
- setActiveOrientToDirection(newValues.orientToDirection);
6205
- }
6206
- if (newValues.shadow !== void 0 && newValues.shadow !== activeShadow) {
6207
- setActiveShadow(newValues.shadow);
6208
- }
6209
- if ("geometryType" in newValues || "geometryArgs" in newValues) {
6210
- const geoType = (_B = newValues.geometryType) != null ? _B : prevGeometryTypeRef.current;
6211
- const geoArgs = (_C = newValues.geometryArgs) != null ? _C : prevGeometryArgsRef.current;
6212
- const geoTypeChanged = "geometryType" in newValues && geoType !== prevGeometryTypeRef.current;
6213
- const geoArgsChanged = "geometryArgs" in newValues && JSON.stringify(geoArgs) !== JSON.stringify(prevGeometryArgsRef.current);
6214
- if (geoTypeChanged || geoArgsChanged) {
6215
- prevGeometryTypeRef.current = geoType;
6216
- prevGeometryArgsRef.current = geoArgs;
6217
- Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(
6218
- ({ createGeometry: createGeometry2, GeometryType: GeometryType2 }) => {
6219
- if (geoType === GeometryType2.NONE || !geoType) {
6220
- if (activeGeometry !== null && !geometry) {
6221
- activeGeometry.dispose();
6222
- }
6223
- setActiveGeometry(null);
6224
- } else {
6225
- const newGeometry = createGeometry2(geoType, geoArgs);
6226
- if (newGeometry) {
6227
- if (activeGeometry !== null && activeGeometry !== geometry) {
6538
+ if ("colorStart" in newValues || "colorEnd" in newValues) {
6539
+ const startLen = (_q = (_p = (_m = newValues.colorStart) == null ? void 0 : _m.length) != null ? _p : (_o = (_n = debugValuesRef.current) == null ? void 0 : _n.colorStart) == null ? void 0 : _o.length) != null ? _q : 1;
6540
+ const hasColorEnd = "colorEnd" in newValues ? newValues.colorEnd !== null : ((_r = debugValuesRef.current) == null ? void 0 : _r.colorEnd) !== null;
6541
+ const needsPerParticle = startLen > 1 || hasColorEnd;
6542
+ if (needsPerParticle !== activeNeedsPerParticleColor) {
6543
+ setActiveNeedsPerParticleColor(needsPerParticle);
6544
+ }
6545
+ }
6546
+ if ("emitterShape" in newValues) {
6547
+ uniforms.emitterShapeType.value = (_s = newValues.emitterShape) != null ? _s : EmitterShape2.BOX;
6548
+ }
6549
+ if ("emitterRadius" in newValues) {
6550
+ const emitterRadiusR = toRange(newValues.emitterRadius, [0, 1]);
6551
+ uniforms.emitterRadiusInner.value = emitterRadiusR[0];
6552
+ uniforms.emitterRadiusOuter.value = emitterRadiusR[1];
6553
+ }
6554
+ if ("emitterAngle" in newValues) {
6555
+ uniforms.emitterAngle.value = (_t = newValues.emitterAngle) != null ? _t : Math.PI / 4;
6556
+ }
6557
+ if ("emitterHeight" in newValues) {
6558
+ const emitterHeightR = toRange(newValues.emitterHeight, [0, 1]);
6559
+ uniforms.emitterHeightMin.value = emitterHeightR[0];
6560
+ uniforms.emitterHeightMax.value = emitterHeightR[1];
6561
+ }
6562
+ if ("emitterSurfaceOnly" in newValues) {
6563
+ uniforms.emitterSurfaceOnly.value = newValues.emitterSurfaceOnly ? 1 : 0;
6564
+ }
6565
+ if ("emitterDirection" in newValues && newValues.emitterDirection && Array.isArray(newValues.emitterDirection)) {
6566
+ const dir = new THREE2.Vector3(
6567
+ ...newValues.emitterDirection
6568
+ ).normalize();
6569
+ uniforms.emitterDir.value.x = dir.x;
6570
+ uniforms.emitterDir.value.y = dir.y;
6571
+ uniforms.emitterDir.value.z = dir.z;
6572
+ }
6573
+ if ("turbulence" in newValues) {
6574
+ uniforms.turbulenceIntensity.value = (_v = (_u = newValues.turbulence) == null ? void 0 : _u.intensity) != null ? _v : 0;
6575
+ uniforms.turbulenceFrequency.value = (_x = (_w = newValues.turbulence) == null ? void 0 : _w.frequency) != null ? _x : 1;
6576
+ uniforms.turbulenceSpeed.value = (_z = (_y = newValues.turbulence) == null ? void 0 : _y.speed) != null ? _z : 1;
6577
+ turbulenceRef.current = newValues.turbulence;
6578
+ const needsTurbulence = newValues.turbulence !== null && ((_B = (_A = newValues.turbulence) == null ? void 0 : _A.intensity) != null ? _B : 0) > 0;
6579
+ if (needsTurbulence !== activeTurbulence) {
6580
+ setActiveTurbulence(needsTurbulence);
6581
+ }
6582
+ }
6583
+ if ("attractToCenter" in newValues) {
6584
+ uniforms.attractToCenter.value = newValues.attractToCenter ? 1 : 0;
6585
+ }
6586
+ if ("startPositionAsDirection" in newValues) {
6587
+ uniforms.startPositionAsDirection.value = newValues.startPositionAsDirection ? 1 : 0;
6588
+ }
6589
+ if ("softParticles" in newValues) {
6590
+ uniforms.softParticlesEnabled.value = newValues.softParticles ? 1 : 0;
6591
+ }
6592
+ if ("softDistance" in newValues) {
6593
+ uniforms.softDistance.value = (_C = newValues.softDistance) != null ? _C : 0.5;
6594
+ }
6595
+ if ("collision" in newValues) {
6596
+ uniforms.collisionEnabled.value = newValues.collision ? 1 : 0;
6597
+ uniforms.collisionPlaneY.value = (_F = (_E = (_D = newValues.collision) == null ? void 0 : _D.plane) == null ? void 0 : _E.y) != null ? _F : 0;
6598
+ uniforms.collisionBounce.value = (_H = (_G = newValues.collision) == null ? void 0 : _G.bounce) != null ? _H : 0.3;
6599
+ uniforms.collisionFriction.value = (_J = (_I = newValues.collision) == null ? void 0 : _I.friction) != null ? _J : 0.8;
6600
+ uniforms.collisionDie.value = ((_K = newValues.collision) == null ? void 0 : _K.die) ? 1 : 0;
6601
+ uniforms.sizeBasedGravity.value = (_M = (_L = newValues.collision) == null ? void 0 : _L.sizeBasedGravity) != null ? _M : 0;
6602
+ const needsCollision = newValues.collision !== null && newValues.collision !== void 0;
6603
+ if (needsCollision !== activeCollision) {
6604
+ setActiveCollision(needsCollision);
6605
+ }
6606
+ }
6607
+ if ("attractors" in newValues) {
6608
+ const needsAttractors = newValues.attractors !== null && ((_N = newValues.attractors) == null ? void 0 : _N.length) > 0;
6609
+ if (needsAttractors !== activeAttractors) {
6610
+ setActiveAttractors(needsAttractors);
6611
+ }
6612
+ }
6613
+ if (newValues.position) {
6614
+ positionRef.current = newValues.position;
6615
+ }
6616
+ if ("delay" in newValues) delayRef.current = (_O = newValues.delay) != null ? _O : 0;
6617
+ if ("emitCount" in newValues)
6618
+ emitCountRef.current = (_P = newValues.emitCount) != null ? _P : 1;
6619
+ if (newValues.autoStart !== void 0) {
6620
+ setEmitting(newValues.autoStart);
6621
+ }
6622
+ if (material && newValues.blending !== void 0) {
6623
+ material.blending = newValues.blending;
6624
+ material.needsUpdate = true;
6625
+ }
6626
+ if (newValues.maxParticles !== void 0 && newValues.maxParticles !== activeMaxParticles) {
6627
+ setActiveMaxParticles(newValues.maxParticles);
6628
+ initialized.current = false;
6629
+ nextIndex.current = 0;
6630
+ }
6631
+ if (newValues.lighting !== void 0 && newValues.lighting !== activeLighting) {
6632
+ setActiveLighting(newValues.lighting);
6633
+ }
6634
+ if (newValues.appearance !== void 0 && newValues.appearance !== activeAppearance) {
6635
+ setActiveAppearance(newValues.appearance);
6636
+ }
6637
+ if (newValues.orientToDirection !== void 0 && newValues.orientToDirection !== activeOrientToDirection) {
6638
+ setActiveOrientToDirection(newValues.orientToDirection);
6639
+ }
6640
+ if (newValues.shadow !== void 0 && newValues.shadow !== activeShadow) {
6641
+ setActiveShadow(newValues.shadow);
6642
+ }
6643
+ if ("geometryType" in newValues || "geometryArgs" in newValues) {
6644
+ const geoType = (_Q = newValues.geometryType) != null ? _Q : prevGeometryTypeRef.current;
6645
+ const geoArgs = (_R = newValues.geometryArgs) != null ? _R : prevGeometryArgsRef.current;
6646
+ const geoTypeChanged = "geometryType" in newValues && geoType !== prevGeometryTypeRef.current;
6647
+ const geoArgsChanged = "geometryArgs" in newValues && JSON.stringify(geoArgs) !== JSON.stringify(prevGeometryArgsRef.current);
6648
+ if (geoTypeChanged || geoArgsChanged) {
6649
+ prevGeometryTypeRef.current = geoType;
6650
+ prevGeometryArgsRef.current = geoArgs;
6651
+ Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(
6652
+ ({ createGeometry: createGeometry2, GeometryType: GeometryType2 }) => {
6653
+ if (geoType === GeometryType2.NONE || !geoType) {
6654
+ if (activeGeometry !== null && !geometry) {
6228
6655
  activeGeometry.dispose();
6229
6656
  }
6230
- setActiveGeometry(newGeometry);
6657
+ setActiveGeometry(null);
6658
+ } else {
6659
+ const newGeometry = createGeometry2(geoType, geoArgs);
6660
+ if (newGeometry) {
6661
+ if (activeGeometry !== null && activeGeometry !== geometry) {
6662
+ activeGeometry.dispose();
6663
+ }
6664
+ setActiveGeometry(newGeometry);
6665
+ }
6231
6666
  }
6232
6667
  }
6233
- }
6234
- );
6668
+ );
6669
+ }
6670
+ }
6671
+ },
6672
+ [
6673
+ uniforms,
6674
+ material,
6675
+ renderObject,
6676
+ activeMaxParticles,
6677
+ activeLighting,
6678
+ activeAppearance,
6679
+ activeOrientToDirection,
6680
+ activeShadow,
6681
+ activeGeometry,
6682
+ activeNeedsPerParticleColor,
6683
+ activeNeedsRotation,
6684
+ activeTurbulence,
6685
+ activeAttractors,
6686
+ activeCollision,
6687
+ geometry
6688
+ ]
6689
+ );
6690
+ useEffect3(() => {
6691
+ if (!debug) return;
6692
+ const initialValues = __spreadValues({
6693
+ name,
6694
+ // Include name for curve baking filename
6695
+ maxParticles,
6696
+ size,
6697
+ colorStart,
6698
+ colorEnd,
6699
+ fadeSize,
6700
+ fadeSizeCurve: fadeSizeCurve || null,
6701
+ // null = linear (no curve)
6702
+ fadeOpacity,
6703
+ fadeOpacityCurve: fadeOpacityCurve || null,
6704
+ // null = linear (no curve)
6705
+ velocityCurve: velocityCurve || null,
6706
+ // null = use friction (no curve)
6707
+ gravity,
6708
+ lifetime,
6709
+ direction,
6710
+ startPosition,
6711
+ startPositionAsDirection,
6712
+ speed,
6713
+ friction,
6714
+ appearance,
6715
+ rotation,
6716
+ rotationSpeed,
6717
+ rotationSpeedCurve: rotationSpeedCurve || null,
6718
+ // null = constant speed (no curve)
6719
+ orientToDirection,
6720
+ orientAxis,
6721
+ stretchBySpeed: stretchBySpeed || null,
6722
+ lighting,
6723
+ shadow,
6724
+ blending,
6725
+ intensity,
6726
+ position,
6727
+ autoStart,
6728
+ delay,
6729
+ emitCount,
6730
+ emitterShape,
6731
+ emitterRadius,
6732
+ emitterAngle,
6733
+ emitterHeight,
6734
+ emitterSurfaceOnly,
6735
+ emitterDirection,
6736
+ turbulence,
6737
+ attractToCenter,
6738
+ softParticles,
6739
+ softDistance,
6740
+ collision
6741
+ }, detectGeometryTypeAndArgs(geometry));
6742
+ function detectGeometryTypeAndArgs(geo) {
6743
+ var _a2, _b, _c, _d, _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, _J, _K, _L, _M, _N, _O, _P, _Q;
6744
+ if (!geo) return { geometryType: "none", geometryArgs: null };
6745
+ const name2 = geo.constructor.name;
6746
+ const params = geo.parameters || {};
6747
+ switch (name2) {
6748
+ case "BoxGeometry":
6749
+ return {
6750
+ geometryType: "box",
6751
+ geometryArgs: {
6752
+ width: (_a2 = params.width) != null ? _a2 : 1,
6753
+ height: (_b = params.height) != null ? _b : 1,
6754
+ depth: (_c = params.depth) != null ? _c : 1,
6755
+ widthSegments: (_d = params.widthSegments) != null ? _d : 1,
6756
+ heightSegments: (_e = params.heightSegments) != null ? _e : 1,
6757
+ depthSegments: (_f = params.depthSegments) != null ? _f : 1
6758
+ }
6759
+ };
6760
+ case "SphereGeometry":
6761
+ return {
6762
+ geometryType: "sphere",
6763
+ geometryArgs: {
6764
+ radius: (_g = params.radius) != null ? _g : 0.5,
6765
+ widthSegments: (_h = params.widthSegments) != null ? _h : 16,
6766
+ heightSegments: (_i = params.heightSegments) != null ? _i : 12
6767
+ }
6768
+ };
6769
+ case "CylinderGeometry":
6770
+ return {
6771
+ geometryType: "cylinder",
6772
+ geometryArgs: {
6773
+ radiusTop: (_j = params.radiusTop) != null ? _j : 0.5,
6774
+ radiusBottom: (_k = params.radiusBottom) != null ? _k : 0.5,
6775
+ height: (_l = params.height) != null ? _l : 1,
6776
+ radialSegments: (_m = params.radialSegments) != null ? _m : 16,
6777
+ heightSegments: (_n = params.heightSegments) != null ? _n : 1
6778
+ }
6779
+ };
6780
+ case "ConeGeometry":
6781
+ return {
6782
+ geometryType: "cone",
6783
+ geometryArgs: {
6784
+ radius: (_o = params.radius) != null ? _o : 0.5,
6785
+ height: (_p = params.height) != null ? _p : 1,
6786
+ radialSegments: (_q = params.radialSegments) != null ? _q : 16,
6787
+ heightSegments: (_r = params.heightSegments) != null ? _r : 1
6788
+ }
6789
+ };
6790
+ case "TorusGeometry":
6791
+ return {
6792
+ geometryType: "torus",
6793
+ geometryArgs: {
6794
+ radius: (_s = params.radius) != null ? _s : 0.5,
6795
+ tube: (_t = params.tube) != null ? _t : 0.2,
6796
+ radialSegments: (_u = params.radialSegments) != null ? _u : 12,
6797
+ tubularSegments: (_v = params.tubularSegments) != null ? _v : 24
6798
+ }
6799
+ };
6800
+ case "PlaneGeometry":
6801
+ return {
6802
+ geometryType: "plane",
6803
+ geometryArgs: {
6804
+ width: (_w = params.width) != null ? _w : 1,
6805
+ height: (_x = params.height) != null ? _x : 1,
6806
+ widthSegments: (_y = params.widthSegments) != null ? _y : 1,
6807
+ heightSegments: (_z = params.heightSegments) != null ? _z : 1
6808
+ }
6809
+ };
6810
+ case "CircleGeometry":
6811
+ return {
6812
+ geometryType: "circle",
6813
+ geometryArgs: {
6814
+ radius: (_A = params.radius) != null ? _A : 0.5,
6815
+ segments: (_B = params.segments) != null ? _B : 16
6816
+ }
6817
+ };
6818
+ case "RingGeometry":
6819
+ return {
6820
+ geometryType: "ring",
6821
+ geometryArgs: {
6822
+ innerRadius: (_C = params.innerRadius) != null ? _C : 0.25,
6823
+ outerRadius: (_D = params.outerRadius) != null ? _D : 0.5,
6824
+ thetaSegments: (_E = params.thetaSegments) != null ? _E : 16
6825
+ }
6826
+ };
6827
+ case "DodecahedronGeometry":
6828
+ return {
6829
+ geometryType: "dodecahedron",
6830
+ geometryArgs: {
6831
+ radius: (_F = params.radius) != null ? _F : 0.5,
6832
+ detail: (_G = params.detail) != null ? _G : 0
6833
+ }
6834
+ };
6835
+ case "IcosahedronGeometry":
6836
+ return {
6837
+ geometryType: "icosahedron",
6838
+ geometryArgs: {
6839
+ radius: (_H = params.radius) != null ? _H : 0.5,
6840
+ detail: (_I = params.detail) != null ? _I : 0
6841
+ }
6842
+ };
6843
+ case "OctahedronGeometry":
6844
+ return {
6845
+ geometryType: "octahedron",
6846
+ geometryArgs: {
6847
+ radius: (_J = params.radius) != null ? _J : 0.5,
6848
+ detail: (_K = params.detail) != null ? _K : 0
6849
+ }
6850
+ };
6851
+ case "TetrahedronGeometry":
6852
+ return {
6853
+ geometryType: "tetrahedron",
6854
+ geometryArgs: {
6855
+ radius: (_L = params.radius) != null ? _L : 0.5,
6856
+ detail: (_M = params.detail) != null ? _M : 0
6857
+ }
6858
+ };
6859
+ case "CapsuleGeometry":
6860
+ return {
6861
+ geometryType: "capsule",
6862
+ geometryArgs: {
6863
+ radius: (_N = params.radius) != null ? _N : 0.25,
6864
+ length: (_O = params.length) != null ? _O : 0.5,
6865
+ capSegments: (_P = params.capSegments) != null ? _P : 4,
6866
+ radialSegments: (_Q = params.radialSegments) != null ? _Q : 8
6867
+ }
6868
+ };
6869
+ default:
6870
+ return { geometryType: "none", geometryArgs: null };
6235
6871
  }
6236
6872
  }
6237
- },
6238
- [
6239
- uniforms,
6240
- material,
6241
- renderObject,
6242
- activeMaxParticles,
6243
- activeLighting,
6244
- activeAppearance,
6245
- activeOrientToDirection,
6246
- activeShadow,
6247
- activeGeometry,
6248
- geometry
6249
- ]
6250
- );
6251
- useEffect2(() => {
6252
- if (!debug) return;
6253
- const initialValues = __spreadValues({
6254
- maxParticles,
6255
- size,
6256
- colorStart,
6257
- colorEnd,
6258
- fadeSize,
6259
- fadeSizeCurve: fadeSizeCurve || null,
6260
- // null = linear (no curve)
6261
- fadeOpacity,
6262
- fadeOpacityCurve: fadeOpacityCurve || null,
6263
- // null = linear (no curve)
6264
- velocityCurve: velocityCurve || null,
6265
- // null = use friction (no curve)
6266
- gravity,
6267
- lifetime,
6268
- direction,
6269
- startPosition,
6270
- startPositionAsDirection,
6271
- speed,
6272
- friction,
6273
- appearance,
6274
- rotation,
6275
- rotationSpeed,
6276
- rotationSpeedCurve: rotationSpeedCurve || null,
6277
- // null = constant speed (no curve)
6278
- orientToDirection,
6279
- orientAxis,
6280
- stretchBySpeed: stretchBySpeed || null,
6281
- lighting,
6282
- shadow,
6283
- blending,
6284
- intensity,
6285
- position,
6286
- autoStart,
6287
- delay,
6288
- emitCount,
6289
- emitterShape,
6290
- emitterRadius,
6291
- emitterAngle,
6292
- emitterHeight,
6293
- emitterSurfaceOnly,
6294
- emitterDirection,
6295
- turbulence,
6296
- attractToCenter,
6297
- softParticles,
6298
- softDistance,
6299
- collision
6300
- }, detectGeometryTypeAndArgs(geometry));
6301
- function detectGeometryTypeAndArgs(geo) {
6302
- var _a, _b, _c, _d, _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, _J, _K, _L, _M, _N, _O, _P, _Q;
6303
- if (!geo) return { geometryType: "none", geometryArgs: null };
6304
- const name2 = geo.constructor.name;
6305
- const params = geo.parameters || {};
6306
- switch (name2) {
6307
- case "BoxGeometry":
6308
- return {
6309
- geometryType: "box",
6310
- geometryArgs: {
6311
- width: (_a = params.width) != null ? _a : 1,
6312
- height: (_b = params.height) != null ? _b : 1,
6313
- depth: (_c = params.depth) != null ? _c : 1,
6314
- widthSegments: (_d = params.widthSegments) != null ? _d : 1,
6315
- heightSegments: (_e = params.heightSegments) != null ? _e : 1,
6316
- depthSegments: (_f = params.depthSegments) != null ? _f : 1
6317
- }
6318
- };
6319
- case "SphereGeometry":
6320
- return {
6321
- geometryType: "sphere",
6322
- geometryArgs: {
6323
- radius: (_g = params.radius) != null ? _g : 0.5,
6324
- widthSegments: (_h = params.widthSegments) != null ? _h : 16,
6325
- heightSegments: (_i = params.heightSegments) != null ? _i : 12
6326
- }
6327
- };
6328
- case "CylinderGeometry":
6329
- return {
6330
- geometryType: "cylinder",
6331
- geometryArgs: {
6332
- radiusTop: (_j = params.radiusTop) != null ? _j : 0.5,
6333
- radiusBottom: (_k = params.radiusBottom) != null ? _k : 0.5,
6334
- height: (_l = params.height) != null ? _l : 1,
6335
- radialSegments: (_m = params.radialSegments) != null ? _m : 16,
6336
- heightSegments: (_n = params.heightSegments) != null ? _n : 1
6337
- }
6338
- };
6339
- case "ConeGeometry":
6340
- return {
6341
- geometryType: "cone",
6342
- geometryArgs: {
6343
- radius: (_o = params.radius) != null ? _o : 0.5,
6344
- height: (_p = params.height) != null ? _p : 1,
6345
- radialSegments: (_q = params.radialSegments) != null ? _q : 16,
6346
- heightSegments: (_r = params.heightSegments) != null ? _r : 1
6347
- }
6348
- };
6349
- case "TorusGeometry":
6350
- return {
6351
- geometryType: "torus",
6352
- geometryArgs: {
6353
- radius: (_s = params.radius) != null ? _s : 0.5,
6354
- tube: (_t = params.tube) != null ? _t : 0.2,
6355
- radialSegments: (_u = params.radialSegments) != null ? _u : 12,
6356
- tubularSegments: (_v = params.tubularSegments) != null ? _v : 24
6357
- }
6358
- };
6359
- case "PlaneGeometry":
6360
- return {
6361
- geometryType: "plane",
6362
- geometryArgs: {
6363
- width: (_w = params.width) != null ? _w : 1,
6364
- height: (_x = params.height) != null ? _x : 1,
6365
- widthSegments: (_y = params.widthSegments) != null ? _y : 1,
6366
- heightSegments: (_z = params.heightSegments) != null ? _z : 1
6367
- }
6368
- };
6369
- case "CircleGeometry":
6370
- return {
6371
- geometryType: "circle",
6372
- geometryArgs: {
6373
- radius: (_A = params.radius) != null ? _A : 0.5,
6374
- segments: (_B = params.segments) != null ? _B : 16
6375
- }
6376
- };
6377
- case "RingGeometry":
6378
- return {
6379
- geometryType: "ring",
6380
- geometryArgs: {
6381
- innerRadius: (_C = params.innerRadius) != null ? _C : 0.25,
6382
- outerRadius: (_D = params.outerRadius) != null ? _D : 0.5,
6383
- thetaSegments: (_E = params.thetaSegments) != null ? _E : 16
6384
- }
6385
- };
6386
- case "DodecahedronGeometry":
6387
- return {
6388
- geometryType: "dodecahedron",
6389
- geometryArgs: {
6390
- radius: (_F = params.radius) != null ? _F : 0.5,
6391
- detail: (_G = params.detail) != null ? _G : 0
6392
- }
6393
- };
6394
- case "IcosahedronGeometry":
6395
- return {
6396
- geometryType: "icosahedron",
6397
- geometryArgs: {
6398
- radius: (_H = params.radius) != null ? _H : 0.5,
6399
- detail: (_I = params.detail) != null ? _I : 0
6400
- }
6401
- };
6402
- case "OctahedronGeometry":
6403
- return {
6404
- geometryType: "octahedron",
6405
- geometryArgs: {
6406
- radius: (_J = params.radius) != null ? _J : 0.5,
6407
- detail: (_K = params.detail) != null ? _K : 0
6408
- }
6409
- };
6410
- case "TetrahedronGeometry":
6411
- return {
6412
- geometryType: "tetrahedron",
6413
- geometryArgs: {
6414
- radius: (_L = params.radius) != null ? _L : 0.5,
6415
- detail: (_M = params.detail) != null ? _M : 0
6416
- }
6417
- };
6418
- case "CapsuleGeometry":
6419
- return {
6420
- geometryType: "capsule",
6421
- geometryArgs: {
6422
- radius: (_N = params.radius) != null ? _N : 0.25,
6423
- length: (_O = params.length) != null ? _O : 0.5,
6424
- capSegments: (_P = params.capSegments) != null ? _P : 4,
6425
- radialSegments: (_Q = params.radialSegments) != null ? _Q : 8
6426
- }
6427
- };
6428
- default:
6429
- return { geometryType: "none", geometryArgs: null };
6430
- }
6431
- }
6432
- debugValuesRef.current = initialValues;
6433
- prevGeometryTypeRef.current = initialValues.geometryType;
6434
- prevGeometryArgsRef.current = initialValues.geometryArgs;
6435
- Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ renderDebugPanel: renderDebugPanel2 }) => {
6436
- renderDebugPanel2(initialValues, handleDebugUpdate);
6437
- });
6438
- return () => {
6439
- Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ destroyDebugPanel: destroyDebugPanel2 }) => {
6440
- destroyDebugPanel2();
6873
+ debugValuesRef.current = initialValues;
6874
+ prevGeometryTypeRef.current = initialValues.geometryType;
6875
+ prevGeometryArgsRef.current = initialValues.geometryArgs;
6876
+ Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ renderDebugPanel: renderDebugPanel2 }) => {
6877
+ renderDebugPanel2(initialValues, handleDebugUpdate);
6441
6878
  });
6442
- };
6443
- }, [debug, geometry]);
6444
- useEffect2(() => {
6445
- if (!debug) return;
6446
- Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ updateDebugPanel: updateDebugPanel2 }) => {
6447
- if (debugValuesRef.current) {
6448
- updateDebugPanel2(__spreadValues({}, debugValuesRef.current), handleDebugUpdate);
6449
- }
6450
- });
6451
- }, [debug, handleDebugUpdate]);
6452
- return /* @__PURE__ */ jsx2("primitive", { ref: spriteRef, object: renderObject });
6453
- });
6879
+ return () => {
6880
+ Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ destroyDebugPanel: destroyDebugPanel2 }) => {
6881
+ destroyDebugPanel2();
6882
+ });
6883
+ };
6884
+ }, [debug, geometry]);
6885
+ useEffect3(() => {
6886
+ if (!debug) return;
6887
+ Promise.resolve().then(() => (init_VFXParticlesDebugPanel(), VFXParticlesDebugPanel_exports)).then(({ updateDebugPanel: updateDebugPanel2 }) => {
6888
+ if (debugValuesRef.current) {
6889
+ updateDebugPanel2(__spreadValues({}, debugValuesRef.current), handleDebugUpdate);
6890
+ }
6891
+ });
6892
+ }, [debug, handleDebugUpdate]);
6893
+ return /* @__PURE__ */ jsx2("primitive", { ref: spriteRef, object: renderObject });
6894
+ }
6895
+ );
6454
6896
  }
6455
6897
  });
6456
6898
 
@@ -6460,8 +6902,8 @@ init_VFXParticles();
6460
6902
  // src/VFXEmitter.tsx
6461
6903
  init_react_store();
6462
6904
  import {
6463
- useRef as useRef3,
6464
- useEffect as useEffect3,
6905
+ useRef as useRef4,
6906
+ useEffect as useEffect4,
6465
6907
  useCallback as useCallback3,
6466
6908
  forwardRef as forwardRef2,
6467
6909
  useImperativeHandle as useImperativeHandle2
@@ -6486,10 +6928,10 @@ var VFXEmitter = forwardRef2(function VFXEmitter2({
6486
6928
  onEmit,
6487
6929
  children
6488
6930
  }, ref) {
6489
- const groupRef = useRef3(null);
6490
- const emitAccumulator = useRef3(0);
6491
- const emitting = useRef3(autoStart);
6492
- const hasEmittedOnce = useRef3(false);
6931
+ const groupRef = useRef4(null);
6932
+ const emitAccumulator = useRef4(0);
6933
+ const emitting = useRef4(autoStart);
6934
+ const hasEmittedOnce = useRef4(false);
6493
6935
  const getParticleSystem = useCallback3(() => {
6494
6936
  if (particlesRef) {
6495
6937
  return particlesRef.current || particlesRef;
@@ -6504,11 +6946,7 @@ var VFXEmitter = forwardRef2(function VFXEmitter2({
6504
6946
  dirRange[2][0]
6505
6947
  );
6506
6948
  minDir.applyQuaternion(quat);
6507
- const maxDir = new Vector32(
6508
- dirRange[0][1],
6509
- dirRange[1][1],
6510
- dirRange[2][1]
6511
- );
6949
+ const maxDir = new Vector32(dirRange[0][1], dirRange[1][1], dirRange[2][1]);
6512
6950
  maxDir.applyQuaternion(quat);
6513
6951
  return [
6514
6952
  [Math.min(minDir.x, maxDir.x), Math.max(minDir.x, maxDir.x)],
@@ -6531,23 +6969,47 @@ var VFXEmitter = forwardRef2(function VFXEmitter2({
6531
6969
  }
6532
6970
  return { position: emitPos, direction: emitDir };
6533
6971
  }, [localDirection, direction, position, transformDirectionByQuat]);
6534
- const emit = useCallback3(() => {
6535
- const particles = getParticleSystem();
6536
- if (!(particles == null ? void 0 : particles.spawn)) {
6537
- if (name) {
6538
- console.warn(`VFXEmitter: No particle system found for name "${name}"`);
6972
+ const emit = useCallback3(
6973
+ (emitOverrides = null) => {
6974
+ const particles = getParticleSystem();
6975
+ if (!(particles == null ? void 0 : particles.spawn)) {
6976
+ if (name) {
6977
+ console.warn(
6978
+ `VFXEmitter: No particle system found for name "${name}"`
6979
+ );
6980
+ }
6981
+ return false;
6539
6982
  }
6540
- return false;
6541
- }
6542
- const { position: emitPos, direction: emitDir } = getEmitParams();
6543
- const [x, y, z] = emitPos;
6544
- const finalOverrides = emitDir ? __spreadProps(__spreadValues({}, overrides), { direction: emitDir }) : overrides;
6545
- particles.spawn(x, y, z, emitCount, finalOverrides);
6546
- if (onEmit) {
6547
- onEmit({ position: emitPos, count: emitCount, direction: emitDir });
6548
- }
6549
- return true;
6550
- }, [getParticleSystem, getEmitParams, name, emitCount, overrides, onEmit]);
6983
+ const { position: emitPos, direction: emitDir } = getEmitParams();
6984
+ const [x, y, z] = emitPos;
6985
+ const emitTimeDirection = emitOverrides == null ? void 0 : emitOverrides.direction;
6986
+ let finalDir = emitDir;
6987
+ if (emitTimeDirection && localDirection && groupRef.current) {
6988
+ groupRef.current.getWorldQuaternion(_worldQuat);
6989
+ finalDir = transformDirectionByQuat(emitTimeDirection, _worldQuat);
6990
+ } else if (emitTimeDirection) {
6991
+ finalDir = emitTimeDirection;
6992
+ }
6993
+ const _a = emitOverrides || {}, { direction: _ } = _a, emitOverridesWithoutDir = __objRest(_a, ["direction"]);
6994
+ const mergedOverrides = __spreadValues(__spreadValues({}, overrides), emitOverridesWithoutDir);
6995
+ const finalOverrides = finalDir ? __spreadProps(__spreadValues({}, mergedOverrides), { direction: finalDir }) : mergedOverrides;
6996
+ particles.spawn(x, y, z, emitCount, finalOverrides);
6997
+ if (onEmit) {
6998
+ onEmit({ position: emitPos, count: emitCount, direction: finalDir });
6999
+ }
7000
+ return true;
7001
+ },
7002
+ [
7003
+ getParticleSystem,
7004
+ getEmitParams,
7005
+ name,
7006
+ emitCount,
7007
+ overrides,
7008
+ onEmit,
7009
+ localDirection,
7010
+ transformDirectionByQuat
7011
+ ]
7012
+ );
6551
7013
  useFrame2((_, delta) => {
6552
7014
  if (!emitting.current) return;
6553
7015
  if (!loop && hasEmittedOnce.current) {
@@ -6592,7 +7054,7 @@ var VFXEmitter = forwardRef2(function VFXEmitter2({
6592
7054
  },
6593
7055
  [getParticleSystem, getEmitParams, emitCount, overrides, onEmit]
6594
7056
  );
6595
- useEffect3(() => {
7057
+ useEffect4(() => {
6596
7058
  emitting.current = autoStart;
6597
7059
  if (autoStart) {
6598
7060
  hasEmittedOnce.current = false;
@@ -6675,6 +7137,7 @@ function useVFXEmitter(name) {
6675
7137
 
6676
7138
  // src/index.ts
6677
7139
  init_react_store();
7140
+ init_useCurveTextureAsync();
6678
7141
  export {
6679
7142
  Appearance,
6680
7143
  AttractorType2 as AttractorType,
@@ -6686,6 +7149,7 @@ export {
6686
7149
  VFXParticles,
6687
7150
  bakeCurveToArray,
6688
7151
  createCombinedCurveTexture2 as createCombinedCurveTexture,
7152
+ useCurveTextureAsync,
6689
7153
  useVFXEmitter,
6690
7154
  useVFXStore
6691
7155
  };