@guinetik/gcanvas 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/demos/coordinates.html +698 -0
  2. package/demos/cube3d.html +23 -0
  3. package/demos/demos.css +17 -3
  4. package/demos/dino.html +42 -0
  5. package/demos/fluid-simple.html +22 -0
  6. package/demos/fluid.html +37 -0
  7. package/demos/gameobjects.html +626 -0
  8. package/demos/index.html +19 -7
  9. package/demos/js/blob.js +18 -5
  10. package/demos/js/coordinates.js +840 -0
  11. package/demos/js/cube3d.js +789 -0
  12. package/demos/js/dino.js +1420 -0
  13. package/demos/js/fluid-simple.js +253 -0
  14. package/demos/js/fluid.js +527 -0
  15. package/demos/js/gameobjects.js +176 -0
  16. package/demos/js/plane3d.js +256 -0
  17. package/demos/js/platformer.js +1579 -0
  18. package/demos/js/sphere3d.js +229 -0
  19. package/demos/js/sprite.js +473 -0
  20. package/demos/js/tde/accretiondisk.js +65 -12
  21. package/demos/js/tde/blackholescene.js +2 -2
  22. package/demos/js/tde/config.js +2 -2
  23. package/demos/js/tde/index.js +152 -27
  24. package/demos/js/tde/lensedstarfield.js +32 -25
  25. package/demos/js/tde/tdestar.js +78 -98
  26. package/demos/js/tde/tidalstream.js +24 -8
  27. package/demos/plane3d.html +24 -0
  28. package/demos/platformer.html +43 -0
  29. package/demos/sphere3d.html +24 -0
  30. package/demos/sprite.html +18 -0
  31. package/docs/README.md +230 -222
  32. package/docs/api/FluidSystem.md +173 -0
  33. package/docs/concepts/architecture-overview.md +204 -204
  34. package/docs/concepts/coordinate-system.md +384 -0
  35. package/docs/concepts/rendering-pipeline.md +279 -279
  36. package/docs/concepts/shapes-vs-gameobjects.md +187 -0
  37. package/docs/concepts/two-layer-architecture.md +229 -229
  38. package/docs/fluid-dynamics.md +99 -0
  39. package/docs/getting-started/first-game.md +354 -354
  40. package/docs/getting-started/installation.md +175 -157
  41. package/docs/modules/collision/README.md +2 -2
  42. package/docs/modules/fluent/README.md +6 -6
  43. package/docs/modules/game/README.md +303 -303
  44. package/docs/modules/isometric-camera.md +2 -2
  45. package/docs/modules/isometric.md +1 -1
  46. package/docs/modules/painter/README.md +328 -328
  47. package/docs/modules/particle/README.md +3 -3
  48. package/docs/modules/shapes/README.md +221 -221
  49. package/docs/modules/shapes/base/euclidian.md +123 -123
  50. package/docs/modules/shapes/base/shape.md +262 -262
  51. package/docs/modules/shapes/base/transformable.md +243 -243
  52. package/docs/modules/state/README.md +2 -2
  53. package/docs/modules/util/README.md +1 -1
  54. package/docs/modules/util/camera3d.md +3 -3
  55. package/docs/modules/util/scene3d.md +1 -1
  56. package/package.json +3 -1
  57. package/readme.md +19 -5
  58. package/src/collision/collision.js +75 -0
  59. package/src/game/game.js +11 -5
  60. package/src/game/index.js +2 -1
  61. package/src/game/objects/index.js +3 -0
  62. package/src/game/objects/platformer-scene.js +411 -0
  63. package/src/game/objects/scene.js +14 -0
  64. package/src/game/objects/sprite.js +529 -0
  65. package/src/game/pipeline.js +20 -16
  66. package/src/game/systems/FluidSystem.js +835 -0
  67. package/src/game/systems/index.js +11 -0
  68. package/src/game/ui/button.js +39 -18
  69. package/src/game/ui/cursor.js +14 -0
  70. package/src/game/ui/fps.js +12 -4
  71. package/src/game/ui/index.js +2 -0
  72. package/src/game/ui/stepper.js +549 -0
  73. package/src/game/ui/theme.js +123 -0
  74. package/src/game/ui/togglebutton.js +9 -3
  75. package/src/game/ui/tooltip.js +11 -4
  76. package/src/io/input.js +75 -45
  77. package/src/io/mouse.js +44 -19
  78. package/src/io/touch.js +35 -12
  79. package/src/math/fluid.js +507 -0
  80. package/src/math/index.js +2 -0
  81. package/src/mixins/anchor.js +17 -7
  82. package/src/motion/tweenetik.js +16 -0
  83. package/src/shapes/cube3d.js +599 -0
  84. package/src/shapes/index.js +3 -0
  85. package/src/shapes/plane3d.js +687 -0
  86. package/src/shapes/sphere3d.js +75 -6
  87. package/src/util/camera2d.js +315 -0
  88. package/src/util/camera3d.js +218 -12
  89. package/src/util/index.js +1 -0
  90. package/src/webgl/shaders/plane-shaders.js +332 -0
  91. package/src/webgl/shaders/sphere-shaders.js +4 -2
  92. package/types/fluent.d.ts +361 -0
  93. package/types/game.d.ts +303 -0
  94. package/types/index.d.ts +144 -5
  95. package/types/math.d.ts +361 -0
  96. package/types/motion.d.ts +271 -0
  97. package/types/particle.d.ts +373 -0
  98. package/types/shapes.d.ts +107 -9
  99. package/types/util.d.ts +353 -0
  100. package/types/webgl.d.ts +109 -0
  101. package/disk_example.png +0 -0
  102. package/tde.png +0 -0
