pixi-particles-engine 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/LICENSE +21 -0
- package/dist/behaviour.d.ts +69 -0
- package/dist/behaviour.d.ts.map +1 -0
- package/dist/behaviour.js +2 -0
- package/dist/behaviour.js.map +1 -0
- package/dist/behaviours/alpha-behaviour.d.ts +18 -0
- package/dist/behaviours/alpha-behaviour.d.ts.map +1 -0
- package/dist/behaviours/alpha-behaviour.js +21 -0
- package/dist/behaviours/alpha-behaviour.js.map +1 -0
- package/dist/behaviours/alpha-curve-behaviour.d.ts +22 -0
- package/dist/behaviours/alpha-curve-behaviour.d.ts.map +1 -0
- package/dist/behaviours/alpha-curve-behaviour.js +24 -0
- package/dist/behaviours/alpha-curve-behaviour.js.map +1 -0
- package/dist/behaviours/behaviour-utils.d.ts +1 -0
- package/dist/behaviours/behaviour-utils.d.ts.map +1 -0
- package/dist/behaviours/behaviour-utils.js +2 -0
- package/dist/behaviours/behaviour-utils.js.map +1 -0
- package/dist/behaviours/curved-behaviour/curve-key-frame.d.ts +22 -0
- package/dist/behaviours/curved-behaviour/curve-key-frame.d.ts.map +1 -0
- package/dist/behaviours/curved-behaviour/curve-key-frame.js +2 -0
- package/dist/behaviours/curved-behaviour/curve-key-frame.js.map +1 -0
- package/dist/behaviours/curved-behaviour/curve-sampler.d.ts +29 -0
- package/dist/behaviours/curved-behaviour/curve-sampler.d.ts.map +1 -0
- package/dist/behaviours/curved-behaviour/curve-sampler.js +75 -0
- package/dist/behaviours/curved-behaviour/curve-sampler.js.map +1 -0
- package/dist/behaviours/movement-behaviours/gravity-behaviour.d.ts +35 -0
- package/dist/behaviours/movement-behaviours/gravity-behaviour.d.ts.map +1 -0
- package/dist/behaviours/movement-behaviours/gravity-behaviour.js +35 -0
- package/dist/behaviours/movement-behaviours/gravity-behaviour.js.map +1 -0
- package/dist/behaviours/movement-behaviours/movement-curve-behaviour.d.ts +29 -0
- package/dist/behaviours/movement-behaviours/movement-curve-behaviour.d.ts.map +1 -0
- package/dist/behaviours/movement-behaviours/movement-curve-behaviour.js +30 -0
- package/dist/behaviours/movement-behaviours/movement-curve-behaviour.js.map +1 -0
- package/dist/behaviours/movement-behaviours/radial-burst-behaviour.d.ts +37 -0
- package/dist/behaviours/movement-behaviours/radial-burst-behaviour.d.ts.map +1 -0
- package/dist/behaviours/movement-behaviours/radial-burst-behaviour.js +42 -0
- package/dist/behaviours/movement-behaviours/radial-burst-behaviour.js.map +1 -0
- package/dist/behaviours/scale-curve-behaviour.d.ts +21 -0
- package/dist/behaviours/scale-curve-behaviour.d.ts.map +1 -0
- package/dist/behaviours/scale-curve-behaviour.js +26 -0
- package/dist/behaviours/scale-curve-behaviour.js.map +1 -0
- package/dist/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts +16 -0
- package/dist/behaviours/spawn-behaviours/circle-spawn-behaviour.d.ts.map +1 -0
- package/dist/behaviours/spawn-behaviours/circle-spawn-behaviour.js +20 -0
- package/dist/behaviours/spawn-behaviours/circle-spawn-behaviour.js.map +1 -0
- package/dist/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts +15 -0
- package/dist/behaviours/spawn-behaviours/rectangle-spawn-behaviour.d.ts.map +1 -0
- package/dist/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js +21 -0
- package/dist/behaviours/spawn-behaviours/rectangle-spawn-behaviour.js.map +1 -0
- package/dist/behaviours/static-behaviours/static-rotation-behaviour.d.ts +30 -0
- package/dist/behaviours/static-behaviours/static-rotation-behaviour.d.ts.map +1 -0
- package/dist/behaviours/static-behaviours/static-rotation-behaviour.js +24 -0
- package/dist/behaviours/static-behaviours/static-rotation-behaviour.js.map +1 -0
- package/dist/behaviours/static-behaviours/static-scale-behaviour.d.ts +13 -0
- package/dist/behaviours/static-behaviours/static-scale-behaviour.d.ts.map +1 -0
- package/dist/behaviours/static-behaviours/static-scale-behaviour.js +15 -0
- package/dist/behaviours/static-behaviours/static-scale-behaviour.js.map +1 -0
- package/dist/emitter.d.ts +207 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +340 -0
- package/dist/emitter.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/px-particle.d.ts +61 -0
- package/dist/px-particle.d.ts.map +1 -0
- package/dist/px-particle.js +76 -0
- package/dist/px-particle.js.map +1 -0
- package/dist/texture-provider.d.ts +62 -0
- package/dist/texture-provider.d.ts.map +1 -0
- package/dist/texture-provider.js +2 -0
- package/dist/texture-provider.js.map +1 -0
- package/dist/texture-providers/animated-texture-provider.d.ts +98 -0
- package/dist/texture-providers/animated-texture-provider.d.ts.map +1 -0
- package/dist/texture-providers/animated-texture-provider.js +72 -0
- package/dist/texture-providers/animated-texture-provider.js.map +1 -0
- package/dist/texture-providers/single-texture-provider.d.ts +14 -0
- package/dist/texture-providers/single-texture-provider.d.ts.map +1 -0
- package/dist/texture-providers/single-texture-provider.js +15 -0
- package/dist/texture-providers/single-texture-provider.js.map +1 -0
- package/dist/texture-providers/weighted-texture-provider.d.ts +24 -0
- package/dist/texture-providers/weighted-texture-provider.d.ts.map +1 -0
- package/dist/texture-providers/weighted-texture-provider.js +36 -0
- package/dist/texture-providers/weighted-texture-provider.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +12 -0
- package/dist/utils.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aljaz Stucin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ParticleProperties } from "pixi.js";
|
|
2
|
+
import { Emitter } from "./emitter";
|
|
3
|
+
import { PxParticle } from "./px-particle";
|
|
4
|
+
/**
|
|
5
|
+
* A Behaviour is a modular unit of particle logic.
|
|
6
|
+
*
|
|
7
|
+
* Behaviours can:
|
|
8
|
+
* - Initialize particle state at spawn (velocity, alpha, scale, etc)
|
|
9
|
+
* - Update particle state each frame (curves, gravity, drag, color fade, etc)
|
|
10
|
+
* - Clean up any per-particle state when the particle is recycled
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle:
|
|
13
|
+
* - init(emitter) is called once when the behaviour is added to an emitter
|
|
14
|
+
* - onSpawn(p, emitter) is called each time a particle is spawned
|
|
15
|
+
* - update(p, dt, emitter) is called every frame for each active particle
|
|
16
|
+
* - onKill(p, emitter) is called when a particle dies and returns to the pool
|
|
17
|
+
*/
|
|
18
|
+
export interface Behaviour {
|
|
19
|
+
/**
|
|
20
|
+
* Execution order relative to other behaviours.
|
|
21
|
+
*
|
|
22
|
+
* Lower priority runs earlier.
|
|
23
|
+
* When priorities are equal, execution order is stable and follows registration order.
|
|
24
|
+
*
|
|
25
|
+
* Use priority to ensure correct ordering when behaviours depend on each other
|
|
26
|
+
* (e.g. apply movement first, then apply alpha/scale curves).
|
|
27
|
+
*/
|
|
28
|
+
readonly priority?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Dynamic property requirements for this behaviour.
|
|
31
|
+
*
|
|
32
|
+
* PixiJS ParticleContainer uses `dynamicProperties` to decide which attributes
|
|
33
|
+
* must be re-uploaded to the GPU each frame.
|
|
34
|
+
*
|
|
35
|
+
* If your behaviour changes a property over time that affects rendering,
|
|
36
|
+
* declare it here so the emitter enables the correct dynamicProperties.
|
|
37
|
+
*
|
|
38
|
+
* Examples:
|
|
39
|
+
* - Changing `alpha` over time → requires: { color: true }
|
|
40
|
+
* - Changing `scaleX/scaleY` over time → may require: { vertex: true } (depends on Pixi internals)
|
|
41
|
+
* - Changing `rotation` over time → requires: { rotation: true }
|
|
42
|
+
*
|
|
43
|
+
* NOTE:
|
|
44
|
+
* If your behaviour only sets values ON SPAWN and never changes them after,
|
|
45
|
+
* you usually do NOT need to require dynamic properties.
|
|
46
|
+
*/
|
|
47
|
+
readonly requires?: ParticleProperties;
|
|
48
|
+
/**
|
|
49
|
+
* Optional: called once when the behaviour is registered on an emitter.
|
|
50
|
+
* Useful for caching references, precomputing curves, or validating options.
|
|
51
|
+
*/
|
|
52
|
+
init?(emitter: Emitter): void;
|
|
53
|
+
/**
|
|
54
|
+
* Optional: called when a particle is spawned (taken from pool and activated).
|
|
55
|
+
* Use this to initialize per-particle state for this behaviour.
|
|
56
|
+
*/
|
|
57
|
+
onSpawn?(p: PxParticle, emitter: Emitter): void;
|
|
58
|
+
/**
|
|
59
|
+
* Optional: called every frame for each active particle.
|
|
60
|
+
* `dt` is delta time in seconds (already clamped by the emitter).
|
|
61
|
+
*/
|
|
62
|
+
update?(p: PxParticle, dt: number, emitter: Emitter): void;
|
|
63
|
+
/**
|
|
64
|
+
* Optional: called when the particle is killed and returned to the pool.
|
|
65
|
+
* Use this to clear any per-particle state allocated by the behaviour.
|
|
66
|
+
*/
|
|
67
|
+
onKill?(p: PxParticle, emitter: Emitter): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviour.d.ts","sourceRoot":"","sources":["../src/behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAEvC;;;OAGG;IACH,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAE9B;;;OAGG;IACH,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAEhD;;;OAGG;IACH,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAE3D;;;OAGG;IACH,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviour.js","sourceRoot":"","sources":["../src/behaviour.ts"],"names":[],"mappings":"","sourcesContent":["import { ParticleProperties } from \"pixi.js\";\r\nimport { Emitter } from \"./emitter\";\r\nimport { PxParticle } from \"./px-particle\";\r\n\r\n/**\r\n * A Behaviour is a modular unit of particle logic.\r\n *\r\n * Behaviours can:\r\n * - Initialize particle state at spawn (velocity, alpha, scale, etc)\r\n * - Update particle state each frame (curves, gravity, drag, color fade, etc)\r\n * - Clean up any per-particle state when the particle is recycled\r\n *\r\n * Lifecycle:\r\n * - init(emitter) is called once when the behaviour is added to an emitter\r\n * - onSpawn(p, emitter) is called each time a particle is spawned\r\n * - update(p, dt, emitter) is called every frame for each active particle\r\n * - onKill(p, emitter) is called when a particle dies and returns to the pool\r\n */\r\nexport interface Behaviour {\r\n /**\r\n * Execution order relative to other behaviours.\r\n *\r\n * Lower priority runs earlier.\r\n * When priorities are equal, execution order is stable and follows registration order.\r\n *\r\n * Use priority to ensure correct ordering when behaviours depend on each other\r\n * (e.g. apply movement first, then apply alpha/scale curves).\r\n */\r\n readonly priority?: number;\r\n\r\n /**\r\n * Dynamic property requirements for this behaviour.\r\n *\r\n * PixiJS ParticleContainer uses `dynamicProperties` to decide which attributes\r\n * must be re-uploaded to the GPU each frame.\r\n *\r\n * If your behaviour changes a property over time that affects rendering,\r\n * declare it here so the emitter enables the correct dynamicProperties.\r\n *\r\n * Examples:\r\n * - Changing `alpha` over time → requires: { color: true }\r\n * - Changing `scaleX/scaleY` over time → may require: { vertex: true } (depends on Pixi internals)\r\n * - Changing `rotation` over time → requires: { rotation: true }\r\n *\r\n * NOTE:\r\n * If your behaviour only sets values ON SPAWN and never changes them after,\r\n * you usually do NOT need to require dynamic properties.\r\n */\r\n readonly requires?: ParticleProperties;\r\n\r\n /**\r\n * Optional: called once when the behaviour is registered on an emitter.\r\n * Useful for caching references, precomputing curves, or validating options.\r\n */\r\n init?(emitter: Emitter): void;\r\n\r\n /**\r\n * Optional: called when a particle is spawned (taken from pool and activated).\r\n * Use this to initialize per-particle state for this behaviour.\r\n */\r\n onSpawn?(p: PxParticle, emitter: Emitter): void;\r\n\r\n /**\r\n * Optional: called every frame for each active particle.\r\n * `dt` is delta time in seconds (already clamped by the emitter).\r\n */\r\n update?(p: PxParticle, dt: number, emitter: Emitter): void;\r\n\r\n /**\r\n * Optional: called when the particle is killed and returned to the pool.\r\n * Use this to clear any per-particle state allocated by the behaviour.\r\n */\r\n onKill?(p: PxParticle, emitter: Emitter): void;\r\n}\r\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PxParticle } from "../px-particle";
|
|
2
|
+
import { Behaviour } from "../behaviour";
|
|
3
|
+
import { Emitter } from "../emitter";
|
|
4
|
+
/**
|
|
5
|
+
* Linearly fades alpha from startAlpha -> endAlpha over particle lifetime.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AlphaBehaviour implements Behaviour {
|
|
8
|
+
readonly requires: {
|
|
9
|
+
color: boolean;
|
|
10
|
+
};
|
|
11
|
+
readonly priority = 50;
|
|
12
|
+
startAlpha: number;
|
|
13
|
+
endAlpha: number;
|
|
14
|
+
constructor(startAlpha?: number, endAlpha?: number);
|
|
15
|
+
onSpawn(p: PxParticle, _emitter: Emitter): void;
|
|
16
|
+
update(p: PxParticle, _dt: number, _emitter: Emitter): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=alpha-behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha-behaviour.d.ts","sourceRoot":"","sources":["../../src/behaviours/alpha-behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;GAEG;AACH,qBAAa,cAAe,YAAW,SAAS;IAC5C,SAAgB,QAAQ;;MAAmB;IAE3C,SAAgB,QAAQ,MAAM;IAEvB,UAAU,SAAK;IACf,QAAQ,SAAK;gBAER,UAAU,SAAI,EAAE,QAAQ,SAAI;IAKjC,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI/C,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;CAIrE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linearly fades alpha from startAlpha -> endAlpha over particle lifetime.
|
|
3
|
+
*/
|
|
4
|
+
export class AlphaBehaviour {
|
|
5
|
+
constructor(startAlpha = 1, endAlpha = 0) {
|
|
6
|
+
this.requires = { color: true };
|
|
7
|
+
this.priority = 50;
|
|
8
|
+
this.startAlpha = 1;
|
|
9
|
+
this.endAlpha = 0;
|
|
10
|
+
this.startAlpha = startAlpha;
|
|
11
|
+
this.endAlpha = endAlpha;
|
|
12
|
+
}
|
|
13
|
+
onSpawn(p, _emitter) {
|
|
14
|
+
p.alpha = this.startAlpha;
|
|
15
|
+
}
|
|
16
|
+
update(p, _dt, _emitter) {
|
|
17
|
+
const t = p.life > 0 ? Math.min(1, Math.max(0, p.age / p.life)) : 1;
|
|
18
|
+
p.alpha = this.startAlpha + (this.endAlpha - this.startAlpha) * t;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=alpha-behaviour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha-behaviour.js","sourceRoot":"","sources":["../../src/behaviours/alpha-behaviour.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,OAAO,cAAc;IAQvB,YAAY,UAAU,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC;QAPxB,aAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAE3B,aAAQ,GAAG,EAAE,CAAC;QAEvB,eAAU,GAAG,CAAC,CAAC;QACf,aAAQ,GAAG,CAAC,CAAC;QAGhB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAEM,OAAO,CAAC,CAAa,EAAE,QAAiB;QAC3C,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;IAC9B,CAAC;IAEM,MAAM,CAAC,CAAa,EAAE,GAAW,EAAE,QAAiB;QACvD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACtE,CAAC;CACJ","sourcesContent":["import { PxParticle } from \"../px-particle\";\r\nimport { Behaviour } from \"../behaviour\";\r\nimport { Emitter } from \"../emitter\";\r\n\r\n/**\r\n * Linearly fades alpha from startAlpha -> endAlpha over particle lifetime.\r\n */\r\nexport class AlphaBehaviour implements Behaviour {\r\n public readonly requires = { color: true };\r\n\r\n public readonly priority = 50;\r\n\r\n public startAlpha = 1;\r\n public endAlpha = 0;\r\n\r\n constructor(startAlpha = 1, endAlpha = 0) {\r\n this.startAlpha = startAlpha;\r\n this.endAlpha = endAlpha;\r\n }\r\n\r\n public onSpawn(p: PxParticle, _emitter: Emitter): void {\r\n p.alpha = this.startAlpha;\r\n }\r\n\r\n public update(p: PxParticle, _dt: number, _emitter: Emitter): void {\r\n const t = p.life > 0 ? Math.min(1, Math.max(0, p.age / p.life)) : 1;\r\n p.alpha = this.startAlpha + (this.endAlpha - this.startAlpha) * t;\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Behaviour } from "../behaviour";
|
|
2
|
+
import { PxParticle } from "../px-particle";
|
|
3
|
+
import { CurveKeyframe, CurveOptions } from "./curved-behaviour/curve-key-frame";
|
|
4
|
+
import { Emitter } from "../emitter";
|
|
5
|
+
/**
|
|
6
|
+
* Alpha over lifetime driven by a curve.
|
|
7
|
+
*
|
|
8
|
+
* Keyframes are sampled using normalized lifetime t in [0..1].
|
|
9
|
+
* Output is clamped to [0..1].
|
|
10
|
+
*/
|
|
11
|
+
export declare class AlphaCurveBehaviour implements Behaviour {
|
|
12
|
+
/** Alpha changes over time, so ParticleContainer must treat color as dynamic. */
|
|
13
|
+
readonly requires: {
|
|
14
|
+
color: boolean;
|
|
15
|
+
};
|
|
16
|
+
readonly priority = 50;
|
|
17
|
+
private curve;
|
|
18
|
+
constructor(keyframes: CurveKeyframe[], opts?: CurveOptions);
|
|
19
|
+
onSpawn(p: PxParticle): void;
|
|
20
|
+
update(p: PxParticle, _dt?: number, _emitter?: Emitter): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=alpha-curve-behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha-curve-behaviour.d.ts","sourceRoot":"","sources":["../../src/behaviours/alpha-curve-behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEjF,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,SAAS;IACjD,iFAAiF;IACjF,SAAgB,QAAQ;;MAAmB;IAE3C,SAAgB,QAAQ,MAAM;IAE9B,OAAO,CAAC,KAAK,CAAQ;gBAET,SAAS,EAAE,aAAa,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY;IAKpD,OAAO,CAAC,CAAC,EAAE,UAAU;IAIrB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO;CAIhE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Curve } from "./curved-behaviour/curve-sampler";
|
|
2
|
+
/**
|
|
3
|
+
* Alpha over lifetime driven by a curve.
|
|
4
|
+
*
|
|
5
|
+
* Keyframes are sampled using normalized lifetime t in [0..1].
|
|
6
|
+
* Output is clamped to [0..1].
|
|
7
|
+
*/
|
|
8
|
+
export class AlphaCurveBehaviour {
|
|
9
|
+
constructor(keyframes, opts) {
|
|
10
|
+
/** Alpha changes over time, so ParticleContainer must treat color as dynamic. */
|
|
11
|
+
this.requires = { color: true };
|
|
12
|
+
this.priority = 50;
|
|
13
|
+
// Always clamp alpha to [0..1]
|
|
14
|
+
this.curve = new Curve(keyframes, { ...opts, clamp: { min: 0, max: 1 } });
|
|
15
|
+
}
|
|
16
|
+
onSpawn(p) {
|
|
17
|
+
p.alpha = this.curve.sample(0);
|
|
18
|
+
}
|
|
19
|
+
update(p, _dt, _emitter) {
|
|
20
|
+
const t = p.life > 0 ? p.age / p.life : 1;
|
|
21
|
+
p.alpha = this.curve.sample(t);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=alpha-curve-behaviour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alpha-curve-behaviour.js","sourceRoot":"","sources":["../../src/behaviours/alpha-curve-behaviour.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAC;AAGzD;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IAQ5B,YAAY,SAA0B,EAAE,IAAmB;QAP3D,iFAAiF;QACjE,aAAQ,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAE3B,aAAQ,GAAG,EAAE,CAAC;QAK1B,+BAA+B;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC;IAEM,OAAO,CAAC,CAAa;QACxB,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IAEM,MAAM,CAAC,CAAa,EAAE,GAAY,EAAE,QAAkB;QACzD,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;CACJ","sourcesContent":["import { Behaviour } from \"../behaviour\";\r\nimport { PxParticle } from \"../px-particle\";\r\nimport { CurveKeyframe, CurveOptions } from \"./curved-behaviour/curve-key-frame\";\r\nimport { Curve } from \"./curved-behaviour/curve-sampler\";\r\nimport { Emitter } from \"../emitter\";\r\n\r\n/**\r\n * Alpha over lifetime driven by a curve.\r\n *\r\n * Keyframes are sampled using normalized lifetime t in [0..1].\r\n * Output is clamped to [0..1].\r\n */\r\nexport class AlphaCurveBehaviour implements Behaviour {\r\n /** Alpha changes over time, so ParticleContainer must treat color as dynamic. */\r\n public readonly requires = { color: true };\r\n\r\n public readonly priority = 50;\r\n\r\n private curve: Curve;\r\n\r\n constructor(keyframes: CurveKeyframe[], opts?: CurveOptions) {\r\n // Always clamp alpha to [0..1]\r\n this.curve = new Curve(keyframes, { ...opts, clamp: { min: 0, max: 1 } });\r\n }\r\n\r\n public onSpawn(p: PxParticle) {\r\n p.alpha = this.curve.sample(0);\r\n }\r\n\r\n public update(p: PxParticle, _dt?: number, _emitter?: Emitter) {\r\n const t = p.life > 0 ? p.age / p.life : 1;\r\n p.alpha = this.curve.sample(t);\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=behaviour-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviour-utils.d.ts","sourceRoot":"","sources":["../../src/behaviours/behaviour-utils.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviour-utils.js","sourceRoot":"","sources":["../../src/behaviours/behaviour-utils.ts"],"names":[],"mappings":"","sourcesContent":[""]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type EaseFn = (x: number) => number;
|
|
2
|
+
export type CurveKeyframe = {
|
|
3
|
+
/** Normalized lifetime [0..1]. */
|
|
4
|
+
time: number;
|
|
5
|
+
/** Value at this time. */
|
|
6
|
+
value: number;
|
|
7
|
+
/**
|
|
8
|
+
* Optional easing applied to the segment starting at this keyframe,
|
|
9
|
+
* i.e. easing used for interpolation from this keyframe -> next keyframe.
|
|
10
|
+
*/
|
|
11
|
+
ease?: EaseFn;
|
|
12
|
+
};
|
|
13
|
+
export type CurveOptions = {
|
|
14
|
+
/** Default easing used when a segment has no per-keyframe ease. */
|
|
15
|
+
defaultEase?: EaseFn;
|
|
16
|
+
/** Optional clamp on sampled output. */
|
|
17
|
+
clamp?: {
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=curve-key-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curve-key-frame.d.ts","sourceRoot":"","sources":["../../../src/behaviours/curved-behaviour/curve-key-frame.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG;IACxB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wCAAwC;IACxC,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curve-key-frame.js","sourceRoot":"","sources":["../../../src/behaviours/curved-behaviour/curve-key-frame.ts"],"names":[],"mappings":"","sourcesContent":["export type EaseFn = (x: number) => number;\r\n\r\nexport type CurveKeyframe = {\r\n /** Normalized lifetime [0..1]. */\r\n time: number;\r\n\r\n /** Value at this time. */\r\n value: number;\r\n\r\n /**\r\n * Optional easing applied to the segment starting at this keyframe,\r\n * i.e. easing used for interpolation from this keyframe -> next keyframe.\r\n */\r\n ease?: EaseFn;\r\n};\r\n\r\nexport type CurveOptions = {\r\n /** Default easing used when a segment has no per-keyframe ease. */\r\n defaultEase?: EaseFn;\r\n\r\n /** Optional clamp on sampled output. */\r\n clamp?: { min: number; max: number };\r\n};\r\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CurveKeyframe, CurveOptions } from "./curve-key-frame";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight curve sampler for keyframed 1D values over normalized time [0..1].
|
|
4
|
+
*
|
|
5
|
+
* - Keyframes are clamped to [0..1] and sorted by time.
|
|
6
|
+
* - Endpoints at t=0 and t=1 are ensured (added if missing).
|
|
7
|
+
* - Each segment can have its own easing function.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Curve {
|
|
10
|
+
/** Cleaned + sorted keyframes (always includes endpoints at 0 and 1). */
|
|
11
|
+
private keys;
|
|
12
|
+
/** Default easing used when the keyframe has no `ease`. */
|
|
13
|
+
private defaultEase?;
|
|
14
|
+
/** Optional output clamp. */
|
|
15
|
+
private clamp?;
|
|
16
|
+
constructor(keyframes: CurveKeyframe[], opts?: CurveOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Samples the curve at normalized time t01.
|
|
19
|
+
* Input is clamped to [0..1].
|
|
20
|
+
*/
|
|
21
|
+
sample(t01: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* Finds the segment index i such that t is between keys[i] and keys[i+1].
|
|
24
|
+
*/
|
|
25
|
+
private findSegmentIndex;
|
|
26
|
+
/** Applies optional output clamp. */
|
|
27
|
+
private clampValue;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=curve-sampler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curve-sampler.d.ts","sourceRoot":"","sources":["../../../src/behaviours/curved-behaviour/curve-sampler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAU,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAExE;;;;;;GAMG;AACH,qBAAa,KAAK;IACd,yEAAyE;IACzE,OAAO,CAAC,IAAI,CAAkB;IAE9B,2DAA2D;IAC3D,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,6BAA6B;IAC7B,OAAO,CAAC,KAAK,CAAC,CAA+B;gBAEjC,SAAS,EAAE,aAAa,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY;IA4B3D;;;OAGG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAwBlC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB,qCAAqC;IACrC,OAAO,CAAC,UAAU;CAIrB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Utils } from "../../utils";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight curve sampler for keyframed 1D values over normalized time [0..1].
|
|
4
|
+
*
|
|
5
|
+
* - Keyframes are clamped to [0..1] and sorted by time.
|
|
6
|
+
* - Endpoints at t=0 and t=1 are ensured (added if missing).
|
|
7
|
+
* - Each segment can have its own easing function.
|
|
8
|
+
*/
|
|
9
|
+
export class Curve {
|
|
10
|
+
constructor(keyframes, opts) {
|
|
11
|
+
this.defaultEase = opts?.defaultEase;
|
|
12
|
+
this.clamp = opts?.clamp;
|
|
13
|
+
// Normalize and sort keyframes.
|
|
14
|
+
const cleaned = (keyframes ?? [])
|
|
15
|
+
.map((k) => ({
|
|
16
|
+
time: Utils.clamp01(k.time),
|
|
17
|
+
value: k.value,
|
|
18
|
+
ease: k.ease,
|
|
19
|
+
}))
|
|
20
|
+
.sort((a, b) => a.time - b.time);
|
|
21
|
+
// Fallback: flat zero curve.
|
|
22
|
+
if (cleaned.length === 0)
|
|
23
|
+
cleaned.push({ time: 0, value: 0 }, { time: 1, value: 0 });
|
|
24
|
+
// Ensure endpoints exist at t=0 and t=1.
|
|
25
|
+
if (cleaned[0].time !== 0)
|
|
26
|
+
cleaned.unshift({ time: 0, value: cleaned[0].value });
|
|
27
|
+
if (cleaned[cleaned.length - 1].time !== 1)
|
|
28
|
+
cleaned.push({
|
|
29
|
+
time: 1,
|
|
30
|
+
value: cleaned[cleaned.length - 1].value,
|
|
31
|
+
});
|
|
32
|
+
this.keys = cleaned;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Samples the curve at normalized time t01.
|
|
36
|
+
* Input is clamped to [0..1].
|
|
37
|
+
*/
|
|
38
|
+
sample(t01) {
|
|
39
|
+
const t = Utils.clamp01(t01);
|
|
40
|
+
// Find which segment [k0..k1] contains t.
|
|
41
|
+
const i = this.findSegmentIndex(t);
|
|
42
|
+
const k0 = this.keys[i];
|
|
43
|
+
const k1 = this.keys[i + 1];
|
|
44
|
+
const span = k1.time - k0.time;
|
|
45
|
+
if (span <= 0)
|
|
46
|
+
return this.clampValue(k1.value);
|
|
47
|
+
// Normalize t into segment space [0..1].
|
|
48
|
+
let u = (t - k0.time) / span;
|
|
49
|
+
u = Utils.clamp01(u);
|
|
50
|
+
// Apply easing for this segment (if any).
|
|
51
|
+
const ease = k0.ease ?? this.defaultEase;
|
|
52
|
+
if (ease)
|
|
53
|
+
u = Utils.clamp01(ease(u));
|
|
54
|
+
// Linear interpolation between segment endpoints.
|
|
55
|
+
const v = Utils.lerp(k0.value, k1.value, u);
|
|
56
|
+
return this.clampValue(v);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Finds the segment index i such that t is between keys[i] and keys[i+1].
|
|
60
|
+
*/
|
|
61
|
+
findSegmentIndex(t) {
|
|
62
|
+
for (let i = 0; i < this.keys.length - 2; i++) {
|
|
63
|
+
if (t <= this.keys[i + 1].time)
|
|
64
|
+
return i;
|
|
65
|
+
}
|
|
66
|
+
return this.keys.length - 2;
|
|
67
|
+
}
|
|
68
|
+
/** Applies optional output clamp. */
|
|
69
|
+
clampValue(v) {
|
|
70
|
+
if (!this.clamp)
|
|
71
|
+
return v;
|
|
72
|
+
return Math.min(this.clamp.max, Math.max(this.clamp.min, v));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=curve-sampler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curve-sampler.js","sourceRoot":"","sources":["../../../src/behaviours/curved-behaviour/curve-sampler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Utils } from \"../../utils\";\r\nimport { CurveKeyframe, EaseFn, CurveOptions } from \"./curve-key-frame\";\r\n\r\n/**\r\n * Lightweight curve sampler for keyframed 1D values over normalized time [0..1].\r\n *\r\n * - Keyframes are clamped to [0..1] and sorted by time.\r\n * - Endpoints at t=0 and t=1 are ensured (added if missing).\r\n * - Each segment can have its own easing function.\r\n */\r\nexport class Curve {\r\n /** Cleaned + sorted keyframes (always includes endpoints at 0 and 1). */\r\n private keys: CurveKeyframe[];\r\n\r\n /** Default easing used when the keyframe has no `ease`. */\r\n private defaultEase?: EaseFn;\r\n\r\n /** Optional output clamp. */\r\n private clamp?: { min: number; max: number };\r\n\r\n constructor(keyframes: CurveKeyframe[], opts?: CurveOptions) {\r\n this.defaultEase = opts?.defaultEase;\r\n this.clamp = opts?.clamp;\r\n\r\n // Normalize and sort keyframes.\r\n const cleaned: CurveKeyframe[] = (keyframes ?? [])\r\n .map((k) => ({\r\n time: Utils.clamp01(k.time),\r\n value: k.value,\r\n ease: k.ease,\r\n }))\r\n .sort((a, b) => a.time - b.time);\r\n\r\n // Fallback: flat zero curve.\r\n if (cleaned.length === 0) cleaned.push({ time: 0, value: 0 }, { time: 1, value: 0 });\r\n\r\n // Ensure endpoints exist at t=0 and t=1.\r\n if (cleaned[0].time !== 0) cleaned.unshift({ time: 0, value: cleaned[0].value });\r\n\r\n if (cleaned[cleaned.length - 1].time !== 1)\r\n cleaned.push({\r\n time: 1,\r\n value: cleaned[cleaned.length - 1].value,\r\n });\r\n\r\n this.keys = cleaned;\r\n }\r\n\r\n /**\r\n * Samples the curve at normalized time t01.\r\n * Input is clamped to [0..1].\r\n */\r\n public sample(t01: number): number {\r\n const t = Utils.clamp01(t01);\r\n\r\n // Find which segment [k0..k1] contains t.\r\n const i = this.findSegmentIndex(t);\r\n const k0 = this.keys[i];\r\n const k1 = this.keys[i + 1];\r\n\r\n const span = k1.time - k0.time;\r\n if (span <= 0) return this.clampValue(k1.value);\r\n\r\n // Normalize t into segment space [0..1].\r\n let u = (t - k0.time) / span;\r\n u = Utils.clamp01(u);\r\n\r\n // Apply easing for this segment (if any).\r\n const ease = k0.ease ?? this.defaultEase;\r\n if (ease) u = Utils.clamp01(ease(u));\r\n\r\n // Linear interpolation between segment endpoints.\r\n const v = Utils.lerp(k0.value, k1.value, u);\r\n return this.clampValue(v);\r\n }\r\n\r\n /**\r\n * Finds the segment index i such that t is between keys[i] and keys[i+1].\r\n */\r\n private findSegmentIndex(t: number): number {\r\n for (let i = 0; i < this.keys.length - 2; i++) {\r\n if (t <= this.keys[i + 1].time) return i;\r\n }\r\n return this.keys.length - 2;\r\n }\r\n\r\n /** Applies optional output clamp. */\r\n private clampValue(v: number): number {\r\n if (!this.clamp) return v;\r\n return Math.min(this.clamp.max, Math.max(this.clamp.min, v));\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PxParticle } from "../../px-particle";
|
|
2
|
+
import { Behaviour } from "../../behaviour";
|
|
3
|
+
import { CurveKeyframe, CurveOptions } from "../curved-behaviour/curve-key-frame";
|
|
4
|
+
/**
|
|
5
|
+
* Applies an acceleration (gx, gy) scaled by a curve over lifetime.
|
|
6
|
+
*
|
|
7
|
+
* This modifies velocity every frame:
|
|
8
|
+
* v += g * strength(t) * dt
|
|
9
|
+
*
|
|
10
|
+
* where t is normalized particle age in [0..1].
|
|
11
|
+
*
|
|
12
|
+
* Typical uses:
|
|
13
|
+
* - Gravity that ramps up/down over lifetime
|
|
14
|
+
* - Wind that fades in/out
|
|
15
|
+
* - Custom "pull" forces controlled by a curve
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
export declare class GravityCurveBehaviour implements Behaviour {
|
|
19
|
+
readonly requires: {
|
|
20
|
+
position: boolean;
|
|
21
|
+
};
|
|
22
|
+
readonly priority = 0;
|
|
23
|
+
/** Acceleration vector (units: px/s² when strength is 1). */
|
|
24
|
+
gx: number;
|
|
25
|
+
gy: number;
|
|
26
|
+
/** Strength curve sampled by normalized lifetime. */
|
|
27
|
+
private strength;
|
|
28
|
+
constructor(gx: number, gy: number, strengthKeyframes: CurveKeyframe[], opts?: CurveOptions);
|
|
29
|
+
/**
|
|
30
|
+
* Called every frame for each particle.
|
|
31
|
+
* dt is in seconds.
|
|
32
|
+
*/
|
|
33
|
+
update(p: PxParticle, dt: number): void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=gravity-behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gravity-behaviour.d.ts","sourceRoot":"","sources":["../../../src/behaviours/movement-behaviours/gravity-behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAGlF;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,YAAW,SAAS;IACnD,SAAgB,QAAQ;;MAAsB;IAC9C,SAAgB,QAAQ,KAAK;IAE7B,6DAA6D;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IAElB,qDAAqD;IACrD,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY;IAM3F;;;OAGG;IACI,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM;CAO1C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Curve } from "../curved-behaviour/curve-sampler";
|
|
2
|
+
/**
|
|
3
|
+
* Applies an acceleration (gx, gy) scaled by a curve over lifetime.
|
|
4
|
+
*
|
|
5
|
+
* This modifies velocity every frame:
|
|
6
|
+
* v += g * strength(t) * dt
|
|
7
|
+
*
|
|
8
|
+
* where t is normalized particle age in [0..1].
|
|
9
|
+
*
|
|
10
|
+
* Typical uses:
|
|
11
|
+
* - Gravity that ramps up/down over lifetime
|
|
12
|
+
* - Wind that fades in/out
|
|
13
|
+
* - Custom "pull" forces controlled by a curve
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export class GravityCurveBehaviour {
|
|
17
|
+
constructor(gx, gy, strengthKeyframes, opts) {
|
|
18
|
+
this.requires = { position: true };
|
|
19
|
+
this.priority = 0;
|
|
20
|
+
this.gx = gx;
|
|
21
|
+
this.gy = gy;
|
|
22
|
+
this.strength = new Curve(strengthKeyframes, opts);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Called every frame for each particle.
|
|
26
|
+
* dt is in seconds.
|
|
27
|
+
*/
|
|
28
|
+
update(p, dt) {
|
|
29
|
+
const t = p.life > 0 ? p.age / p.life : 1;
|
|
30
|
+
const s = this.strength.sample(t);
|
|
31
|
+
p.vx += this.gx * s * dt;
|
|
32
|
+
p.vy += this.gy * s * dt;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=gravity-behaviour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gravity-behaviour.js","sourceRoot":"","sources":["../../../src/behaviours/movement-behaviours/gravity-behaviour.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,qBAAqB;IAW9B,YAAY,EAAU,EAAE,EAAU,EAAE,iBAAkC,EAAE,IAAmB;QAV3E,aAAQ,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC9B,aAAQ,GAAG,CAAC,CAAC;QAUzB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,CAAa,EAAE,EAAU;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAElC,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;QACzB,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IAC7B,CAAC;CACJ","sourcesContent":["import { PxParticle } from \"../../px-particle\";\r\nimport { Behaviour } from \"../../behaviour\";\r\nimport { CurveKeyframe, CurveOptions } from \"../curved-behaviour/curve-key-frame\";\r\nimport { Curve } from \"../curved-behaviour/curve-sampler\";\r\n\r\n/**\r\n * Applies an acceleration (gx, gy) scaled by a curve over lifetime.\r\n *\r\n * This modifies velocity every frame:\r\n * v += g * strength(t) * dt\r\n *\r\n * where t is normalized particle age in [0..1].\r\n *\r\n * Typical uses:\r\n * - Gravity that ramps up/down over lifetime\r\n * - Wind that fades in/out\r\n * - Custom \"pull\" forces controlled by a curve\r\n *\r\n */\r\nexport class GravityCurveBehaviour implements Behaviour {\r\n public readonly requires = { position: true };\r\n public readonly priority = 0;\r\n\r\n /** Acceleration vector (units: px/s² when strength is 1). */\r\n public gx: number;\r\n public gy: number;\r\n\r\n /** Strength curve sampled by normalized lifetime. */\r\n private strength: Curve;\r\n\r\n constructor(gx: number, gy: number, strengthKeyframes: CurveKeyframe[], opts?: CurveOptions) {\r\n this.gx = gx;\r\n this.gy = gy;\r\n this.strength = new Curve(strengthKeyframes, opts);\r\n }\r\n\r\n /**\r\n * Called every frame for each particle.\r\n * dt is in seconds.\r\n */\r\n public update(p: PxParticle, dt: number) {\r\n const t = p.life > 0 ? p.age / p.life : 1;\r\n const s = this.strength.sample(t);\r\n\r\n p.vx += this.gx * s * dt;\r\n p.vy += this.gy * s * dt;\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PxParticle } from "../../px-particle";
|
|
2
|
+
import { Behaviour } from "../../behaviour";
|
|
3
|
+
import { CurveKeyframe, CurveOptions } from "../curved-behaviour/curve-key-frame";
|
|
4
|
+
/**
|
|
5
|
+
* Drives particle velocity directly using curves over lifetime.
|
|
6
|
+
*
|
|
7
|
+
* Each frame:
|
|
8
|
+
* vx = vxCurve(t)
|
|
9
|
+
* vy = vyCurve(t)
|
|
10
|
+
*
|
|
11
|
+
* where t is normalized lifetime in [0..1].
|
|
12
|
+
*
|
|
13
|
+
* IMPORTANT:
|
|
14
|
+
* - This behaviour overwrites velocity every frame.
|
|
15
|
+
* - Forces like GravityCurveBehaviour should run AFTER this behaviour
|
|
16
|
+
* if you want gravity to modify the curve-driven motion.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
export declare class MovementCurveBehaviour implements Behaviour {
|
|
20
|
+
readonly requires: {
|
|
21
|
+
position: boolean;
|
|
22
|
+
};
|
|
23
|
+
readonly priority = -10;
|
|
24
|
+
private vxCurve;
|
|
25
|
+
private vyCurve;
|
|
26
|
+
constructor(vxKeyframes: CurveKeyframe[], vyKeyframes: CurveKeyframe[], opts?: CurveOptions);
|
|
27
|
+
update(p: PxParticle, dt: number): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=movement-curve-behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"movement-curve-behaviour.d.ts","sourceRoot":"","sources":["../../../src/behaviours/movement-behaviours/movement-curve-behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAGlF;;;;;;;;;;;;;;GAcG;AACH,qBAAa,sBAAuB,YAAW,SAAS;IACpD,SAAgB,QAAQ;;MAAsB;IAC9C,SAAgB,QAAQ,OAAO;IAE/B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAQ;gBAEX,WAAW,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY;IAKpF,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM;CAM1C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Curve } from "../curved-behaviour/curve-sampler";
|
|
2
|
+
/**
|
|
3
|
+
* Drives particle velocity directly using curves over lifetime.
|
|
4
|
+
*
|
|
5
|
+
* Each frame:
|
|
6
|
+
* vx = vxCurve(t)
|
|
7
|
+
* vy = vyCurve(t)
|
|
8
|
+
*
|
|
9
|
+
* where t is normalized lifetime in [0..1].
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT:
|
|
12
|
+
* - This behaviour overwrites velocity every frame.
|
|
13
|
+
* - Forces like GravityCurveBehaviour should run AFTER this behaviour
|
|
14
|
+
* if you want gravity to modify the curve-driven motion.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
export class MovementCurveBehaviour {
|
|
18
|
+
constructor(vxKeyframes, vyKeyframes, opts) {
|
|
19
|
+
this.requires = { position: true };
|
|
20
|
+
this.priority = -10;
|
|
21
|
+
this.vxCurve = new Curve(vxKeyframes, opts);
|
|
22
|
+
this.vyCurve = new Curve(vyKeyframes, opts);
|
|
23
|
+
}
|
|
24
|
+
update(p, dt) {
|
|
25
|
+
const t = p.life > 0 ? p.age / p.life : 1;
|
|
26
|
+
p.vx = this.vxCurve.sample(t);
|
|
27
|
+
p.vy = this.vyCurve.sample(t);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=movement-curve-behaviour.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"movement-curve-behaviour.js","sourceRoot":"","sources":["../../../src/behaviours/movement-behaviours/movement-curve-behaviour.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,sBAAsB;IAO/B,YAAY,WAA4B,EAAE,WAA4B,EAAE,IAAmB;QAN3E,aAAQ,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC9B,aAAQ,GAAG,CAAC,EAAE,CAAC;QAM3B,IAAI,CAAC,OAAO,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IAEM,MAAM,CAAC,CAAa,EAAE,EAAU;QACnC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1C,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;CACJ","sourcesContent":["import { PxParticle } from \"../../px-particle\";\r\nimport { Behaviour } from \"../../behaviour\";\r\nimport { CurveKeyframe, CurveOptions } from \"../curved-behaviour/curve-key-frame\";\r\nimport { Curve } from \"../curved-behaviour/curve-sampler\";\r\n\r\n/**\r\n * Drives particle velocity directly using curves over lifetime.\r\n *\r\n * Each frame:\r\n * vx = vxCurve(t)\r\n * vy = vyCurve(t)\r\n *\r\n * where t is normalized lifetime in [0..1].\r\n *\r\n * IMPORTANT:\r\n * - This behaviour overwrites velocity every frame.\r\n * - Forces like GravityCurveBehaviour should run AFTER this behaviour\r\n * if you want gravity to modify the curve-driven motion.\r\n *\r\n */\r\nexport class MovementCurveBehaviour implements Behaviour {\r\n public readonly requires = { position: true };\r\n public readonly priority = -10;\r\n\r\n private vxCurve: Curve;\r\n private vyCurve: Curve;\r\n\r\n constructor(vxKeyframes: CurveKeyframe[], vyKeyframes: CurveKeyframe[], opts?: CurveOptions) {\r\n this.vxCurve = new Curve(vxKeyframes, opts);\r\n this.vyCurve = new Curve(vyKeyframes, opts);\r\n }\r\n\r\n public update(p: PxParticle, dt: number) {\r\n const t = p.life > 0 ? p.age / p.life : 1;\r\n\r\n p.vx = this.vxCurve.sample(t);\r\n p.vy = this.vyCurve.sample(t);\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PxParticle } from "../../px-particle";
|
|
2
|
+
import { Behaviour } from "../../behaviour";
|
|
3
|
+
import { ParticleProperties } from "pixi.js";
|
|
4
|
+
/**
|
|
5
|
+
* Initializes particle velocity on spawn in a radial/cone burst.
|
|
6
|
+
*
|
|
7
|
+
* - Picks a random angle within [direction - spread/2, direction + spread/2]
|
|
8
|
+
* - Picks a random speed within [minSpeed, maxSpeed]
|
|
9
|
+
* - Sets particle velocity (vx, vy) in pixels/sec
|
|
10
|
+
*
|
|
11
|
+
* Notes:
|
|
12
|
+
* - This behaviour does NOT move particles directly; the emitter integrates vx/vy each tick.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RadialBurstBehaviour implements Behaviour {
|
|
15
|
+
readonly priority = -80;
|
|
16
|
+
requires: ParticleProperties;
|
|
17
|
+
/** Minimum initial speed (px/sec). */
|
|
18
|
+
minSpeed: number;
|
|
19
|
+
/** Maximum initial speed (px/sec). */
|
|
20
|
+
maxSpeed: number;
|
|
21
|
+
/**
|
|
22
|
+
* Center direction in radians.
|
|
23
|
+
* Pixi coordinate system:
|
|
24
|
+
* - 0 = right
|
|
25
|
+
* - PI/2 = down
|
|
26
|
+
*/
|
|
27
|
+
direction: number;
|
|
28
|
+
/**
|
|
29
|
+
* Cone spread in radians.
|
|
30
|
+
* - 2π = full circle
|
|
31
|
+
* - PI/3 ≈ 60° cone
|
|
32
|
+
*/
|
|
33
|
+
spread: number;
|
|
34
|
+
constructor(minSpeed: number, maxSpeed: number, direction?: number, spread?: number);
|
|
35
|
+
onSpawn(p: PxParticle): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=radial-burst-behaviour.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radial-burst-behaviour.d.ts","sourceRoot":"","sources":["../../../src/behaviours/movement-behaviours/radial-burst-behaviour.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;GASG;AACH,qBAAa,oBAAqB,YAAW,SAAS;IAClD,SAAgB,QAAQ,OAAO;IAExB,QAAQ,EAAE,kBAAkB,CAAsB;IAEzD,sCAAsC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IAExB,sCAAsC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACI,SAAS,EAAE,MAAM,CAAK;IAE7B;;;;OAIG;IACI,MAAM,EAAE,MAAM,CAAe;gBAExB,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,EAAE,MAAM,GAAE,MAAoB;IAO5F,OAAO,CAAC,CAAC,EAAE,UAAU;CAQ/B"}
|