@newkrok/nape-js 3.31.0 → 3.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2199,6 +2199,357 @@ declare class RadialGravityFieldGroup {
2199
2199
  apply(space: Space): void;
2200
2200
  }
2201
2201
 
2202
+ /** Shape used for each spawned particle body. */
2203
+ type ParticleShape = "circle" | "polygon";
2204
+ /** State snapshot passed to the `onSpawn` hook. */
2205
+ interface ParticleSpawnState {
2206
+ /** World-space spawn position. */
2207
+ position: Vec2;
2208
+ /** Initial linear velocity. */
2209
+ velocity: Vec2;
2210
+ /** Initial rotation (rad). */
2211
+ angle: number;
2212
+ /** Initial angular velocity (rad/s). */
2213
+ angularVelocity: number;
2214
+ /** Lifetime in seconds. `<= 0` disables auto-death. */
2215
+ lifetime: number;
2216
+ /** Free-form per-particle payload (color, frame index, damage, etc.). */
2217
+ userData: unknown;
2218
+ }
2219
+ /**
2220
+ * Spawn-position pattern. Position is sampled once per particle, in
2221
+ * emitter-local space (relative to {@link ParticleEmitter.origin}), then
2222
+ * translated into world space.
2223
+ *
2224
+ * - `point` — always at the origin.
2225
+ * - `rect` — uniform inside an axis-aligned rectangle centred on the origin.
2226
+ * - `circle` — uniform inside a disk; `hollow: true` samples the rim only.
2227
+ * - `arc` — on the rim of a circular arc, `angle*` in radians.
2228
+ * - `custom` — user-provided sampler. Receives the emitter's RNG.
2229
+ */
2230
+ type SpawnPattern = {
2231
+ kind: "point";
2232
+ } | {
2233
+ kind: "rect";
2234
+ width: number;
2235
+ height: number;
2236
+ } | {
2237
+ kind: "circle";
2238
+ radius: number;
2239
+ hollow?: boolean;
2240
+ } | {
2241
+ kind: "arc";
2242
+ radius: number;
2243
+ angleStart: number;
2244
+ angleEnd: number;
2245
+ } | {
2246
+ kind: "custom";
2247
+ sample: (rng: () => number) => Vec2;
2248
+ };
2249
+ /**
2250
+ * Initial-velocity pattern. The local spawn position is passed to the
2251
+ * `radial` and `custom` samplers so the velocity can depend on where the
2252
+ * particle was spawned (radial = "outward from origin").
2253
+ *
2254
+ * - `fixed` — every particle gets the same velocity vector.
2255
+ * - `cone` — uniformly random direction inside a cone of half-width
2256
+ * `spread` rad, centred on `direction` rad. Speed uniform in
2257
+ * `[speedMin, speedMax]`.
2258
+ * - `radial` — outward from the spawn point relative to the origin.
2259
+ * Speed uniform in `[speedMin, speedMax]`. If the spawn point is exactly
2260
+ * at the origin, falls back to a random direction.
2261
+ * - `custom` — user-provided sampler. Receives RNG and the local spawn
2262
+ * position.
2263
+ */
2264
+ type VelocityPattern = {
2265
+ kind: "fixed";
2266
+ value: Vec2;
2267
+ } | {
2268
+ kind: "cone";
2269
+ direction: number;
2270
+ spread: number;
2271
+ speedMin: number;
2272
+ speedMax: number;
2273
+ } | {
2274
+ kind: "radial";
2275
+ speedMin: number;
2276
+ speedMax: number;
2277
+ } | {
2278
+ kind: "custom";
2279
+ sample: (rng: () => number, localPos: Vec2) => Vec2;
2280
+ };
2281
+ /**
2282
+ * What to do when {@link ParticleEmitterOptions.maxParticles} is full and a
2283
+ * new spawn is requested.
2284
+ *
2285
+ * - `drop-oldest` (default) — kill the oldest live particle to make room for
2286
+ * the new one. Keeps emitter responsive (e.g. bullets always come out).
2287
+ * - `drop-new` — silently drop the new spawn. Protects already-visible
2288
+ * particles from churn.
2289
+ */
2290
+ type ParticleOverflowPolicy = "drop-oldest" | "drop-new";
2291
+ /** Reason a particle was killed, passed to `onDeath`. */
2292
+ type ParticleDeathReason = "lifetime" | "manual" | "bounds";
2293
+ /** World-space rectangle outside which particles auto-die. */
2294
+ interface ParticleBounds {
2295
+ x: number;
2296
+ y: number;
2297
+ w: number;
2298
+ h: number;
2299
+ }
2300
+ /** Configuration options for {@link ParticleEmitter}. */
2301
+ interface ParticleEmitterOptions {
2302
+ /** Space the emitted particle bodies live in. Required. */
2303
+ space: Space;
2304
+ /**
2305
+ * Spawn anchor. A `Vec2` is captured by reference (mutating it after
2306
+ * construction moves the emitter); a `Body` is tracked by position each
2307
+ * spawn (the body does not need to be in the same space). Required.
2308
+ */
2309
+ origin: Vec2 | Body;
2310
+ /** Spawn-position pattern. @default `{ kind: "point" }` */
2311
+ spawn?: SpawnPattern;
2312
+ /** Initial velocity pattern. @default `{ kind: "fixed", value: (0, 0) }` */
2313
+ velocity?: VelocityPattern;
2314
+ /**
2315
+ * Continuous spawn rate in particles/second. Accumulated across `update()`
2316
+ * calls — fractional rates work. `0` disables continuous spawning (use
2317
+ * {@link ParticleEmitter.emit} for manual bursts).
2318
+ * @default `0`
2319
+ */
2320
+ rate?: number;
2321
+ /**
2322
+ * Periodic-burst count (particles per burst). Combined with
2323
+ * `burstInterval`, fires a burst every `burstInterval` seconds.
2324
+ * @default `0`
2325
+ */
2326
+ burstCount?: number;
2327
+ /**
2328
+ * Period of automatic bursts in seconds. Has no effect when `burstCount`
2329
+ * is `0`.
2330
+ * @default `0`
2331
+ */
2332
+ burstInterval?: number;
2333
+ /**
2334
+ * Maximum simultaneously alive particles. The pool size is capped at this
2335
+ * value too. @default `512`
2336
+ */
2337
+ maxParticles?: number;
2338
+ /** Lifetime range minimum (s). @default `1` */
2339
+ lifetimeMin?: number;
2340
+ /** Lifetime range maximum (s). @default `1` */
2341
+ lifetimeMax?: number;
2342
+ /** Body shape for each particle. @default `"circle"` */
2343
+ particleShape?: ParticleShape;
2344
+ /** Radius for circle particles. Ignored for polygon. @default `2` */
2345
+ particleRadius?: number;
2346
+ /**
2347
+ * Polygon vertices in body-local space (used when
2348
+ * `particleShape: "polygon"`). Defaults to a small square.
2349
+ */
2350
+ particlePolygon?: Vec2[];
2351
+ /** Material applied to every particle shape. @default `new Material()` */
2352
+ particleMaterial?: Material;
2353
+ /**
2354
+ * Filter applied to every particle shape. If omitted and `selfCollision`
2355
+ * is `false`, the emitter generates a self-excluding filter automatically.
2356
+ */
2357
+ particleFilter?: InteractionFilter;
2358
+ /**
2359
+ * Collision-callback type tagged on every particle body. Required for
2360
+ * `onCollide` to fire. The emitter never auto-creates one — pass your own
2361
+ * if you need it (so multiple emitters can share a type, or a single
2362
+ * emitter can match a user-defined cbType).
2363
+ */
2364
+ particleCbType?: CbType;
2365
+ /** Whether particles can rotate. @default `true` */
2366
+ allowRotation?: boolean;
2367
+ /**
2368
+ * When `false` and no explicit `particleFilter` is given, particles
2369
+ * receive a generated filter that skips its own group — particles in the
2370
+ * same emitter never collide with each other. Has no effect when
2371
+ * `particleFilter` is provided. @default `false`
2372
+ */
2373
+ selfCollision?: boolean;
2374
+ /** Policy when `maxParticles` is reached. @default `"drop-oldest"` */
2375
+ overflowPolicy?: ParticleOverflowPolicy;
2376
+ /** Optional world-space bounds — particles outside die instantly. */
2377
+ bounds?: ParticleBounds;
2378
+ /**
2379
+ * Deterministic RNG. All emitter randomness (spawn jitter, velocity cone,
2380
+ * lifetime sampling) flows through this. @default `Math.random` */
2381
+ random?: () => number;
2382
+ /** Whether the emitter is active. @default `true` */
2383
+ enabled?: boolean;
2384
+ /** Fired once per spawn, after the body is in the space. */
2385
+ onSpawn?: (state: ParticleSpawnState, body: Body) => void;
2386
+ /** Fired every `update()` for each live particle (ages > 0). */
2387
+ onUpdate?: (body: Body, age: number, dt: number) => void;
2388
+ /** Fired when a particle dies (lifetime, bounds, manual, or `killAll`). */
2389
+ onDeath?: (body: Body, reason: ParticleDeathReason) => void;
2390
+ /**
2391
+ * Fired when a particle's body collides with another body. Requires
2392
+ * `particleCbType` to be set. The handler runs from inside a Space
2393
+ * callback — do not mutate the space synchronously; use
2394
+ * {@link ParticleEmitter.requestKill} for deferred cleanup.
2395
+ */
2396
+ onCollide?: (body: Body, other: Body) => void;
2397
+ }
2398
+ /**
2399
+ * Physics-aware particle emitter — a pooled, lifecycle-managed swarm of
2400
+ * dynamic bodies. Each particle is a real {@link Body} with a {@link Circle}
2401
+ * or {@link Polygon} shape, so it collides with the world, reacts to
2402
+ * gravity / fluids / forces, and triggers callbacks like any other body.
2403
+ *
2404
+ * @example
2405
+ * ```ts
2406
+ * // Volcano: emit lava drops upward in a 40-deg cone.
2407
+ * const volcano = new ParticleEmitter({
2408
+ * space,
2409
+ * origin: new Vec2(400, 100),
2410
+ * velocity: {
2411
+ * kind: "cone",
2412
+ * direction: -Math.PI / 2,
2413
+ * spread: Math.PI / 9,
2414
+ * speedMin: 350,
2415
+ * speedMax: 600,
2416
+ * },
2417
+ * rate: 80,
2418
+ * lifetimeMin: 4,
2419
+ * lifetimeMax: 8,
2420
+ * particleRadius: 3,
2421
+ * maxParticles: 600,
2422
+ * });
2423
+ *
2424
+ * // Each frame, before space.step():
2425
+ * volcano.update(1 / 60);
2426
+ * space.step(1 / 60);
2427
+ * ```
2428
+ */
2429
+ declare class ParticleEmitter {
2430
+ enabled: boolean;
2431
+ origin: Vec2 | Body;
2432
+ spawn: SpawnPattern;
2433
+ velocity: VelocityPattern;
2434
+ rate: number;
2435
+ burstCount: number;
2436
+ burstInterval: number;
2437
+ maxParticles: number;
2438
+ lifetimeMin: number;
2439
+ lifetimeMax: number;
2440
+ allowRotation: boolean;
2441
+ overflowPolicy: ParticleOverflowPolicy;
2442
+ bounds: ParticleBounds | null;
2443
+ onSpawn: ((state: ParticleSpawnState, body: Body) => void) | null;
2444
+ onUpdate: ((body: Body, age: number, dt: number) => void) | null;
2445
+ onDeath: ((body: Body, reason: ParticleDeathReason) => void) | null;
2446
+ onCollide: ((body: Body, other: Body) => void) | null;
2447
+ readonly space: Space;
2448
+ readonly particleShape: ParticleShape;
2449
+ readonly particleRadius: number;
2450
+ readonly particlePolygon: Vec2[] | null;
2451
+ readonly particleMaterial: Material;
2452
+ readonly particleFilter: InteractionFilter;
2453
+ readonly particleCbType: CbType | null;
2454
+ readonly random: () => number;
2455
+ private _alive;
2456
+ private _ages;
2457
+ private _lifetimes;
2458
+ private _pool;
2459
+ private _totalSpawned;
2460
+ private _rateAccumulator;
2461
+ private _burstAccumulator;
2462
+ private _killSet;
2463
+ private _listener;
2464
+ private _destroyed;
2465
+ constructor(options: ParticleEmitterOptions);
2466
+ /** Live particle bodies. Read-only — do not mutate. */
2467
+ get active(): ReadonlyArray<Body>;
2468
+ /**
2469
+ * Per-particle age in seconds, indexed parallel to {@link active}.
2470
+ * Read-only — do not mutate. Useful for renderers that fade particles
2471
+ * by `age / lifetime`.
2472
+ */
2473
+ get ages(): ReadonlyArray<number>;
2474
+ /**
2475
+ * Per-particle lifetime in seconds, indexed parallel to {@link active}.
2476
+ * Read-only — do not mutate.
2477
+ */
2478
+ get lifetimes(): ReadonlyArray<number>;
2479
+ /** Number of bodies currently in the recycle pool. */
2480
+ get poolSize(): number;
2481
+ /** Total spawn count over the lifetime of this emitter. */
2482
+ get totalSpawned(): number;
2483
+ private _originXY;
2484
+ /** Sample a position in emitter-local space. */
2485
+ private _sampleSpawn;
2486
+ /** Sample initial velocity given the local spawn position. */
2487
+ private _sampleVelocity;
2488
+ private _sampleLifetime;
2489
+ private _buildBody;
2490
+ /** Take a body out of the pool, or build a new one. */
2491
+ private _acquire;
2492
+ /**
2493
+ * Reset a body's per-life mutable state and add it to the space at the
2494
+ * given world position with the given velocity.
2495
+ */
2496
+ private _reviveBody;
2497
+ /**
2498
+ * Spawn `count` particles immediately. Returns the live bodies that were
2499
+ * spawned (length may be < `count` when the emitter is full and
2500
+ * `overflowPolicy` is `"drop-new"`).
2501
+ */
2502
+ emit(count: number): Body[];
2503
+ /** Spawn a single particle. Returns the body or `null` if dropped. */
2504
+ private _spawnOne;
2505
+ /** Remove the live particle at `index` (swap-pop) and return it to the pool. */
2506
+ private _killAt;
2507
+ /**
2508
+ * Mark a body for death at the start of the next `update()` call. Safe to
2509
+ * call from inside collision callbacks. No-op if the body is not a live
2510
+ * particle of this emitter.
2511
+ */
2512
+ requestKill(body: Body): void;
2513
+ private _flushKillSet;
2514
+ /** Kill every live particle. Bodies return to the pool. */
2515
+ killAll(): void;
2516
+ /**
2517
+ * Advance lifetimes, fire `onUpdate`, kill expired / out-of-bounds
2518
+ * particles, and run continuous / periodic spawning.
2519
+ *
2520
+ * Call once per frame, **before** `space.step()`. `dt` should match the
2521
+ * step size you'll pass to `space.step()`.
2522
+ */
2523
+ update(dt: number): void;
2524
+ /**
2525
+ * Remove every body (live + pooled) from the space, drop the listener,
2526
+ * and mark the emitter unusable. Subsequent `update` / `emit` calls
2527
+ * throw.
2528
+ */
2529
+ destroy(): void;
2530
+ private _installCollisionListener;
2531
+ }
2532
+ /**
2533
+ * Composable collection of {@link ParticleEmitter}s — analogous to
2534
+ * {@link RadialGravityFieldGroup}. One `update(dt)` runs every member emitter.
2535
+ */
2536
+ declare class ParticleEmitterGroup {
2537
+ /** Ordered list of emitters. Mutate via {@link add} / {@link remove}. */
2538
+ readonly emitters: ParticleEmitter[];
2539
+ /** Add an emitter to the group and return it. */
2540
+ add(emitter: ParticleEmitter): ParticleEmitter;
2541
+ /** Remove an emitter from the group. Returns `true` if it was present. */
2542
+ remove(emitter: ParticleEmitter): boolean;
2543
+ /** Remove all emitters (does NOT call `destroy` on them). */
2544
+ clear(): void;
2545
+ /** Number of emitters currently in the group. */
2546
+ get length(): number;
2547
+ /** Advance every emitter. */
2548
+ update(dt: number): void;
2549
+ /** Call `destroy()` on every emitter and clear the group. */
2550
+ destroyAll(): void;
2551
+ }
2552
+
2202
2553
  declare const VERSION: string;
