@newkrok/three-particles 2.15.1 → 2.15.2

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 CHANGED
@@ -1801,6 +1801,12 @@ type ParticleSystemInstance = {
1801
1801
  trailAlphaAttr?: THREE.BufferAttribute;
1802
1802
  /** Trail geometry color attribute */
1803
1803
  trailColorAttr?: THREE.BufferAttribute;
1804
+ /** Trail geometry next-position attribute (cached to avoid repeated getAttribute) */
1805
+ trailNextAttr?: THREE.BufferAttribute;
1806
+ /** Trail geometry half-width attribute (cached) */
1807
+ trailHalfWidthAttr?: THREE.BufferAttribute;
1808
+ /** Trail geometry UV attribute (cached) */
1809
+ trailUVAttr?: THREE.BufferAttribute;
1804
1810
  /** Trail width curve function */
1805
1811
  trailWidthCurveFn?: CurveFunction;
1806
1812
  /** Trail opacity curve function */
package/dist/index.js CHANGED
@@ -2152,6 +2152,9 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
2152
2152
  let trailPositionAttr;
2153
2153
  let trailAlphaAttr;
2154
2154
  let trailColorAttr;
2155
+ let trailNextAttr;
2156
+ let trailHalfWidthAttr;
2157
+ let trailUVAttr;
2155
2158
  let trailIndexAttr;
2156
2159
  let trailWidthCurveFn;
2157
2160
  let trailOpacityCurveFn;
@@ -2191,15 +2194,15 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
2191
2194
  }
2192
2195
  trailPositionAttr = new THREE4.BufferAttribute(trailPositions, 3);
2193
2196
  trailPositionAttr.setUsage(THREE4.DynamicDrawUsage);
2194
- const trailNextAttr = new THREE4.BufferAttribute(trailNextPositions, 3);
2197
+ trailNextAttr = new THREE4.BufferAttribute(trailNextPositions, 3);
2195
2198
  trailNextAttr.setUsage(THREE4.DynamicDrawUsage);
2196
2199
  trailAlphaAttr = new THREE4.BufferAttribute(trailAlphas, 1);
2197
2200
  trailAlphaAttr.setUsage(THREE4.DynamicDrawUsage);
2198
2201
  trailColorAttr = new THREE4.BufferAttribute(trailColors, 4);
2199
2202
  trailColorAttr.setUsage(THREE4.DynamicDrawUsage);
2200
- const trailHalfWidthAttr = new THREE4.BufferAttribute(trailHalfWidths, 1);
2203
+ trailHalfWidthAttr = new THREE4.BufferAttribute(trailHalfWidths, 1);
2201
2204
  trailHalfWidthAttr.setUsage(THREE4.DynamicDrawUsage);
2202
- const trailUVAttr = new THREE4.BufferAttribute(trailUVs, 2);
2205
+ trailUVAttr = new THREE4.BufferAttribute(trailUVs, 2);
2203
2206
  trailUVAttr.setUsage(THREE4.DynamicDrawUsage);
2204
2207
  trailIndexAttr = new THREE4.BufferAttribute(trailIndices, 1);
2205
2208
  trailGeometry.setAttribute("position", trailPositionAttr);
@@ -2381,6 +2384,9 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
2381
2384
  trailPositionAttr,
2382
2385
  trailAlphaAttr,
2383
2386
  trailColorAttr,
2387
+ trailNextAttr,
2388
+ trailHalfWidthAttr,
2389
+ trailUVAttr,
2384
2390
  trailWidthCurveFn,
2385
2391
  trailOpacityCurveFn,
2386
2392
  trailColorOverTrailFns,
@@ -2809,13 +2815,16 @@ var updateTrailGeometry = (props, now) => {
2809
2815
  trailPositionAttr,
2810
2816
  trailAlphaAttr,
2811
2817
  trailColorAttr,
2818
+ trailNextAttr: trailNextAttrCached,
2819
+ trailHalfWidthAttr: trailHalfWidthAttrCached,
2820
+ trailUVAttr: trailUVAttrCached,
2812
2821
  trailWidthCurveFn,
2813
2822
  trailOpacityCurveFn,
2814
2823
  trailColorOverTrailFns,
2815
2824
  trailConfig,
2816
2825
  mappedAttributes: ma
2817
2826
  } = props;
