sparcoon 0.5.0 → 0.6.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.
Files changed (106) hide show
  1. package/README.md +6 -6
  2. package/dist/emitter/FXEmitter.Internal.d.ts +50 -2
  3. package/dist/emitter/FXEmitter.Internal.js +1 -2
  4. package/dist/emitter/FXEmitter.d.ts +48 -1
  5. package/dist/emitter/FXEmitter.js +74 -11
  6. package/dist/emitter/behavior/FXBehavior.d.ts +12 -2
  7. package/dist/emitter/behavior/FXBehavior.js +3 -2
  8. package/dist/emitter/behavior/FXBehaviorDirectionalForce.d.ts +25 -0
  9. package/dist/emitter/behavior/FXBehaviorDirectionalForce.js +74 -0
  10. package/dist/emitter/behavior/FXBehaviorPointForce.d.ts +40 -0
  11. package/dist/emitter/behavior/FXBehaviorPointForce.js +98 -0
  12. package/dist/emitter/behavior/FXBehaviorScaleOverLife.d.ts +9 -8
  13. package/dist/emitter/behavior/FXBehaviorScaleOverLife.js +12 -29
  14. package/dist/emitter/behavior/FXBehaviorTorqueDamping.d.ts +4 -3
  15. package/dist/emitter/behavior/FXBehaviorTorqueDamping.js +3 -2
  16. package/dist/emitter/behavior/FXBehaviorTorqueNoise.d.ts +4 -3
  17. package/dist/emitter/behavior/FXBehaviorTorqueNoise.js +3 -2
  18. package/dist/emitter/behavior/FXBehaviorTorqueOverLife.d.ts +17 -0
  19. package/dist/emitter/behavior/FXBehaviorTorqueOverLife.js +34 -0
  20. package/dist/emitter/behavior/FXBehaviorVelocityDamping.d.ts +3 -2
  21. package/dist/emitter/behavior/FXBehaviorVelocityDamping.js +3 -2
  22. package/dist/emitter/behavior/FXBehaviorVelocityNoise.d.ts +6 -5
  23. package/dist/emitter/behavior/FXBehaviorVelocityNoise.js +6 -5
  24. package/dist/emitter/behavior/FXBehaviorVelocityOverLife.d.ts +20 -0
  25. package/dist/emitter/behavior/FXBehaviorVelocityOverLife.js +48 -0
  26. package/dist/emitter/spawn/FXSpawn.d.ts +4 -2
  27. package/dist/emitter/spawn/FXSpawn.js +3 -2
  28. package/dist/emitter/spawn/FXSpawnBox.d.ts +8 -16
  29. package/dist/emitter/spawn/FXSpawnBox.js +23 -39
  30. package/dist/emitter/spawn/{FXSpawnRandomLifetime.d.ts → FXSpawnLifetime.d.ts} +3 -5
  31. package/dist/emitter/spawn/{FXSpawnRandomLifetime.js → FXSpawnLifetime.js} +8 -10
  32. package/dist/emitter/spawn/FXSpawnOffset.d.ts +9 -0
  33. package/dist/emitter/spawn/FXSpawnOffset.js +9 -0
  34. package/dist/emitter/spawn/FXSpawnPoint.d.ts +8 -0
  35. package/dist/emitter/spawn/FXSpawnPoint.js +8 -0
  36. package/dist/emitter/spawn/{FXSpawnRandomRotation.d.ts → FXSpawnRotation.d.ts} +3 -5
  37. package/dist/emitter/spawn/{FXSpawnRandomRotation.js → FXSpawnRotation.js} +8 -10
  38. package/dist/emitter/spawn/{FXSpawnRandomScale.d.ts → FXSpawnScale.d.ts} +4 -6
  39. package/dist/emitter/spawn/{FXSpawnRandomScale.js → FXSpawnScale.js} +12 -14
  40. package/dist/emitter/spawn/FXSpawnSphere.d.ts +11 -6
  41. package/dist/emitter/spawn/FXSpawnSphere.js +11 -6
  42. package/dist/emitter/spawn/{FXSpawnRandomTorque.d.ts → FXSpawnTorque.d.ts} +3 -5
  43. package/dist/emitter/spawn/{FXSpawnRandomTorque.js → FXSpawnTorque.js} +8 -10
  44. package/dist/emitter/spawn/FXSpawnVelocity.d.ts +32 -0
  45. package/dist/emitter/spawn/{FXSpawnRandomVelocity.js → FXSpawnVelocity.js} +26 -11
  46. package/dist/index.d.ts +23 -16
  47. package/dist/index.js +20 -16
  48. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.d.ts +4 -4
  49. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.js +2 -2
  50. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.d.ts +55 -5
  51. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.js +9 -2
  52. package/dist/materials/FXMaterial/FXDepthMaterial.Internal.d.ts +3 -3
  53. package/dist/materials/FXMaterial/FXDistanceMaterial.Internal.d.ts +3 -3
  54. package/dist/materials/FXMaterial/FXMaterial.d.ts +51 -5
  55. package/dist/materials/FXMaterial/FXMaterial.js +5 -0
  56. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.Internal.d.ts +3 -3
  57. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.d.ts +3 -3
  58. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.js +3 -3
  59. package/dist/miscellaneous/curve/FXCurve1D.Internal.d.ts +20 -0
  60. package/dist/miscellaneous/curve/FXCurve1D.d.ts +17 -0
  61. package/dist/miscellaneous/curve/FXCurve1D.js +94 -0
  62. package/dist/miscellaneous/miscellaneous.d.ts +3 -1
  63. package/dist/miscellaneous/miscellaneous.js +8 -4
  64. package/dist/miscellaneous/texture/FXTextureView.Internal.js +6 -0
  65. package/dist/miscellaneous/texture/FXTextureView.js +234 -0
  66. package/dist/nodes/color/FXNodeColor.d.ts +7 -0
  67. package/dist/nodes/color/FXNodeColor.js +11 -0
  68. package/dist/nodes/color/FXNodeColorOverLife.d.ts +25 -0
  69. package/dist/nodes/color/FXNodeColorOverLife.js +60 -0
  70. package/dist/nodes/color/FXNodeSphericalClip.d.ts +18 -0
  71. package/dist/nodes/color/FXNodeSphericalClip.js +45 -0
  72. package/dist/nodes/normal/FXNodeFlatNormal.d.ts +7 -0
  73. package/dist/nodes/normal/FXNodeFlatNormal.js +17 -0
  74. package/dist/nodes/normal/FXNodeNormal.d.ts +7 -0
  75. package/dist/nodes/normal/FXNodeNormal.js +7 -0
  76. package/dist/nodes/normal/FXNodeSphericalNormal.d.ts +7 -0
  77. package/dist/nodes/normal/{FXSphericalNormalNode.js → FXNodeSphericalNormal.js} +7 -4
  78. package/dist/nodes/texture/FXNodeAnimatedTexture.d.ts +47 -0
  79. package/dist/nodes/texture/FXNodeAnimatedTexture.js +137 -0
  80. package/dist/nodes/texture/FXNodeStaticTexture.d.ts +18 -0
  81. package/dist/nodes/texture/FXNodeStaticTexture.js +60 -0
  82. package/dist/nodes/texture/FXNodeTexture.d.ts +7 -0
  83. package/dist/nodes/texture/FXNodeTexture.js +11 -0
  84. package/package.json +2 -4
  85. package/dist/emitter/behavior/FXBehaviorDirectionalGravity.d.ts +0 -21
  86. package/dist/emitter/behavior/FXBehaviorDirectionalGravity.js +0 -51
  87. package/dist/emitter/behavior/FXBehaviorPointGravity.d.ts +0 -39
  88. package/dist/emitter/behavior/FXBehaviorPointGravity.js +0 -116
  89. package/dist/emitter/spawn/FXSpawnRandomVelocity.d.ts +0 -17
  90. package/dist/nodes/color/FXColorNode.d.ts +0 -3
  91. package/dist/nodes/color/FXColorNode.js +0 -8
  92. package/dist/nodes/color/FXColorOverLifeNode.d.ts +0 -6
  93. package/dist/nodes/color/FXColorOverLifeNode.js +0 -44
  94. package/dist/nodes/color/FXSphericalClipNode.d.ts +0 -5
  95. package/dist/nodes/color/FXSphericalClipNode.js +0 -30
  96. package/dist/nodes/normal/FXFlatNormalNode.d.ts +0 -4
  97. package/dist/nodes/normal/FXFlatNormalNode.js +0 -14
  98. package/dist/nodes/normal/FXNormalNode.d.ts +0 -3
  99. package/dist/nodes/normal/FXNormalNode.js +0 -4
  100. package/dist/nodes/normal/FXSphericalNormalNode.d.ts +0 -4
  101. package/dist/nodes/texture/FXAnimatedTextureNode.d.ts +0 -12
  102. package/dist/nodes/texture/FXAnimatedTextureNode.js +0 -88
  103. package/dist/nodes/texture/FXStaticTextureNode.d.ts +0 -6
  104. package/dist/nodes/texture/FXStaticTextureNode.js +0 -34
  105. package/dist/nodes/texture/FXTextureNode.d.ts +0 -3
  106. package/dist/nodes/texture/FXTextureNode.js +0 -8