2203
2554
 
2204
- export { AABB, AngleJoint, Arbiter, Body, BodyCallback, type BodyFilter, BodyListener, BodyType, Callback, Capsule, CbEvent, CbType, CharacterController, type CharacterControllerOptions, Circle, CollisionArbiter, type ConcaveBodyOptions, Constraint, ConstraintCallback, ConstraintListener, Contact, DebugDrawFlags, DistanceJoint, type FractureOptions, type FractureResult, Geom, GeomPoly, type GravityFalloff, InteractionCallback, InteractionFilter, InteractionListener, InteractionType, Interactor, type LDtkIntGridLayer, LineJoint, Listener, MarchingSquares, MatMN, Material, MotorJoint, type MoveResult, OptionType, PivotJoint, PreCallback, PreFlag, PreListener, PulleyJoint, RadialGravityField, RadialGravityFieldGroup, type RadialGravityFieldOptions, Shape, ShapeType, Space, SpringJoint, type TiledTileLayer, type TilemapGrid, type TilemapMergeMode, type TilemapOptions, type TilemapRect, type TilemapSolidPredicate, type TilemapTileSize, type TriggerHandler, TriggerZone, type TriggerZoneOptions, UserConstraint, VERSION, ValidationResult, Vec2, Vec3, type VoronoiCell, type VoronoiPoint, type VoronoiResult, WeldJoint, Winding, buildTilemapBody, computeVoronoi, createConcaveBody, fractureBody, generateFractureSites, ldtkLayerToGrid, meshTilemap, tiledLayerToGrid };
2555
+ export { AABB, AngleJoint, Arbiter, Body, BodyCallback, type BodyFilter, BodyListener, BodyType, Callback, Capsule, CbEvent, CbType, CharacterController, type CharacterControllerOptions, Circle, CollisionArbiter, type ConcaveBodyOptions, Constraint, ConstraintCallback, ConstraintListener, Contact, DebugDrawFlags, DistanceJoint, type FractureOptions, type FractureResult, Geom, GeomPoly, type GravityFalloff, InteractionCallback, InteractionFilter, InteractionListener, InteractionType, Interactor, type LDtkIntGridLayer, LineJoint, Listener, MarchingSquares, MatMN, Material, MotorJoint, type MoveResult, OptionType, type ParticleBounds, type ParticleDeathReason, ParticleEmitter, ParticleEmitterGroup, type ParticleEmitterOptions, type ParticleOverflowPolicy, type ParticleShape, type ParticleSpawnState, PivotJoint, PreCallback, PreFlag, PreListener, PulleyJoint, RadialGravityField, RadialGravityFieldGroup, type RadialGravityFieldOptions, Shape, ShapeType, Space, type SpawnPattern, SpringJoint, type TiledTileLayer, type TilemapGrid, type TilemapMergeMode, type TilemapOptions, type TilemapRect, type TilemapSolidPredicate, type TilemapTileSize, type TriggerHandler, TriggerZone, type TriggerZoneOptions, UserConstraint, VERSION, ValidationResult, Vec2, Vec3, type VelocityPattern, type VoronoiCell, type VoronoiPoint, type VoronoiResult, WeldJoint, Winding, buildTilemapBody, computeVoronoi, createConcaveBody, fractureBody, generateFractureSites, ldtkLayerToGrid, meshTilemap, tiledLayerToGrid };