pixi-particles-engine 0.1.8 → 0.1.10

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 (71) hide show
  1. package/dist/cjs/behaviours/rotation-curve-behaviour.d.ts +21 -0
  2. package/dist/cjs/behaviours/rotation-curve-behaviour.d.ts.map +1 -0
  3. package/dist/cjs/behaviours/rotation-curve-behaviour.js +26 -0
  4. package/dist/cjs/behaviours/rotation-curve-behaviour.js.map +1 -0
  5. package/dist/cjs/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts +12 -5
  6. package/dist/cjs/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts.map +1 -1
  7. package/dist/cjs/behaviours/spawn-behaviours/circle-spawn-behaviour.js +15 -5
  8. package/dist/cjs/behaviours/spawn-behaviours/circle-spawn-behaviour.js.map +1 -1
  9. package/dist/cjs/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts +15 -5
  10. package/dist/cjs/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts.map +1 -1
  11. package/dist/cjs/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js +36 -7
  12. package/dist/cjs/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js.map +1 -1
  13. package/dist/cjs/behaviours/static-behaviours/static-rotation-behaviour.d.ts +41 -3
  14. package/dist/cjs/behaviours/static-behaviours/static-rotation-behaviour.d.ts.map +1 -1
  15. package/dist/cjs/behaviours/static-behaviours/static-rotation-behaviour.js +46 -5
  16. package/dist/cjs/behaviours/static-behaviours/static-rotation-behaviour.js.map +1 -1
  17. package/dist/cjs/index.d.ts +1 -0
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/index.js +1 -0
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/px-particle.d.ts +7 -2
  22. package/dist/cjs/px-particle.d.ts.map +1 -1
  23. package/dist/cjs/px-particle.js +17 -4
  24. package/dist/cjs/px-particle.js.map +1 -1
  25. package/dist/esm/behaviours/rotation-curve-behaviour.d.ts +21 -0
  26. package/dist/esm/behaviours/rotation-curve-behaviour.d.ts.map +1 -0
  27. package/dist/esm/behaviours/rotation-curve-behaviour.js +22 -0
  28. package/dist/esm/behaviours/rotation-curve-behaviour.js.map +1 -0
  29. package/dist/esm/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts +12 -5
  30. package/dist/esm/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts.map +1 -1
  31. package/dist/esm/behaviours/spawn-behaviours/circle-spawn-behaviour.js +15 -5
  32. package/dist/esm/behaviours/spawn-behaviours/circle-spawn-behaviour.js.map +1 -1
  33. package/dist/esm/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts +15 -5
  34. package/dist/esm/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts.map +1 -1
  35. package/dist/esm/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js +36 -7
  36. package/dist/esm/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js.map +1 -1
  37. package/dist/esm/behaviours/static-behaviours/static-rotation-behaviour.d.ts +41 -3
  38. package/dist/esm/behaviours/static-behaviours/static-rotation-behaviour.d.ts.map +1 -1
  39. package/dist/esm/behaviours/static-behaviours/static-rotation-behaviour.js +46 -5
  40. package/dist/esm/behaviours/static-behaviours/static-rotation-behaviour.js.map +1 -1
  41. package/dist/esm/index.d.ts +1 -0
  42. package/dist/esm/index.d.ts.map +1 -1
  43. package/dist/esm/index.js +1 -0
  44. package/dist/esm/index.js.map +1 -1
  45. package/dist/esm/px-particle.d.ts +7 -2
  46. package/dist/esm/px-particle.d.ts.map +1 -1
  47. package/dist/esm/px-particle.js +17 -4
  48. package/dist/esm/px-particle.js.map +1 -1
  49. package/package.json +2 -1
  50. package/src/behaviour.ts +74 -0
  51. package/src/behaviours/alpha-behaviour.ts +29 -0
  52. package/src/behaviours/alpha-curve-behaviour.ts +34 -0
  53. package/src/behaviours/curved-behaviour/curve-key-frame.ts +23 -0
  54. package/src/behaviours/curved-behaviour/curve-sampler.ts +92 -0
  55. package/src/behaviours/movement-behaviours/gravity-behaviour.ts +48 -0
  56. package/src/behaviours/movement-behaviours/movement-curve-behaviour.ts +39 -0
  57. package/src/behaviours/movement-behaviours/radial-burst-behaviour.ts +57 -0
  58. package/src/behaviours/rotation-curve-behaviour.ts +32 -0
  59. package/src/behaviours/scale-curve-behaviour.ts +36 -0
  60. package/src/behaviours/spawn-behaviours/circle-spawn-behaviour.ts +37 -0
  61. package/src/behaviours/spawn-behaviours/rectangle-spawn-behaviour.ts +60 -0
  62. package/src/behaviours/static-behaviours/static-rotation-behaviour.ts +99 -0
  63. package/src/behaviours/static-behaviours/static-scale-behaviour.ts +21 -0
  64. package/src/emitter.ts +517 -0
  65. package/src/index.ts +19 -0
  66. package/src/px-particle.ts +125 -0
  67. package/src/texture-provider.ts +66 -0
  68. package/src/texture-providers/animated-texture-provider.ts +146 -0
  69. package/src/texture-providers/single-texture-provider.ts +22 -0
  70. package/src/texture-providers/weighted-texture-provider.ts +52 -0
  71. package/src/utils.ts +13 -0