2818
- if (!trailPositionAttr || !trailAlphaAttr || !trailColorAttr || !trailWidthCurveFn || !trailOpacityCurveFn || !trailConfig || !generalData.positionHistory || !generalData.positionHistoryIndex || !generalData.positionHistoryCount)
2827
+ if (!trailPositionAttr || !trailAlphaAttr || !trailColorAttr || !trailNextAttrCached || !trailHalfWidthAttrCached || !trailUVAttrCached || !trailWidthCurveFn || !trailOpacityCurveFn || !trailConfig || !generalData.positionHistory || !generalData.positionHistoryIndex || !generalData.positionHistoryCount)
2819
2828
  return;
2820
2829
  const trailLength = trailConfig.length;
2821
2830
  const positionHistory = generalData.positionHistory;
@@ -2841,10 +2850,9 @@ var updateTrailGeometry = (props, now) => {
2841
2850
  const trailPosArr = trailPositionAttr.array;
2842
2851
  const trailAlphaArr = trailAlphaAttr.array;
2843
2852
  const trailColorArr = trailColorAttr.array;
2844
- const trailMesh = props.trailMesh;
2845
- const trailNextArr = trailMesh.geometry.getAttribute("trailNext").array;
2846
- const trailUVArr = trailMesh.geometry.getAttribute("trailUV").array;
2847
- const trailHalfWidthArr = trailMesh.geometry.getAttribute("trailHalfWidth").array;
2853
+ const trailNextArr = trailNextAttrCached.array;
2854
+ const trailUVArr = trailUVAttrCached.array;
2855
+ const trailHalfWidthArr = trailHalfWidthAttrCached.array;
2848
2856
  const verticesPerParticle = trailLength * 2;
2849
2857
  const creationTimesLength = generalData.creationTimes.length;
2850
2858
  let hasUpdates = false;
@@ -3073,6 +3081,13 @@ var updateTrailGeometry = (props, now) => {
3073
3081
  nx = finalPts[(s + 1) * 3];
3074
3082
  ny = finalPts[(s + 1) * 3 + 1];
3075
3083
  nz = finalPts[(s + 1) * 3 + 2];
3084
+ } else if (finalCount >= 2) {
3085
+ const prevX = finalPts[(s - 1) * 3];
3086
+ const prevY = finalPts[(s - 1) * 3 + 1];
3087
+ const prevZ = finalPts[(s - 1) * 3 + 2];
3088
+ nx = hx + (hx - prevX);
3089
+ ny = hy + (hy - prevY);
3090
+ nz = hz + (hz - prevZ);
3076
3091
  } else {
3077
3092
  nx = hx;
3078
3093
  ny = hy + 1e-3;
@@ -3081,14 +3096,24 @@ var updateTrailGeometry = (props, now) => {
3081
3096
  const t = finalCount > 1 ? s / (finalCount - 1) : 0;
3082
3097
  let timeFade = 1;
3083
3098
  if (maxTime > 0 && sampleTimes && effectiveCount > 0) {
3084
- const rawS = useSmoothing ? Math.min(
3085
- Math.floor(s / Math.max(finalCount - 1, 1) * (rawCount - 1)),
3086
- rawCount - 1
3087
- ) : Math.min(s, rawCount - 1);
3088
- const sampleSlot = (historyIndex[index] - 1 - rawS + trailLength * 2) % trailLength;
3089
3099
  const sampleBase = index * trailLength;
3090
- const age = now - sampleTimes[sampleBase + sampleSlot];
3091
- timeFade = 1 - Math.min(age / maxTimeMs, 1);
3100
+ if (useSmoothing && rawCount >= 2) {
3101
+ const rawF = s / Math.max(finalCount - 1, 1) * (rawCount - 1);
3102
+ const rawLo = Math.min(Math.floor(rawF), rawCount - 1);
3103
+ const rawHi = Math.min(rawLo + 1, rawCount - 1);
3104
+ const frac = rawF - rawLo;
3105
+ const slotLo = (historyIndex[index] - 1 - rawLo + trailLength * 2) % trailLength;
3106
+ const slotHi = (historyIndex[index] - 1 - rawHi + trailLength * 2) % trailLength;
3107
+ const ageLo = now - sampleTimes[sampleBase + slotLo];
3108
+ const ageHi = now - sampleTimes[sampleBase + slotHi];
3109
+ const age = ageLo + (ageHi - ageLo) * frac;
3110
+ timeFade = 1 - Math.min(age / maxTimeMs, 1);
3111
+ } else {
3112
+ const rawS = Math.min(s, rawCount - 1);
3113
+ const sampleSlot = (historyIndex[index] - 1 - rawS + trailLength * 2) % trailLength;
3114
+ const age = now - sampleTimes[sampleBase + sampleSlot];
3115
+ timeFade = 1 - Math.min(age / maxTimeMs, 1);
3116
+ }
3092
3117
  }
3093
3118
  const widthScale = trailWidthCurveFn(t);
3094
3119
  const opacityScale = trailOpacityCurveFn(t);
@@ -3321,16 +3346,34 @@ var updateTrailGeometry = (props, now) => {
3321
3346
  nx = _rawPoints[(s + 1) * 3];
3322
3347
  ny = _rawPoints[(s + 1) * 3 + 1];
3323
3348
  nz = _rawPoints[(s + 1) * 3 + 2];
3349
+ } else if (filledCount >= 2) {
3350
+ const prevX = _rawPoints[(s - 1) * 3];
3351
+ const prevY = _rawPoints[(s - 1) * 3 + 1];
3352
+ const prevZ = _rawPoints[(s - 1) * 3 + 2];
3353
+ nx = ptx + (ptx - prevX);
3354
+ ny = pty + (pty - prevY);
3355
+ nz = ptz + (ptz - prevZ);
3324
3356
  } else {
3325
3357
  nx = ptx;
3326
3358
  ny = pty + 1e-3;
3327
3359
  nz = ptz;
3328
3360
  }
3329
3361
  const t = filledCount > 1 ? s / (filledCount - 1) : 0;
3362
+ let ribbonTimeFade = 1;
3363
+ if (maxTime > 0 && controlCount >= 2) {
3364
+ const ctrlF = t * (controlCount - 1);
3365
+ const ctrlLo = Math.min(Math.floor(ctrlF), controlCount - 1);
3366
+ const ctrlHi = Math.min(ctrlLo + 1, controlCount - 1);
3367
+ const frac = ctrlF - ctrlLo;
3368
+ const ageLo = now - generalData.creationTimes[_ribbonIndices[ctrlLo]];
3369
+ const ageHi = now - generalData.creationTimes[_ribbonIndices[ctrlHi]];
3370
+ const age = ageLo + (ageHi - ageLo) * frac;
3371
+ ribbonTimeFade = 1 - Math.min(age / maxTimeMs, 1);
3372
+ }
3330
3373
  const widthScale = trailWidthCurveFn(t);
3331
3374
  const opacityScale = trailOpacityCurveFn(t);
3332
3375
  const halfWidth = trailConfig.width * widthScale * 0.5;
3333
- const alpha = leaderCa * opacityScale;
3376
+ const alpha = leaderCa * opacityScale * ribbonTimeFade;
3334
3377
  const fr = trailColorOverTrailFns ? leaderCr * trailColorOverTrailFns.r(t) : leaderCr;
3335
3378
  const fg = trailColorOverTrailFns ? leaderCg * trailColorOverTrailFns.g(t) : leaderCg;
3336
3379
  const fb = trailColorOverTrailFns ? leaderCb * trailColorOverTrailFns.b(t) : leaderCb;
@@ -3360,6 +3403,55 @@ var updateTrailGeometry = (props, now) => {
3360
3403
  trailColorArr
3361
3404
  );
3362
3405
  }
3406
+ if (useTwistPrevention && prevNormal && filledCount >= 2) {
3407
+ const nIdx = leader * 3;
3408
+ const tx = _rawPoints[3] - _rawPoints[0];
3409
+ const ty = _rawPoints[4] - _rawPoints[1];
3410
+ const tz = _rawPoints[5] - _rawPoints[2];
3411
+ const tLen = Math.sqrt(tx * tx + ty * ty + tz * tz);
3412
+ if (tLen > 1e-4) {
3413
+ const ntx = tx / tLen;
3414
+ const nty = ty / tLen;
3415
+ const ntz = tz / tLen;
3416
+ let upx = 0, upy = 1, upz = 0;
3417
+ const dot = ntx * upx + nty * upy + ntz * upz;
3418
+ if (Math.abs(dot) > 0.999) {
3419
+ upx = 1;
3420
+ upy = 0;
3421
+ upz = 0;
3422
+ }
3423
+ let cnx = nty * upz - ntz * upy;
3424
+ let cny = ntz * upx - ntx * upz;
3425
+ let cnz = ntx * upy - nty * upx;
3426
+ const cnLen = Math.sqrt(cnx * cnx + cny * cny + cnz * cnz);
3427
+ if (cnLen > 1e-4) {
3428
+ cnx /= cnLen;
3429
+ cny /= cnLen;
3430
+ cnz /= cnLen;
3431
+ }
3432
+ const prevNx = prevNormal[nIdx];
3433
+ const prevNy = prevNormal[nIdx + 1];
3434
+ const prevNz = prevNormal[nIdx + 2];
3435
+ const hasPrev = prevNx !== 0 || prevNy !== 0 || prevNz !== 0;
3436
+ if (hasPrev) {
3437
+ const normalDot = cnx * prevNx + cny * prevNy + cnz * prevNz;
3438
+ if (normalDot < 0) {
3439
+ for (let s = 0; s < Math.min(filledCount, trailLength); s++) {
3440
+ const aIdx = leaderVertBase + s * 2;
3441
+ const hw = trailHalfWidthArr[aIdx];
3442
+ trailHalfWidthArr[aIdx] = -hw;
3443
+ trailHalfWidthArr[aIdx + 1] = -hw;
3444
+ }
3445
+ cnx = -cnx;
3446
+ cny = -cny;
3447
+ cnz = -cnz;
3448
+ }
3449
+ }
3450
+ prevNormal[nIdx] = cnx;
3451
+ prevNormal[nIdx + 1] = cny;
3452
+ prevNormal[nIdx + 2] = cnz;
3453
+ }
3454
+ }
3363
3455
  for (let ri = 1; ri < _ribbonCount; ri++) {
3364
3456
  const pIdx = _ribbonIndices[ri];
3365
3457
  const pVertBase = pIdx * verticesPerParticle;
@@ -3390,18 +3482,9 @@ var updateTrailGeometry = (props, now) => {
3390
3482
  trailPositionAttr.needsUpdate = true;
3391
3483
  trailAlphaAttr.needsUpdate = true;
3392
3484
  trailColorAttr.needsUpdate = true;
3393
- const nextAttr = trailMesh.geometry.getAttribute(
3394
- "trailNext"
3395
- );
3396
- const hwAttr = trailMesh.geometry.getAttribute(
3397
- "trailHalfWidth"
3398
- );
3399
- nextAttr.needsUpdate = true;
3400
- hwAttr.needsUpdate = true;
3401
- const uvAttr = trailMesh.geometry.getAttribute(
3402
- "trailUV"
3403
- );
3404
- uvAttr.needsUpdate = true;
3485
+ trailNextAttrCached.needsUpdate = true;
3486
+ trailHalfWidthAttrCached.needsUpdate = true;
3487
+ trailUVAttrCached.needsUpdate = true;
3405
3488
  }
3406
3489
  };
3407
3490
  var updateParticleSystems = (cycleData) => {