@newkrok/three-particles 2.14.1 → 2.15.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/README.md +8 -2
- package/dist/index.d.ts +33 -0
- package/dist/index.js +101 -23
- package/dist/index.js.map +1 -1
- package/dist/three-particles.min.js +1 -1
- package/dist/three-particles.min.js.map +1 -1
- package/llms-full.txt +1 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,12 +64,18 @@ const effect = {
|
|
|
64
64
|
// Your effect configuration here
|
|
65
65
|
// It can be empty to use default settings
|
|
66
66
|
};
|
|
67
|
-
const
|
|
68
|
-
scene.add(instance);
|
|
67
|
+
const system = createParticleSystem(effect);
|
|
68
|
+
scene.add(system.instance);
|
|
69
69
|
|
|
70
70
|
// Update the particle system in your animation loop
|
|
71
71
|
// Pass the current time, delta time, and elapsed time
|
|
72
72
|
updateParticleSystems({now, delta, elapsed});
|
|
73
|
+
|
|
74
|
+
// Update configuration at runtime without recreating the system
|
|
75
|
+
system.updateConfig({
|
|
76
|
+
gravity: -9.8,
|
|
77
|
+
forceFields: [{ type: 'DIRECTIONAL', direction: { x: 1, y: 0, z: 0 }, strength: 5 }],
|
|
78
|
+
});
|
|
73
79
|
```
|
|
74
80
|
|
|
75
81
|
# Usage with React Three Fiber
|
package/dist/index.d.ts
CHANGED
|
@@ -1849,6 +1849,39 @@ type ParticleSystem = {
|
|
|
1849
1849
|
pauseEmitter: () => void;
|
|
1850
1850
|
dispose: () => void;
|
|
1851
1851
|
update: (cycleData: CycleData) => void;
|
|
1852
|
+
/**
|
|
1853
|
+
* Updates the particle system configuration at runtime without recreating the system.
|
|
1854
|
+
*
|
|
1855
|
+
* System-level properties (gravity, force fields, noise, emission rates, color/size/opacity
|
|
1856
|
+
* over lifetime curves) take effect immediately for all particles.
|
|
1857
|
+
* Per-particle spawn properties (startColor, startSize, startSpeed, startLifetime, etc.)
|
|
1858
|
+
* only affect newly emitted particles — already-alive particles retain their original values.
|
|
1859
|
+
*
|
|
1860
|
+
* @param config - A partial configuration object. Only the provided properties will be updated;
|
|
1861
|
+
* all other settings remain unchanged.
|
|
1862
|
+
*
|
|
1863
|
+
* @remarks
|
|
1864
|
+
* Structural properties that are set at creation time cannot be changed at runtime:
|
|
1865
|
+
* `maxParticles`, `renderer.rendererType`, `shape`, and `map` (texture).
|
|
1866
|
+
* Passing these will update the internal config but have no visible effect since the
|
|
1867
|
+
* geometry and material are pre-allocated.
|
|
1868
|
+
*
|
|
1869
|
+
* @example
|
|
1870
|
+
* ```typescript
|
|
1871
|
+
* const system = createParticleSystem(config);
|
|
1872
|
+
*
|
|
1873
|
+
* // Change wind direction in real time
|
|
1874
|
+
* system.updateConfig({
|
|
1875
|
+
* forceFields: [{ type: ForceFieldType.DIRECTIONAL, direction: { x: 1, y: 0, z: 0 }, strength: 5 }],
|
|
1876
|
+
* });
|
|
1877
|
+
*
|
|
1878
|
+
* // Gradually change color of new particles
|
|
1879
|
+
* system.updateConfig({
|
|
1880
|
+
* startColor: { min: { r: 1, g: 0, b: 0 }, max: { r: 1, g: 0.5, b: 0 } },
|
|
1881
|
+
* });
|
|
1882
|
+
* ```
|
|
1883
|
+
*/
|
|
1884
|
+
updateConfig: (config: Partial<ParticleSystemConfig>) => void;
|
|
1852
1885
|
};
|
|
1853
1886
|
/**
|
|
1854
1887
|
* Data representing the current cycle of the particle system's update loop.
|
package/dist/index.js
CHANGED
|
@@ -1171,6 +1171,10 @@ var _particleSystemId = 0;
|
|
|
1171
1171
|
var createdParticleSystems = [];
|
|
1172
1172
|
var _subEmitterPosition = new THREE4.Vector3();
|
|
1173
1173
|
var _lastWorldPositionSnapshot = new THREE4.Vector3();
|
|
1174
|
+
var _localForceFieldPos = new THREE4.Vector3();
|
|
1175
|
+
var _localForceFieldDir = new THREE4.Vector3();
|
|
1176
|
+
var _inverseQuat = new THREE4.Quaternion();
|
|
1177
|
+
var _localForceFields = [];
|
|
1174
1178
|
new THREE4.Vector3();
|
|
1175
1179
|
new THREE4.Vector3();
|
|
1176
1180
|
new THREE4.Vector3();
|
|
@@ -1184,6 +1188,16 @@ var _modifierParams = {
|
|
|
1184
1188
|
particleLifetimePercentage: 0,
|
|
1185
1189
|
particleIndex: 0
|
|
1186
1190
|
};
|
|
1191
|
+
var toVector3 = (v, fallback) => v ? new THREE4.Vector3(v.x ?? 0, v.y ?? 0, v.z ?? 0) : fallback.clone();
|
|
1192
|
+
var normalizeForceFields = (rawForceFields) => (rawForceFields ?? []).map((ff) => ({
|
|
1193
|
+
isActive: ff.isActive ?? true,
|
|
1194
|
+
type: ff.type ?? "POINT" /* POINT */,
|
|
1195
|
+
position: toVector3(ff.position, new THREE4.Vector3(0, 0, 0)),
|
|
1196
|
+
direction: toVector3(ff.direction, new THREE4.Vector3(0, 1, 0)).normalize(),
|
|
1197
|
+
strength: ff.strength ?? 1,
|
|
1198
|
+
range: Math.max(0, ff.range ?? Infinity),
|
|
1199
|
+
falloff: ff.falloff ?? "LINEAR" /* LINEAR */
|
|
1200
|
+
}));
|
|
1187
1201
|
var blendingMap = {
|
|
1188
1202
|
"THREE.NoBlending": THREE4.NoBlending,
|
|
1189
1203
|
"THREE.NormalBlending": THREE4.NormalBlending,
|
|
@@ -1507,16 +1521,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1507
1521
|
subEmitters,
|
|
1508
1522
|
forceFields: rawForceFields
|
|
1509
1523
|
} = normalizedConfig;
|
|
1510
|
-
const
|
|
1511
|
-
const normalizedForceFields = (rawForceFields ?? []).map((ff) => ({
|
|
1512
|
-
isActive: ff.isActive ?? true,
|
|
1513
|
-
type: ff.type ?? "POINT" /* POINT */,
|
|
1514
|
-
position: toVector3(ff.position, new THREE4.Vector3(0, 0, 0)),
|
|
1515
|
-
direction: toVector3(ff.direction, new THREE4.Vector3(0, 1, 0)).normalize(),
|
|
1516
|
-
strength: ff.strength ?? 1,
|
|
1517
|
-
range: Math.max(0, ff.range ?? Infinity),
|
|
1518
|
-
falloff: ff.falloff ?? "LINEAR" /* LINEAR */
|
|
1519
|
-
}));
|
|
1524
|
+
const normalizedForceFields = normalizeForceFields(rawForceFields);
|
|
1520
1525
|
if (typeof renderer?.blending === "string")
|
|
1521
1526
|
renderer.blending = blendingMap[renderer.blending];
|
|
1522
1527
|
const startPositions = Array.from(
|
|
@@ -1952,44 +1957,45 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1952
1957
|
if (generalData.noise.offsets)
|
|
1953
1958
|
generalData.noise.offsets[particleIndex] = Math.random() * 100;
|
|
1954
1959
|
const colorRandomRatio2 = Math.random();
|
|
1955
|
-
|
|
1960
|
+
const cfgStartColor = normalizedConfig.startColor;
|
|
1961
|
+
aColorR.array[particleIndex] = cfgStartColor.min.r + colorRandomRatio2 * (cfgStartColor.max.r - cfgStartColor.min.r);
|
|
1956
1962
|
aColorR.needsUpdate = true;
|
|
1957
|
-
aColorG.array[particleIndex] =
|
|
1963
|
+
aColorG.array[particleIndex] = cfgStartColor.min.g + colorRandomRatio2 * (cfgStartColor.max.g - cfgStartColor.min.g);
|
|
1958
1964
|
aColorG.needsUpdate = true;
|
|
1959
|
-
aColorB.array[particleIndex] =
|
|
1965
|
+
aColorB.array[particleIndex] = cfgStartColor.min.b + colorRandomRatio2 * (cfgStartColor.max.b - cfgStartColor.min.b);
|
|
1960
1966
|
aColorB.needsUpdate = true;
|
|
1961
1967
|
generalData.startValues.startColorR[particleIndex] = aColorR.array[particleIndex];
|
|
1962
1968
|
generalData.startValues.startColorG[particleIndex] = aColorG.array[particleIndex];
|
|
1963
1969
|
generalData.startValues.startColorB[particleIndex] = aColorB.array[particleIndex];
|
|
1964
|
-
aStartFrame.array[particleIndex] = textureSheetAnimation.startFrame ? calculateValue(
|
|
1970
|
+
aStartFrame.array[particleIndex] = normalizedConfig.textureSheetAnimation.startFrame ? calculateValue(
|
|
1965
1971
|
generalData.particleSystemId,
|
|
1966
|
-
textureSheetAnimation.startFrame,
|
|
1972
|
+
normalizedConfig.textureSheetAnimation.startFrame,
|
|
1967
1973
|
0
|
|
1968
1974
|
) : 0;
|
|
1969
1975
|
aStartFrame.needsUpdate = true;
|
|
1970
1976
|
aStartLifetime.array[particleIndex] = calculateValue(
|
|
1971
1977
|
generalData.particleSystemId,
|
|
1972
|
-
startLifetime,
|
|
1978
|
+
normalizedConfig.startLifetime,
|
|
1973
1979
|
generalData.normalizedLifetimePercentage
|
|
1974
1980
|
) * 1e3;
|
|
1975
1981
|
aStartLifetime.needsUpdate = true;
|
|
1976
1982
|
generalData.startValues.startSize[particleIndex] = calculateValue(
|
|
1977
1983
|
generalData.particleSystemId,
|
|
1978
|
-
startSize,
|
|
1984
|
+
normalizedConfig.startSize,
|
|
1979
1985
|
generalData.normalizedLifetimePercentage
|
|
1980
1986
|
);
|
|
1981
1987
|
aSize.array[particleIndex] = generalData.startValues.startSize[particleIndex];
|
|
1982
1988
|
aSize.needsUpdate = true;
|
|
1983
1989
|
generalData.startValues.startOpacity[particleIndex] = calculateValue(
|
|
1984
1990
|
generalData.particleSystemId,
|
|
1985
|
-
startOpacity,
|
|
1991
|
+
normalizedConfig.startOpacity,
|
|
1986
1992
|
generalData.normalizedLifetimePercentage
|
|
1987
1993
|
);
|
|
1988
1994
|
aColorA.array[particleIndex] = generalData.startValues.startOpacity[particleIndex];
|
|
1989
1995
|
aColorA.needsUpdate = true;
|
|
1990
1996
|
aRotation.array[particleIndex] = calculateValue(
|
|
1991
1997
|
generalData.particleSystemId,
|
|
1992
|
-
startRotation,
|
|
1998
|
+
normalizedConfig.startRotation,
|
|
1993
1999
|
generalData.normalizedLifetimePercentage
|
|
1994
2000
|
);
|
|
1995
2001
|
aRotation.needsUpdate = true;
|
|
@@ -2010,8 +2016,8 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2010
2016
|
);
|
|
2011
2017
|
calculatePositionAndVelocity(
|
|
2012
2018
|
generalData,
|
|
2013
|
-
shape,
|
|
2014
|
-
startSpeed,
|
|
2019
|
+
normalizedConfig.shape,
|
|
2020
|
+
normalizedConfig.startSpeed,
|
|
2015
2021
|
startPositions[particleIndex],
|
|
2016
2022
|
velocities[particleIndex]
|
|
2017
2023
|
);
|
|
@@ -2406,12 +2412,53 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2406
2412
|
for (const sub of instances) sub.update(cycleData);
|
|
2407
2413
|
}
|
|
2408
2414
|
};
|
|
2415
|
+
const updateConfig = (partialConfig) => {
|
|
2416
|
+
ObjectUtils.deepMerge(instanceData.normalizedConfig, partialConfig, {
|
|
2417
|
+
applyToFirstObject: true,
|
|
2418
|
+
skippedProperties: []
|
|
2419
|
+
});
|
|
2420
|
+
const cfg = instanceData.normalizedConfig;
|
|
2421
|
+
if (partialConfig.gravity !== void 0) {
|
|
2422
|
+
instanceData.gravity = cfg.gravity;
|
|
2423
|
+
generalData.lastWorldQuaternion.x = -99999;
|
|
2424
|
+
}
|
|
2425
|
+
if (partialConfig.duration !== void 0)
|
|
2426
|
+
instanceData.duration = cfg.duration;
|
|
2427
|
+
if (partialConfig.looping !== void 0) instanceData.looping = cfg.looping;
|
|
2428
|
+
if (partialConfig.simulationSpace !== void 0)
|
|
2429
|
+
instanceData.simulationSpace = cfg.simulationSpace;
|
|
2430
|
+
if (partialConfig.emission !== void 0)
|
|
2431
|
+
instanceData.emission = cfg.emission;
|
|
2432
|
+
if (partialConfig.forceFields !== void 0) {
|
|
2433
|
+
instanceData.normalizedForceFields = normalizeForceFields(
|
|
2434
|
+
cfg.forceFields
|
|
2435
|
+
);
|
|
2436
|
+
}
|
|
2437
|
+
if (partialConfig.noise !== void 0) {
|
|
2438
|
+
const n = cfg.noise;
|
|
2439
|
+
generalData.noise = {
|
|
2440
|
+
isActive: n.isActive,
|
|
2441
|
+
strength: n.strength,
|
|
2442
|
+
noisePower: 0.15 * n.strength,
|
|
2443
|
+
positionAmount: n.positionAmount,
|
|
2444
|
+
rotationAmount: n.rotationAmount,
|
|
2445
|
+
sizeAmount: n.sizeAmount,
|
|
2446
|
+
sampler: n.isActive ? new FBM({
|
|
2447
|
+
seed: Math.random(),
|
|
2448
|
+
scale: n.frequency,
|
|
2449
|
+
octaves: n.octaves
|
|
2450
|
+
}) : void 0,
|
|
2451
|
+
offsets: n.useRandomOffset ? generalData.noise.offsets ?? Array.from({ length: maxParticles }, () => Math.random() * 100) : void 0
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2409
2455
|
return {
|
|
2410
2456
|
instance: wrapper || particleSystem,
|
|
2411
2457
|
resumeEmitter,
|
|
2412
2458
|
pauseEmitter,
|
|
2413
2459
|
dispose,
|
|
2414
|
-
update
|
|
2460
|
+
update,
|
|
2461
|
+
updateConfig
|
|
2415
2462
|
};
|
|
2416
2463
|
};
|
|
2417
2464
|
var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
|
|
@@ -2484,6 +2531,37 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
|
|
|
2484
2531
|
);
|
|
2485
2532
|
particleSystem.worldToLocal(gravityVelocity);
|
|
2486
2533
|
}
|
|
2534
|
+
if (hasForceFields) {
|
|
2535
|
+
_inverseQuat.copy(worldQuaternion).invert();
|
|
2536
|
+
_localForceFields.length = normalizedForceFields.length;
|
|
2537
|
+
for (let i = 0; i < normalizedForceFields.length; i++) {
|
|
2538
|
+
const src = normalizedForceFields[i];
|
|
2539
|
+
let dst = _localForceFields[i];
|
|
2540
|
+
if (!dst) {
|
|
2541
|
+
dst = {
|
|
2542
|
+
isActive: true,
|
|
2543
|
+
type: "POINT" /* POINT */,
|
|
2544
|
+
position: new THREE4.Vector3(),
|
|
2545
|
+
direction: new THREE4.Vector3(),
|
|
2546
|
+
strength: 0,
|
|
2547
|
+
range: 0,
|
|
2548
|
+
falloff: "LINEAR" /* LINEAR */
|
|
2549
|
+
};
|
|
2550
|
+
_localForceFields[i] = dst;
|
|
2551
|
+
}
|
|
2552
|
+
dst.isActive = src.isActive;
|
|
2553
|
+
dst.type = src.type;
|
|
2554
|
+
dst.strength = src.strength;
|
|
2555
|
+
dst.range = src.range;
|
|
2556
|
+
dst.falloff = src.falloff;
|
|
2557
|
+
_localForceFieldPos.copy(src.position);
|
|
2558
|
+
particleSystem.worldToLocal(_localForceFieldPos);
|
|
2559
|
+
dst.position.copy(_localForceFieldPos);
|
|
2560
|
+
_localForceFieldDir.copy(src.direction);
|
|
2561
|
+
_localForceFieldDir.applyQuaternion(_inverseQuat);
|
|
2562
|
+
dst.direction.copy(_localForceFieldDir);
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2487
2565
|
const creationTimes = generalData.creationTimes;
|
|
2488
2566
|
const isActiveArr = ma.isActive.array;
|
|
2489
2567
|
const startLifetimeArr = ma.startLifetime.array;
|
|
@@ -2511,7 +2589,7 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
|
|
|
2511
2589
|
if (hasForceFields) {
|
|
2512
2590
|
applyForceFields({
|
|
2513
2591
|
particleSystemId: generalData.particleSystemId,
|
|
2514
|
-
forceFields:
|
|
2592
|
+
forceFields: _localForceFields,
|
|
2515
2593
|
velocity,
|
|
2516
2594
|
positionArr,
|
|
2517
2595
|
positionIndex: index * 3,
|