package/types/motion.d.ts CHANGED
@@ -676,3 +676,274 @@ export class Motion {
676
676
  state?: MotionState | null
677
677
  ): MotionResult;
678
678
  }
679
+
680
+ // ==========================================================================
681
+ // Standalone Motion Functions (V1 API)
682
+ // ==========================================================================
683
+
684
+ /**
685
+ * Standalone bezier curve motion animation.
686
+ * @see Motion.bezier for class method equivalent
687
+ */
688
+ export function bezierV1(
689
+ p0: [number, number],
690
+ p1: [number, number],
691
+ p2: [number, number],
692
+ p3: [number, number],
693
+ elapsedTime: number,
694
+ duration: number,
695
+ loop?: boolean,
696
+ yoyo?: boolean,
697
+ easingFn?: EasingFunction | null,
698
+ callbacks?: MotionCallbacks,
699
+ state?: MotionState | null
700
+ ): MotionPositionResult;
701
+
702
+ /**
703
+ * Standalone bounce animation.
704
+ * @see Motion.bounce for class method equivalent
705
+ */
706
+ export function bounceV1(
707
+ maxHeight: number,
708
+ groundY: number,
709
+ bounceCount: number,
710
+ elapsedTime: number,
711
+ duration: number,
712
+ loop?: boolean,
713
+ easingFn?: EasingFunction | null,
714
+ callbacks?: MotionCallbacks,
715
+ state?: MotionState | null
716
+ ): MotionValueResult;
717
+
718
+ /**
719
+ * Standalone floating motion animation.
720
+ * @see Motion.float for class method equivalent
721
+ */
722
+ export function floatV1(
723
+ target: PositionTarget,
724
+ elapsedTime: number,
725
+ duration: number,
726
+ speed: number,
727
+ randomness: number,
728
+ radius: number,
729
+ loop?: boolean,
730
+ easingFn?: EasingFunction | null,
731
+ callbacks?: MotionCallbacks,
732
+ state?: MotionState | null
733
+ ): MotionPositionResult;
734
+
735
+ /**
736
+ * Standalone path following animation.
737
+ * @see Motion.follow for class method equivalent
738
+ */
739
+ export function followPath(
740
+ points: [number, number][],
741
+ closed: boolean,
742
+ elapsedTime: number,
743
+ duration: number,
744
+ loop?: boolean,
745
+ easingFn?: EasingFunction | null,
746
+ callbacks?: MotionCallbacks,
747
+ state?: MotionState | null
748
+ ): MotionPositionResult;
749
+
750
+ /**
751
+ * Standalone orbital motion animation.
752
+ * @see Motion.orbit for class method equivalent
753
+ */
754
+ export function orbitV1(
755
+ centerX: number,
756
+ centerY: number,
757
+ radiusX: number,
758
+ radiusY: number,
759
+ startAngle: number,
760
+ elapsedTime: number,
761
+ duration: number,
762
+ loop?: boolean,
763
+ clockwise?: boolean,
764
+ easingFn?: EasingFunction | null,
765
+ callbacks?: MotionCallbacks,
766
+ state?: MotionState | null
767
+ ): MotionPositionResult;
768
+
769
+ /**
770
+ * Standalone oscillation animation.
771
+ * @see Motion.oscillate for class method equivalent
772
+ */
773
+ export function oscillateV1(
774
+ min: number,
775
+ max: number,
776
+ elapsedTime: number,
777
+ duration: number,
778
+ loop?: boolean,
779
+ easingFn?: EasingFunction | null,
780
+ callbacks?: MotionCallbacks,
781
+ state?: MotionState | null
782
+ ): MotionValueResult;
783
+
784
+ /**
785
+ * Standalone parabolic arc animation.
786
+ * @see Motion.parabolic for class method equivalent
787
+ */
788
+ export function parabolicV1(
789
+ start: number,
790
+ peak: number,
791
+ end: number,
792
+ elapsedTime: number,
793
+ duration: number,
794
+ loop?: boolean,
795
+ yoyo?: boolean,
796
+ easingFn?: EasingFunction | null,
797
+ callbacks?: MotionCallbacks,
798
+ state?: MotionState | null
799
+ ): MotionValueResult;
800
+
801
+ /**
802
+ * Standalone patrol animation.
803
+ * @see Motion.patrol for class method equivalent
804
+ */
805
+ export function patrolV1(
806
+ initialX: number,
807
+ initialY: number,
808
+ elapsedTime: number,
809
+ moveTime: number,
810
+ waitTime: number,
811
+ radius: number,
812
+ loop?: boolean,
813
+ state?: MotionState | null
814
+ ): MotionPositionResult;
815
+
816
+ /**
817
+ * Standalone pendulum animation.
818
+ * @see Motion.pendulum for class method equivalent
819
+ */
820
+ export function pendulumV1(
821
+ originAngle: number,
822
+ amplitude: number,
823
+ elapsedTime: number,
824
+ duration: number,
825
+ loop?: boolean,
826
+ damped?: boolean,
827
+ easingFn?: EasingFunction | null,
828
+ callbacks?: MotionCallbacks,
829
+ state?: MotionState | null
830
+ ): MotionValueResult;
831
+
832
+ /**
833
+ * Standalone pulse animation.
834
+ * @see Motion.pulse for class method equivalent
835
+ */
836
+ export function pulseV1(
837
+ min: number,
838
+ max: number,
839
+ elapsedTime: number,
840
+ duration: number,
841
+ loop?: boolean,
842
+ yoyo?: boolean,
843
+ easingFn?: EasingFunction | null,
844
+ callbacks?: MotionCallbacks
845
+ ): MotionValueResult;
846
+
847
+ /**
848
+ * Standalone hop/jump animation.
849
+ * @see Motion.hop for class method equivalent
850
+ */
851
+ export function hopV1(
852
+ startX: number,
853
+ startY: number,
854
+ endX: number,
855
+ endY: number,
856
+ height: number,
857
+ elapsedTime: number,
858
+ duration: number,
859
+ loop?: boolean,
860
+ easingFn?: EasingFunction | null,
861
+ callbacks?: MotionCallbacks,
862
+ state?: MotionState | null
863
+ ): MotionPositionResult;
864
+
865
+ /**
866
+ * Standalone shake animation.
867
+ * @see Motion.shake for class method equivalent
868
+ */
869
+ export function shakeV1(
870
+ centerX: number,
871
+ centerY: number,
872
+ maxOffsetX: number,
873
+ maxOffsetY: number,
874
+ frequency: number,
875
+ decay: number,
876
+ elapsedTime: number,
877
+ duration: number,
878
+ loop?: boolean,
879
+ easingFn?: EasingFunction | null,
880
+ callbacks?: MotionCallbacks,
881
+ state?: MotionState | null
882
+ ): MotionPositionResult;
883
+
884
+ /**
885
+ * Standalone spiral animation.
886
+ * @see Motion.spiral for class method equivalent
887
+ */
888
+ export function spiralV1(
889
+ centerX: number,
890
+ centerY: number,
891
+ startRadius: number,
892
+ endRadius: number,
893
+ startAngle: number,
894
+ revolutions: number,
895
+ elapsedTime: number,
896
+ duration: number,
897
+ loop?: boolean,
898
+ yoyo?: boolean,
899
+ easingFn?: EasingFunction | null,
900
+ callbacks?: MotionCallbacks,
901
+ state?: MotionState | null
902
+ ): MotionPositionResult;
903
+
904
+ /**
905
+ * Standalone spring animation.
906
+ * @see Motion.spring for class method equivalent
907
+ */
908
+ export function springV1(
909
+ initial: number,
910
+ target: number,
911
+ elapsedTime: number,
912
+ duration: number,
913
+ loop?: boolean,
914
+ yoyo?: boolean,
915
+ springParams?: SpringParams,
916
+ callbacks?: MotionCallbacks
917
+ ): SpringResult;
918
+
919
+ /**
920
+ * Standalone swing animation.
921
+ * @see Motion.swing for class method equivalent
922
+ */
923
+ export function swingV1(
924
+ centerX: number,
925
+ centerY: number,
926
+ maxAngle: number,
927
+ elapsedTime: number,
928
+ duration: number,
929
+ loop?: boolean,
930
+ yoyo?: boolean,
931
+ easingFn?: EasingFunction | null,
932
+ callbacks?: MotionCallbacks,
933
+ state?: MotionState | null
934
+ ): MotionPositionResult;
935
+
936
+ /**
937
+ * Standalone waypoint animation.
938
+ * @see Motion.waypoint for class method equivalent
939
+ */
940
+ export function waypointV1(
941
+ target: PositionTarget,
942
+ elapsedTime: number,
943
+ waypoints: [number, number][],
944
+ speed: number,
945
+ waitTime: number,
946
+ loop?: boolean,
947
+ callbacks?: MotionCallbacks,
948
+ state?: MotionState | null
949
+ ): WaypointResult;
@@ -0,0 +1,373 @@
1
+ /// <reference lib="es2015" />
2
+
3
+ /**
4
+ * GCanvas Particle System Module
5
+ * High-performance particle system with optional Camera3D support.
6
+ * @module particle
7
+ */
8
+
9
+ import { GameObject, GameObjectOptions, Game } from './game';
10
+
11
+ // ==========================================================================
12
+ // Particle Class
13
+ // ==========================================================================
14
+
15
+ /** RGBA color object */
16
+ export interface ParticleColor {
17
+ r: number;
18
+ g: number;
19
+ b: number;
20
+ a: number;
21
+ }
22
+
23
+ /** Particle shape type */
24
+ export type ParticleShape = 'circle' | 'square' | 'triangle';
25
+
26
+ /**
27
+ * Lightweight data class for particle systems.
28
+ * Uses object pooling via reset() to minimize garbage collection.
29
+ *
30
+ * @example
31
+ * const p = new Particle();
32
+ * p.x = 100;
33
+ * p.y = 200;
34
+ * p.vx = 5;
35
+ * p.lifetime = 2;
36
+ */
37
+ export class Particle {
38
+ /** X position */
39
+ x: number;
40
+ /** Y position */
41
+ y: number;
42
+ /** Z position (for 3D systems) */
43
+ z: number;
44
+
45
+ /** X velocity */
46
+ vx: number;
47
+ /** Y velocity */
48
+ vy: number;
49
+ /** Z velocity */
50
+ vz: number;
51
+
52
+ /** Particle size */
53
+ size: number;
54
+ /** Particle color */
55
+ color: ParticleColor;
56
+ /** Particle shape */
57
+ shape: ParticleShape;
58
+
59
+ /** Current age in seconds */
60
+ age: number;
61
+ /** Maximum lifetime in seconds */
62
+ lifetime: number;
63
+ /** Whether particle is alive */
64
+ alive: boolean;
65
+
66
+ /** Custom data for domain-specific behaviors */
67
+ custom: Record<string, any>;
68
+
69
+ /** Progress through lifetime (0 = born, 1 = about to die) */
70
+ readonly progress: number;
71
+
72
+ constructor();
73
+
74
+ /** Reset all properties for object pooling */
75
+ reset(): void;
76
+ }
77
+
78
+ // ==========================================================================
79
+ // ParticleEmitter Class
80
+ // ==========================================================================
81
+
82
+ /** Options for ParticleEmitter */
83
+ export interface ParticleEmitterOptions {
84
+ /** Emission rate (particles per second) */
85
+ rate?: number;
86
+ /** Position X */
87
+ x?: number;
88
+ /** Position Y */
89
+ y?: number;
90
+ /** Position Z */
91
+ z?: number;
92
+ /** Position spread (randomness) */
93
+ spread?: { x?: number; y?: number; z?: number };
94
+ /** Initial velocity */
95
+ velocity?: { x?: number; y?: number; z?: number };
96
+ /** Velocity spread (randomness) */
97
+ velocitySpread?: { x?: number; y?: number; z?: number };
98
+ /** Particle size range [min, max] */
99
+ size?: [number, number];
100
+ /** Particle lifetime range [min, max] */
101
+ lifetime?: [number, number];
102
+ /** Particle color */
103
+ color?: ParticleColor | ((particle: Particle) => ParticleColor);
104
+ /** Particle shape */
105
+ shape?: ParticleShape;
106
+ /** Custom initializer function */
107
+ init?: (particle: Particle, emitter: ParticleEmitter) => void;
108
+ }
109
+
110
+ /**
111
+ * Emitter that spawns particles with configurable properties.
112
+ *
113
+ * @example
114
+ * const emitter = new ParticleEmitter({
115
+ * rate: 50,
116
+ * x: 400, y: 300,
117
+ * velocity: { x: 0, y: -100 },
118
+ * velocitySpread: { x: 50, y: 20 },
119
+ * lifetime: [1, 3],
120
+ * size: [2, 8],
121
+ * });
122
+ */
123
+ export class ParticleEmitter {
124
+ /** Whether emitter is active */
125
+ active: boolean;
126
+ /** Emission rate (particles per second) */
127
+ rate: number;
128
+ /** Emitter position X */
129
+ x: number;
130
+ /** Emitter position Y */
131
+ y: number;
132
+ /** Emitter position Z */
133
+ z: number;
134
+
135
+ constructor(options?: ParticleEmitterOptions);
136
+
137
+ /**
138
+ * Update emitter and return number of particles to spawn.
139
+ * @param dt - Delta time in seconds
140
+ * @returns Number of particles to spawn this frame
141
+ */
142
+ update(dt: number): number;
143
+
144
+ /**
145
+ * Initialize a particle with this emitter's settings.
146
+ * @param particle - Particle to initialize
147
+ */
148
+ emit(particle: Particle): void;
149
+
150
+ /** Start emitting */
151
+ start(): void;
152
+
153
+ /** Stop emitting */
154
+ stop(): void;
155
+
156
+ /** Burst spawn a specific number of particles */
157
+ burst(count: number): void;
158
+ }
159
+
160
+ // ==========================================================================
161
+ // ParticleSystem Class
162
+ // ==========================================================================
163
+
164
+ /** Options for ParticleSystem */
165
+ export interface ParticleSystemOptions extends GameObjectOptions {
166
+ /** Maximum active particles (default: 5000) */
167
+ maxParticles?: number;
168
+ /** Optional Camera3D for 3D projection */
169
+ camera?: any; // Camera3D
170
+ /** Enable depth sorting (requires camera) */
171
+ depthSort?: boolean;
172
+ /** Canvas blend mode (default: 'source-over') */
173
+ blendMode?: GlobalCompositeOperation;
174
+ /** Array of updater functions */
175
+ updaters?: ParticleUpdater[];
176
+ /** Position particles in world space */
177
+ worldSpace?: boolean;
178
+ }
179
+
180
+ /** Particle updater function signature */
181
+ export type ParticleUpdater = (particle: Particle, dt: number, system: ParticleSystem) => void;
182
+
183
+ /**
184
+ * High-performance particle management GameObject.
185
+ *
186
+ * @example
187
+ * const particles = new ParticleSystem(this, {
188
+ * camera: this.camera,
189
+ * depthSort: true,
190
+ * maxParticles: 3000,
191
+ * blendMode: 'screen',
192
+ * updaters: [Updaters.velocity, Updaters.lifetime, Updaters.gravity(150)],
193
+ * });
194
+ * particles.addEmitter('fountain', new ParticleEmitter({ rate: 50 }));
195
+ * this.pipeline.add(particles);
196
+ */
197
+ export class ParticleSystem extends GameObject {
198
+ /** Active particles */
199
+ particles: Particle[];
200
+ /** Object pool for recycled particles */
201
+ pool: Particle[];
202
+ /** Maximum particles allowed */
203
+ maxParticles: number;
204
+ /** Named emitters */
205
+ emitters: Map<string, ParticleEmitter>;
206
+ /** Optional Camera3D for 3D projection */
207
+ camera: any | null;
208
+ /** Whether to depth sort particles */
209
+ depthSort: boolean;
210
+ /** Updater functions */
211
+ updaters: ParticleUpdater[];
212
+ /** Canvas blend mode (set via options, not an accessor) */
213
+ readonly _blendMode: GlobalCompositeOperation;
214
+ /** Position in world space */
215
+ worldSpace: boolean;
216
+
217
+ /** Current particle count */
218
+ readonly particleCount: number;
219
+ /** Pool size (recycled particles ready for reuse) */
220
+ readonly poolSize: number;
221
+
222
+ constructor(game: Game, options?: ParticleSystemOptions);
223
+
224
+ /**
225
+ * Add an emitter to the system.
226
+ * @param name - Emitter identifier
227
+ * @param emitter - Emitter instance
228
+ */
229
+ addEmitter(name: string, emitter: ParticleEmitter): ParticleSystem;
230
+
231
+ /**
232
+ * Remove an emitter from the system.
233
+ * @param name - Emitter identifier
234
+ */
235
+ removeEmitter(name: string): ParticleSystem;
236
+
237
+ /**
238
+ * Get an emitter by name.
239
+ * @param name - Emitter identifier
240
+ */
241
+ getEmitter(name: string): ParticleEmitter | undefined;
242
+
243
+ /**
244
+ * Acquire a particle from pool or create new.
245
+ */
246
+ acquire(): Particle;
247
+
248
+ /**
249
+ * Release a particle back to pool.
250
+ * @param particle - Particle to release
251
+ */
252
+ release(particle: Particle): void;
253
+
254
+ /**
255
+ * Emit particles using an emitter.
256
+ * @param count - Number of particles to emit
257
+ * @param emitter - Emitter to use
258
+ */
259
+ emitParticles(count: number, emitter: ParticleEmitter): void;
260
+
261
+ /**
262
+ * Burst spawn particles.
263
+ * @param count - Number of particles
264
+ * @param emitterOrName - Emitter instance or name
265
+ */
266
+ burst(count: number, emitterOrName: ParticleEmitter | string): void;
267
+
268
+ /** Clear all particles and return them to pool */
269
+ clear(): void;
270
+
271
+ /**
272
+ * Draw a single particle (override for custom rendering).
273
+ * @param ctx - Canvas context
274
+ * @param p - Particle to draw
275
+ * @param x - Screen X position
276
+ * @param y - Screen Y position
277
+ * @param scale - Size scale factor
278
+ */
279
+ drawParticle(ctx: CanvasRenderingContext2D, p: Particle, x: number, y: number, scale: number): void;
280
+ }
281
+
282
+ // ==========================================================================
283
+ // Updaters
284
+ // ==========================================================================
285
+
286
+ /**
287
+ * Collection of composable particle updater functions.
288
+ *
289
+ * @example
290
+ * const system = new ParticleSystem(game, {
291
+ * updaters: [
292
+ * Updaters.velocity,
293
+ * Updaters.lifetime,
294
+ * Updaters.gravity(200),
295
+ * Updaters.fadeOut,
296
+ * Updaters.shrink,
297
+ * ]
298
+ * });
299
+ */
300
+ export namespace Updaters {
301
+ /** Apply velocity to position */
302
+ const velocity: ParticleUpdater;
303
+
304
+ /** Update age and kill expired particles */
305
+ const lifetime: ParticleUpdater;
306
+
307
+ /** Fade out alpha over lifetime */
308
+ const fadeOut: ParticleUpdater;
309
+
310
+ /** Shrink size over lifetime */
311
+ const shrink: ParticleUpdater;
312
+
313
+ /** Grow size over lifetime */
314
+ const grow: ParticleUpdater;
315
+
316
+ /**
317
+ * Apply gravity acceleration.
318
+ * @param strength - Gravity strength (pixels per second squared)
319
+ * @param axis - Axis to apply gravity ('y' by default)
320
+ */
321
+ function gravity(strength: number, axis?: 'x' | 'y' | 'z'): ParticleUpdater;
322
+
323
+ /**
324
+ * Apply friction/drag.
325
+ * @param factor - Friction factor (0-1, lower = more friction)
326
+ */
327
+ function friction(factor: number): ParticleUpdater;
328
+
329
+ /**
330
+ * Apply wind force.
331
+ * @param forceX - X force
332
+ * @param forceY - Y force
333
+ */
334
+ function wind(forceX: number, forceY: number): ParticleUpdater;
335
+
336
+ /**
337
+ * Constrain particles to bounds.
338
+ * @param bounds - Bounding box
339
+ * @param bounce - Bounce factor (0-1)
340
+ */
341
+ function bounds(bounds: { x: number; y: number; width: number; height: number }, bounce?: number): ParticleUpdater;
342
+
343
+ /**
344
+ * Color transition over lifetime.
345
+ * @param startColor - Starting color
346
+ * @param endColor - Ending color
347
+ */
348
+ function colorTransition(startColor: ParticleColor, endColor: ParticleColor): ParticleUpdater;
349
+
350
+ /**
351
+ * Attract/repel from a point.
352
+ * @param x - Attractor X position
353
+ * @param y - Attractor Y position
354
+ * @param strength - Attraction strength (negative = repel)
355
+ */
356
+ function attract(x: number, y: number, strength: number): ParticleUpdater;
357
+
358
+ /**
359
+ * Apply turbulence/noise to velocity.
360
+ * @param strength - Turbulence strength
361
+ * @param scale - Noise scale
362
+ */
363
+ function turbulence(strength: number, scale?: number): ParticleUpdater;
364
+
365
+ /**
366
+ * Orbital motion around a point.
367
+ * @param centerX - Center X
368
+ * @param centerY - Center Y
369
+ * @param speed - Angular speed
370
+ */
371
+ function orbital(centerX: number, centerY: number, speed: number): ParticleUpdater;
372
+ }
373
+