r3f-vfx 0.1.3 → 0.1.4
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.d.ts +18 -8
- package/dist/index.js +150 -218
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { RefObject, ReactNode } from 'react';
|
|
3
3
|
import * as THREE from 'three/webgpu';
|
|
4
4
|
import { CurveData, Rotation3DInput, Appearance, Lighting, ParticleData, EmitterShape, CoreState } from 'core-vfx';
|
|
5
|
-
export { Appearance, AttractorConfig, AttractorType, BaseParticleProps, Blending, CollisionConfig, CurveData, CurvePoint, Easing, EmitterShape, FlipbookConfig, FrictionConfig, Lighting, ParticleData, Rotation3DInput, StretchConfig, TurbulenceConfig, bakeCurveToArray, createCombinedCurveTexture } from 'core-vfx';
|
|
5
|
+
export { Appearance, AttractorConfig, AttractorType, BaseParticleProps, Blending, CollisionConfig, CurveChannel, CurveData, CurvePoint, CurveTextureResult, Easing, EmitterShape, FlipbookConfig, FrictionConfig, Lighting, ParticleData, Rotation3DInput, StretchConfig, TurbulenceConfig, bakeCurveToArray, buildCurveTextureBin, createCombinedCurveTexture } from 'core-vfx';
|
|
6
6
|
|
|
7
7
|
type VFXParticlesProps = {
|
|
8
8
|
/** Optional name for registering with useVFXStore (enables VFXEmitter linking) */
|
|
@@ -264,14 +264,24 @@ declare const useVFXStore: typeof useVFXStoreImpl & {
|
|
|
264
264
|
getInitialState: () => CoreState;
|
|
265
265
|
};
|
|
266
266
|
|
|
267
|
+
type CurveTextureHookResult = {
|
|
268
|
+
texture: THREE.DataTexture;
|
|
269
|
+
/** Per-channel enabled state, combining curve props and loaded .bin channels */
|
|
270
|
+
sizeEnabled: boolean;
|
|
271
|
+
opacityEnabled: boolean;
|
|
272
|
+
velocityEnabled: boolean;
|
|
273
|
+
rotationSpeedEnabled: boolean;
|
|
274
|
+
};
|
|
267
275
|
/**
|
|
268
|
-
* Hook for curve texture loading/baking
|
|
269
|
-
*
|
|
276
|
+
* Hook for curve texture loading/baking.
|
|
277
|
+
*
|
|
278
|
+
* If curveTexturePath is provided, loads pre-baked texture from file.
|
|
279
|
+
* The .bin file contains a header with a bitmask of which channels are active.
|
|
280
|
+
* Only those channels override the curve props; the rest use curve props or defaults.
|
|
270
281
|
*
|
|
271
|
-
* If
|
|
272
|
-
* If curves
|
|
273
|
-
* If no curves AND no path, returns default texture (no baking needed)
|
|
282
|
+
* If curves are defined (no path), bakes them synchronously on the main thread.
|
|
283
|
+
* If no curves AND no path, returns default texture (no baking needed).
|
|
274
284
|
*/
|
|
275
|
-
declare const useCurveTextureAsync: (sizeCurve: CurveData | null, opacityCurve: CurveData | null, velocityCurve: CurveData | null, rotationSpeedCurve: CurveData | null, curveTexturePath?: string | null) =>
|
|
285
|
+
declare const useCurveTextureAsync: (sizeCurve: CurveData | null, opacityCurve: CurveData | null, velocityCurve: CurveData | null, rotationSpeedCurve: CurveData | null, curveTexturePath?: string | null) => CurveTextureHookResult;
|
|
276
286
|
|
|
277
|
-
export { VFXEmitter, VFXParticles, useCurveTextureAsync, useVFXEmitter, useVFXStore };
|
|
287
|
+
export { type CurveTextureHookResult, VFXEmitter, VFXParticles, useCurveTextureAsync, useVFXEmitter, useVFXStore };
|
package/dist/index.js
CHANGED
|
@@ -58,11 +58,12 @@ var init_react_store = __esm({
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
// src/useCurveTextureAsync.ts
|
|
61
|
-
import { useRef, useEffect, useMemo } from "react";
|
|
61
|
+
import { useRef, useEffect, useMemo, useState } from "react";
|
|
62
62
|
import {
|
|
63
63
|
createDefaultCurveTexture,
|
|
64
64
|
createCombinedCurveTexture,
|
|
65
|
-
loadCurveTextureFromPath
|
|
65
|
+
loadCurveTextureFromPath,
|
|
66
|
+
CurveChannel
|
|
66
67
|
} from "core-vfx";
|
|
67
68
|
var useCurveTextureAsync;
|
|
68
69
|
var init_useCurveTextureAsync = __esm({
|
|
@@ -70,61 +71,67 @@ var init_useCurveTextureAsync = __esm({
|
|
|
70
71
|
"use strict";
|
|
71
72
|
useCurveTextureAsync = (sizeCurve, opacityCurve, velocityCurve, rotationSpeedCurve, curveTexturePath = null) => {
|
|
72
73
|
const hasAnyCurve = sizeCurve || opacityCurve || velocityCurve || rotationSpeedCurve;
|
|
73
|
-
const
|
|
74
|
-
if (!textureRef.current) {
|
|
74
|
+
const texture = useMemo(() => {
|
|
75
75
|
if (!curveTexturePath && hasAnyCurve) {
|
|
76
|
-
|
|
76
|
+
return createCombinedCurveTexture(
|
|
77
77
|
sizeCurve,
|
|
78
78
|
opacityCurve,
|
|
79
79
|
velocityCurve,
|
|
80
80
|
rotationSpeedCurve
|
|
81
81
|
);
|
|
82
|
-
} else {
|
|
83
|
-
textureRef.current = createDefaultCurveTexture();
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
useMemo(() => {
|
|
87
|
-
if (!curveTexturePath && hasAnyCurve && textureRef.current) {
|
|
88
|
-
const bakedTexture = createCombinedCurveTexture(
|
|
89
|
-
sizeCurve,
|
|
90
|
-
opacityCurve,
|
|
91
|
-
velocityCurve,
|
|
92
|
-
rotationSpeedCurve
|
|
93
|
-
);
|
|
94
|
-
const srcData = bakedTexture.image.data;
|
|
95
|
-
const dstData = textureRef.current.image.data;
|
|
96
|
-
if (srcData && dstData) {
|
|
97
|
-
dstData.set(srcData);
|
|
98
|
-
textureRef.current.needsUpdate = true;
|
|
99
|
-
}
|
|
100
|
-
bakedTexture.dispose();
|
|
101
82
|
}
|
|
102
|
-
|
|
83
|
+
return createDefaultCurveTexture();
|
|
84
|
+
}, [
|
|
85
|
+
sizeCurve,
|
|
86
|
+
opacityCurve,
|
|
87
|
+
velocityCurve,
|
|
88
|
+
rotationSpeedCurve,
|
|
89
|
+
curveTexturePath,
|
|
90
|
+
hasAnyCurve
|
|
91
|
+
]);
|
|
92
|
+
const [loadedTexture, setLoadedTexture] = useState(
|
|
93
|
+
null
|
|
94
|
+
);
|
|
95
|
+
const [loadedChannels, setLoadedChannels] = useState(0);
|
|
103
96
|
useEffect(() => {
|
|
104
|
-
if (!curveTexturePath
|
|
105
|
-
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
if (!curveTexturePath) {
|
|
98
|
+
setLoadedTexture(null);
|
|
99
|
+
setLoadedChannels(0);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let cancelled = false;
|
|
103
|
+
loadCurveTextureFromPath(curveTexturePath).then((result) => {
|
|
104
|
+
if (!cancelled) {
|
|
105
|
+
setLoadedTexture(result.texture);
|
|
106
|
+
setLoadedChannels(result.activeChannels);
|
|
107
|
+
} else {
|
|
108
|
+
result.texture.dispose();
|
|
109
|
+
}
|
|
110
|
+
}).catch((err) => {
|
|
111
|
+
console.warn(
|
|
112
|
+
`Failed to load curve texture: ${curveTexturePath}, falling back to baking`,
|
|
113
|
+
err
|
|
114
|
+
);
|
|
115
|
+
if (!cancelled && hasAnyCurve) {
|
|
116
|
+
setLoadedTexture(
|
|
117
|
+
createCombinedCurveTexture(
|
|
113
118
|
sizeCurve,
|
|
114
119
|
opacityCurve,
|
|
115
120
|
velocityCurve,
|
|
116
121
|
rotationSpeedCurve
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
let mask = 0;
|
|
125
|
+
if (sizeCurve) mask |= CurveChannel.SIZE;
|
|
126
|
+
if (opacityCurve) mask |= CurveChannel.OPACITY;
|
|
127
|
+
if (velocityCurve) mask |= CurveChannel.VELOCITY;
|
|
128
|
+
if (rotationSpeedCurve) mask |= CurveChannel.ROTATION_SPEED;
|
|
129
|
+
setLoadedChannels(mask);
|
|
126
130
|
}
|
|
127
|
-
);
|
|
131
|
+
});
|
|
132
|
+
return () => {
|
|
133
|
+
cancelled = true;
|
|
134
|
+
};
|
|
128
135
|
}, [
|
|
129
136
|
curveTexturePath,
|
|
130
137
|
sizeCurve,
|
|
@@ -133,14 +140,33 @@ var init_useCurveTextureAsync = __esm({
|
|
|
133
140
|
rotationSpeedCurve,
|
|
134
141
|
hasAnyCurve
|
|
135
142
|
]);
|
|
143
|
+
const activeTexture = loadedTexture != null ? loadedTexture : texture;
|
|
144
|
+
const sizeEnabled = loadedTexture ? !!(loadedChannels & CurveChannel.SIZE) : !!sizeCurve;
|
|
145
|
+
const opacityEnabled = loadedTexture ? !!(loadedChannels & CurveChannel.OPACITY) : !!opacityCurve;
|
|
146
|
+
const velocityEnabled = loadedTexture ? !!(loadedChannels & CurveChannel.VELOCITY) : !!velocityCurve;
|
|
147
|
+
const rotationSpeedEnabled = loadedTexture ? !!(loadedChannels & CurveChannel.ROTATION_SPEED) : !!rotationSpeedCurve;
|
|
148
|
+
const prevTextureRef = useRef(null);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const prev = prevTextureRef.current;
|
|
151
|
+
if (prev && prev !== activeTexture) {
|
|
152
|
+
prev.dispose();
|
|
153
|
+
}
|
|
154
|
+
prevTextureRef.current = activeTexture;
|
|
155
|
+
}, [activeTexture]);
|
|
136
156
|
useEffect(() => {
|
|
137
157
|
return () => {
|
|
138
158
|
var _a;
|
|
139
|
-
(_a =
|
|
140
|
-
|
|
159
|
+
(_a = prevTextureRef.current) == null ? void 0 : _a.dispose();
|
|
160
|
+
prevTextureRef.current = null;
|
|
141
161
|
};
|
|
142
162
|
}, []);
|
|
143
|
-
return
|
|
163
|
+
return {
|
|
164
|
+
texture: activeTexture,
|
|
165
|
+
sizeEnabled,
|
|
166
|
+
opacityEnabled,
|
|
167
|
+
velocityEnabled,
|
|
168
|
+
rotationSpeedEnabled
|
|
169
|
+
};
|
|
144
170
|
};
|
|
145
171
|
}
|
|
146
172
|
});
|
|
@@ -157,7 +183,8 @@ __export(VFXParticlesDebugPanel_exports, {
|
|
|
157
183
|
updateDebugPanel: () => updateDebugPanel
|
|
158
184
|
});
|
|
159
185
|
import { createRoot } from "react-dom/client";
|
|
160
|
-
import { useState, useCallback, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
186
|
+
import { useState as useState2, useCallback, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
187
|
+
import { buildCurveTextureBin } from "core-vfx";
|
|
161
188
|
import * as THREE from "three";
|
|
162
189
|
import { create } from "zustand";
|
|
163
190
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1221,10 +1248,10 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1221
1248
|
onToggleEnabled,
|
|
1222
1249
|
hidden = false
|
|
1223
1250
|
}) => {
|
|
1224
|
-
const [isOpen, setIsOpen] =
|
|
1225
|
-
const [isHovered, setIsHovered] =
|
|
1251
|
+
const [isOpen, setIsOpen] = useState2(defaultOpen);
|
|
1252
|
+
const [isHovered, setIsHovered] = useState2(false);
|
|
1226
1253
|
const contentRef = useRef2(null);
|
|
1227
|
-
const [contentHeight, setContentHeight] =
|
|
1254
|
+
const [contentHeight, setContentHeight] = useState2(defaultOpen ? "auto" : 0);
|
|
1228
1255
|
useEffect2(() => {
|
|
1229
1256
|
if (contentRef.current) {
|
|
1230
1257
|
if (isOpen) {
|
|
@@ -1306,7 +1333,7 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1306
1333
|
const hasMoved = useRef2(false);
|
|
1307
1334
|
const startX = useRef2(0);
|
|
1308
1335
|
const startValue = useRef2(0);
|
|
1309
|
-
const [isDragging, setIsDragging] =
|
|
1336
|
+
const [isDragging, setIsDragging] = useState2(false);
|
|
1310
1337
|
const handleMouseDown = useCallback(
|
|
1311
1338
|
(e) => {
|
|
1312
1339
|
if (e.button !== 0) return;
|
|
@@ -1364,8 +1391,8 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1364
1391
|
placeholder
|
|
1365
1392
|
}) => {
|
|
1366
1393
|
const inputRef = useRef2(null);
|
|
1367
|
-
const [localValue, setLocalValue] =
|
|
1368
|
-
const [isFocused, setIsFocused] =
|
|
1394
|
+
const [localValue, setLocalValue] = useState2(String(value));
|
|
1395
|
+
const [isFocused, setIsFocused] = useState2(false);
|
|
1369
1396
|
const { handleMouseDown, hasMoved, isDragging } = useScrubber(
|
|
1370
1397
|
value,
|
|
1371
1398
|
onChange,
|
|
@@ -1492,7 +1519,7 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1492
1519
|
step = 0.01
|
|
1493
1520
|
}) => {
|
|
1494
1521
|
const [minVal, maxVal] = parseRange(value, [0, 0]);
|
|
1495
|
-
const [linked, setLinked] =
|
|
1522
|
+
const [linked, setLinked] = useState2(false);
|
|
1496
1523
|
const handleMinChange = useCallback(
|
|
1497
1524
|
(v) => {
|
|
1498
1525
|
if (linked) {
|
|
@@ -1743,8 +1770,8 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1743
1770
|
label
|
|
1744
1771
|
] }) });
|
|
1745
1772
|
CustomColorPicker = ({ color, onChange }) => {
|
|
1746
|
-
const [isOpen, setIsOpen] =
|
|
1747
|
-
const [hexInput, setHexInput] =
|
|
1773
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
1774
|
+
const [hexInput, setHexInput] = useState2(color);
|
|
1748
1775
|
const pickerRef = useRef2(null);
|
|
1749
1776
|
const gradientRef = useRef2(null);
|
|
1750
1777
|
const isDraggingGradient = useRef2(false);
|
|
@@ -1840,7 +1867,7 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
1840
1867
|
const toHex = (x) => Math.round(x * 255).toString(16).padStart(2, "0");
|
|
1841
1868
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1842
1869
|
};
|
|
1843
|
-
const [hsv, setHsv] =
|
|
1870
|
+
const [hsv, setHsv] = useState2(() => hexToHsv(color));
|
|
1844
1871
|
useEffect2(() => {
|
|
1845
1872
|
if (!isOpen) {
|
|
1846
1873
|
setHsv(hexToHsv(color));
|
|
@@ -2181,12 +2208,12 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
2181
2208
|
const containerRef = useRef2(null);
|
|
2182
2209
|
const draggingRef = useRef2(null);
|
|
2183
2210
|
const localDataRef = useRef2((value == null ? void 0 : value.points) || defaultValue.points);
|
|
2184
|
-
const [, forceUpdate] =
|
|
2185
|
-
const [hoverItem, setHoverItem] =
|
|
2186
|
-
const [selectedPoint, setSelectedPoint] =
|
|
2187
|
-
const [isScaling, setIsScaling] =
|
|
2211
|
+
const [, forceUpdate] = useState2(0);
|
|
2212
|
+
const [hoverItem, setHoverItem] = useState2(null);
|
|
2213
|
+
const [selectedPoint, setSelectedPoint] = useState2(null);
|
|
2214
|
+
const [isScaling, setIsScaling] = useState2(false);
|
|
2188
2215
|
const scaleStartRef = useRef2(null);
|
|
2189
|
-
const [isRotating, setIsRotating] =
|
|
2216
|
+
const [isRotating, setIsRotating] = useState2(false);
|
|
2190
2217
|
const rotateStartRef = useRef2(null);
|
|
2191
2218
|
const SIZE = 260;
|
|
2192
2219
|
const PADDING = 30;
|
|
@@ -2816,8 +2843,8 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
2816
2843
|
]
|
|
2817
2844
|
}
|
|
2818
2845
|
];
|
|
2819
|
-
const [easingIntensity, setEasingIntensity] =
|
|
2820
|
-
const [easingFrequency, setEasingFrequency] =
|
|
2846
|
+
const [easingIntensity, setEasingIntensity] = useState2(1);
|
|
2847
|
+
const [easingFrequency, setEasingFrequency] = useState2(3);
|
|
2821
2848
|
const generateBounce = useCallback((intensity, frequency) => {
|
|
2822
2849
|
const points2 = [{ pos: [0, 0], handleOut: [0.1, 0] }];
|
|
2823
2850
|
const bounces = Math.max(1, Math.round(frequency));
|
|
@@ -3526,22 +3553,22 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
3526
3553
|
);
|
|
3527
3554
|
DebugPanelContent = ({ initialValues, onUpdate }) => {
|
|
3528
3555
|
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, _R, _S, _T, _U, _V, _W, _X;
|
|
3529
|
-
const [isMinimized, setIsMinimized] =
|
|
3530
|
-
const [panelSize, setPanelSize] =
|
|
3531
|
-
const [copySuccess, setCopySuccess] =
|
|
3532
|
-
const [bakeSuccess, setBakeSuccess] =
|
|
3533
|
-
const [hasPendingChanges, setHasPendingChanges] =
|
|
3556
|
+
const [isMinimized, setIsMinimized] = useState2(false);
|
|
3557
|
+
const [panelSize, setPanelSize] = useState2({ width: 380, height: null });
|
|
3558
|
+
const [copySuccess, setCopySuccess] = useState2(false);
|
|
3559
|
+
const [bakeSuccess, setBakeSuccess] = useState2(false);
|
|
3560
|
+
const [hasPendingChanges, setHasPendingChanges] = useState2(false);
|
|
3534
3561
|
const valuesRef = useRef2(initialValues);
|
|
3535
3562
|
const dirtyKeysRef = useRef2(/* @__PURE__ */ new Set());
|
|
3536
|
-
const [, forceUpdate] =
|
|
3563
|
+
const [, forceUpdate] = useState2(0);
|
|
3537
3564
|
const isResizing = useRef2(false);
|
|
3538
3565
|
const resizeType = useRef2(null);
|
|
3539
3566
|
const debounceTimerRef = useRef2(null);
|
|
3540
3567
|
const DEBOUNCE_DELAY = 500;
|
|
3541
|
-
const [searchQuery, setSearchQuery] =
|
|
3568
|
+
const [searchQuery, setSearchQuery] = useState2("");
|
|
3542
3569
|
const historyRef = useRef2([JSON.parse(JSON.stringify(initialValues))]);
|
|
3543
|
-
const [historyIndex, setHistoryIndex] =
|
|
3544
|
-
const [historyLength, setHistoryLength] =
|
|
3570
|
+
const [historyIndex, setHistoryIndex] = useState2(0);
|
|
3571
|
+
const [historyLength, setHistoryLength] = useState2(1);
|
|
3545
3572
|
const MAX_HISTORY = 50;
|
|
3546
3573
|
const isUndoingRef = useRef2(false);
|
|
3547
3574
|
const prevInitialValuesRef = useRef2(initialValues);
|
|
@@ -3607,98 +3634,15 @@ ${" ".repeat(indent - 2)}}`;
|
|
|
3607
3634
|
flushChanges();
|
|
3608
3635
|
}
|
|
3609
3636
|
const values2 = valuesRef.current;
|
|
3610
|
-
const
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
const mt = 1 - t;
|
|
3617
|
-
const mt2 = mt * mt;
|
|
3618
|
-
const mt3 = mt2 * mt;
|
|
3619
|
-
const t2 = t * t;
|
|
3620
|
-
const t3 = t2 * t;
|
|
3621
|
-
return [
|
|
3622
|
-
mt3 * cp0[0] + 3 * mt2 * t * cp1[0] + 3 * mt * t2 * cp2[0] + t3 * cp3[0],
|
|
3623
|
-
mt3 * cp0[1] + 3 * mt2 * t * cp1[1] + 3 * mt * t2 * cp2[1] + t3 * cp3[1]
|
|
3624
|
-
];
|
|
3625
|
-
};
|
|
3626
|
-
const sampleCurveAtX = (x, points) => {
|
|
3627
|
-
var _a2, _b2, _c2, _d2;
|
|
3628
|
-
if (!points || points.length < 2) return x;
|
|
3629
|
-
if (!((_a2 = points[0]) == null ? void 0 : _a2.pos) || !((_b2 = points[points.length - 1]) == null ? void 0 : _b2.pos)) return x;
|
|
3630
|
-
let segmentIdx = 0;
|
|
3631
|
-
for (let i = 0; i < points.length - 1; i++) {
|
|
3632
|
-
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]) {
|
|
3633
|
-
segmentIdx = i;
|
|
3634
|
-
break;
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
|
-
const p0 = points[segmentIdx];
|
|
3638
|
-
const p1 = points[segmentIdx + 1];
|
|
3639
|
-
if (!(p0 == null ? void 0 : p0.pos) || !(p1 == null ? void 0 : p1.pos)) return x;
|
|
3640
|
-
let tLow = 0, tHigh = 1, t = 0.5;
|
|
3641
|
-
for (let iter = 0; iter < 20; iter++) {
|
|
3642
|
-
const [px] = evaluateBezierSegment(
|
|
3643
|
-
t,
|
|
3644
|
-
p0.pos,
|
|
3645
|
-
p1.pos,
|
|
3646
|
-
p0.handleOut,
|
|
3647
|
-
p1.handleIn
|
|
3648
|
-
);
|
|
3649
|
-
if (Math.abs(px - x) < 1e-4) break;
|
|
3650
|
-
if (px < x) {
|
|
3651
|
-
tLow = t;
|
|
3652
|
-
} else {
|
|
3653
|
-
tHigh = t;
|
|
3654
|
-
}
|
|
3655
|
-
t = (tLow + tHigh) / 2;
|
|
3656
|
-
}
|
|
3657
|
-
const [, py] = evaluateBezierSegment(
|
|
3658
|
-
t,
|
|
3659
|
-
p0.pos,
|
|
3660
|
-
p1.pos,
|
|
3661
|
-
p0.handleOut,
|
|
3662
|
-
p1.handleIn
|
|
3663
|
-
);
|
|
3664
|
-
return Math.max(-0.5, Math.min(1.5, py));
|
|
3665
|
-
};
|
|
3666
|
-
const bakeCurveToArray2 = (curveData) => {
|
|
3667
|
-
const data = new Float32Array(CURVE_RESOLUTION);
|
|
3668
|
-
if (!(curveData == null ? void 0 : curveData.points) || !Array.isArray(curveData.points) || curveData.points.length < 2) {
|
|
3669
|
-
for (let i = 0; i < CURVE_RESOLUTION; i++) {
|
|
3670
|
-
data[i] = 1 - i / (CURVE_RESOLUTION - 1);
|
|
3671
|
-
}
|
|
3672
|
-
return data;
|
|
3673
|
-
}
|
|
3674
|
-
const firstPoint = curveData.points[0];
|
|
3675
|
-
const lastPoint = curveData.points[curveData.points.length - 1];
|
|
3676
|
-
if (!(firstPoint == null ? void 0 : firstPoint.pos) || !(lastPoint == null ? void 0 : lastPoint.pos) || !Array.isArray(firstPoint.pos) || !Array.isArray(lastPoint.pos)) {
|
|
3677
|
-
for (let i = 0; i < CURVE_RESOLUTION; i++) {
|
|
3678
|
-
data[i] = 1 - i / (CURVE_RESOLUTION - 1);
|
|
3679
|
-
}
|
|
3680
|
-
return data;
|
|
3681
|
-
}
|
|
3682
|
-
for (let i = 0; i < CURVE_RESOLUTION; i++) {
|
|
3683
|
-
const x = i / (CURVE_RESOLUTION - 1);
|
|
3684
|
-
data[i] = sampleCurveAtX(x, curveData.points);
|
|
3685
|
-
}
|
|
3686
|
-
return data;
|
|
3687
|
-
};
|
|
3688
|
-
const sizeData = bakeCurveToArray2(values2.fadeSizeCurve);
|
|
3689
|
-
const opacityData = bakeCurveToArray2(values2.fadeOpacityCurve);
|
|
3690
|
-
const velocityData = bakeCurveToArray2(values2.velocityCurve);
|
|
3691
|
-
const rotationSpeedData = bakeCurveToArray2(values2.rotationSpeedCurve);
|
|
3692
|
-
const rgba = new Float32Array(CURVE_RESOLUTION * 4);
|
|
3693
|
-
for (let i = 0; i < CURVE_RESOLUTION; i++) {
|
|
3694
|
-
rgba[i * 4] = sizeData[i];
|
|
3695
|
-
rgba[i * 4 + 1] = opacityData[i];
|
|
3696
|
-
rgba[i * 4 + 2] = velocityData[i];
|
|
3697
|
-
rgba[i * 4 + 3] = rotationSpeedData[i];
|
|
3698
|
-
}
|
|
3637
|
+
const binBuffer = buildCurveTextureBin(
|
|
3638
|
+
values2.fadeSizeCurve || null,
|
|
3639
|
+
values2.fadeOpacityCurve || null,
|
|
3640
|
+
values2.velocityCurve || null,
|
|
3641
|
+
values2.rotationSpeedCurve || null
|
|
3642
|
+
);
|
|
3699
3643
|
const vfxName = values2.name || `vfx-curves-${Date.now()}`;
|
|
3700
3644
|
const filename = `${vfxName.replace(/[^a-zA-Z0-9-_]/g, "-")}.bin`;
|
|
3701
|
-
const blob = new Blob([
|
|
3645
|
+
const blob = new Blob([binBuffer], { type: "application/octet-stream" });
|
|
3702
3646
|
const link = document.createElement("a");
|
|
3703
3647
|
link.download = filename;
|
|
3704
3648
|
link.href = URL.createObjectURL(blob);
|
|
@@ -5405,7 +5349,7 @@ import {
|
|
|
5405
5349
|
useRef as useRef3,
|
|
5406
5350
|
useMemo as useMemo2,
|
|
5407
5351
|
useCallback as useCallback2,
|
|
5408
|
-
useState as
|
|
5352
|
+
useState as useState3
|
|
5409
5353
|
} from "react";
|
|
5410
5354
|
import { useFrame, useThree } from "@react-three/fiber";
|
|
5411
5355
|
import * as THREE2 from "three/webgpu";
|
|
@@ -5435,7 +5379,9 @@ import {
|
|
|
5435
5379
|
Easing as Easing2,
|
|
5436
5380
|
Lighting,
|
|
5437
5381
|
bakeCurveToArray,
|
|
5438
|
-
createCombinedCurveTexture as createCombinedCurveTexture3
|
|
5382
|
+
createCombinedCurveTexture as createCombinedCurveTexture3,
|
|
5383
|
+
buildCurveTextureBin as buildCurveTextureBin2,
|
|
5384
|
+
CurveChannel as CurveChannel2
|
|
5439
5385
|
} from "core-vfx";
|
|
5440
5386
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
5441
5387
|
var VFXParticles;
|
|
@@ -5562,29 +5508,29 @@ var init_VFXParticles = __esm({
|
|
|
5562
5508
|
const spriteRef = useRef3(null);
|
|
5563
5509
|
const initialized = useRef3(false);
|
|
5564
5510
|
const nextIndex = useRef3(0);
|
|
5565
|
-
const [emitting, setEmitting] =
|
|
5511
|
+
const [emitting, setEmitting] = useState3(autoStart);
|
|
5566
5512
|
const emitAccumulator = useRef3(0);
|
|
5567
5513
|
const delayRef = useRef3(delay);
|
|
5568
5514
|
const emitCountRef = useRef3(emitCount);
|
|
5569
5515
|
const turbulenceRef = useRef3(turbulence);
|
|
5570
|
-
const [activeMaxParticles, setActiveMaxParticles] =
|
|
5571
|
-
const [activeLighting, setActiveLighting] =
|
|
5572
|
-
const [activeAppearance, setActiveAppearance] =
|
|
5573
|
-
const [activeOrientToDirection, setActiveOrientToDirection] =
|
|
5574
|
-
const [activeGeometry, setActiveGeometry] =
|
|
5575
|
-
const [activeShadow, setActiveShadow] =
|
|
5576
|
-
const [activeFadeSizeCurve, setActiveFadeSizeCurve] =
|
|
5577
|
-
const [activeFadeOpacityCurve, setActiveFadeOpacityCurve] =
|
|
5578
|
-
const [activeVelocityCurve, setActiveVelocityCurve] =
|
|
5579
|
-
const [activeRotationSpeedCurve, setActiveRotationSpeedCurve] =
|
|
5580
|
-
const [activeTurbulence, setActiveTurbulence] =
|
|
5516
|
+
const [activeMaxParticles, setActiveMaxParticles] = useState3(maxParticles);
|
|
5517
|
+
const [activeLighting, setActiveLighting] = useState3(lighting);
|
|
5518
|
+
const [activeAppearance, setActiveAppearance] = useState3(appearance);
|
|
5519
|
+
const [activeOrientToDirection, setActiveOrientToDirection] = useState3(orientToDirection);
|
|
5520
|
+
const [activeGeometry, setActiveGeometry] = useState3(geometry);
|
|
5521
|
+
const [activeShadow, setActiveShadow] = useState3(shadow);
|
|
5522
|
+
const [activeFadeSizeCurve, setActiveFadeSizeCurve] = useState3(fadeSizeCurve);
|
|
5523
|
+
const [activeFadeOpacityCurve, setActiveFadeOpacityCurve] = useState3(fadeOpacityCurve);
|
|
5524
|
+
const [activeVelocityCurve, setActiveVelocityCurve] = useState3(velocityCurve);
|
|
5525
|
+
const [activeRotationSpeedCurve, setActiveRotationSpeedCurve] = useState3(rotationSpeedCurve);
|
|
5526
|
+
const [activeTurbulence, setActiveTurbulence] = useState3(
|
|
5581
5527
|
turbulence !== null && ((_a = turbulence == null ? void 0 : turbulence.intensity) != null ? _a : 0) > 0
|
|
5582
5528
|
);
|
|
5583
|
-
const [activeAttractors, setActiveAttractors] =
|
|
5529
|
+
const [activeAttractors, setActiveAttractors] = useState3(
|
|
5584
5530
|
attractors !== null && attractors.length > 0
|
|
5585
5531
|
);
|
|
5586
|
-
const [activeCollision, setActiveCollision] =
|
|
5587
|
-
const [activeNeedsPerParticleColor, setActiveNeedsPerParticleColor] =
|
|
5532
|
+
const [activeCollision, setActiveCollision] = useState3(collision !== null);
|
|
5533
|
+
const [activeNeedsPerParticleColor, setActiveNeedsPerParticleColor] = useState3(colorStart.length > 1 || colorEnd !== null);
|
|
5588
5534
|
const isNonDefaultRotation = (r) => {
|
|
5589
5535
|
if (typeof r === "number") return r !== 0;
|
|
5590
5536
|
if (Array.isArray(r) && r.length === 2 && typeof r[0] === "number") {
|
|
@@ -5597,7 +5543,7 @@ var init_VFXParticles = __esm({
|
|
|
5597
5543
|
}
|
|
5598
5544
|
return false;
|
|
5599
5545
|
};
|
|
5600
|
-
const [activeNeedsRotation, setActiveNeedsRotation] =
|
|
5546
|
+
const [activeNeedsRotation, setActiveNeedsRotation] = useState3(
|
|
5601
5547
|
isNonDefaultRotation(rotation) || isNonDefaultRotation(rotationSpeed)
|
|
5602
5548
|
);
|
|
5603
5549
|
useEffect3(() => {
|
|
@@ -5657,22 +5603,19 @@ var init_VFXParticles = __esm({
|
|
|
5657
5603
|
() => toRange(fadeOpacity, [1, 0]),
|
|
5658
5604
|
[fadeOpacity]
|
|
5659
5605
|
);
|
|
5660
|
-
const
|
|
5606
|
+
const {
|
|
5607
|
+
texture: curveTexture,
|
|
5608
|
+
sizeEnabled: curveTextureSizeEnabled,
|
|
5609
|
+
opacityEnabled: curveTextureOpacityEnabled,
|
|
5610
|
+
velocityEnabled: curveTextureVelocityEnabled,
|
|
5611
|
+
rotationSpeedEnabled: curveTextureRotationSpeedEnabled
|
|
5612
|
+
} = useCurveTextureAsync(
|
|
5661
5613
|
activeFadeSizeCurve,
|
|
5662
5614
|
activeFadeOpacityCurve,
|
|
5663
5615
|
activeVelocityCurve,
|
|
5664
5616
|
activeRotationSpeedCurve,
|
|
5665
5617
|
curveTexturePath
|
|
5666
5618
|
);
|
|
5667
|
-
const prevCurveTextureRef = useRef3(null);
|
|
5668
|
-
useEffect3(() => {
|
|
5669
|
-
prevCurveTextureRef.current = curveTexture;
|
|
5670
|
-
return () => {
|
|
5671
|
-
if (curveTexture) {
|
|
5672
|
-
curveTexture.dispose();
|
|
5673
|
-
}
|
|
5674
|
-
};
|
|
5675
|
-
}, [curveTexture]);
|
|
5676
5619
|
const lifetimeRange = useMemo2(() => toRange(lifetime, [1, 2]), [lifetime]);
|
|
5677
5620
|
const rotation3D = useMemo2(() => toRotation3D(rotation), [rotation]);
|
|
5678
5621
|
const rotationSpeed3D = useMemo2(
|
|
@@ -5854,23 +5797,11 @@ var init_VFXParticles = __esm({
|
|
|
5854
5797
|
// Soft particles
|
|
5855
5798
|
softParticlesEnabled: uniform(softParticles ? 1 : 0),
|
|
5856
5799
|
softDistance: uniform(softDistance),
|
|
5857
|
-
//
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
),
|
|
5862
|
-
// Rotation speed curve (modulates rotation speed over lifetime)
|
|
5863
|
-
rotationSpeedCurveEnabled: uniform(
|
|
5864
|
-
rotationSpeedCurve || curveTexturePath ? 1 : 0
|
|
5865
|
-
),
|
|
5866
|
-
// Fade size curve (when disabled, uses fadeSize prop interpolation)
|
|
5867
|
-
fadeSizeCurveEnabled: uniform(
|
|
5868
|
-
fadeSizeCurve || curveTexturePath ? 1 : 0
|
|
5869
|
-
),
|
|
5870
|
-
// Fade opacity curve (when disabled, uses fadeOpacity prop interpolation)
|
|
5871
|
-
fadeOpacityCurveEnabled: uniform(
|
|
5872
|
-
fadeOpacityCurve || curveTexturePath ? 1 : 0
|
|
5873
|
-
),
|
|
5800
|
+
// Curve enabled flags (set by useCurveTextureAsync per-channel info)
|
|
5801
|
+
velocityCurveEnabled: uniform(0),
|
|
5802
|
+
rotationSpeedCurveEnabled: uniform(0),
|
|
5803
|
+
fadeSizeCurveEnabled: uniform(0),
|
|
5804
|
+
fadeOpacityCurveEnabled: uniform(0),
|
|
5874
5805
|
// Orient axis: 0=+X, 1=+Y, 2=+Z, 3=-X, 4=-Y, 5=-Z
|
|
5875
5806
|
orientAxisType: uniform(axisToNumber(orientAxis)),
|
|
5876
5807
|
// Stretch by speed (uses effective velocity after curve modifier)
|
|
@@ -5981,10 +5912,10 @@ var init_VFXParticles = __esm({
|
|
|
5981
5912
|
uniforms.startPositionAsDirection.value = startPositionAsDirection ? 1 : 0;
|
|
5982
5913
|
uniforms.softParticlesEnabled.value = softParticles ? 1 : 0;
|
|
5983
5914
|
uniforms.softDistance.value = softDistance;
|
|
5984
|
-
uniforms.velocityCurveEnabled.value =
|
|
5985
|
-
uniforms.rotationSpeedCurveEnabled.value =
|
|
5986
|
-
uniforms.fadeSizeCurveEnabled.value =
|
|
5987
|
-
uniforms.fadeOpacityCurveEnabled.value =
|
|
5915
|
+
uniforms.velocityCurveEnabled.value = curveTextureVelocityEnabled ? 1 : 0;
|
|
5916
|
+
uniforms.rotationSpeedCurveEnabled.value = curveTextureRotationSpeedEnabled ? 1 : 0;
|
|
5917
|
+
uniforms.fadeSizeCurveEnabled.value = curveTextureSizeEnabled ? 1 : 0;
|
|
5918
|
+
uniforms.fadeOpacityCurveEnabled.value = curveTextureOpacityEnabled ? 1 : 0;
|
|
5988
5919
|
uniforms.orientAxisType.value = axisToNumber(orientAxis);
|
|
5989
5920
|
uniforms.stretchEnabled.value = stretchBySpeed ? 1 : 0;
|
|
5990
5921
|
uniforms.stretchFactor.value = (_h = stretchBySpeed == null ? void 0 : stretchBySpeed.factor) != null ? _h : 1;
|
|
@@ -6029,11 +5960,10 @@ var init_VFXParticles = __esm({
|
|
|
6029
5960
|
startPositionAsDirection,
|
|
6030
5961
|
softParticles,
|
|
6031
5962
|
softDistance,
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
curveTexturePath,
|
|
5963
|
+
curveTextureVelocityEnabled,
|
|
5964
|
+
curveTextureRotationSpeedEnabled,
|
|
5965
|
+
curveTextureSizeEnabled,
|
|
5966
|
+
curveTextureOpacityEnabled,
|
|
6037
5967
|
orientAxis,
|
|
6038
5968
|
stretchBySpeed
|
|
6039
5969
|
]);
|
|
@@ -7119,12 +7049,14 @@ export {
|
|
|
7119
7049
|
Appearance,
|
|
7120
7050
|
AttractorType2 as AttractorType,
|
|
7121
7051
|
Blending,
|
|
7052
|
+
CurveChannel2 as CurveChannel,
|
|
7122
7053
|
Easing2 as Easing,
|
|
7123
7054
|
EmitterShape,
|
|
7124
7055
|
Lighting,
|
|
7125
7056
|
VFXEmitter,
|
|
7126
7057
|
VFXParticles,
|
|
7127
7058
|
bakeCurveToArray,
|
|
7059
|
+
buildCurveTextureBin2 as buildCurveTextureBin,
|
|
7128
7060
|
createCombinedCurveTexture3 as createCombinedCurveTexture,
|
|
7129
7061
|
useCurveTextureAsync,
|
|
7130
7062
|
useVFXEmitter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "r3f-vfx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"prepublishOnly": "bun run copy-readme"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"core-vfx": "0.0.
|
|
27
|
+
"core-vfx": "0.0.7",
|
|
28
28
|
"zustand": "5.0.10"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|