@@ -1,24 +1,74 @@
1
1
  import type { ColorRepresentation } from "three";
2
- import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
- import type { FXNormalNode } from "../../nodes/normal/FXNormalNode";
4
- import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
2
+ import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
3
+ import type { FXNodeNormal } from "../../nodes/normal/FXNodeNormal";
4
+ import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
5
5
  import type { FXMaterialOptions } from "../FXMaterial/FXMaterial";
6
6
  import { FXMaterial } from "../FXMaterial/FXMaterial";
7
+ /**
8
+ * Configuration options for {@link FXDiffuseMaterial}
9
+ */
7
10
  export interface FXDiffuseMaterialOptions extends FXMaterialOptions {
8
- normalNodes: (FXTextureNode | FXNormalNode)[];
9
- emissionNodes: (FXColorNode | FXTextureNode)[];
11
+ /**
12
+ * Normal nodes for lighting; multiple nodes are blended together
13
+ *
14
+ * @defaultValue `[new FXNodeSphericalNormal()]`
15
+ */
16
+ normalNodes: (FXNodeTexture | FXNodeNormal)[];
17
+ /**
18
+ * Emission color nodes composited for emissive output
19
+ *
20
+ * @defaultValue `[]`
21
+ */
22
+ emissionNodes: (FXNodeColor | FXNodeTexture)[];
23
+ /**
24
+ * Enable subsurface scattering approximation
25
+ *
26
+ * @defaultValue `false`
27
+ */
10
28
  enableScatter: boolean;
29
+ /**
30
+ * Tint color applied to the scatter contribution
31
+ *
32
+ * @defaultValue `0xffd999`
33
+ */
11
34
  scatterTint: ColorRepresentation;
35
+ /**
36
+ * Scatter lobe sharpness; higher values produce a tighter highlight
37
+ *
38
+ * @defaultValue `10`
39
+ */
12
40
  scatterPower: number;
41
+ /**
42
+ * Forward scatter intensity (light-facing side)
43
+ *
44
+ * @defaultValue `1`
45
+ */
13
46
  forwardScatterStrength: number;
47
+ /**
48
+ * Back scatter intensity (back-lit side)
49
+ *
50
+ * @defaultValue `1`
51
+ */
14
52
  backScatterStrength: number;
53
+ /**
54
+ * Shadow influence (`0` = no shadows, `1` = full shadows)
55
+ *
56
+ * @defaultValue `1`
57
+ */
15
58
  shadowSensitivity: number;
16
59
  }