@@ -0,0 +1,66 @@
1
+ import { ParticleProperties, Texture } from "pixi.js";
2
+ import { PxParticle } from "./px-particle";
3
+
4
+ /**
5
+ * TextureProvider decides which {@link Texture} a particle uses.
6
+ *
7
+ * It is called in two different phases:
8
+ * 1) Pool creation: `initialTexture()` (required by Pixi to construct the particle)
9
+ * 2) Spawn / simulation: `textureForSpawn()` and optional `update()`
10
+ *
11
+ * Providers may be stateless (single texture) or stateful (animated textures, weighted random, etc).
12
+ * Keep provider methods lightweight: they can be called very frequently.
13
+ */
14
+ export interface TextureProvider {
15
+ /**
16
+ * Dynamic property requirements for this provider.
17
+ *
18
+ * PixiJS ParticleContainer can skip updating GPU buffers unless you mark certain fields as dynamic.
19
+ * If your provider changes something over time that affects rendering (e.g. UVs for animation),
20
+ * declare it here so the emitter enables the correct `dynamicProperties`.
21
+ *
22
+ * Example:
23
+ * requires: { uvs: true }
24
+ */
25
+ readonly requires?: ParticleProperties;
26
+
27
+ /**
28
+ * Called once per pooled particle, at pool initialization time.
29
+ *
30
+ * Pixi requires a texture to construct each Particle, so this must always return a valid Texture.
31
+ * The texture returned here is just an initial placeholder; it can be replaced on spawn.
32
+ */
33
+ initialTexture(): Texture;
34
+
35
+ /**
36
+ * Called every time a particle is spawned.
37
+ *
38
+ * Must return a valid texture. May depend on:
39
+ * - random selection (weighted sets)
40
+ * - emitter state
41
+ * - particle state (reused pooled particle)
42
+ *
43
+ */
44
+ textureForSpawn?(p: PxParticle): Texture;
45
+
46
+ /**
47
+ * Optional per-frame hook.
48
+ *
49
+ * Use this when the texture can change during the particle's life:
50
+ * - animated textures (flipbook)
51
+ * - texture swapping
52
+ *
53
+ * If you mutate anything that affects rendering (like UVs), ensure `requires`
54
+ * contains the correct dynamicProperties.
55
+ */
56
+ update?(p: PxParticle, dt: number): void;
57
+
58
+ /**
59
+ * Optional recycle hook.
60
+ *
61
+ * Called when a particle is killed and returned to the pool.
62
+ * Use this to clear any provider-specific state stored on the particle
63
+ * (e.g. animation frame index, timers, cached references).
64
+ */
65
+ onKill?(p: PxParticle): void;
66
+ }
@@ -0,0 +1,146 @@
1
+ import { Texture } from "pixi.js";
2
+ import { TextureProvider } from "../texture-provider";
3
+ import { PxParticle } from "../px-particle";
4
+
5
+ /**
6
+ * Configuration for AnimatedTextureProvider.
7
+ *
8
+ * Frames are generated using:
9
+ * `${texturePrefix}${frameNumber}`
10
+ *
11
+ * Example:
12
+ * texturePrefix: "Explosion_"
13
+ * numberOfFrames: 16
14
+ * padLength: 3
15
+ *
16
+ * Generates:
17
+ * Explosion_000
18
+ * Explosion_001
19
+ * ...
20
+ * Explosion_015
21
+ */
22
+ export interface AnimatedTextureProviderOptions {
23
+ /**
24
+ * Prefix used to construct frame aliases.
25
+ */
26
+ texturePrefix: string;
27
+
28
+ /** Total number of frames in the animation sequence. */
29
+ numberOfFrames: number;
30
+
31
+ /** Optional starting frame index (default: 0). */
32
+ firstFrame?: number;
33
+
34
+ /**
35
+ * Optional zero-padding length.
36
+ * If omitted, defaults to numberOfFrames digit length.
37
+ *
38
+ * Example:
39
+ * numberOfFrames = 16 → default padLength = 2
40
+ * frame 3 → "03"
41
+ */
42
+ padLength?: number;
43
+
44
+ /** Frames per second (default: 60). */
45
+ fps?: number;
46
+
47
+ /**
48
+ * If true, animation loops.
49
+ * If false, animation stops at the last frame.
50
+ * Default: true.
51
+ */
52
+ loop?: boolean;
53
+ }
54
+
55
+ /**
56
+ * Flipbook-style animated texture provider.
57
+ *
58
+ * Each particle cycles through a pre-generated array of textures
59
+ * based on elapsed time and configured FPS.
60
+ *
61
+ * This is NOT a Pixi AnimatedSprite.
62
+ * Instead, it swaps particle.texture manually each frame.
63
+ *
64
+ * Because UVs change when textures change, this provider declares:
65
+ * requires = { uvs: true }
66
+ *
67
+ * so the Emitter enables the correct ParticleContainer dynamicProperties.
68
+ */
69
+ export class AnimatedTextureProvider implements TextureProvider {
70
+ /** UV updates are required because textures change during lifetime. */
71
+ public readonly requires = { uvs: true };
72
+
73
+ /** Preloaded frame textures. */
74
+ private readonly frames: Texture[];
75
+
76
+ /** Frames per second for animation playback. */
77
+ private readonly fps: number;
78
+
79
+ /** Whether animation loops. */
80
+ private readonly loop: boolean;
81
+
82
+ constructor(options: AnimatedTextureProviderOptions) {
83
+ const start = options.firstFrame ?? 0;
84
+
85
+ const padLength = options.padLength ?? options.numberOfFrames.toString().length;
86
+
87
+ this.frames = [];
88
+
89
+ for (let i = start; i < options.numberOfFrames + start; i++) {
90
+ const alias = `${options.texturePrefix}${i.toString().padStart(padLength, "0")}`;
91
+ this.frames.push(Texture.from(alias));
92
+ }
93
+
94
+ if (this.frames.length === 0) {
95
+ throw new Error("AnimatedTextureProvider: no frames generated");
96
+ }
97
+
98
+ this.fps = options.fps ?? 60;
99
+ this.loop = options.loop ?? true;
100
+ }
101
+
102
+ /**
103
+ * Used when constructing pooled particles.
104
+ * Returns the first frame as a placeholder texture.
105
+ */
106
+ public initialTexture(): Texture {
107
+ return this.frames[0];
108
+ }
109
+
110
+ /**
111
+ * Called each time a particle is spawned.
112
+ *
113
+ * Initializes per-particle animation state
114
+ * and resets animation to first frame.
115
+ */
116
+ public textureForSpawn(p: PxParticle): Texture {
117
+ p.animatedParticleState = { t: 0 };
118
+ return this.frames[0];
119
+ }
120
+
121
+ /**
122
+ * Per-frame update hook.
123
+ *
124
+ * Advances animation time and selects the appropriate frame.
125
+ */
126
+ public update(p: PxParticle, dt: number): void {
127
+ if (!p.animatedParticleState || this.frames.length <= 1) return;
128
+
129
+ p.animatedParticleState.t += dt;
130
+
131
+ const time = p.animatedParticleState.t;
132
+ const rawFrame = Math.floor(time * this.fps);
133
+
134
+ const idx = this.loop ? rawFrame % this.frames.length : Math.min(rawFrame, this.frames.length - 1);
135
+
136
+ p.texture = this.frames[idx];
137
+ }
138
+
139
+ /**
140
+ * Called when particle is recycled.
141
+ * Clears animation state to avoid stale data in pooled particles.
142
+ */
143
+ public onKill(p: PxParticle): void {
144
+ p.animatedParticleState = undefined;
145
+ }
146
+ }
@@ -0,0 +1,22 @@
1
+ import { Texture } from "pixi.js";
2
+ import { TextureProvider } from "../texture-provider";
3
+
4
+ /**
5
+ * Always returns the same texture for every particle.
6
+ * Useful for simple effects (sparks, smoke puffs, etc).
7
+ */
8
+ export class SingleTextureProvider implements TextureProvider {
9
+ /** Key/URL/alias passed to PixiJS Texture.from(). */
10
+ private readonly textureId: string;
11
+
12
+ private readonly texture: Texture;
13
+
14
+ constructor(textureId: string) {
15
+ this.textureId = textureId;
16
+ this.texture = Texture.from(textureId);
17
+ }
18
+
19
+ public initialTexture(): Texture {
20
+ return this.texture;
21
+ }
22
+ }
@@ -0,0 +1,52 @@
1
+ import { Texture } from "pixi.js";
2
+ import { TextureProvider } from "../texture-provider";
3
+ import { PxParticle } from "../px-particle";
4
+
5
+ type WeightedTexture = {
6
+ /** Key/URL/alias passed to PixiJS Texture.from(). */
7
+ textureId: string;
8
+ weight: number;
9
+ };
10
+
11
+ /**
12
+ * Chooses a random texture at spawn time using weighted probabilities.
13
+ *
14
+ * - Good for variety (different spark shapes, debris pieces, etc.)
15
+ * - Selection happens only on spawn (not per frame)
16
+ */
17
+ export class WeightedTextureProvider implements TextureProvider {
18
+ private readonly fallback: Texture;
19
+ private readonly items: { texture: Texture; weight: number }[];
20
+
21
+ private totalWeight = 0;
22
+
23
+ constructor(items: WeightedTexture[], fallbackTextureId: string) {
24
+ this.fallback = Texture.from(fallbackTextureId);
25
+
26
+ // Pre-cache textures and compute total weight (ignoring negatives)
27
+ this.items = items.map((it) => ({
28
+ texture: Texture.from(it.textureId),
29
+ weight: Math.max(0, it.weight),
30
+ }));
31
+
32
+ for (const it of this.items) this.totalWeight += it.weight;
33
+ }
34
+
35
+ public initialTexture(): Texture {
36
+ return this.fallback;
37
+ }
38
+
39
+ public textureForSpawn(_p: PxParticle): Texture {
40
+ if (this.totalWeight <= 0 || this.items.length === 0) return this.fallback;
41
+
42
+ let r = Math.random() * this.totalWeight;
43
+
44
+ for (const it of this.items) {
45
+ r -= it.weight;
46
+ if (r <= 0) return it.texture;
47
+ }
48
+
49
+ // Floating point edge-case fallback
50
+ return this.items[this.items.length - 1]!.texture;
51
+ }
52
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,13 @@
1
+ export class Utils {
2
+ public static lerp(a: number, b: number, t: number): number {
3
+ return a + (b - a) * t;
4
+ }
5
+
6
+ public static clamp01(v: number) {
7
+ return v < 0 ? 0 : v > 1 ? 1 : v;
8
+ }
9
+
10
+ public static rand(min: number, max: number) {
11
+ return min + Math.random() * (max - min);
12
+ }
13
+ }