core-vfx 0.0.10 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -207,6 +207,10 @@ var MAX_ATTRACTORS = 4;
207
207
  var CURVE_RESOLUTION = 256;
208
208
 
209
209
  // src/utils.ts
210
+ var isWebGPUBackend = (renderer) => {
211
+ var _a;
212
+ return ((_a = renderer == null ? void 0 : renderer.backend) == null ? void 0 : _a.isWebGPUBackend) === true;
213
+ };
210
214
  var hexToRgb = (hex) => {
211
215
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
212
216
  return result ? [
@@ -296,6 +300,156 @@ var toRotation3D = (value) => {
296
300
  ];
297
301
  };
298
302
  var lifetimeToFadeRate = (seconds) => 1 / seconds;
303
+ var isNonDefaultRotation = (r) => {
304
+ if (r === null || r === void 0) return false;
305
+ if (typeof r === "number") return r !== 0;
306
+ if (Array.isArray(r) && r.length === 2 && typeof r[0] === "number") {
307
+ return r[0] !== 0 || r[1] !== 0;
308
+ }
309
+ if (Array.isArray(r)) {
310
+ return r.some(
311
+ (axis) => Array.isArray(axis) && (axis[0] !== 0 || axis[1] !== 0)
312
+ );
313
+ }
314
+ return false;
315
+ };
316
+ var normalizeProps = (props) => {
317
+ 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;
318
+ const maxParticles = (_a = props.maxParticles) != null ? _a : 1e4;
319
+ const size = (_b = props.size) != null ? _b : [0.1, 0.3];
320
+ const speed = (_c = props.speed) != null ? _c : [0.1, 0.1];
321
+ const fadeSize = (_d = props.fadeSize) != null ? _d : [1, 0];
322
+ const fadeOpacity = (_e = props.fadeOpacity) != null ? _e : [1, 0];
323
+ const lifetime = (_f = props.lifetime) != null ? _f : [1, 2];
324
+ const gravity = (_g = props.gravity) != null ? _g : [0, 0, 0];
325
+ const direction = (_h = props.direction) != null ? _h : [
326
+ [-1, 1],
327
+ [0, 1],
328
+ [-1, 1]
329
+ ];
330
+ const startPosition = (_i = props.startPosition) != null ? _i : [
331
+ [0, 0],
332
+ [0, 0],
333
+ [0, 0]
334
+ ];
335
+ const rotation = (_j = props.rotation) != null ? _j : [0, 0];
336
+ const rotationSpeed = (_k = props.rotationSpeed) != null ? _k : [0, 0];
337
+ const friction = (_l = props.friction) != null ? _l : { intensity: 0, easing: "linear" };
338
+ const colorStart = (_m = props.colorStart) != null ? _m : ["#ffffff"];
339
+ const colorEnd = (_n = props.colorEnd) != null ? _n : null;
340
+ const emitterRadius = (_o = props.emitterRadius) != null ? _o : [0, 1];
341
+ const emitterHeight = (_p = props.emitterHeight) != null ? _p : [0, 1];
342
+ const intensity = (_q = props.intensity) != null ? _q : 1;
343
+ const position = (_r = props.position) != null ? _r : [0, 0, 0];
344
+ const autoStart = (_s = props.autoStart) != null ? _s : true;
345
+ const delay = (_t = props.delay) != null ? _t : 0;
346
+ const emitCount = (_u = props.emitCount) != null ? _u : 1;
347
+ const emitterShape = (_v = props.emitterShape) != null ? _v : EmitterShape.BOX;
348
+ const emitterAngle = (_w = props.emitterAngle) != null ? _w : Math.PI / 4;
349
+ const emitterSurfaceOnly = (_x = props.emitterSurfaceOnly) != null ? _x : false;
350
+ const emitterDirection = (_y = props.emitterDirection) != null ? _y : [0, 1, 0];
351
+ const turbulence = (_z = props.turbulence) != null ? _z : null;
352
+ const attractors = (_A = props.attractors) != null ? _A : null;
353
+ const attractToCenter = (_B = props.attractToCenter) != null ? _B : false;
354
+ const startPositionAsDirection = (_C = props.startPositionAsDirection) != null ? _C : false;
355
+ const softParticles = (_D = props.softParticles) != null ? _D : false;
356
+ const softDistance = (_E = props.softDistance) != null ? _E : 0.5;
357
+ const collision = (_F = props.collision) != null ? _F : null;
358
+ const appearance = (_G = props.appearance) != null ? _G : Appearance.GRADIENT;
359
+ const alphaMap = (_H = props.alphaMap) != null ? _H : null;
360
+ const flipbook = (_I = props.flipbook) != null ? _I : null;
361
+ const geometry = (_J = props.geometry) != null ? _J : null;
362
+ const orientToDirection = (_K = props.orientToDirection) != null ? _K : false;
363
+ const orientAxis = (_L = props.orientAxis) != null ? _L : "z";
364
+ const stretchBySpeed = (_M = props.stretchBySpeed) != null ? _M : null;
365
+ const lighting = (_N = props.lighting) != null ? _N : Lighting.STANDARD;
366
+ const shadow = (_O = props.shadow) != null ? _O : false;
367
+ const blending = (_P = props.blending) != null ? _P : Blending.NORMAL;
368
+ const sizeRange = toRange(size, [0.1, 0.3]);
369
+ const speedRange = toRange(speed, [0.1, 0.1]);
370
+ const fadeSizeRange = toRange(fadeSize, [1, 0]);
371
+ const fadeOpacityRange = toRange(fadeOpacity, [1, 0]);
372
+ const lifetimeRange = toRange(lifetime, [1, 2]);
373
+ const direction3D = toRotation3D(direction);
374
+ const startPosition3D = toRotation3D(startPosition);
375
+ const rotation3D = toRotation3D(rotation);
376
+ const rotationSpeed3D = toRotation3D(rotationSpeed);
377
+ const emitterRadiusRange = toRange(emitterRadius, [0, 1]);
378
+ const emitterHeightRange = toRange(emitterHeight, [0, 1]);
379
+ const frictionIntensityRange = typeof friction === "object" && friction !== null && "intensity" in friction ? toRange(friction.intensity, [0, 0]) : [0, 0];
380
+ const frictionEasingType = typeof friction === "object" && friction !== null && "easing" in friction ? easingToType((_Q = friction.easing) != null ? _Q : "linear") : 0;
381
+ const startColors = colorStart.slice(0, 8).map(hexToRgb);
382
+ while (startColors.length < 8)
383
+ startColors.push(startColors[startColors.length - 1] || [1, 1, 1]);
384
+ const effectiveColorEnd = colorEnd != null ? colorEnd : colorStart;
385
+ const endColors = effectiveColorEnd.slice(0, 8).map(hexToRgb);
386
+ while (endColors.length < 8)
387
+ endColors.push(endColors[endColors.length - 1] || [1, 1, 1]);
388
+ return {
389
+ maxParticles,
390
+ sizeRange,
391
+ speedRange,
392
+ fadeSizeRange,
393
+ fadeOpacityRange,
394
+ lifetimeRange,
395
+ gravity,
396
+ direction3D,
397
+ startPosition3D,
398
+ rotation3D,
399
+ rotationSpeed3D,
400
+ frictionIntensityRange,
401
+ frictionEasingType,
402
+ startColors,
403
+ endColors,
404
+ colorStartCount: colorStart.length,
405
+ colorEndCount: effectiveColorEnd.length,
406
+ emitterRadiusRange,
407
+ emitterHeightRange,
408
+ intensity,
409
+ position,
410
+ autoStart,
411
+ delay,
412
+ emitCount,
413
+ emitterShape,
414
+ emitterAngle,
415
+ emitterSurfaceOnly,
416
+ emitterDirection,
417
+ turbulence,
418
+ attractors,
419
+ attractToCenter,
420
+ startPositionAsDirection,
421
+ softParticles,
422
+ softDistance,
423
+ collision,
424
+ appearance,
425
+ alphaMap,
426
+ flipbook,
427
+ rotation,
428
+ rotationSpeed,
429
+ geometry,
430
+ orientToDirection,
431
+ orientAxis,
432
+ stretchBySpeed,
433
+ lighting,
434
+ shadow,
435
+ blending,
436
+ depthTest: true,
437
+ renderOrder: 0,
438
+ colorStart,
439
+ colorEnd,
440
+ // Keep raw values
441
+ size,
442
+ speed,
443
+ fadeSize,
444
+ fadeOpacity,
445
+ lifetime,
446
+ direction,
447
+ startPosition,
448
+ friction,
449
+ emitterRadius,
450
+ emitterHeight
451
+ };
452
+ };
299
453
 
300
454
  // src/curves.ts
301
455
  import * as THREE2 from "three/webgpu";
@@ -511,6 +665,68 @@ var loadCurveTextureFromPath = async (path) => {
511
665
  tex.needsUpdate = true;
512
666
  return { texture: tex, activeChannels };
513
667
  };
668
+ var resolveCurveTexture = async (options) => {
669
+ const {
670
+ fadeSizeCurve = null,
671
+ fadeOpacityCurve = null,
672
+ velocityCurve = null,
673
+ rotationSpeedCurve = null,
674
+ curveTexturePath = null
675
+ } = options;
676
+ const hasAnyCurve = fadeSizeCurve || fadeOpacityCurve || velocityCurve || rotationSpeedCurve;
677
+ if (curveTexturePath) {
678
+ try {
679
+ const result = await loadCurveTextureFromPath(curveTexturePath);
680
+ return {
681
+ texture: result.texture,
682
+ sizeEnabled: !!(result.activeChannels & CurveChannel.SIZE),
683
+ opacityEnabled: !!(result.activeChannels & CurveChannel.OPACITY),
684
+ velocityEnabled: !!(result.activeChannels & CurveChannel.VELOCITY),
685
+ rotationSpeedEnabled: !!(result.activeChannels & CurveChannel.ROTATION_SPEED)
686
+ };
687
+ } catch (err) {
688
+ console.warn(
689
+ `Failed to load curve texture: ${curveTexturePath}, falling back to baking`,
690
+ err
691
+ );
692
+ if (hasAnyCurve) {
693
+ return {
694
+ texture: createCombinedCurveTexture(
695
+ fadeSizeCurve,
696
+ fadeOpacityCurve,
697
+ velocityCurve,
698
+ rotationSpeedCurve
699
+ ),
700
+ sizeEnabled: !!fadeSizeCurve,
701
+ opacityEnabled: !!fadeOpacityCurve,
702
+ velocityEnabled: !!velocityCurve,
703
+ rotationSpeedEnabled: !!rotationSpeedCurve
704
+ };
705
+ }
706
+ }
707
+ }
708
+ if (hasAnyCurve) {
709
+ return {
710
+ texture: createCombinedCurveTexture(
711
+ fadeSizeCurve,
712
+ fadeOpacityCurve,
713
+ velocityCurve,
714
+ rotationSpeedCurve
715
+ ),
716
+ sizeEnabled: !!fadeSizeCurve,
717
+ opacityEnabled: !!fadeOpacityCurve,
718
+ velocityEnabled: !!velocityCurve,
719
+ rotationSpeedEnabled: !!rotationSpeedCurve
720
+ };
721
+ }
722
+ return {
723
+ texture: createDefaultCurveTexture(),
724
+ sizeEnabled: false,
725
+ opacityEnabled: false,
726
+ velocityEnabled: false,
727
+ rotationSpeedEnabled: false
728
+ };
729
+ };
514
730
 
515
731
  // src/shaders/helpers.ts
516
732
  var selectColor = (idx, c0, c1, c2, c3, c4, c5, c6, c7) => {
@@ -816,7 +1032,9 @@ var DEFAULT_FEATURES = {
816
1032
  attractors: true,
817
1033
  collision: true,
818
1034
  rotation: true,
819
- perParticleColor: true
1035
+ perParticleColor: true,
1036
+ needsPerParticleColor: true,
1037
+ needsRotation: true
820
1038
  };
821
1039
  var createUpdateCompute = (storage, uniforms, curveTexture, maxParticles, features = {}) => {
822
1040
  const f = __spreadValues(__spreadValues({}, DEFAULT_FEATURES), features);
@@ -1277,6 +1495,957 @@ var createParticleMaterial = (storage, uniforms, curveTexture, options) => {
1277
1495
  return mat;
1278
1496
  }
1279
1497
  };
1498
+
1499
+ // src/uniforms.ts
1500
+ import * as THREE4 from "three/webgpu";
1501
+ import { uniform } from "three/tsl";
1502
+ function createUniforms(props) {
1503
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
1504
+ return {
1505
+ sizeMin: uniform(props.sizeRange[0]),
1506
+ sizeMax: uniform(props.sizeRange[1]),
1507
+ fadeSizeStart: uniform(props.fadeSizeRange[0]),
1508
+ fadeSizeEnd: uniform(props.fadeSizeRange[1]),
1509
+ fadeOpacityStart: uniform(props.fadeOpacityRange[0]),
1510
+ fadeOpacityEnd: uniform(props.fadeOpacityRange[1]),
1511
+ gravity: uniform(new THREE4.Vector3(...props.gravity)),
1512
+ frictionIntensityStart: uniform(props.frictionIntensityRange[0]),
1513
+ frictionIntensityEnd: uniform(props.frictionIntensityRange[1]),
1514
+ frictionEasingType: uniform(props.frictionEasingType),
1515
+ speedMin: uniform(props.speedRange[0]),
1516
+ speedMax: uniform(props.speedRange[1]),
1517
+ lifetimeMin: uniform(lifetimeToFadeRate(props.lifetimeRange[1])),
1518
+ lifetimeMax: uniform(lifetimeToFadeRate(props.lifetimeRange[0])),
1519
+ deltaTime: uniform(0.016),
1520
+ // 3D direction ranges
1521
+ dirMinX: uniform(props.direction3D[0][0]),
1522
+ dirMaxX: uniform(props.direction3D[0][1]),
1523
+ dirMinY: uniform(props.direction3D[1][0]),
1524
+ dirMaxY: uniform(props.direction3D[1][1]),
1525
+ dirMinZ: uniform(props.direction3D[2][0]),
1526
+ dirMaxZ: uniform(props.direction3D[2][1]),
1527
+ // 3D start position offset ranges
1528
+ startPosMinX: uniform(props.startPosition3D[0][0]),
1529
+ startPosMaxX: uniform(props.startPosition3D[0][1]),
1530
+ startPosMinY: uniform(props.startPosition3D[1][0]),
1531
+ startPosMaxY: uniform(props.startPosition3D[1][1]),
1532
+ startPosMinZ: uniform(props.startPosition3D[2][0]),
1533
+ startPosMaxZ: uniform(props.startPosition3D[2][1]),
1534
+ spawnPosition: uniform(new THREE4.Vector3(...props.position)),
1535
+ spawnIndexStart: uniform(0),
1536
+ spawnIndexEnd: uniform(0),
1537
+ spawnSeed: uniform(0),
1538
+ intensity: uniform(props.intensity),
1539
+ // 3D rotation ranges
1540
+ rotationMinX: uniform(props.rotation3D[0][0]),
1541
+ rotationMaxX: uniform(props.rotation3D[0][1]),
1542
+ rotationMinY: uniform(props.rotation3D[1][0]),
1543
+ rotationMaxY: uniform(props.rotation3D[1][1]),
1544
+ rotationMinZ: uniform(props.rotation3D[2][0]),
1545
+ rotationMaxZ: uniform(props.rotation3D[2][1]),
1546
+ // 3D rotation speed ranges
1547
+ rotationSpeedMinX: uniform(props.rotationSpeed3D[0][0]),
1548
+ rotationSpeedMaxX: uniform(props.rotationSpeed3D[0][1]),
1549
+ rotationSpeedMinY: uniform(props.rotationSpeed3D[1][0]),
1550
+ rotationSpeedMaxY: uniform(props.rotationSpeed3D[1][1]),
1551
+ rotationSpeedMinZ: uniform(props.rotationSpeed3D[2][0]),
1552
+ rotationSpeedMaxZ: uniform(props.rotationSpeed3D[2][1]),
1553
+ // Color arrays (8 colors max each)
1554
+ colorStartCount: uniform(props.colorStartCount),
1555
+ colorEndCount: uniform(props.colorEndCount),
1556
+ colorStart0: uniform(new THREE4.Color(...props.startColors[0])),
1557
+ colorStart1: uniform(new THREE4.Color(...props.startColors[1])),
1558
+ colorStart2: uniform(new THREE4.Color(...props.startColors[2])),
1559
+ colorStart3: uniform(new THREE4.Color(...props.startColors[3])),
1560
+ colorStart4: uniform(new THREE4.Color(...props.startColors[4])),
1561
+ colorStart5: uniform(new THREE4.Color(...props.startColors[5])),
1562
+ colorStart6: uniform(new THREE4.Color(...props.startColors[6])),
1563
+ colorStart7: uniform(new THREE4.Color(...props.startColors[7])),
1564
+ colorEnd0: uniform(new THREE4.Color(...props.endColors[0])),
1565
+ colorEnd1: uniform(new THREE4.Color(...props.endColors[1])),
1566
+ colorEnd2: uniform(new THREE4.Color(...props.endColors[2])),
1567
+ colorEnd3: uniform(new THREE4.Color(...props.endColors[3])),
1568
+ colorEnd4: uniform(new THREE4.Color(...props.endColors[4])),
1569
+ colorEnd5: uniform(new THREE4.Color(...props.endColors[5])),
1570
+ colorEnd6: uniform(new THREE4.Color(...props.endColors[6])),
1571
+ colorEnd7: uniform(new THREE4.Color(...props.endColors[7])),
1572
+ // Emitter shape uniforms
1573
+ emitterShapeType: uniform(props.emitterShape),
1574
+ emitterRadiusInner: uniform(props.emitterRadiusRange[0]),
1575
+ emitterRadiusOuter: uniform(props.emitterRadiusRange[1]),
1576
+ emitterAngle: uniform(props.emitterAngle),
1577
+ emitterHeightMin: uniform(props.emitterHeightRange[0]),
1578
+ emitterHeightMax: uniform(props.emitterHeightRange[1]),
1579
+ emitterSurfaceOnly: uniform(props.emitterSurfaceOnly ? 1 : 0),
1580
+ emitterDir: uniform(
1581
+ new THREE4.Vector3(...props.emitterDirection).normalize()
1582
+ ),
1583
+ // Turbulence uniforms
1584
+ turbulenceIntensity: uniform((_b = (_a = props.turbulence) == null ? void 0 : _a.intensity) != null ? _b : 0),
1585
+ turbulenceFrequency: uniform((_d = (_c = props.turbulence) == null ? void 0 : _c.frequency) != null ? _d : 1),
1586
+ turbulenceSpeed: uniform((_f = (_e = props.turbulence) == null ? void 0 : _e.speed) != null ? _f : 1),
1587
+ turbulenceTime: uniform(0),
1588
+ // Attractor uniforms (up to 4)
1589
+ attractorCount: uniform(0),
1590
+ attractor0Pos: uniform(new THREE4.Vector3(0, 0, 0)),
1591
+ attractor0Strength: uniform(0),
1592
+ attractor0Radius: uniform(1),
1593
+ attractor0Type: uniform(0),
1594
+ attractor0Axis: uniform(new THREE4.Vector3(0, 1, 0)),
1595
+ attractor1Pos: uniform(new THREE4.Vector3(0, 0, 0)),
1596
+ attractor1Strength: uniform(0),
1597
+ attractor1Radius: uniform(1),
1598
+ attractor1Type: uniform(0),
1599
+ attractor1Axis: uniform(new THREE4.Vector3(0, 1, 0)),
1600
+ attractor2Pos: uniform(new THREE4.Vector3(0, 0, 0)),
1601
+ attractor2Strength: uniform(0),
1602
+ attractor2Radius: uniform(1),
1603
+ attractor2Type: uniform(0),
1604
+ attractor2Axis: uniform(new THREE4.Vector3(0, 1, 0)),
1605
+ attractor3Pos: uniform(new THREE4.Vector3(0, 0, 0)),
1606
+ attractor3Strength: uniform(0),
1607
+ attractor3Radius: uniform(1),
1608
+ attractor3Type: uniform(0),
1609
+ attractor3Axis: uniform(new THREE4.Vector3(0, 1, 0)),
1610
+ // Simple attract to center
1611
+ attractToCenter: uniform(props.attractToCenter ? 1 : 0),
1612
+ // Use start position as direction
1613
+ startPositionAsDirection: uniform(props.startPositionAsDirection ? 1 : 0),
1614
+ // Soft particles
1615
+ softParticlesEnabled: uniform(props.softParticles ? 1 : 0),
1616
+ softDistance: uniform(props.softDistance),
1617
+ // Curve enabled flags
1618
+ velocityCurveEnabled: uniform(0),
1619
+ rotationSpeedCurveEnabled: uniform(0),
1620
+ fadeSizeCurveEnabled: uniform(0),
1621
+ fadeOpacityCurveEnabled: uniform(0),
1622
+ // Orient axis
1623
+ orientAxisType: uniform(axisToNumber(props.orientAxis)),
1624
+ // Stretch by speed
1625
+ stretchEnabled: uniform(props.stretchBySpeed ? 1 : 0),
1626
+ stretchFactor: uniform((_h = (_g = props.stretchBySpeed) == null ? void 0 : _g.factor) != null ? _h : 1),
1627
+ stretchMax: uniform((_j = (_i = props.stretchBySpeed) == null ? void 0 : _i.maxStretch) != null ? _j : 5),
1628
+ // Collision uniforms
1629
+ collisionEnabled: uniform(props.collision ? 1 : 0),
1630
+ collisionPlaneY: uniform((_m = (_l = (_k = props.collision) == null ? void 0 : _k.plane) == null ? void 0 : _l.y) != null ? _m : 0),
1631
+ collisionBounce: uniform((_o = (_n = props.collision) == null ? void 0 : _n.bounce) != null ? _o : 0.3),
1632
+ collisionFriction: uniform((_q = (_p = props.collision) == null ? void 0 : _p.friction) != null ? _q : 0.8),
1633
+ collisionDie: uniform(((_r = props.collision) == null ? void 0 : _r.die) ? 1 : 0),
1634
+ sizeBasedGravity: uniform((_t = (_s = props.collision) == null ? void 0 : _s.sizeBasedGravity) != null ? _t : 0)
1635
+ };
1636
+ }
1637
+ function updateUniforms(uniforms, props) {
1638
+ 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;
1639
+ const u = uniforms;
1640
+ u.sizeMin.value = props.sizeRange[0];
1641
+ u.sizeMax.value = props.sizeRange[1];
1642
+ u.fadeSizeStart.value = props.fadeSizeRange[0];
1643
+ u.fadeSizeEnd.value = props.fadeSizeRange[1];
1644
+ u.fadeOpacityStart.value = props.fadeOpacityRange[0];
1645
+ u.fadeOpacityEnd.value = props.fadeOpacityRange[1];
1646
+ u.gravity.value.set(...props.gravity);
1647
+ u.frictionIntensityStart.value = props.frictionIntensityRange[0];
1648
+ u.frictionIntensityEnd.value = props.frictionIntensityRange[1];
1649
+ u.frictionEasingType.value = props.frictionEasingType;
1650
+ u.speedMin.value = props.speedRange[0];
1651
+ u.speedMax.value = props.speedRange[1];
1652
+ u.lifetimeMin.value = lifetimeToFadeRate(props.lifetimeRange[1]);
1653
+ u.lifetimeMax.value = lifetimeToFadeRate(props.lifetimeRange[0]);
1654
+ u.dirMinX.value = props.direction3D[0][0];
1655
+ u.dirMaxX.value = props.direction3D[0][1];
1656
+ u.dirMinY.value = props.direction3D[1][0];
1657
+ u.dirMaxY.value = props.direction3D[1][1];
1658
+ u.dirMinZ.value = props.direction3D[2][0];
1659
+ u.dirMaxZ.value = props.direction3D[2][1];
1660
+ u.startPosMinX.value = props.startPosition3D[0][0];
1661
+ u.startPosMaxX.value = props.startPosition3D[0][1];
1662
+ u.startPosMinY.value = props.startPosition3D[1][0];
1663
+ u.startPosMaxY.value = props.startPosition3D[1][1];
1664
+ u.startPosMinZ.value = props.startPosition3D[2][0];
1665
+ u.startPosMaxZ.value = props.startPosition3D[2][1];
1666
+ u.rotationMinX.value = props.rotation3D[0][0];
1667
+ u.rotationMaxX.value = props.rotation3D[0][1];
1668
+ u.rotationMinY.value = props.rotation3D[1][0];
1669
+ u.rotationMaxY.value = props.rotation3D[1][1];
1670
+ u.rotationMinZ.value = props.rotation3D[2][0];
1671
+ u.rotationMaxZ.value = props.rotation3D[2][1];
1672
+ u.rotationSpeedMinX.value = props.rotationSpeed3D[0][0];
1673
+ u.rotationSpeedMaxX.value = props.rotationSpeed3D[0][1];
1674
+ u.rotationSpeedMinY.value = props.rotationSpeed3D[1][0];
1675
+ u.rotationSpeedMaxY.value = props.rotationSpeed3D[1][1];
1676
+ u.rotationSpeedMinZ.value = props.rotationSpeed3D[2][0];
1677
+ u.rotationSpeedMaxZ.value = props.rotationSpeed3D[2][1];
1678
+ u.intensity.value = props.intensity;
1679
+ u.colorStartCount.value = props.colorStartCount;
1680
+ u.colorEndCount.value = props.colorEndCount;
1681
+ props.startColors.forEach((c, i) => {
1682
+ var _a2;
1683
+ (_a2 = u[`colorStart${i}`]) == null ? void 0 : _a2.value.setRGB(...c);
1684
+ });
1685
+ props.endColors.forEach((c, i) => {
1686
+ var _a2;
1687
+ (_a2 = u[`colorEnd${i}`]) == null ? void 0 : _a2.value.setRGB(...c);
1688
+ });
1689
+ u.emitterShapeType.value = props.emitterShape;
1690
+ u.emitterRadiusInner.value = props.emitterRadiusRange[0];
1691
+ u.emitterRadiusOuter.value = props.emitterRadiusRange[1];
1692
+ u.emitterAngle.value = props.emitterAngle;
1693
+ u.emitterHeightMin.value = props.emitterHeightRange[0];
1694
+ u.emitterHeightMax.value = props.emitterHeightRange[1];
1695
+ u.emitterSurfaceOnly.value = props.emitterSurfaceOnly ? 1 : 0;
1696
+ u.emitterDir.value.set(...props.emitterDirection).normalize();
1697
+ u.turbulenceIntensity.value = (_b = (_a = props.turbulence) == null ? void 0 : _a.intensity) != null ? _b : 0;
1698
+ u.turbulenceFrequency.value = (_d = (_c = props.turbulence) == null ? void 0 : _c.frequency) != null ? _d : 1;
1699
+ u.turbulenceSpeed.value = (_f = (_e = props.turbulence) == null ? void 0 : _e.speed) != null ? _f : 1;
1700
+ const attractorList = (_g = props.attractors) != null ? _g : [];
1701
+ u.attractorCount.value = Math.min(attractorList.length, MAX_ATTRACTORS);
1702
+ for (let i = 0; i < MAX_ATTRACTORS; i++) {
1703
+ const a = attractorList[i];
1704
+ if (a) {
1705
+ ;
1706
+ u[`attractor${i}Pos`].value.set(
1707
+ ...(_h = a.position) != null ? _h : [0, 0, 0]
1708
+ );
1709
+ u[`attractor${i}Strength`].value = (_i = a.strength) != null ? _i : 1;
1710
+ u[`attractor${i}Radius`].value = (_j = a.radius) != null ? _j : 0;
1711
+ u[`attractor${i}Type`].value = a.type === "vortex" ? 1 : 0;
1712
+ u[`attractor${i}Axis`].value.set(...(_k = a.axis) != null ? _k : [0, 1, 0]).normalize();
1713
+ } else {
1714
+ u[`attractor${i}Strength`].value = 0;
1715
+ }
1716
+ }
1717
+ u.attractToCenter.value = props.attractToCenter ? 1 : 0;
1718
+ u.startPositionAsDirection.value = props.startPositionAsDirection ? 1 : 0;
1719
+ u.softParticlesEnabled.value = props.softParticles ? 1 : 0;
1720
+ u.softDistance.value = props.softDistance;
1721
+ u.orientAxisType.value = axisToNumber(props.orientAxis);
1722
+ u.stretchEnabled.value = props.stretchBySpeed ? 1 : 0;
1723
+ u.stretchFactor.value = (_m = (_l = props.stretchBySpeed) == null ? void 0 : _l.factor) != null ? _m : 1;
1724
+ u.stretchMax.value = (_o = (_n = props.stretchBySpeed) == null ? void 0 : _n.maxStretch) != null ? _o : 5;
1725
+ u.collisionEnabled.value = props.collision ? 1 : 0;
1726
+ u.collisionPlaneY.value = (_r = (_q = (_p = props.collision) == null ? void 0 : _p.plane) == null ? void 0 : _q.y) != null ? _r : 0;
1727
+ u.collisionBounce.value = (_t = (_s = props.collision) == null ? void 0 : _s.bounce) != null ? _t : 0.3;
1728
+ u.collisionFriction.value = (_v = (_u = props.collision) == null ? void 0 : _u.friction) != null ? _v : 0.8;
1729
+ u.collisionDie.value = ((_w = props.collision) == null ? void 0 : _w.die) ? 1 : 0;
1730
+ u.sizeBasedGravity.value = (_y = (_x = props.collision) == null ? void 0 : _x.sizeBasedGravity) != null ? _y : 0;
1731
+ }
1732
+ function updateUniformsPartial(uniforms, rawProps) {
1733
+ 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;
1734
+ const u = uniforms;
1735
+ if ("size" in rawProps) {
1736
+ const sizeR = toRange(rawProps.size, [0.1, 0.3]);
1737
+ u.sizeMin.value = sizeR[0];
1738
+ u.sizeMax.value = sizeR[1];
1739
+ }
1740
+ if ("fadeSize" in rawProps) {
1741
+ const fadeSizeR = toRange(rawProps.fadeSize, [1, 0]);
1742
+ u.fadeSizeStart.value = fadeSizeR[0];
1743
+ u.fadeSizeEnd.value = fadeSizeR[1];
1744
+ }
1745
+ if ("fadeOpacity" in rawProps) {
1746
+ const fadeOpacityR = toRange(rawProps.fadeOpacity, [1, 0]);
1747
+ u.fadeOpacityStart.value = fadeOpacityR[0];
1748
+ u.fadeOpacityEnd.value = fadeOpacityR[1];
1749
+ }
1750
+ if ("fadeSizeCurve" in rawProps) {
1751
+ u.fadeSizeCurveEnabled.value = rawProps.fadeSizeCurve ? 1 : 0;
1752
+ }
1753
+ if ("fadeOpacityCurve" in rawProps) {
1754
+ u.fadeOpacityCurveEnabled.value = rawProps.fadeOpacityCurve ? 1 : 0;
1755
+ }
1756
+ if ("velocityCurve" in rawProps) {
1757
+ u.velocityCurveEnabled.value = rawProps.velocityCurve ? 1 : 0;
1758
+ }
1759
+ if ("rotationSpeedCurve" in rawProps) {
1760
+ u.rotationSpeedCurveEnabled.value = rawProps.rotationSpeedCurve ? 1 : 0;
1761
+ }
1762
+ if ("orientAxis" in rawProps) {
1763
+ u.orientAxisType.value = axisToNumber(rawProps.orientAxis);
1764
+ }
1765
+ if ("stretchBySpeed" in rawProps) {
1766
+ u.stretchEnabled.value = rawProps.stretchBySpeed ? 1 : 0;
1767
+ u.stretchFactor.value = (_b = (_a = rawProps.stretchBySpeed) == null ? void 0 : _a.factor) != null ? _b : 1;
1768
+ u.stretchMax.value = (_d = (_c = rawProps.stretchBySpeed) == null ? void 0 : _c.maxStretch) != null ? _d : 5;
1769
+ }
1770
+ if ("gravity" in rawProps && rawProps.gravity && Array.isArray(rawProps.gravity)) {
1771
+ u.gravity.value.set(...rawProps.gravity);
1772
+ }
1773
+ if ("speed" in rawProps) {
1774
+ const speedR = toRange(rawProps.speed, [0.1, 0.1]);
1775
+ u.speedMin.value = speedR[0];
1776
+ u.speedMax.value = speedR[1];
1777
+ }
1778
+ if ("lifetime" in rawProps) {
1779
+ const lifetimeR = toRange(rawProps.lifetime, [1, 2]);
1780
+ u.lifetimeMin.value = 1 / lifetimeR[1];
1781
+ u.lifetimeMax.value = 1 / lifetimeR[0];
1782
+ }
1783
+ if ("friction" in rawProps && rawProps.friction) {
1784
+ const frictionR = toRange(rawProps.friction.intensity, [0, 0]);
1785
+ u.frictionIntensityStart.value = frictionR[0];
1786
+ u.frictionIntensityEnd.value = frictionR[1];
1787
+ u.frictionEasingType.value = easingToType(rawProps.friction.easing);
1788
+ }
1789
+ if ("direction" in rawProps) {
1790
+ const dir3D = toRotation3D(rawProps.direction);
1791
+ u.dirMinX.value = dir3D[0][0];
1792
+ u.dirMaxX.value = dir3D[0][1];
1793
+ u.dirMinY.value = dir3D[1][0];
1794
+ u.dirMaxY.value = dir3D[1][1];
1795
+ u.dirMinZ.value = dir3D[2][0];
1796
+ u.dirMaxZ.value = dir3D[2][1];
1797
+ }
1798
+ if ("startPosition" in rawProps) {
1799
+ const startPos3D = toRotation3D(rawProps.startPosition);
1800
+ u.startPosMinX.value = startPos3D[0][0];
1801
+ u.startPosMaxX.value = startPos3D[0][1];
1802
+ u.startPosMinY.value = startPos3D[1][0];
1803
+ u.startPosMaxY.value = startPos3D[1][1];
1804
+ u.startPosMinZ.value = startPos3D[2][0];
1805
+ u.startPosMaxZ.value = startPos3D[2][1];
1806
+ }
1807
+ if ("rotation" in rawProps) {
1808
+ const rot3D = toRotation3D(rawProps.rotation);
1809
+ u.rotationMinX.value = rot3D[0][0];
1810
+ u.rotationMaxX.value = rot3D[0][1];
1811
+ u.rotationMinY.value = rot3D[1][0];
1812
+ u.rotationMaxY.value = rot3D[1][1];
1813
+ u.rotationMinZ.value = rot3D[2][0];
1814
+ u.rotationMaxZ.value = rot3D[2][1];
1815
+ }
1816
+ if ("rotationSpeed" in rawProps) {
1817
+ const rotSpeed3D = toRotation3D(rawProps.rotationSpeed);
1818
+ u.rotationSpeedMinX.value = rotSpeed3D[0][0];
1819
+ u.rotationSpeedMaxX.value = rotSpeed3D[0][1];
1820
+ u.rotationSpeedMinY.value = rotSpeed3D[1][0];
1821
+ u.rotationSpeedMaxY.value = rotSpeed3D[1][1];
1822
+ u.rotationSpeedMinZ.value = rotSpeed3D[2][0];
1823
+ u.rotationSpeedMaxZ.value = rotSpeed3D[2][1];
1824
+ }
1825
+ if ("intensity" in rawProps) {
1826
+ u.intensity.value = (_e = rawProps.intensity) != null ? _e : 1;
1827
+ }
1828
+ if ("colorStart" in rawProps && rawProps.colorStart) {
1829
+ const sColors = rawProps.colorStart.slice(0, 8).map(hexToRgb);
1830
+ while (sColors.length < 8)
1831
+ sColors.push(sColors[sColors.length - 1] || [1, 1, 1]);
1832
+ u.colorStartCount.value = rawProps.colorStart.length;
1833
+ sColors.forEach((c, i) => {
1834
+ if (u[`colorStart${i}`]) u[`colorStart${i}`].value.setRGB(...c);
1835
+ });
1836
+ }
1837
+ if ("colorEnd" in rawProps) {
1838
+ const effectiveEndColors = rawProps.colorEnd || rawProps.colorStart || ["#ffffff"];
1839
+ const eColors = effectiveEndColors.slice(0, 8).map(hexToRgb);
1840
+ while (eColors.length < 8)
1841
+ eColors.push(eColors[eColors.length - 1] || [1, 1, 1]);
1842
+ u.colorEndCount.value = effectiveEndColors.length;
1843
+ eColors.forEach((c, i) => {
1844
+ if (u[`colorEnd${i}`]) u[`colorEnd${i}`].value.setRGB(...c);
1845
+ });
1846
+ }
1847
+ if ("emitterShape" in rawProps) {
1848
+ u.emitterShapeType.value = (_f = rawProps.emitterShape) != null ? _f : 0;
1849
+ }
1850
+ if ("emitterRadius" in rawProps) {
1851
+ const emitterRadiusR = toRange(rawProps.emitterRadius, [0, 1]);
1852
+ u.emitterRadiusInner.value = emitterRadiusR[0];
1853
+ u.emitterRadiusOuter.value = emitterRadiusR[1];
1854
+ }
1855
+ if ("emitterAngle" in rawProps) {
1856
+ u.emitterAngle.value = (_g = rawProps.emitterAngle) != null ? _g : Math.PI / 4;
1857
+ }
1858
+ if ("emitterHeight" in rawProps) {
1859
+ const emitterHeightR = toRange(rawProps.emitterHeight, [0, 1]);
1860
+ u.emitterHeightMin.value = emitterHeightR[0];
1861
+ u.emitterHeightMax.value = emitterHeightR[1];
1862
+ }
1863
+ if ("emitterSurfaceOnly" in rawProps) {
1864
+ u.emitterSurfaceOnly.value = rawProps.emitterSurfaceOnly ? 1 : 0;
1865
+ }
1866
+ if ("emitterDirection" in rawProps && rawProps.emitterDirection && Array.isArray(rawProps.emitterDirection)) {
1867
+ const dir = new THREE4.Vector3(
1868
+ ...rawProps.emitterDirection
1869
+ ).normalize();
1870
+ u.emitterDir.value.x = dir.x;
1871
+ u.emitterDir.value.y = dir.y;
1872
+ u.emitterDir.value.z = dir.z;
1873
+ }
1874
+ if ("turbulence" in rawProps) {
1875
+ u.turbulenceIntensity.value = (_i = (_h = rawProps.turbulence) == null ? void 0 : _h.intensity) != null ? _i : 0;
1876
+ u.turbulenceFrequency.value = (_k = (_j = rawProps.turbulence) == null ? void 0 : _j.frequency) != null ? _k : 1;
1877
+ u.turbulenceSpeed.value = (_m = (_l = rawProps.turbulence) == null ? void 0 : _l.speed) != null ? _m : 1;
1878
+ }
1879
+ if ("attractors" in rawProps) {
1880
+ const attractorList = (_n = rawProps.attractors) != null ? _n : [];
1881
+ u.attractorCount.value = Math.min(attractorList.length, MAX_ATTRACTORS);
1882
+ for (let i = 0; i < MAX_ATTRACTORS; i++) {
1883
+ const a = attractorList[i];
1884
+ if (a) {
1885
+ ;
1886
+ u[`attractor${i}Pos`].value.set(
1887
+ ...(_o = a.position) != null ? _o : [0, 0, 0]
1888
+ );
1889
+ u[`attractor${i}Strength`].value = (_p = a.strength) != null ? _p : 1;
1890
+ u[`attractor${i}Radius`].value = (_q = a.radius) != null ? _q : 0;
1891
+ u[`attractor${i}Type`].value = a.type === "vortex" ? 1 : 0;
1892
+ u[`attractor${i}Axis`].value.set(...(_r = a.axis) != null ? _r : [0, 1, 0]).normalize();
1893
+ } else {
1894
+ u[`attractor${i}Strength`].value = 0;
1895
+ }
1896
+ }
1897
+ }
1898
+ if ("attractToCenter" in rawProps) {
1899
+ u.attractToCenter.value = rawProps.attractToCenter ? 1 : 0;
1900
+ }
1901
+ if ("startPositionAsDirection" in rawProps) {
1902
+ u.startPositionAsDirection.value = rawProps.startPositionAsDirection ? 1 : 0;
1903
+ }
1904
+ if ("softParticles" in rawProps) {
1905
+ u.softParticlesEnabled.value = rawProps.softParticles ? 1 : 0;
1906
+ }
1907
+ if ("softDistance" in rawProps) {
1908
+ u.softDistance.value = (_s = rawProps.softDistance) != null ? _s : 0.5;
1909
+ }
1910
+ if ("collision" in rawProps) {
1911
+ u.collisionEnabled.value = rawProps.collision ? 1 : 0;
1912
+ u.collisionPlaneY.value = (_v = (_u = (_t = rawProps.collision) == null ? void 0 : _t.plane) == null ? void 0 : _u.y) != null ? _v : 0;
1913
+ u.collisionBounce.value = (_x = (_w = rawProps.collision) == null ? void 0 : _w.bounce) != null ? _x : 0.3;
1914
+ u.collisionFriction.value = (_z = (_y = rawProps.collision) == null ? void 0 : _y.friction) != null ? _z : 0.8;
1915
+ u.collisionDie.value = ((_A = rawProps.collision) == null ? void 0 : _A.die) ? 1 : 0;
1916
+ u.sizeBasedGravity.value = (_C = (_B = rawProps.collision) == null ? void 0 : _B.sizeBasedGravity) != null ? _C : 0;
1917
+ }
1918
+ }
1919
+ function updateUniformsCurveFlags(uniforms, flags) {
1920
+ const u = uniforms;
1921
+ u.fadeSizeCurveEnabled.value = flags.fadeSizeCurveEnabled ? 1 : 0;
1922
+ u.fadeOpacityCurveEnabled.value = flags.fadeOpacityCurveEnabled ? 1 : 0;
1923
+ u.velocityCurveEnabled.value = flags.velocityCurveEnabled ? 1 : 0;
1924
+ u.rotationSpeedCurveEnabled.value = flags.rotationSpeedCurveEnabled ? 1 : 0;
1925
+ }
1926
+ function applySpawnOverrides(uniforms, overrides) {
1927
+ if (!overrides) return null;
1928
+ const u = uniforms;
1929
+ const saved = {};
1930
+ const setUniform = (key, value) => {
1931
+ if (u[key]) {
1932
+ saved[key] = u[key].value;
1933
+ u[key].value = value;
1934
+ }
1935
+ };
1936
+ if (overrides.size !== void 0) {
1937
+ const range = toRange(overrides.size, [0.1, 0.3]);
1938
+ setUniform("sizeMin", range[0]);
1939
+ setUniform("sizeMax", range[1]);
1940
+ }
1941
+ if (overrides.speed !== void 0) {
1942
+ const range = toRange(overrides.speed, [0.1, 0.1]);
1943
+ setUniform("speedMin", range[0]);
1944
+ setUniform("speedMax", range[1]);
1945
+ }
1946
+ if (overrides.lifetime !== void 0) {
1947
+ const range = toRange(overrides.lifetime, [1, 2]);
1948
+ setUniform("lifetimeMin", 1 / range[1]);
1949
+ setUniform("lifetimeMax", 1 / range[0]);
1950
+ }
1951
+ if (overrides.direction !== void 0) {
1952
+ const dir3D = toRotation3D(overrides.direction);
1953
+ setUniform("dirMinX", dir3D[0][0]);
1954
+ setUniform("dirMaxX", dir3D[0][1]);
1955
+ setUniform("dirMinY", dir3D[1][0]);
1956
+ setUniform("dirMaxY", dir3D[1][1]);
1957
+ setUniform("dirMinZ", dir3D[2][0]);
1958
+ setUniform("dirMaxZ", dir3D[2][1]);
1959
+ }
1960
+ if (overrides.startPosition !== void 0) {
1961
+ const pos3D = toRotation3D(overrides.startPosition);
1962
+ setUniform("startPosMinX", pos3D[0][0]);
1963
+ setUniform("startPosMaxX", pos3D[0][1]);
1964
+ setUniform("startPosMinY", pos3D[1][0]);
1965
+ setUniform("startPosMaxY", pos3D[1][1]);
1966
+ setUniform("startPosMinZ", pos3D[2][0]);
1967
+ setUniform("startPosMaxZ", pos3D[2][1]);
1968
+ }
1969
+ if (overrides.gravity !== void 0) {
1970
+ saved.gravity = u.gravity.value.clone();
1971
+ u.gravity.value.set(...overrides.gravity);
1972
+ }
1973
+ if (overrides.colorStart !== void 0) {
1974
+ const colors = overrides.colorStart.slice(0, 8).map(hexToRgb);
1975
+ while (colors.length < 8)
1976
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
1977
+ setUniform("colorStartCount", overrides.colorStart.length);
1978
+ colors.forEach((c, i) => {
1979
+ if (u[`colorStart${i}`]) {
1980
+ saved[`colorStart${i}`] = u[`colorStart${i}`].value.clone();
1981
+ u[`colorStart${i}`].value.setRGB(...c);
1982
+ }
1983
+ });
1984
+ }
1985
+ if (overrides.colorEnd !== void 0) {
1986
+ const colors = overrides.colorEnd.slice(0, 8).map(hexToRgb);
1987
+ while (colors.length < 8)
1988
+ colors.push(colors[colors.length - 1] || [1, 1, 1]);
1989
+ setUniform("colorEndCount", overrides.colorEnd.length);
1990
+ colors.forEach((c, i) => {
1991
+ if (u[`colorEnd${i}`]) {
1992
+ saved[`colorEnd${i}`] = u[`colorEnd${i}`].value.clone();
1993
+ u[`colorEnd${i}`].value.setRGB(...c);
1994
+ }
1995
+ });
1996
+ }
1997
+ if (overrides.rotation !== void 0) {
1998
+ const rot3D = toRotation3D(overrides.rotation);
1999
+ setUniform("rotationMinX", rot3D[0][0]);
2000
+ setUniform("rotationMaxX", rot3D[0][1]);
2001
+ setUniform("rotationMinY", rot3D[1][0]);
2002
+ setUniform("rotationMaxY", rot3D[1][1]);
2003
+ setUniform("rotationMinZ", rot3D[2][0]);
2004
+ setUniform("rotationMaxZ", rot3D[2][1]);
2005
+ }
2006
+ if (overrides.emitterShape !== void 0) {
2007
+ setUniform("emitterShapeType", overrides.emitterShape);
2008
+ }
2009
+ if (overrides.emitterRadius !== void 0) {
2010
+ const range = toRange(overrides.emitterRadius, [0, 1]);
2011
+ setUniform("emitterRadiusInner", range[0]);
2012
+ setUniform("emitterRadiusOuter", range[1]);
2013
+ }
2014
+ if (overrides.emitterAngle !== void 0) {
2015
+ setUniform("emitterAngle", overrides.emitterAngle);
2016
+ }
2017
+ if (overrides.emitterHeight !== void 0) {
2018
+ const range = toRange(overrides.emitterHeight, [0, 1]);
2019
+ setUniform("emitterHeightMin", range[0]);
2020
+ setUniform("emitterHeightMax", range[1]);
2021
+ }
2022
+ if (overrides.emitterSurfaceOnly !== void 0) {
2023
+ setUniform("emitterSurfaceOnly", overrides.emitterSurfaceOnly ? 1 : 0);
2024
+ }
2025
+ if (overrides.emitterDirection !== void 0) {
2026
+ saved.emitterDir = u.emitterDir.value.clone();
2027
+ u.emitterDir.value.set(...overrides.emitterDirection).normalize();
2028
+ }
2029
+ return () => {
2030
+ Object.entries(saved).forEach(([key, value]) => {
2031
+ if (u[key]) {
2032
+ u[key].value = value;
2033
+ }
2034
+ });
2035
+ };
2036
+ }
2037
+
2038
+ // src/storage.ts
2039
+ import * as THREE5 from "three/webgpu";
2040
+ import { instancedArray } from "three/tsl";
2041
+ var STRUCTURAL_KEYS = [
2042
+ "maxParticles",
2043
+ "lighting",
2044
+ "appearance",
2045
+ "shadow",
2046
+ "orientToDirection"
2047
+ ];
2048
+ function resolveFeatures(props) {
2049
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2050
+ const colorStart = (_a = props.colorStart) != null ? _a : ["#ffffff"];
2051
+ const colorEnd = (_b = props.colorEnd) != null ? _b : null;
2052
+ const rotation = (_c = props.rotation) != null ? _c : [0, 0];
2053
+ const rotationSpeed = (_d = props.rotationSpeed) != null ? _d : [0, 0];
2054
+ const turbulence = (_e = props.turbulence) != null ? _e : null;
2055
+ const attractors = (_f = props.attractors) != null ? _f : null;
2056
+ const collision = (_g = props.collision) != null ? _g : null;
2057
+ const needsPerParticleColor = colorStart.length > 1 || colorEnd !== null;
2058
+ const needsRotation = isNonDefaultRotation(rotation) || isNonDefaultRotation(rotationSpeed);
2059
+ const hasTurbulence = turbulence !== null && ((_h = turbulence == null ? void 0 : turbulence.intensity) != null ? _h : 0) > 0;
2060
+ const hasAttractors = attractors !== null && attractors.length > 0;
2061
+ const hasCollision = collision !== null;
2062
+ return {
2063
+ needsPerParticleColor,
2064
+ needsRotation,
2065
+ turbulence: hasTurbulence,
2066
+ attractors: hasAttractors,
2067
+ collision: hasCollision,
2068
+ rotation: needsRotation,
2069
+ perParticleColor: needsPerParticleColor
2070
+ };
2071
+ }
2072
+ function needsRecreation(currentFeatures, changedProps, mergedConfig) {
2073
+ if (STRUCTURAL_KEYS.some((key) => key in changedProps)) return true;
2074
+ const newFeatures = resolveFeatures(mergedConfig);
2075
+ if (newFeatures.turbulence !== currentFeatures.turbulence) return true;
2076
+ if (newFeatures.attractors !== currentFeatures.attractors) return true;
2077
+ if (newFeatures.collision !== currentFeatures.collision) return true;
2078
+ if (newFeatures.needsRotation !== currentFeatures.needsRotation) return true;
2079
+ if (newFeatures.needsPerParticleColor !== currentFeatures.needsPerParticleColor)
2080
+ return true;
2081
+ return false;
2082
+ }
2083
+ function createStorageArrays(maxParticles, features) {
2084
+ const arrays = {
2085
+ positions: instancedArray(maxParticles, "vec3"),
2086
+ velocities: instancedArray(maxParticles, "vec3"),
2087
+ lifetimes: instancedArray(maxParticles, "float"),
2088
+ fadeRates: instancedArray(maxParticles, "float"),
2089
+ particleSizes: instancedArray(maxParticles, "float"),
2090
+ particleRotations: null,
2091
+ particleColorStarts: null,
2092
+ particleColorEnds: null
2093
+ };
2094
+ if (features.needsRotation) {
2095
+ arrays.particleRotations = instancedArray(maxParticles, "vec3");
2096
+ }
2097
+ if (features.needsPerParticleColor) {
2098
+ arrays.particleColorStarts = instancedArray(maxParticles, "vec3");
2099
+ arrays.particleColorEnds = instancedArray(maxParticles, "vec3");
2100
+ }
2101
+ return arrays;
2102
+ }
2103
+ function createRenderObject(geometry, material, maxParticles, shadow) {
2104
+ if (geometry) {
2105
+ const mesh = new THREE5.InstancedMesh(geometry, material, maxParticles);
2106
+ mesh.frustumCulled = false;
2107
+ mesh.castShadow = shadow;
2108
+ mesh.receiveShadow = shadow;
2109
+ return mesh;
2110
+ } else {
2111
+ const s = new THREE5.Sprite(material);
2112
+ s.count = maxParticles;
2113
+ s.frustumCulled = false;
2114
+ return s;
2115
+ }
2116
+ }
2117
+
2118
+ // src/particle-system.ts
2119
+ var VFXParticleSystem = class {
2120
+ constructor(renderer, options) {
2121
+ this.nextIndex = 0;
2122
+ this.initialized = false;
2123
+ this.emitAccumulator = 0;
2124
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2125
+ this.renderer = renderer;
2126
+ this.options = options;
2127
+ this.normalizedProps = normalizeProps(options);
2128
+ if (options.depthTest !== void 0) {
2129
+ this.normalizedProps.depthTest = options.depthTest;
2130
+ }
2131
+ if (options.renderOrder !== void 0) {
2132
+ this.normalizedProps.renderOrder = options.renderOrder;
2133
+ }
2134
+ const np = this.normalizedProps;
2135
+ this.features = resolveFeatures(options);
2136
+ this.uniforms = createUniforms(np);
2137
+ this.storage = createStorageArrays(np.maxParticles, this.features);
2138
+ if (options.fadeSizeCurve || options.fadeOpacityCurve || options.velocityCurve || options.rotationSpeedCurve) {
2139
+ this.curveTexture = createCombinedCurveTexture(
2140
+ (_a = options.fadeSizeCurve) != null ? _a : null,
2141
+ (_b = options.fadeOpacityCurve) != null ? _b : null,
2142
+ (_c = options.velocityCurve) != null ? _c : null,
2143
+ (_d = options.rotationSpeedCurve) != null ? _d : null
2144
+ );
2145
+ } else {
2146
+ this.curveTexture = createDefaultCurveTexture();
2147
+ }
2148
+ const u = this.uniforms;
2149
+ u.fadeSizeCurveEnabled.value = options.fadeSizeCurve ? 1 : 0;
2150
+ u.fadeOpacityCurveEnabled.value = options.fadeOpacityCurve ? 1 : 0;
2151
+ u.velocityCurveEnabled.value = options.velocityCurve ? 1 : 0;
2152
+ u.rotationSpeedCurveEnabled.value = options.rotationSpeedCurve ? 1 : 0;
2153
+ this.computeInit = createInitCompute(this.storage, np.maxParticles);
2154
+ this.computeSpawn = createSpawnCompute(
2155
+ this.storage,
2156
+ this.uniforms,
2157
+ np.maxParticles
2158
+ );
2159
+ this.computeUpdate = createUpdateCompute(
2160
+ this.storage,
2161
+ this.uniforms,
2162
+ this.curveTexture,
2163
+ np.maxParticles,
2164
+ {
2165
+ turbulence: this.features.turbulence,
2166
+ attractors: this.features.attractors,
2167
+ collision: this.features.collision,
2168
+ rotation: this.features.rotation,
2169
+ perParticleColor: this.features.perParticleColor
2170
+ }
2171
+ );
2172
+ this.material = createParticleMaterial(
2173
+ this.storage,
2174
+ this.uniforms,
2175
+ this.curveTexture,
2176
+ {
2177
+ alphaMap: np.alphaMap,
2178
+ flipbook: np.flipbook,
2179
+ appearance: np.appearance,
2180
+ lighting: np.lighting,
2181
+ softParticles: np.softParticles,
2182
+ geometry: np.geometry,
2183
+ orientToDirection: np.orientToDirection,
2184
+ shadow: np.shadow,
2185
+ blending: np.blending,
2186
+ opacityNode: (_e = options.opacityNode) != null ? _e : null,
2187
+ colorNode: (_f = options.colorNode) != null ? _f : null,
2188
+ backdropNode: (_g = options.backdropNode) != null ? _g : null,
2189
+ alphaTestNode: (_h = options.alphaTestNode) != null ? _h : null,
2190
+ castShadowNode: (_i = options.castShadowNode) != null ? _i : null
2191
+ }
2192
+ );
2193
+ this.renderObject = createRenderObject(
2194
+ np.geometry,
2195
+ this.material,
2196
+ np.maxParticles,
2197
+ np.shadow
2198
+ );
2199
+ this.isEmitting = np.autoStart;
2200
+ this.turbulenceSpeed = (_k = (_j = np.turbulence) == null ? void 0 : _j.speed) != null ? _k : 1;
2201
+ this.position = [...np.position];
2202
+ }
2203
+ async init() {
2204
+ if (this.initialized) return;
2205
+ await this.renderer.computeAsync(this.computeInit);
2206
+ if (this.options.curveTexturePath) {
2207
+ try {
2208
+ const result = await loadCurveTextureFromPath(
2209
+ this.options.curveTexturePath
2210
+ );
2211
+ const src = result.texture.image.data;
2212
+ const dst = this.curveTexture.image.data;
2213
+ dst.set(src);
2214
+ this.curveTexture.needsUpdate = true;
2215
+ result.texture.dispose();
2216
+ const u = this.uniforms;
2217
+ u.fadeSizeCurveEnabled.value = result.activeChannels & CurveChannel.SIZE ? 1 : 0;
2218
+ u.fadeOpacityCurveEnabled.value = result.activeChannels & CurveChannel.OPACITY ? 1 : 0;
2219
+ u.velocityCurveEnabled.value = result.activeChannels & CurveChannel.VELOCITY ? 1 : 0;
2220
+ u.rotationSpeedCurveEnabled.value = result.activeChannels & CurveChannel.ROTATION_SPEED ? 1 : 0;
2221
+ } catch (err) {
2222
+ console.warn(
2223
+ `Failed to load curve texture: ${this.options.curveTexturePath}, using baked/default`,
2224
+ err
2225
+ );
2226
+ }
2227
+ }
2228
+ this.initialized = true;
2229
+ }
2230
+ dispose() {
2231
+ if (this.material) {
2232
+ this.material.dispose();
2233
+ }
2234
+ if (this.renderObject) {
2235
+ if (this.renderObject.geometry && !this.normalizedProps.geometry) {
2236
+ this.renderObject.geometry.dispose();
2237
+ }
2238
+ }
2239
+ this.initialized = false;
2240
+ this.nextIndex = 0;
2241
+ }
2242
+ spawn(x, y, z, count = 20, overrides = null) {
2243
+ if (!this.initialized || !this.renderer) return;
2244
+ const restore = applySpawnOverrides(this.uniforms, overrides);
2245
+ const u = this.uniforms;
2246
+ const startIdx = this.nextIndex;
2247
+ const endIdx = (startIdx + count) % this.normalizedProps.maxParticles;
2248
+ u.spawnPosition.value.set(x, y, z);
2249
+ u.spawnIndexStart.value = startIdx;
2250
+ u.spawnIndexEnd.value = endIdx;
2251
+ u.spawnSeed.value = Math.random() * 1e4;
2252
+ this.nextIndex = endIdx;
2253
+ this.renderer.computeAsync(this.computeSpawn);
2254
+ if (restore) restore();
2255
+ }
2256
+ async update(delta) {
2257
+ if (!this.initialized || !this.renderer) return;
2258
+ const u = this.uniforms;
2259
+ u.deltaTime.value = delta;
2260
+ u.turbulenceTime.value += delta * this.turbulenceSpeed;
2261
+ await this.renderer.computeAsync(this.computeUpdate);
2262
+ }
2263
+ autoEmit(delta) {
2264
+ if (!this.isEmitting) return;
2265
+ const [px, py, pz] = this.position;
2266
+ const currentDelay = this.normalizedProps.delay;
2267
+ const currentEmitCount = this.normalizedProps.emitCount;
2268
+ if (!currentDelay) {
2269
+ this.spawn(px, py, pz, currentEmitCount);
2270
+ } else {
2271
+ this.emitAccumulator += delta;
2272
+ if (this.emitAccumulator >= currentDelay) {
2273
+ this.emitAccumulator -= currentDelay;
2274
+ this.spawn(px, py, pz, currentEmitCount);
2275
+ }
2276
+ }
2277
+ }
2278
+ start() {
2279
+ this.isEmitting = true;
2280
+ this.emitAccumulator = 0;
2281
+ }
2282
+ stop() {
2283
+ this.isEmitting = false;
2284
+ }
2285
+ clear() {
2286
+ ;
2287
+ this.renderer.computeAsync(this.computeInit);
2288
+ this.nextIndex = 0;
2289
+ }
2290
+ updateProps(props) {
2291
+ const np = normalizeProps(__spreadValues(__spreadValues({}, this.options), props));
2292
+ updateUniforms(this.uniforms, np);
2293
+ }
2294
+ setPosition(position) {
2295
+ this.position = [...position];
2296
+ }
2297
+ setDelay(delay) {
2298
+ this.normalizedProps.delay = delay;
2299
+ }
2300
+ setEmitCount(emitCount) {
2301
+ this.normalizedProps.emitCount = emitCount;
2302
+ }
2303
+ setTurbulenceSpeed(speed) {
2304
+ this.turbulenceSpeed = speed;
2305
+ }
2306
+ setCurveTexture(texture3) {
2307
+ this.curveTexture = texture3;
2308
+ }
2309
+ };
2310
+
2311
+ // src/emitter.ts
2312
+ import { Vector3 as Vector32 } from "three/webgpu";
2313
+ var tempVec = new Vector32();
2314
+ var EmitterController = class {
2315
+ constructor(options) {
2316
+ this.system = null;
2317
+ this.emitAccumulator = 0;
2318
+ this.hasEmittedOnce = false;
2319
+ var _a;
2320
+ this.options = __spreadValues({}, options);
2321
+ this.isEmitting = (_a = options.autoStart) != null ? _a : true;
2322
+ }
2323
+ setSystem(system) {
2324
+ this.system = system;
2325
+ }
2326
+ getSystem() {
2327
+ return this.system;
2328
+ }
2329
+ updateOptions(options) {
2330
+ this.options = __spreadValues(__spreadValues({}, this.options), options);
2331
+ if (options.autoStart !== void 0) {
2332
+ this.isEmitting = options.autoStart;
2333
+ if (options.autoStart) {
2334
+ this.hasEmittedOnce = false;
2335
+ this.emitAccumulator = 0;
2336
+ }
2337
+ }
2338
+ }
2339
+ // Transform a direction range by quaternion
2340
+ transformDirectionByQuat(dirRange, quat) {
2341
+ const minDir = tempVec.set(dirRange[0][0], dirRange[1][0], dirRange[2][0]);
2342
+ minDir.applyQuaternion(quat);
2343
+ const maxDir = new Vector32(dirRange[0][1], dirRange[1][1], dirRange[2][1]);
2344
+ maxDir.applyQuaternion(quat);
2345
+ return [
2346
+ [Math.min(minDir.x, maxDir.x), Math.max(minDir.x, maxDir.x)],
2347
+ [Math.min(minDir.y, maxDir.y), Math.max(minDir.y, maxDir.y)],
2348
+ [Math.min(minDir.z, maxDir.z), Math.max(minDir.z, maxDir.z)]
2349
+ ];
2350
+ }
2351
+ update(delta, worldPosition, worldQuaternion) {
2352
+ var _a, _b;
2353
+ if (!this.isEmitting) return;
2354
+ const loop = (_a = this.options.loop) != null ? _a : true;
2355
+ if (!loop && this.hasEmittedOnce) return;
2356
+ const delay = (_b = this.options.delay) != null ? _b : 0;
2357
+ if (delay <= 0) {
2358
+ const success = this.emitAtPosition(worldPosition, worldQuaternion);
2359
+ if (success) this.hasEmittedOnce = true;
2360
+ } else {
2361
+ this.emitAccumulator += delta;
2362
+ if (this.emitAccumulator >= delay) {
2363
+ this.emitAccumulator -= delay;
2364
+ const success = this.emitAtPosition(worldPosition, worldQuaternion);
2365
+ if (success) this.hasEmittedOnce = true;
2366
+ }
2367
+ }
2368
+ }
2369
+ emit(emitOverrides = null) {
2370
+ var _a;
2371
+ if (!((_a = this.system) == null ? void 0 : _a.spawn)) return false;
2372
+ return this.doEmit({ x: 0, y: 0, z: 0 }, void 0, emitOverrides);
2373
+ }
2374
+ emitAtPosition(worldPosition, worldQuaternion, emitOverrides = null) {
2375
+ return this.doEmit(worldPosition, worldQuaternion, emitOverrides);
2376
+ }
2377
+ burst(count, worldPosition, worldQuaternion) {
2378
+ var _a, _b, _c;
2379
+ if (!((_a = this.system) == null ? void 0 : _a.spawn)) return false;
2380
+ const direction = this.options.direction;
2381
+ let emitDir = direction;
2382
+ if (this.options.localDirection && direction && worldQuaternion) {
2383
+ emitDir = this.transformDirectionByQuat(direction, worldQuaternion);
2384
+ }
2385
+ const finalOverrides = emitDir ? __spreadProps(__spreadValues({}, this.options.overrides), { direction: emitDir }) : this.options.overrides;
2386
+ this.system.spawn(
2387
+ worldPosition.x,
2388
+ worldPosition.y,
2389
+ worldPosition.z,
2390
+ (_b = count != null ? count : this.options.emitCount) != null ? _b : 10,
2391
+ finalOverrides
2392
+ );
2393
+ if (this.options.onEmit) {
2394
+ this.options.onEmit({
2395
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
2396
+ count: (_c = count != null ? count : this.options.emitCount) != null ? _c : 10,
2397
+ direction: emitDir
2398
+ });
2399
+ }
2400
+ return true;
2401
+ }
2402
+ start() {
2403
+ this.isEmitting = true;
2404
+ this.hasEmittedOnce = false;
2405
+ this.emitAccumulator = 0;
2406
+ }
2407
+ stop() {
2408
+ this.isEmitting = false;
2409
+ }
2410
+ doEmit(worldPosition, worldQuaternion, emitOverrides = null) {
2411
+ var _a, _c;
2412
+ if (!((_a = this.system) == null ? void 0 : _a.spawn)) return false;
2413
+ const direction = this.options.direction;
2414
+ let emitDir = direction;
2415
+ if (this.options.localDirection && direction && worldQuaternion) {
2416
+ emitDir = this.transformDirectionByQuat(direction, worldQuaternion);
2417
+ }
2418
+ const emitTimeDirection = emitOverrides == null ? void 0 : emitOverrides.direction;
2419
+ let finalDir = emitDir;
2420
+ if (emitTimeDirection && this.options.localDirection && worldQuaternion) {
2421
+ finalDir = this.transformDirectionByQuat(
2422
+ emitTimeDirection,
2423
+ worldQuaternion
2424
+ );
2425
+ } else if (emitTimeDirection) {
2426
+ finalDir = emitTimeDirection;
2427
+ }
2428
+ const _b = emitOverrides || {}, { direction: _ } = _b, emitOverridesWithoutDir = __objRest(_b, ["direction"]);
2429
+ const mergedOverrides = __spreadValues(__spreadValues({}, this.options.overrides), emitOverridesWithoutDir);
2430
+ const finalOverrides = finalDir ? __spreadProps(__spreadValues({}, mergedOverrides), { direction: finalDir }) : mergedOverrides;
2431
+ const emitCount = (_c = this.options.emitCount) != null ? _c : 10;
2432
+ this.system.spawn(
2433
+ worldPosition.x,
2434
+ worldPosition.y,
2435
+ worldPosition.z,
2436
+ emitCount,
2437
+ finalOverrides
2438
+ );
2439
+ if (this.options.onEmit) {
2440
+ this.options.onEmit({
2441
+ position: [worldPosition.x, worldPosition.y, worldPosition.z],
2442
+ count: emitCount,
2443
+ direction: finalDir
2444
+ });
2445
+ }
2446
+ return true;
2447
+ }
2448
+ };
1280
2449
  export {
1281
2450
  Appearance,
1282
2451
  AttractorType,
@@ -1285,9 +2454,13 @@ export {
1285
2454
  CurveChannel,
1286
2455
  DEFAULT_LINEAR_CURVE,
1287
2456
  Easing,
2457
+ EmitterController,
1288
2458
  EmitterShape,
1289
2459
  Lighting,
1290
2460
  MAX_ATTRACTORS,
2461
+ STRUCTURAL_KEYS,
2462
+ VFXParticleSystem,
2463
+ applySpawnOverrides,
1291
2464
  axisToNumber,
1292
2465
  bakeCurveToArray,
1293
2466
  buildCurveTextureBin,
@@ -1296,15 +2469,27 @@ export {
1296
2469
  createDefaultCurveTexture,
1297
2470
  createInitCompute,
1298
2471
  createParticleMaterial,
2472
+ createRenderObject,
1299
2473
  createSpawnCompute,
2474
+ createStorageArrays,
2475
+ createUniforms,
1300
2476
  createUpdateCompute,
1301
2477
  easingToType,
1302
2478
  evaluateBezierSegment,
1303
2479
  hexToRgb,
2480
+ isNonDefaultRotation,
2481
+ isWebGPUBackend,
1304
2482
  lifetimeToFadeRate,
1305
2483
  loadCurveTextureFromPath,
2484
+ needsRecreation,
2485
+ normalizeProps,
2486
+ resolveCurveTexture,
2487
+ resolveFeatures,
1306
2488
  sampleCurveAtX,
1307
2489
  selectColor,
1308
2490
  toRange,
1309
- toRotation3D
2491
+ toRotation3D,
2492
+ updateUniforms,
2493
+ updateUniformsCurveFlags,
2494
+ updateUniformsPartial
1310
2495
  };