60
+ /**
61
+ * Diffuse particle material with lighting, normals, emission, and optional subsurface scattering
62
+ */
17
63
  export declare class FXDiffuseMaterial extends FXMaterial {
18
64
  private readonly normalNodes;
19
65
  private readonly emissionNodes;
20
66
  private readonly scatterUniforms;
21
67
  private readonly shadowSensitivity;
68
+ /**
69
+ * @param options - Material configuration
70
+ */
22
71
  constructor(options?: Partial<FXDiffuseMaterialOptions>);
72
+ /** Releases resources held by all albedo, normal, and emission nodes */
23
73
  destroy(): void;
24
74
  }
@@ -1,12 +1,18 @@
1
1
  import { FXColor } from '../../miscellaneous/color/FXColor.js';
2
- import { FXSphericalNormalNode } from '../../nodes/normal/FXSphericalNormalNode.js';
2
+ import { FXNodeSphericalNormal } from '../../nodes/normal/FXNodeSphericalNormal.js';
3
3
  import { FXMaterial } from '../FXMaterial/FXMaterial.js';
4
4
  import { buildFXDiffuseMaterial } from './FXDiffuseMaterial.Internal.js';
5
5
 
6
+ /**
7
+ * Diffuse particle material with lighting, normals, emission, and optional subsurface scattering
8
+ */
6
9
  class FXDiffuseMaterial extends FXMaterial {
10
+ /**
11
+ * @param options - Material configuration
12
+ */
7
13
  constructor(options = {}) {
8
14
  super(options);
9
- this._private_normalNodes = options.normalNodes ?? [new FXSphericalNormalNode()];
15
+ this._private_normalNodes = options.normalNodes ?? [new FXNodeSphericalNormal()];
10
16
  this._private_emissionNodes = options.emissionNodes ?? [];
11
17
  this._private_scatterUniforms =
12
18
  options.enableScatter === true
@@ -23,6 +29,7 @@ class FXDiffuseMaterial extends FXMaterial {
23
29
  : undefined;
24
30
  this._private_shadowSensitivity = { value: options.shadowSensitivity ?? 1 };
25
31
  }
32
+ /** Releases resources held by all albedo, normal, and emission nodes */
26
33
  destroy() {
27
34
  super.destroy();
28
35
  for (const node of this._private_normalNodes) {
@@ -1,4 +1,4 @@
1
1
  import { MeshDepthMaterial } from "three";
2
- import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
- import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
4
- export declare function buildDepthMaterial(albedoNodes: readonly (FXColorNode | FXTextureNode)[], depthAlphaTest: number, useDepthAlphaHash: boolean, useSphericalDepth: boolean): MeshDepthMaterial;
2
+ import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
3
+ import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
4
+ export declare function buildDepthMaterial(albedoNodes: readonly (FXNodeColor | FXNodeTexture)[], depthAlphaTest: number, useDepthAlphaHash: boolean, useSphericalDepth: boolean): MeshDepthMaterial;
@@ -1,4 +1,4 @@
1
1
  import { MeshDistanceMaterial } from "three";
2
- import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
- import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
4
- export declare function buildDistanceMaterial(albedoNodes: readonly (FXColorNode | FXTextureNode)[], distanceAlphaTest: number, useDistanceAlphaHash: boolean, useSphericalDepth: boolean): MeshDistanceMaterial;
2
+ import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
3
+ import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
4
+ export declare function buildDistanceMaterial(albedoNodes: readonly (FXNodeColor | FXNodeTexture)[], distanceAlphaTest: number, useDistanceAlphaHash: boolean, useSphericalDepth: boolean): MeshDistanceMaterial;
@@ -1,21 +1,67 @@
1
- import type { Blending, MeshDistanceMaterial } from "three";
2
- import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
- import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
1
+ import type { Blending } from "three";
2
+ import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
3
+ import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
4
+ /**
5
+ * Configuration options shared by all {@link FXMaterial} subclasses
6
+ */
4
7
  export interface FXMaterialOptions {
5
- albedoNodes: (FXColorNode | FXTextureNode)[];
8
+ /**
9
+ * Color and texture nodes composited for particle color
10
+ *
11
+ * @defaultValue `[]`
12
+ */
13
+ albedoNodes: (FXNodeColor | FXNodeTexture)[];
14
+ /**
15
+ * Three.js blending mode
16
+ *
17
+ * @defaultValue `NormalBlending`
18
+ */
6
19
  blending: Blending;
20
+ /**
21
+ * Use alpha hashing instead of standard transparency
22
+ *
23
+ * @defaultValue `false`
24
+ */
7
25
  useAlphaHashing: boolean;
26
+ /**
27
+ * Alpha cutoff threshold for color passes
28
+ *
29
+ * @defaultValue `0.0075`
30
+ */
8
31
  alphaTest: number;
32
+ /**
33
+ * Alpha cutoff threshold for depth and shadow passes
34
+ *
35
+ * @defaultValue `0.5`
36
+ */
9
37
  depthAlphaTest: number;
38
+ /**
39
+ * Use alpha hashing in depth and shadow passes
40
+ *
41
+ * @defaultValue `false`
42
+ */
10
43
  useDepthAlphaHash: boolean;
44
+ /**
45
+ * Approximate spherical depth for shadow maps
46
+ *
47
+ * @defaultValue `true`
48
+ */
11
49
  useSphericalDepth: boolean;
50
+ /**
51
+ * Use premultiplied alpha blending
52
+ *
53
+ * @defaultValue `true`
54
+ */
12
55
  premultipliedAlpha: boolean;
13
56
  }
57
+ /**
58
+ * Abstract base class for particle materials
59
+ */
14
60
  export declare abstract class FXMaterial {
15
61
  private readonly depthAlphaTest;
16
62
  private readonly useDepthAlphaHash;
17
63
  private readonly useSphericalDepth;
18
64
  constructor(options?: Partial<FXMaterialOptions>);
65
+ /** Releases resources held by all albedo nodes */
19
66
  destroy(): void;
20
- buildDistanceMaterial(): MeshDistanceMaterial;
21
67
  }
@@ -2,6 +2,9 @@ import { NormalBlending } from 'three';
2
2
  import { buildDepthMaterial } from './FXDepthMaterial.Internal.js';
3
3
  import { buildDistanceMaterial } from './FXDistanceMaterial.Internal.js';
4
4
 
5
+ /**
6
+ * Abstract base class for particle materials
7
+ */
5
8
  class FXMaterial {
6
9
  constructor(options = {}) {
7
10
  this.albedoNodes = options.albedoNodes ?? [];
@@ -14,6 +17,7 @@ class FXMaterial {
14
17
  this._private_useDepthAlphaHash = options.useDepthAlphaHash ?? false;
15
18
  this._private_useSphericalDepth = options.useSphericalDepth ?? true;
16
19
  }
20
+ /** Releases resources held by all albedo nodes */
17
21
  destroy() {
18
22
  for (const node of this.albedoNodes) {
19
23
  node.destroy?.();
@@ -23,6 +27,7 @@ class FXMaterial {
23
27
  buildDepthMaterial() {
24
28
  return buildDepthMaterial(this.albedoNodes, this._private_depthAlphaTest, this._private_useDepthAlphaHash, this._private_useSphericalDepth);
25
29
  }
30
+ /** @internal */
26
31
  buildDistanceMaterial() {
27
32
  return buildDistanceMaterial(this.albedoNodes, this._private_depthAlphaTest, this._private_useDepthAlphaHash, this._private_useSphericalDepth);
28
33
  }
@@ -1,6 +1,6 @@
1
1
  import type { Blending } from "three";
2
2
  import { MeshBasicMaterial } from "three";
3
3
  import type { GLTypeInfo } from "../../instancedParticle/shared";
4
- import type { FXColorNode } from "../../nodes/color/FXColorNode";
5
- import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
6
- export declare function buildFXUnlitMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, alphaTest: number, premultipliedAlpha: boolean, albedoNodes: readonly (FXColorNode | FXTextureNode)[]): MeshBasicMaterial;
4
+ import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
5
+ import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
6
+ export declare function buildFXUnlitMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, alphaTest: number, premultipliedAlpha: boolean, albedoNodes: readonly (FXNodeColor | FXNodeTexture)[]): MeshBasicMaterial;
@@ -1,6 +1,6 @@
1
- import type { FXMaterialOptions } from "../FXMaterial/FXMaterial";
2
1
  import { FXMaterial } from "../FXMaterial/FXMaterial";
3
- export type FXUnlitMaterialOptions = FXMaterialOptions;
2
+ /**
3
+ * Unlit particle material - renders particles without lighting or shadows
4
+ */
4
5
  export declare class FXUnlitMaterial extends FXMaterial {
5
- constructor(options?: Partial<FXUnlitMaterialOptions>);
6
6
  }
@@ -1,10 +1,10 @@
1
1
  import { FXMaterial } from '../FXMaterial/FXMaterial.js';
2
2
  import { buildFXUnlitMaterial } from './FXUnlitMaterial.Internal.js';
3
3
 
4
+ /**
5
+ * Unlit particle material - renders particles without lighting or shadows
6
+ */
4
7
  class FXUnlitMaterial extends FXMaterial {
5
- constructor(options = {}) {
6
- super(options);
7
- }
8
8
  /** @internal */
9
9
  buildThreeMaterial(varyings) {
10
10
  return buildFXUnlitMaterial(varyings, this.blending, this.useAlphaHashing, this.alphaTest, this.premultipliedAlpha, this.albedoNodes);
@@ -0,0 +1,20 @@
1
+ import type { FXCurve1D } from "./FXCurve1D";
2
+ /** Input point for {@link FXCurve1D}. */
3
+ export interface FXCurve1DPoint<T> {
4
+ /** Output value at this position. */
5
+ value: T;
6
+ /** Normalized position in [0, 1]. */
7
+ position: number;
8
+ }
9
+ /**
10
+ * Accepts either:
11
+ * - Explicit anchor points ({@link FXCurve1DPoint}\<T>[])
12
+ * - A uniform shorthand (`T[]`) where anchors are distributed evenly across [0, 1]
13
+ * - Another {@link FXCurve1D}\<T> instance to copy anchors from
14
+ */
15
+ export type FXCurve1DConfig<T> = FXCurve1DPoint<T>[] | T[] | FXCurve1D<T>;
16
+ /** Resolved anchor stored internally by {@link FXCurve1D}. */
17
+ export interface FXCurve1DAnchor<T> {
18
+ readonly value: T;
19
+ readonly position: number;
20
+ }
@@ -0,0 +1,17 @@
1
+ import type { FXCurve1DAnchor, FXCurve1DConfig, FXCurve1DPoint } from "./FXCurve1D.Internal";
2
+ export type { FXCurve1DAnchor, FXCurve1DConfig, FXCurve1DPoint };
3
+ /**
4
+ * 1D curve defined by anchor points at explicit normalized positions.
5
+ *
6
+ * Anchors must be strictly ascending by `value`, first must be `0`, last must be `1`.
7
+ * Output at each anchor is a value of type `T` - interpolation is left to the caller.
8
+ */
9
+ export declare class FXCurve1D<T> {
10
+ private readonly anchorsInternal;
11
+ /**
12
+ * @param config - Explicit anchor points, a uniform shorthand array, or another {@link FXCurve1D} to copy
13
+ */
14
+ constructor(config: FXCurve1DConfig<T>);
15
+ /** Resolved anchor points ordered ascending by `value`. */
16
+ get anchors(): readonly FXCurve1DAnchor<T>[];
17
+ }
@@ -0,0 +1,94 @@
1
+ import { assertValidNumber } from '../asserts.js';
2
+
3
+ /**
4
+ * 1D curve defined by anchor points at explicit normalized positions.
5
+ *
6
+ * Anchors must be strictly ascending by `value`, first must be `0`, last must be `1`.
7
+ * Output at each anchor is a value of type `T` - interpolation is left to the caller.
8
+ */
9
+ class FXCurve1D {
10
+ /**
11
+ * @param config - Explicit anchor points, a uniform shorthand array, or another {@link FXCurve1D} to copy
12
+ */
13
+ constructor(config) {
14
+ if (config instanceof FXCurve1D) {
15
+ this._private_anchorsInternal = config._private_anchorsInternal.map((anchor) => ({ ...anchor }));
16
+ return;
17
+ }
18
+ const isPointArray = config.length > 0 &&
19
+ typeof config[0] === "object" &&
20
+ !Array.isArray(config[0]) &&
21
+ "value" in config[0];
22
+ const points = isPointArray
23
+ ? config
24
+ : config.map((value, index) => ({
25
+ value,
26
+ position: index / (config.length - 1),
27
+ }));
28
+ if (points.length < 2) {
29
+ throw new Error("FXCurve1D: at least 2 anchor points are required");
30
+ }
31
+ if (points[0].position !== 0) {
32
+ throw new Error(`FXCurve1D: first anchor value must be 0, got ${points[0].position}`);
33
+ }
34
+ if (points[points.length - 1].position !== 1) {
35
+ throw new Error(`FXCurve1D: last anchor value must be 1, got ${points[points.length - 1].position}`);
36
+ }
37
+ this._private_anchorsInternal = [];
38
+ for (let index = 0; index < points.length; index++) {
39
+ const { value, position } = points[index];
40
+ if (position < 0 || position > 1) {
41
+ throw new Error(`FXCurve1D: anchor[${index}].value must be in [0, 1], got ${position}`);
42
+ }
43
+ if (index > 0 && position <= points[index - 1].position) {
44
+ throw new Error(`FXCurve1D: anchor[${index}].value (${position}) must be strictly greater than anchor[${index - 1}].value (${points[index - 1].position})`);
45
+ }
46
+ this._private_anchorsInternal.push({ value, position });
47
+ }
48
+ }
49
+ /** Resolved anchor points ordered ascending by `value`. */
50
+ get anchors() {
51
+ return this._private_anchorsInternal;
52
+ }
53
+ /**
54
+ * Samples the curve at normalized position `t`.
55
+ *
56
+ * Returns the two bracketing anchor values and the local interpolation factor `t` in [0, 1].
57
+ * The caller is responsible for interpolating between `a` and `b` using `t`.
58
+ *
59
+ * @param t - Normalized position in [0, 1]
60
+ * @internal
61
+ */
62
+ sample(t) {
63
+ assertValidNumber(t, "FXCurve1D.sample.t");
64
+ const anchors = this._private_anchorsInternal;
65
+ const anchorCount = anchors.length;
66
+ let segmentIndex;
67
+ if (anchorCount < 10) {
68
+ segmentIndex = 0;
69
+ while (segmentIndex < anchorCount - 2 && anchors[segmentIndex + 1].position <= t) {
70
+ segmentIndex++;
71
+ }
72
+ }
73
+ else {
74
+ let low = 0;
75
+ let high = anchorCount - 2;
76
+ while (low < high) {
77
+ const mid = (low + high + 1) >> 1;
78
+ if (anchors[mid].position <= t) {
79
+ low = mid;
80
+ }
81
+ else {
82
+ high = mid - 1;
83
+ }
84
+ }
85
+ segmentIndex = low;
86
+ }
87
+ const anchorA = anchors[segmentIndex];
88
+ const anchorB = anchors[segmentIndex + 1];
89
+ const localT = (t - anchorA.position) / (anchorB.position - anchorA.position);
90
+ return { a: anchorA.value, b: anchorB.value, t: localT };
91
+ }
92
+ }
93
+
94
+ export { FXCurve1D };
@@ -3,6 +3,8 @@ import { DataTexture } from "three";
3
3
  import type { Vector3Like } from "../miscellaneous/math";
4
4
  import type { FXTextureConfig } from "../miscellaneous/texture/FXTextureView.Internal";
5
5
  import type { FXColor } from "./color/FXColor";
6
+ import type { FXCurve1D } from "./curve/FXCurve1D";
7
+ export declare function getNextInstanceId(): number;
6
8
  export interface FXRange {
7
9
  min: number;
8
10
  max: number;
@@ -13,7 +15,7 @@ export type FXAspectConfig = number | FXTextureConfig;
13
15
  export declare function resolveFXRangeConfig(config: FXRangeConfig): FXRange;
14
16
  export declare function resolveFXVector3Config(config: FXVector3Config): Vector3Like;
15
17
  export declare function resolveAspect(config: number | FXTextureConfig): number;
16
- export declare function buildGradientTexture(colors: FXColor[]): DataTexture;
18
+ export declare function buildGradientTexture(curve: FXCurve1D<FXColor>): DataTexture;
17
19
  export declare const BUILTIN_OFFSET_POSITION_X = 0;
18
20
  export declare const BUILTIN_OFFSET_POSITION_Y = 1;
19
21
  export declare const BUILTIN_OFFSET_POSITION_Z = 2;
@@ -1,5 +1,9 @@
1
1
  import { Texture, DataTexture, RGBAFormat, UnsignedByteType, UVMapping, ClampToEdgeWrapping, LinearFilter, SRGBColorSpace } from 'three';
2
2
 
3
+ let nextInstanceId = 0;
4
+ function getNextInstanceId() {
5
+ return nextInstanceId++;
6
+ }
3
7
  function resolveFXRangeConfig(config) {
4
8
  if (typeof config === "number") {
5
9
  return { min: config, max: config };
@@ -27,12 +31,12 @@ function resolveAspect(config) {
27
31
  }
28
32
  return config.sourceSize.w / config.sourceSize.h;
29
33
  }
30
- function buildGradientTexture(colors) {
31
- const width = colors.length;
34
+ function buildGradientTexture(curve) {
35
+ const width = curve.anchors.length;
32
36
  const height = 1;
33
37
  const data = new Uint8Array(width * height * 4);
34
38
  for (let i = 0; i < width; i++) {
35
- const color = colors[i];
39
+ const color = curve.anchors[i].value;
36
40
  const index = i * 4;
37
41
  data[index] = Math.round(color.r * 255);
38
42
  data[index + 1] = Math.round(color.g * 255);
@@ -82,4 +86,4 @@ const PARTICLE_DEFINES = `
82
86
  #define PARTICLE_RANDOM_C p_builtin[3][3]
83
87
  `;
84
88
 
85
- export { BUILTIN_OFFSET_AGE, BUILTIN_OFFSET_LIFETIME, BUILTIN_OFFSET_POSITION_X, BUILTIN_OFFSET_POSITION_Y, BUILTIN_OFFSET_POSITION_Z, BUILTIN_OFFSET_RANDOM_A, BUILTIN_OFFSET_RANDOM_B, BUILTIN_OFFSET_RANDOM_C, BUILTIN_OFFSET_ROTATION, BUILTIN_OFFSET_SCALE_X, BUILTIN_OFFSET_SCALE_Y, BUILTIN_OFFSET_TORQUE, BUILTIN_OFFSET_VELOCITY_X, BUILTIN_OFFSET_VELOCITY_Y, BUILTIN_OFFSET_VELOCITY_Z, PARTICLE_DEFINES, buildGradientTexture, resolveAspect, resolveFXRangeConfig, resolveFXVector3Config };
89
+ export { BUILTIN_OFFSET_AGE, BUILTIN_OFFSET_LIFETIME, BUILTIN_OFFSET_POSITION_X, BUILTIN_OFFSET_POSITION_Y, BUILTIN_OFFSET_POSITION_Z, BUILTIN_OFFSET_RANDOM_A, BUILTIN_OFFSET_RANDOM_B, BUILTIN_OFFSET_RANDOM_C, BUILTIN_OFFSET_ROTATION, BUILTIN_OFFSET_SCALE_X, BUILTIN_OFFSET_SCALE_Y, BUILTIN_OFFSET_TORQUE, BUILTIN_OFFSET_VELOCITY_X, BUILTIN_OFFSET_VELOCITY_Y, BUILTIN_OFFSET_VELOCITY_Z, PARTICLE_DEFINES, buildGradientTexture, getNextInstanceId, resolveAspect, resolveFXRangeConfig, resolveFXVector3Config };
@@ -0,0 +1,6 @@
1
+ import { Texture } from 'three';
2
+
3
+ const TEXTURE_DEFAULT_TEXTURE = new Texture();
4
+ const TEXTURE_DEFAULT_SIZE = 2;
5
+
6
+ export { TEXTURE_DEFAULT_SIZE, TEXTURE_DEFAULT_TEXTURE };