angular-three-rapier 4.0.0-next.119 → 4.0.0-next.120

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/README.md CHANGED
@@ -19,17 +19,22 @@ npm install angular-three-rapier @dimforge/rapier3d-compat
19
19
  ## Usage
20
20
 
21
21
  ```typescript
22
- import { Component, CUSTOM_ELEMENTS_SCHEMA, viewChild, ElementRef } from '@angular/core';
23
- import { NgtrPhysics, NgtrRigidBody, NgtrCuboidCollider } from 'angular-three-rapier';
24
- import { Mesh } from 'three';
22
+ import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
23
+ import { extend, NgtArgs } from 'angular-three';
24
+ import { NgtrPhysics, NgtrRigidBody } from 'angular-three-rapier';
25
+ import * as THREE from 'three';
26
+
27
+ extend(THREE);
25
28
 
26
29
  @Component({
27
30
  selector: 'app-box',
28
31
  template: `
29
- <ngt-mesh ngtrRigidBody="dynamic" [position]="[0, 5, 0]">
30
- <ngt-box-geometry />
31
- <ngt-mesh-standard-material color="hotpink" />
32
- </ngt-mesh>
32
+ <ngt-object3D rigidBody [position]="[0, 5, 0]">
33
+ <ngt-mesh>
34
+ <ngt-box-geometry />
35
+ <ngt-mesh-standard-material color="hotpink" />
36
+ </ngt-mesh>
37
+ </ngt-object3D>
33
38
  `,
34
39
  imports: [NgtrRigidBody],
35
40
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
@@ -39,12 +44,14 @@ export class Box {}
39
44
  @Component({
40
45
  selector: 'app-ground',
41
46
  template: `
42
- <ngt-mesh ngtrRigidBody="fixed" [position]="[0, -1, 0]">
43
- <ngt-box-geometry [args]="[20, 1, 20]" />
44
- <ngt-mesh-standard-material color="gray" />
45
- </ngt-mesh>
47
+ <ngt-object3D rigidBody="fixed" [position]="[0, -1, 0]">
48
+ <ngt-mesh>
49
+ <ngt-box-geometry *args="[20, 1, 20]" />
50
+ <ngt-mesh-standard-material color="gray" />
51
+ </ngt-mesh>
52
+ </ngt-object3D>
46
53
  `,
47
- imports: [NgtrRigidBody],
54
+ imports: [NgtrRigidBody, NgtArgs],
48
55
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
49
56
  })
50
57
  export class Ground {}
@@ -52,8 +59,10 @@ export class Ground {}
52
59
  @Component({
53
60
  template: `
54
61
  <ngtr-physics [options]="{ gravity: [0, -9.81, 0] }">
55
- <app-box />
56
- <app-ground />
62
+ <ng-template>
63
+ <app-box />
64
+ <app-ground />
65
+ </ng-template>
57
66
  </ngtr-physics>
58
67
  `,
59
68
  imports: [NgtrPhysics, Box, Ground],
@@ -73,46 +82,298 @@ export class SceneGraph {}
73
82
  | `interpolate` | Enable transform interpolation | `true` |
74
83
  | `updateLoop` | Update loop type: `'follow'` or `'independent'` | `'follow'` |
75
84
 
76
- ## Rigid Body Types
85
+ ## Rigid Body
86
+
87
+ Use `ngt-object3D` with the `rigidBody` attribute. The rigid body type is specified as the attribute value:
88
+
89
+ ```html
90
+ <!-- Dynamic (default when empty) -->
91
+ <ngt-object3D rigidBody [position]="[0, 5, 0]">
92
+ <ngt-mesh>...</ngt-mesh>
93
+ </ngt-object3D>
94
+
95
+ <!-- Fixed (static) -->
96
+ <ngt-object3D rigidBody="fixed" [position]="[0, -1, 0]">
97
+ <ngt-mesh>...</ngt-mesh>
98
+ </ngt-object3D>
99
+
100
+ <!-- Kinematic -->
101
+ <ngt-object3D rigidBody="kinematicPosition">
102
+ <ngt-mesh>...</ngt-mesh>
103
+ </ngt-object3D>
104
+ ```
77
105
 
78
- - `'dynamic'` - Affected by forces and collisions
106
+ ### Rigid Body Types
107
+
108
+ - `''` or `'dynamic'` - Affected by forces and collisions
79
109
  - `'fixed'` - Static, immovable body
80
110
  - `'kinematicPosition'` - Controlled by position, affects dynamic bodies
81
111
  - `'kinematicVelocity'` - Controlled by velocity, affects dynamic bodies
82
112
 
83
- ## Collider Types
113
+ ### Rigid Body Options
114
+
115
+ ```html
116
+ <ngt-object3D
117
+ rigidBody
118
+ [options]="{
119
+ colliders: 'ball',
120
+ ccd: true,
121
+ gravityScale: 0.5,
122
+ linearVelocity: [0, 10, 0],
123
+ angularVelocity: [0, 1, 0]
124
+ }"
125
+ >
126
+ ...
127
+ </ngt-object3D>
128
+ ```
129
+
130
+ ### Rigid Body Events
131
+
132
+ ```html
133
+ <ngt-object3D
134
+ rigidBody
135
+ (collisionEnter)="onCollisionEnter($event)"
136
+ (collisionExit)="onCollisionExit($event)"
137
+ (intersectionEnter)="onIntersectionEnter($event)"
138
+ (intersectionExit)="onIntersectionExit($event)"
139
+ (contactForce)="onContactForce($event)"
140
+ (sleep)="onSleep()"
141
+ (wake)="onWake()"
142
+ >
143
+ ...
144
+ </ngt-object3D>
145
+ ```
146
+
147
+ ## Colliders
84
148
 
85
- Built-in collider directives:
149
+ Colliders use `ngt-object3D` with specific collider attributes. By default, rigid bodies auto-generate colliders from child meshes.
86
150
 
87
- - `NgtrCuboidCollider` - Box shape
88
- - `NgtrBallCollider` - Sphere shape
89
- - `NgtrCapsuleCollider` - Capsule shape
90
- - `NgtrCylinderCollider` - Cylinder shape
91
- - `NgtrConeCollider` - Cone shape
92
- - `NgtrTrimeshCollider` - Triangle mesh (static only)
93
- - `NgtrConvexHullCollider` - Convex hull
94
- - `NgtrHeightfieldCollider` - Terrain heightfield
151
+ ### Explicit Colliders
152
+
153
+ ```html
154
+ <!-- Ball collider -->
155
+ <ngt-object3D [ballCollider]="[0.5]" [position]="[0, 2, 0]" />
156
+
157
+ <!-- Cuboid collider (half-extents) -->
158
+ <ngt-object3D [cuboidCollider]="[1, 0.5, 2]" [position]="[0, 0, 0]" />
159
+
160
+ <!-- Capsule collider (half-height, radius) -->
161
+ <ngt-object3D [capsuleCollider]="[0.5, 0.25]" [position]="[0, 1, 0]" />
162
+
163
+ <!-- Cylinder collider (half-height, radius) -->
164
+ <ngt-object3D [cylinderCollider]="[1, 0.5]" />
165
+
166
+ <!-- Cone collider (half-height, radius) -->
167
+ <ngt-object3D [coneCollider]="[1, 0.5]" />
168
+ ```
169
+
170
+ ### Available Collider Directives
171
+
172
+ | Directive | Args | Description |
173
+ | --------------------------- | --------------------------------- | ------------------- |
174
+ | `NgtrBallCollider` | `[radius]` | Sphere shape |
175
+ | `NgtrCuboidCollider` | `[halfW, halfH, halfD]` | Box shape |
176
+ | `NgtrCapsuleCollider` | `[halfHeight, radius]` | Capsule shape |
177
+ | `NgtrCylinderCollider` | `[halfHeight, radius]` | Cylinder shape |
178
+ | `NgtrConeCollider` | `[halfHeight, radius]` | Cone shape |
179
+ | `NgtrConvexHullCollider` | `[vertices]` | Convex hull |
180
+ | `NgtrTrimeshCollider` | `[vertices, indices]` | Triangle mesh |
181
+ | `NgtrHeightfieldCollider` | `[width, height, heights, scale]` | Terrain heightfield |
182
+ | `NgtrRoundCuboidCollider` | `[halfW, halfH, halfD, radius]` | Rounded box |
183
+ | `NgtrRoundCylinderCollider` | `[halfH, radius, borderRadius]` | Rounded cylinder |
184
+ | `NgtrRoundConeCollider` | `[halfH, radius, borderRadius]` | Rounded cone |
185
+
186
+ ### Disabling Auto-Colliders
187
+
188
+ ```html
189
+ <ngt-object3D rigidBody [options]="{ colliders: false }">
190
+ <!-- Manual colliders only -->
191
+ <ngt-object3D [ballCollider]="[0.5]" />
192
+ </ngt-object3D>
193
+ ```
194
+
195
+ ### Mesh Collider
196
+
197
+ Generate colliders from mesh geometry:
198
+
199
+ ```html
200
+ <ngt-object3D rigidBody [options]="{ colliders: false }">
201
+ <ngt-object3D [meshCollider]="'trimesh'">
202
+ <ngt-mesh>
203
+ <ngt-torus-geometry />
204
+ <ngt-mesh-standard-material />
205
+ </ngt-mesh>
206
+ </ngt-object3D>
207
+ </ngt-object3D>
208
+ ```
95
209
 
96
210
  ## Joints
97
211
 
98
- Create joints between rigid bodies:
212
+ Create joints between rigid bodies using injectable functions:
99
213
 
100
214
  ```typescript
101
- import { fixedJoint, sphericalJoint, revoluteJoint, prismaticJoint } from 'angular-three-rapier';
215
+ import { Component, viewChild } from '@angular/core';
216
+ import {
217
+ NgtrRigidBody,
218
+ sphericalJoint,
219
+ revoluteJoint,
220
+ prismaticJoint,
221
+ fixedJoint,
222
+ ropeJoint,
223
+ springJoint,
224
+ } from 'angular-three-rapier';
102
225
 
103
- // In your component
104
- fixedJoint(bodyA, bodyB, {
105
- body1Anchor: [0, 0, 0],
106
- body2Anchor: [0, 1, 0],
107
- });
226
+ @Component({
227
+ template: `
228
+ <ngt-object3D rigidBody="fixed" #bodyA="rigidBody">...</ngt-object3D>
229
+ <ngt-object3D rigidBody #bodyB="rigidBody">...</ngt-object3D>
230
+ `,
231
+ })
232
+ export class JointExample {
233
+ bodyA = viewChild.required<NgtrRigidBody>('bodyA');
234
+ bodyB = viewChild.required<NgtrRigidBody>('bodyB');
235
+
236
+ // Spherical joint (ball-and-socket)
237
+ joint = sphericalJoint(
238
+ () => this.bodyA().rigidBody(),
239
+ () => this.bodyB().rigidBody(),
240
+ {
241
+ data: {
242
+ body1Anchor: [0, -0.5, 0],
243
+ body2Anchor: [0, 0.5, 0],
244
+ },
245
+ },
246
+ );
247
+
248
+ // Revolute joint (hinge) with limits
249
+ hingeJoint = revoluteJoint(
250
+ () => this.bodyA().rigidBody(),
251
+ () => this.bodyB().rigidBody(),
252
+ {
253
+ data: {
254
+ body1Anchor: [0, 0, 0],
255
+ body2Anchor: [0, 1, 0],
256
+ axis: [0, 1, 0],
257
+ limits: [-Math.PI / 2, Math.PI / 2],
258
+ },
259
+ },
260
+ );
261
+
262
+ // Prismatic joint (slider)
263
+ sliderJoint = prismaticJoint(
264
+ () => this.bodyA().rigidBody(),
265
+ () => this.bodyB().rigidBody(),
266
+ {
267
+ data: {
268
+ body1Anchor: [0, 0, 0],
269
+ body2Anchor: [2, 0, 0],
270
+ axis: [1, 0, 0],
271
+ limits: [-1, 1],
272
+ },
273
+ },
274
+ );
275
+
276
+ // Rope joint (max distance constraint)
277
+ rope = ropeJoint(
278
+ () => this.bodyA().rigidBody(),
279
+ () => this.bodyB().rigidBody(),
280
+ {
281
+ data: {
282
+ body1Anchor: [0, 0, 0],
283
+ body2Anchor: [0, 0, 0],
284
+ length: 5,
285
+ },
286
+ },
287
+ );
288
+
289
+ // Spring joint
290
+ spring = springJoint(
291
+ () => this.bodyA().rigidBody(),
292
+ () => this.bodyB().rigidBody(),
293
+ {
294
+ data: {
295
+ body1Anchor: [0, 0, 0],
296
+ body2Anchor: [0, 0, 0],
297
+ restLength: 2,
298
+ stiffness: 100,
299
+ damping: 10,
300
+ },
301
+ },
302
+ );
303
+ }
304
+ ```
305
+
306
+ ## Instanced Rigid Bodies
307
+
308
+ For efficient physics with many identical objects:
309
+
310
+ ```typescript
311
+ import { NgtArgs } from 'angular-three';
312
+ import { NgtrInstancedRigidBodies } from 'angular-three-rapier';
313
+
314
+ @Component({
315
+ template: `
316
+ <ngt-object3D [instancedRigidBodies]="instances">
317
+ <ngt-instanced-mesh [count]="instances.length" castShadow>
318
+ <ngt-sphere-geometry *args="[0.5]" />
319
+ <ngt-mesh-standard-material color="orange" />
320
+ </ngt-instanced-mesh>
321
+ </ngt-object3D>
322
+ `,
323
+ imports: [NgtrInstancedRigidBodies, NgtArgs],
324
+ })
325
+ export class Spheres {
326
+ instances = Array.from({ length: 100 }, (_, i) => ({
327
+ key: i,
328
+ position: [Math.random() * 10, Math.random() * 10, 0] as [number, number, number],
329
+ }));
330
+ }
331
+ ```
332
+
333
+ ## Interaction Groups
334
+
335
+ Filter collisions between objects:
336
+
337
+ ```typescript
338
+ import { interactionGroups } from 'angular-three-rapier';
339
+
340
+ // Member of group 0, collides with groups 0 and 1
341
+ const groups = interactionGroups([0], [0, 1]);
342
+ ```
343
+
344
+ ```html
345
+ <!-- Using directive -->
346
+ <ngt-object3D rigidBody [interactionGroups]="[[0], [0, 1]]">...</ngt-object3D>
347
+ ```
348
+
349
+ ## Physics Hooks
350
+
351
+ ```typescript
352
+ import { beforePhysicsStep, afterPhysicsStep } from 'angular-three-rapier';
353
+
354
+ @Component({...})
355
+ export class MyComponent {
356
+ constructor() {
357
+ beforePhysicsStep((world) => {
358
+ // Run before each physics step
359
+ });
360
+
361
+ afterPhysicsStep((world) => {
362
+ // Run after each physics step
363
+ });
364
+ }
365
+ }
108
366
  ```
109
367
 
110
368
  ## Debug Visualization
111
369
 
370
+ Enable debug rendering via physics options:
371
+
112
372
  ```html
113
- <ngtr-physics>
114
- <ngtr-debug />
115
- <!-- your physics objects -->
373
+ <ngtr-physics [options]="{ debug: true }">
374
+ <ng-template>
375
+ <!-- your physics objects -->
376
+ </ng-template>
116
377
  </ngtr-physics>
117
378
  ```
118
379
 
@@ -127,7 +388,22 @@ import { NgtrAttractor } from 'angular-three-rapier/addons';
127
388
  ```
128
389
 
129
390
  ```html
130
- <ngt-mesh ngtrAttractor [options]="{ strength: 10, range: 20, type: 'linear' }">
131
- <!-- attractor geometry -->
132
- </ngt-mesh>
391
+ <!-- Attractor with default options -->
392
+ <ngt-object3D attractor />
393
+
394
+ <!-- Attractor with custom options -->
395
+ <ngt-object3D [attractor]="{ strength: 10, range: 20, type: 'linear' }" />
396
+
397
+ <!-- Repeller (negative strength) -->
398
+ <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
399
+
400
+ <!-- Newtonian gravity -->
401
+ <ngt-object3D
402
+ [attractor]="{
403
+ strength: 1000,
404
+ range: 50,
405
+ type: 'newtonian',
406
+ gravitationalConstant: 0.01
407
+ }"
408
+ />
133
409
  ```
package/addons/README.md CHANGED
@@ -17,11 +17,14 @@ A directive that creates a gravitational attractor point in the physics world. A
17
17
  ### Basic Usage
18
18
 
19
19
  ```html
20
- <!-- Simple attractor at origin -->
21
- <ngt-object3D attractor [options]="{ strength: 5, range: 20 }" />
20
+ <!-- Simple attractor at origin with default options -->
21
+ <ngt-object3D attractor />
22
+
23
+ <!-- Attractor with custom options -->
24
+ <ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
22
25
 
23
26
  <!-- Repeller (negative strength) -->
24
- <ngt-object3D attractor [options]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
27
+ <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
25
28
  ```
26
29
 
27
30
  ### Gravity Types
@@ -30,20 +33,19 @@ The attractor supports three different gravity calculation models:
30
33
 
31
34
  ```html
32
35
  <!-- Static: Constant force regardless of distance -->
33
- <ngt-object3D attractor [options]="{ type: 'static', strength: 5, range: 20 }" />
36
+ <ngt-object3D [attractor]="{ type: 'static', strength: 5, range: 20 }" />
34
37
 
35
38
  <!-- Linear: Force increases as objects get closer -->
36
- <ngt-object3D attractor [options]="{ type: 'linear', strength: 5, range: 20 }" />
39
+ <ngt-object3D [attractor]="{ type: 'linear', strength: 5, range: 20 }" />
37
40
 
38
41
  <!-- Newtonian: Realistic inverse-square law (like real gravity) -->
39
42
  <ngt-object3D
40
- attractor
41
- [options]="{
42
- type: 'newtonian',
43
- strength: 1000,
44
- range: 50,
45
- gravitationalConstant: 0.01
46
- }"
43
+ [attractor]="{
44
+ type: 'newtonian',
45
+ strength: 1000,
46
+ range: 50,
47
+ gravitationalConstant: 0.01
48
+ }"
47
49
  />
48
50
  ```
49
51
 
@@ -48,13 +48,11 @@ function attractorDebug(object, options, injector) {
48
48
  });
49
49
  });
50
50
  beforeRender(() => {
51
- if (!physics['debug']())
51
+ if (!physics['debug']() || !mesh || !normalsHelper)
52
52
  return;
53
- if (mesh) {
54
- const worldPosition = object.getWorldPosition(_v3);
55
- mesh.position.copy(worldPosition);
56
- normalsHelper?.update();
57
- }
53
+ const worldPosition = object.getWorldPosition(_v3);
54
+ mesh.position.copy(worldPosition);
55
+ normalsHelper.update();
58
56
  });
59
57
  });
60
58
  }
@@ -141,14 +139,17 @@ const defaultOptions = {
141
139
  *
142
140
  * @example
143
141
  * ```html
144
- * <!-- Simple attractor at origin -->
145
- * <ngt-object3D attractor [options]="{ strength: 5, range: 20 }" />
142
+ * <!-- Simple attractor at origin with default options -->
143
+ * <ngt-object3D attractor />
144
+ *
145
+ * <!-- Attractor with custom options -->
146
+ * <ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
146
147
  *
147
148
  * <!-- Repeller (negative strength) -->
148
- * <ngt-object3D attractor [options]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
149
+ * <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
149
150
  *
150
151
  * <!-- Newtonian gravity -->
151
- * <ngt-object3D attractor [options]="{
152
+ * <ngt-object3D [attractor]="{
152
153
  * strength: 1000,
153
154
  * range: 50,
154
155
  * type: 'newtonian',
@@ -158,7 +159,7 @@ const defaultOptions = {
158
159
  */
159
160
  class NgtrAttractor {
160
161
  position = input([0, 0, 0], ...(ngDevMode ? [{ debugName: "position" }] : []));
161
- options = input(defaultOptions, { ...(ngDevMode ? { debugName: "options" } : {}), transform: mergeInputs(defaultOptions) });
162
+ options = input(defaultOptions, { ...(ngDevMode ? { debugName: "options" } : {}), alias: 'attractor', transform: mergeInputs(defaultOptions) });
162
163
  objectRef = inject(ElementRef);
163
164
  collisionGroups = pick(this.options, 'collisionGroups');
164
165
  linkedCollisionGroups = linkedSignal(this.collisionGroups, ...(ngDevMode ? [{ debugName: "linkedCollisionGroups" }] : []));
@@ -185,7 +186,7 @@ class NgtrAttractor {
185
186
  attractorDebug(this.objectRef.nativeElement, this.options);
186
187
  }
187
188
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NgtrAttractor, deps: [], target: i0.ɵɵFactoryTarget.Directive });
188
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: NgtrAttractor, isStandalone: true, selector: "ngt-object3D[attractor]", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
189
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: NgtrAttractor, isStandalone: true, selector: "ngt-object3D[attractor]", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "attractor", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
189
190
  {
190
191
  provide: COLLISION_GROUPS_HANDLER,
191
192
  useFactory: (attractor) => {
@@ -213,7 +214,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
213
214
  },
214
215
  ],
215
216
  }]
216
- }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
217
+ }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "attractor", required: false }] }] } });
217
218
 
218
219
  /**
219
220
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"angular-three-rapier-addons.mjs","sources":["../../../../libs/rapier/addons/src/lib/attractor-debug.ts","../../../../libs/rapier/addons/src/lib/attractor.ts","../../../../libs/rapier/addons/src/angular-three-rapier-addons.ts"],"sourcesContent":["import { computed, effect, inject, Injector } from '@angular/core';\nimport { beforeRender, injectStore, pick } from 'angular-three';\nimport { NgtrPhysics } from 'angular-three-rapier';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport * as THREE from 'three';\nimport { VertexNormalsHelper } from 'three-stdlib';\nimport { NgtrAttactorOptions } from './attractor';\n\nconst _v3 = new THREE.Vector3();\n\n/**\n * Creates debug visualization for an attractor.\n * Shows a sphere at the attractor position with normals indicating the range.\n * Blue indicates attraction, red indicates repulsion.\n *\n * This is automatically called by NgtrAttractor when physics debug mode is enabled.\n *\n * @param object - The Object3D representing the attractor position\n * @param options - Getter function for attractor options\n * @param injector - Optional injector for dependency injection context\n *\n * @internal\n */\nexport function attractorDebug(object: THREE.Object3D, options: () => NgtrAttactorOptions, injector?: Injector) {\n\treturn assertInjector(attractorDebug, injector, () => {\n\t\tconst physics = inject(NgtrPhysics);\n\t\tconst store = injectStore();\n\n\t\tconst strength = pick(options, 'strength');\n\t\tconst range = pick(options, 'range');\n\t\tconst color = computed(() => (strength() > 0 ? 0x0000ff : 0xff0000));\n\n\t\tlet mesh: THREE.Mesh;\n\t\tlet normalsHelper: VertexNormalsHelper;\n\n\t\teffect((onCleanup) => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tmesh = new THREE.Mesh(\n\t\t\t\tnew THREE.SphereGeometry(0.2, 6, 6),\n\t\t\t\tnew THREE.MeshBasicMaterial({ color: color(), wireframe: true }),\n\t\t\t);\n\n\t\t\tnormalsHelper = new VertexNormalsHelper(mesh, range(), color());\n\t\t\tnormalsHelper.frustumCulled = false;\n\n\t\t\tstore.snapshot.scene.add(mesh);\n\t\t\tstore.snapshot.scene.add(normalsHelper);\n\n\t\t\tonCleanup(() => {\n\t\t\t\tif (mesh) {\n\t\t\t\t\tstore.snapshot.scene.remove(mesh);\n\t\t\t\t}\n\n\t\t\t\tif (normalsHelper) {\n\t\t\t\t\tstore.snapshot.scene.remove(normalsHelper);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tbeforeRender(() => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tif (mesh) {\n\t\t\t\tconst worldPosition = object.getWorldPosition(_v3);\n\t\t\t\tmesh.position.copy(worldPosition);\n\t\t\t\tnormalsHelper?.update();\n\t\t\t}\n\t\t});\n\t});\n}\n","import { Directive, effect, ElementRef, inject, input, linkedSignal, untracked } from '@angular/core';\nimport { InteractionGroups, RigidBody } from '@dimforge/rapier3d-compat';\nimport { applyProps, NgtVector3, pick } from 'angular-three';\nimport { beforePhysicsStep, COLLISION_GROUPS_HANDLER } from 'angular-three-rapier';\nimport { mergeInputs } from 'ngxtension/inject-inputs';\nimport * as THREE from 'three';\nimport { attractorDebug } from './attractor-debug';\n\n/**\n * Force calculation functions for different gravity types.\n * - static: Constant force regardless of distance\n * - linear: Force increases linearly as distance decreases\n * - newtonian: Force follows Newton's law of universal gravitation\n */\nconst calcForceByType = {\n\tstatic: (s: number, m2: number, r: number, d: number, G: number) => s,\n\tlinear: (s: number, m2: number, r: number, d: number, G: number) => s * (d / r),\n\tnewtonian: (s: number, m2: number, r: number, d: number, G: number) => (G * s * m2) / Math.pow(d, 2),\n};\n\nconst _position = new THREE.Vector3();\nconst _vector3 = new THREE.Vector3();\n\n/**\n * Applies attractor force to a rigid body based on its distance from the attractor.\n * Used internally by NgtrAttractor but can be called manually for custom behavior.\n *\n * @param rigidBody - The rigid body to apply the force to\n * @param options - The attractor configuration including position, strength, and type\n *\n * @example\n * ```typescript\n * beforePhysicsStep((world) => {\n * world.bodies.forEach((body) => {\n * if (body.isDynamic()) {\n * applyAttractorForceOnRigidBody(body, {\n * object: attractorMesh,\n * strength: 10,\n * range: 20,\n * type: 'newtonian',\n * gravitationalConstant: 6.673e-11\n * });\n * }\n * });\n * });\n * ```\n */\nexport function applyAttractorForceOnRigidBody(\n\trigidBody: RigidBody,\n\t{\n\t\tobject,\n\t\tstrength,\n\t\trange,\n\t\tgravitationalConstant,\n\t\tcollisionGroups,\n\t\ttype,\n\t}: NgtrAttactorOptions & { object: THREE.Object3D },\n) {\n\tconst rbPosition = rigidBody.translation();\n\t_position.set(rbPosition.x, rbPosition.y, rbPosition.z);\n\n\tconst worldPosition = object.getWorldPosition(new THREE.Vector3());\n\n\tconst distance: number = worldPosition.distanceTo(_position);\n\n\tif (distance < range) {\n\t\tlet force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant);\n\n\t\t// Prevent wild forces when Attractors collide\n\t\tforce = force === Infinity ? strength : force;\n\n\t\t// Naively test if the rigidBody contains a collider in one of the collision groups\n\t\tlet isRigidBodyInCollisionGroup = collisionGroups === undefined;\n\t\tif (collisionGroups !== undefined) {\n\t\t\tfor (let i = 0; i < rigidBody.numColliders(); i++) {\n\t\t\t\tconst collider = rigidBody.collider(i);\n\t\t\t\tconst colliderCollisionGroups = collider.collisionGroups();\n\t\t\t\tif (\n\t\t\t\t\t((collisionGroups >> 16) & colliderCollisionGroups) != 0 &&\n\t\t\t\t\t((colliderCollisionGroups >> 16) & collisionGroups) != 0\n\t\t\t\t) {\n\t\t\t\t\tisRigidBodyInCollisionGroup = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (isRigidBodyInCollisionGroup) {\n\t\t\t_vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);\n\n\t\t\trigidBody.applyImpulse(_vector3, true);\n\t\t}\n\t}\n}\n\n/**\n * Type of gravity calculation for attractors.\n * - `'static'` - Constant force regardless of distance\n * - `'linear'` - Force scales linearly with distance (closer = stronger)\n * - `'newtonian'` - Force follows Newton's law of universal gravitation (inverse square)\n */\nexport type NgtrAttractorGravityType = 'static' | 'linear' | 'newtonian';\n\n/**\n * Configuration options for the attractor directive.\n */\nexport interface NgtrAttactorOptions {\n\t/**\n\t * The strength of the attractor.\n\t * Positive values attract, negative values repel.\n\t *\n\t * @defaultValue 1\n\t */\n\tstrength: number;\n\n\t/**\n\t * The range of the attractor. Will not affect objects outside of this range.\n\t *\n\t * @defaultValue 10\n\t * @min 0\n\t */\n\trange: number;\n\n\t/**\n\t * The type of gravity to use.\n\t * - static: The gravity is constant and does not change over time.\n\t * - linear: The gravity is linearly interpolated the closer the object is to the attractor.\n\t * - newtonian: The gravity is calculated using the newtonian gravity formula.\n\t * @defaultValue \"static\"\n\t */\n\ttype: NgtrAttractorGravityType;\n\n\t/**\n\t * The mass of the attractor. Used when type is `newtonian`.\n\t * @defaultValue 6.673e-11\n\t */\n\tgravitationalConstant: number;\n\n\t/**\n\t * The collision groups that this attractor will apply effects to. If a RigidBody contains one or more colliders that are in one of the mask group, it will be affected by this attractor.\n\t * If not specified, the attractor will apply effects to all RigidBodies.\n\t */\n\tcollisionGroups?: InteractionGroups;\n}\n\nconst defaultOptions: NgtrAttactorOptions = {\n\tstrength: 1,\n\trange: 10,\n\ttype: 'static',\n\tgravitationalConstant: 6.673e-11,\n};\n\n/**\n * Directive that creates a gravitational attractor point in the physics world.\n * All dynamic rigid bodies within range will be attracted (or repelled) towards this point.\n *\n * The attractor can use different gravity models:\n * - Static: constant force\n * - Linear: force increases as objects get closer\n * - Newtonian: realistic inverse-square law\n *\n * @example\n * ```html\n * <!-- Simple attractor at origin -->\n * <ngt-object3D attractor [options]=\"{ strength: 5, range: 20 }\" />\n *\n * <!-- Repeller (negative strength) -->\n * <ngt-object3D attractor [options]=\"{ strength: -10, range: 15 }\" [position]=\"[5, 0, 0]\" />\n *\n * <!-- Newtonian gravity -->\n * <ngt-object3D attractor [options]=\"{\n * strength: 1000,\n * range: 50,\n * type: 'newtonian',\n * gravitationalConstant: 0.01\n * }\" />\n * ```\n */\n@Directive({\n\tselector: 'ngt-object3D[attractor]',\n\tproviders: [\n\t\t{\n\t\t\tprovide: COLLISION_GROUPS_HANDLER,\n\t\t\tuseFactory: (attractor: NgtrAttractor) => {\n\t\t\t\treturn () => (interactionGroups: InteractionGroups) => {\n\t\t\t\t\tattractor.linkedCollisionGroups.set(interactionGroups);\n\t\t\t\t};\n\t\t\t},\n\t\t\tdeps: [NgtrAttractor],\n\t\t},\n\t],\n})\nexport class NgtrAttractor {\n\tposition = input<NgtVector3>([0, 0, 0]);\n\toptions = input(defaultOptions, { transform: mergeInputs(defaultOptions) });\n\n\tprivate objectRef = inject<ElementRef<THREE.Object3D>>(ElementRef);\n\tprivate collisionGroups = pick(this.options, 'collisionGroups');\n\tlinkedCollisionGroups = linkedSignal(this.collisionGroups);\n\n\tconstructor() {\n\t\teffect(() => {\n\t\t\tapplyProps(this.objectRef.nativeElement, { position: this.position() });\n\t\t});\n\n\t\tbeforePhysicsStep((world) => {\n\t\t\tconst { strength, range, type, gravitationalConstant } = untracked(this.options);\n\t\t\tconst collisionGroups = untracked(this.linkedCollisionGroups);\n\t\t\tworld.bodies.forEach((body) => {\n\t\t\t\tif (body.isDynamic()) {\n\t\t\t\t\tapplyAttractorForceOnRigidBody(body, {\n\t\t\t\t\t\tobject: this.objectRef.nativeElement,\n\t\t\t\t\t\tstrength,\n\t\t\t\t\t\trange,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tgravitationalConstant,\n\t\t\t\t\t\tcollisionGroups,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tattractorDebug(this.objectRef.nativeElement, this.options);\n\t}\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;AAQA,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE;AAE/B;;;;;;;;;;;;AAYG;SACa,cAAc,CAAC,MAAsB,EAAE,OAAkC,EAAE,QAAmB,EAAA;AAC7G,IAAA,OAAO,cAAc,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAK;AACpD,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC;AACnC,QAAA,MAAM,KAAK,GAAG,WAAW,EAAE;QAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;QACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,QAAQ,EAAE,GAAG,CAAC,GAAG,QAAQ,GAAG,QAAQ,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,OAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAEpE,QAAA,IAAI,IAAgB;AACpB,QAAA,IAAI,aAAkC;AAEtC,QAAA,MAAM,CAAC,CAAC,SAAS,KAAI;AACpB,YAAA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;gBAAE;AAEzB,YAAA,IAAI,GAAG,IAAI,KAAK,CAAC,IAAI,CACpB,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EACnC,IAAI,KAAK,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAChE;AAED,YAAA,aAAa,GAAG,IAAI,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC;AAC/D,YAAA,aAAa,CAAC,aAAa,GAAG,KAAK;YAEnC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;YAEvC,SAAS,CAAC,MAAK;gBACd,IAAI,IAAI,EAAE;oBACT,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;gBAClC;gBAEA,IAAI,aAAa,EAAE;oBAClB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;gBAC3C;AACD,YAAA,CAAC,CAAC;AACH,QAAA,CAAC,CAAC;QAEF,YAAY,CAAC,MAAK;AACjB,YAAA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;gBAAE;YAEzB,IAAI,IAAI,EAAE;gBACT,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC;AAClD,gBAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;gBACjC,aAAa,EAAE,MAAM,EAAE;YACxB;AACD,QAAA,CAAC,CAAC;AACH,IAAA,CAAC,CAAC;AACH;;AC9DA;;;;;AAKG;AACH,MAAM,eAAe,GAAG;AACvB,IAAA,MAAM,EAAE,CAAC,CAAS,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,KAAK,CAAC;IACrE,MAAM,EAAE,CAAC,CAAS,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/E,IAAA,SAAS,EAAE,CAAC,CAAS,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;CACpG;AAED,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE;AACrC,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE;AAEpC;;;;;;;;;;;;;;;;;;;;;;;AAuBG;SACa,8BAA8B,CAC7C,SAAoB,EACpB,EACC,MAAM,EACN,QAAQ,EACR,KAAK,EACL,qBAAqB,EACrB,eAAe,EACf,IAAI,GAC8C,EAAA;AAEnD,IAAA,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,EAAE;AAC1C,IAAA,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAEvD,IAAA,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;IAElE,MAAM,QAAQ,GAAW,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC;AAE5D,IAAA,IAAI,QAAQ,GAAG,KAAK,EAAE;QACrB,IAAI,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,qBAAqB,CAAC;;AAGrG,QAAA,KAAK,GAAG,KAAK,KAAK,QAAQ,GAAG,QAAQ,GAAG,KAAK;;AAG7C,QAAA,IAAI,2BAA2B,GAAG,eAAe,KAAK,SAAS;AAC/D,QAAA,IAAI,eAAe,KAAK,SAAS,EAAE;AAClC,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;gBAClD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtC,gBAAA,MAAM,uBAAuB,GAAG,QAAQ,CAAC,eAAe,EAAE;gBAC1D,IACC,CAAC,CAAC,eAAe,IAAI,EAAE,IAAI,uBAAuB,KAAK,CAAC;oBACxD,CAAC,CAAC,uBAAuB,IAAI,EAAE,IAAI,eAAe,KAAK,CAAC,EACvD;oBACD,2BAA2B,GAAG,IAAI;oBAClC;gBACD;YACD;QACD;QAEA,IAAI,2BAA2B,EAAE;YAChC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC;AAE5F,YAAA,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC;QACvC;IACD;AACD;AAoDA,MAAM,cAAc,GAAwB;AAC3C,IAAA,QAAQ,EAAE,CAAC;AACX,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,IAAI,EAAE,QAAQ;AACd,IAAA,qBAAqB,EAAE,SAAS;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;MAeU,aAAa,CAAA;IACzB,QAAQ,GAAG,KAAK,CAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,UAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AACvC,IAAA,OAAO,GAAG,KAAK,CAAC,cAAc,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,SAAA,EAAA,GAAA,EAAA,CAAA,EAAI,SAAS,EAAE,WAAW,CAAC,cAAc,CAAC,EAAA,CAAG;AAEnE,IAAA,SAAS,GAAG,MAAM,CAA6B,UAAU,CAAC;IAC1D,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC;AAC/D,IAAA,qBAAqB,GAAG,YAAY,CAAC,IAAI,CAAC,eAAe,iEAAC;AAE1D,IAAA,WAAA,GAAA;QACC,MAAM,CAAC,MAAK;AACX,YAAA,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;AACxE,QAAA,CAAC,CAAC;AAEF,QAAA,iBAAiB,CAAC,CAAC,KAAK,KAAI;AAC3B,YAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;YAChF,MAAM,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,qBAAqB,CAAC;YAC7D,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;AAC7B,gBAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;oBACrB,8BAA8B,CAAC,IAAI,EAAE;AACpC,wBAAA,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa;wBACpC,QAAQ;wBACR,KAAK;wBACL,IAAI;wBACJ,qBAAqB;wBACrB,eAAe;AACf,qBAAA,CAAC;gBACH;AACD,YAAA,CAAC,CAAC;AACH,QAAA,CAAC,CAAC;QAEF,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC;IAC3D;uGA/BY,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,SAAA,EAZd;AACV,YAAA;AACC,gBAAA,OAAO,EAAE,wBAAwB;AACjC,gBAAA,UAAU,EAAE,CAAC,SAAwB,KAAI;AACxC,oBAAA,OAAO,MAAM,CAAC,iBAAoC,KAAI;AACrD,wBAAA,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACvD,oBAAA,CAAC;gBACF,CAAC;gBACD,IAAI,EAAE,CAAC,aAAa,CAAC;AACrB,aAAA;AACD,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAEW,aAAa,EAAA,UAAA,EAAA,CAAA;kBAdzB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,QAAQ,EAAE,yBAAyB;AACnC,oBAAA,SAAS,EAAE;AACV,wBAAA;AACC,4BAAA,OAAO,EAAE,wBAAwB;AACjC,4BAAA,UAAU,EAAE,CAAC,SAAwB,KAAI;AACxC,gCAAA,OAAO,MAAM,CAAC,iBAAoC,KAAI;AACrD,oCAAA,SAAS,CAAC,qBAAqB,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACvD,gCAAA,CAAC;4BACF,CAAC;AACD,4BAAA,IAAI,EAAE,CAAA,aAAA,CAAe;AACrB,yBAAA;AACD,qBAAA;AACD,iBAAA;;;AC/LD;;AAEG;;;;"}
1
+ {"version":3,"file":"angular-three-rapier-addons.mjs","sources":["../../../../libs/rapier/addons/src/lib/attractor-debug.ts","../../../../libs/rapier/addons/src/lib/attractor.ts","../../../../libs/rapier/addons/src/angular-three-rapier-addons.ts"],"sourcesContent":["import { computed, effect, inject, Injector } from '@angular/core';\nimport { beforeRender, injectStore, pick } from 'angular-three';\nimport { NgtrPhysics } from 'angular-three-rapier';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport * as THREE from 'three';\nimport { VertexNormalsHelper } from 'three-stdlib';\nimport { NgtrAttactorOptions } from './attractor';\n\nconst _v3 = new THREE.Vector3();\n\n/**\n * Creates debug visualization for an attractor.\n * Shows a sphere at the attractor position with normals indicating the range.\n * Blue indicates attraction, red indicates repulsion.\n *\n * This is automatically called by NgtrAttractor when physics debug mode is enabled.\n *\n * @param object - The Object3D representing the attractor position\n * @param options - Getter function for attractor options\n * @param injector - Optional injector for dependency injection context\n *\n * @internal\n */\nexport function attractorDebug(object: THREE.Object3D, options: () => NgtrAttactorOptions, injector?: Injector) {\n\treturn assertInjector(attractorDebug, injector, () => {\n\t\tconst physics = inject(NgtrPhysics);\n\t\tconst store = injectStore();\n\n\t\tconst strength = pick(options, 'strength');\n\t\tconst range = pick(options, 'range');\n\t\tconst color = computed(() => (strength() > 0 ? 0x0000ff : 0xff0000));\n\n\t\tlet mesh: THREE.Mesh;\n\t\tlet normalsHelper: VertexNormalsHelper;\n\n\t\teffect((onCleanup) => {\n\t\t\tif (!physics['debug']()) return;\n\n\t\t\tmesh = new THREE.Mesh(\n\t\t\t\tnew THREE.SphereGeometry(0.2, 6, 6),\n\t\t\t\tnew THREE.MeshBasicMaterial({ color: color(), wireframe: true }),\n\t\t\t);\n\n\t\t\tnormalsHelper = new VertexNormalsHelper(mesh, range(), color());\n\t\t\tnormalsHelper.frustumCulled = false;\n\n\t\t\tstore.snapshot.scene.add(mesh);\n\t\t\tstore.snapshot.scene.add(normalsHelper);\n\n\t\t\tonCleanup(() => {\n\t\t\t\tif (mesh) {\n\t\t\t\t\tstore.snapshot.scene.remove(mesh);\n\t\t\t\t}\n\n\t\t\t\tif (normalsHelper) {\n\t\t\t\t\tstore.snapshot.scene.remove(normalsHelper);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tbeforeRender(() => {\n\t\t\tif (!physics['debug']() || !mesh || !normalsHelper) return;\n\n\t\t\tconst worldPosition = object.getWorldPosition(_v3);\n\t\t\tmesh.position.copy(worldPosition);\n\t\t\tnormalsHelper.update();\n\t\t});\n\t});\n}\n","import { Directive, effect, ElementRef, inject, input, linkedSignal, untracked } from '@angular/core';\nimport { InteractionGroups, RigidBody } from '@dimforge/rapier3d-compat';\nimport { applyProps, NgtVector3, pick } from 'angular-three';\nimport { beforePhysicsStep, COLLISION_GROUPS_HANDLER } from 'angular-three-rapier';\nimport { mergeInputs } from 'ngxtension/inject-inputs';\nimport * as THREE from 'three';\nimport { attractorDebug } from './attractor-debug';\n\n/**\n * Force calculation functions for different gravity types.\n * - static: Constant force regardless of distance\n * - linear: Force increases linearly as distance decreases\n * - newtonian: Force follows Newton's law of universal gravitation\n */\nconst calcForceByType = {\n\tstatic: (s: number, m2: number, r: number, d: number, G: number) => s,\n\tlinear: (s: number, m2: number, r: number, d: number, G: number) => s * (d / r),\n\tnewtonian: (s: number, m2: number, r: number, d: number, G: number) => (G * s * m2) / Math.pow(d, 2),\n};\n\nconst _position = new THREE.Vector3();\nconst _vector3 = new THREE.Vector3();\n\n/**\n * Applies attractor force to a rigid body based on its distance from the attractor.\n * Used internally by NgtrAttractor but can be called manually for custom behavior.\n *\n * @param rigidBody - The rigid body to apply the force to\n * @param options - The attractor configuration including position, strength, and type\n *\n * @example\n * ```typescript\n * beforePhysicsStep((world) => {\n * world.bodies.forEach((body) => {\n * if (body.isDynamic()) {\n * applyAttractorForceOnRigidBody(body, {\n * object: attractorMesh,\n * strength: 10,\n * range: 20,\n * type: 'newtonian',\n * gravitationalConstant: 6.673e-11\n * });\n * }\n * });\n * });\n * ```\n */\nexport function applyAttractorForceOnRigidBody(\n\trigidBody: RigidBody,\n\t{\n\t\tobject,\n\t\tstrength,\n\t\trange,\n\t\tgravitationalConstant,\n\t\tcollisionGroups,\n\t\ttype,\n\t}: NgtrAttactorOptions & { object: THREE.Object3D },\n) {\n\tconst rbPosition = rigidBody.translation();\n\t_position.set(rbPosition.x, rbPosition.y, rbPosition.z);\n\n\tconst worldPosition = object.getWorldPosition(new THREE.Vector3());\n\n\tconst distance: number = worldPosition.distanceTo(_position);\n\n\tif (distance < range) {\n\t\tlet force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant);\n\n\t\t// Prevent wild forces when Attractors collide\n\t\tforce = force === Infinity ? strength : force;\n\n\t\t// Naively test if the rigidBody contains a collider in one of the collision groups\n\t\tlet isRigidBodyInCollisionGroup = collisionGroups === undefined;\n\t\tif (collisionGroups !== undefined) {\n\t\t\tfor (let i = 0; i < rigidBody.numColliders(); i++) {\n\t\t\t\tconst collider = rigidBody.collider(i);\n\t\t\t\tconst colliderCollisionGroups = collider.collisionGroups();\n\t\t\t\tif (\n\t\t\t\t\t((collisionGroups >> 16) & colliderCollisionGroups) != 0 &&\n\t\t\t\t\t((colliderCollisionGroups >> 16) & collisionGroups) != 0\n\t\t\t\t) {\n\t\t\t\t\tisRigidBodyInCollisionGroup = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (isRigidBodyInCollisionGroup) {\n\t\t\t_vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);\n\n\t\t\trigidBody.applyImpulse(_vector3, true);\n\t\t}\n\t}\n}\n\n/**\n * Type of gravity calculation for attractors.\n * - `'static'` - Constant force regardless of distance\n * - `'linear'` - Force scales linearly with distance (closer = stronger)\n * - `'newtonian'` - Force follows Newton's law of universal gravitation (inverse square)\n */\nexport type NgtrAttractorGravityType = 'static' | 'linear' | 'newtonian';\n\n/**\n * Configuration options for the attractor directive.\n */\nexport interface NgtrAttactorOptions {\n\t/**\n\t * The strength of the attractor.\n\t * Positive values attract, negative values repel.\n\t *\n\t * @defaultValue 1\n\t */\n\tstrength: number;\n\n\t/**\n\t * The range of the attractor. Will not affect objects outside of this range.\n\t *\n\t * @defaultValue 10\n\t * @min 0\n\t */\n\trange: number;\n\n\t/**\n\t * The type of gravity to use.\n\t * - static: The gravity is constant and does not change over time.\n\t * - linear: The gravity is linearly interpolated the closer the object is to the attractor.\n\t * - newtonian: The gravity is calculated using the newtonian gravity formula.\n\t * @defaultValue \"static\"\n\t */\n\ttype: NgtrAttractorGravityType;\n\n\t/**\n\t * The mass of the attractor. Used when type is `newtonian`.\n\t * @defaultValue 6.673e-11\n\t */\n\tgravitationalConstant: number;\n\n\t/**\n\t * The collision groups that this attractor will apply effects to. If a RigidBody contains one or more colliders that are in one of the mask group, it will be affected by this attractor.\n\t * If not specified, the attractor will apply effects to all RigidBodies.\n\t */\n\tcollisionGroups?: InteractionGroups;\n}\n\nconst defaultOptions: NgtrAttactorOptions = {\n\tstrength: 1,\n\trange: 10,\n\ttype: 'static',\n\tgravitationalConstant: 6.673e-11,\n};\n\n/**\n * Directive that creates a gravitational attractor point in the physics world.\n * All dynamic rigid bodies within range will be attracted (or repelled) towards this point.\n *\n * The attractor can use different gravity models:\n * - Static: constant force\n * - Linear: force increases as objects get closer\n * - Newtonian: realistic inverse-square law\n *\n * @example\n * ```html\n * <!-- Simple attractor at origin with default options -->\n * <ngt-object3D attractor />\n *\n * <!-- Attractor with custom options -->\n * <ngt-object3D [attractor]=\"{ strength: 5, range: 20 }\" />\n *\n * <!-- Repeller (negative strength) -->\n * <ngt-object3D [attractor]=\"{ strength: -10, range: 15 }\" [position]=\"[5, 0, 0]\" />\n *\n * <!-- Newtonian gravity -->\n * <ngt-object3D [attractor]=\"{\n * strength: 1000,\n * range: 50,\n * type: 'newtonian',\n * gravitationalConstant: 0.01\n * }\" />\n * ```\n */\n@Directive({\n\tselector: 'ngt-object3D[attractor]',\n\tproviders: [\n\t\t{\n\t\t\tprovide: COLLISION_GROUPS_HANDLER,\n\t\t\tuseFactory: (attractor: NgtrAttractor) => {\n\t\t\t\treturn () => (interactionGroups: InteractionGroups) => {\n\t\t\t\t\tattractor.linkedCollisionGroups.set(interactionGroups);\n\t\t\t\t};\n\t\t\t},\n\t\t\tdeps: [NgtrAttractor],\n\t\t},\n\t],\n})\nexport class NgtrAttractor {\n\tposition = input<NgtVector3>([0, 0, 0]);\n\toptions = input(defaultOptions, { alias: 'attractor', transform: mergeInputs(defaultOptions) });\n\n\tprivate objectRef = inject<ElementRef<THREE.Object3D>>(ElementRef);\n\tprivate collisionGroups = pick(this.options, 'collisionGroups');\n\tlinkedCollisionGroups = linkedSignal(this.collisionGroups);\n\n\tconstructor() {\n\t\teffect(() => {\n\t\t\tapplyProps(this.objectRef.nativeElement, { position: this.position() });\n\t\t});\n\n\t\tbeforePhysicsStep((world) => {\n\t\t\tconst { strength, range, type, gravitationalConstant } = untracked(this.options);\n\t\t\tconst collisionGroups = untracked(this.linkedCollisionGroups);\n\t\t\tworld.bodies.forEach((body) => {\n\t\t\t\tif (body.isDynamic()) {\n\t\t\t\t\tapplyAttractorForceOnRigidBody(body, {\n\t\t\t\t\t\tobject: this.objectRef.nativeElement,\n\t\t\t\t\t\tstrength,\n\t\t\t\t\t\trange,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tgravitationalConstant,\n\t\t\t\t\t\tcollisionGroups,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tattractorDebug(this.objectRef.nativeElement, this.options);\n\t}\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angular-three-rapier",
3
- "version": "4.0.0-next.119",
3
+ "version": "4.0.0-next.120",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -84,14 +84,17 @@ interface NgtrAttactorOptions {
84
84
  *
85
85
  * @example
86
86
  * ```html
87
- * <!-- Simple attractor at origin -->
88
- * <ngt-object3D attractor [options]="{ strength: 5, range: 20 }" />
87
+ * <!-- Simple attractor at origin with default options -->
88
+ * <ngt-object3D attractor />
89
+ *
90
+ * <!-- Attractor with custom options -->
91
+ * <ngt-object3D [attractor]="{ strength: 5, range: 20 }" />
89
92
  *
90
93
  * <!-- Repeller (negative strength) -->
91
- * <ngt-object3D attractor [options]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
94
+ * <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
92
95
  *
93
96
  * <!-- Newtonian gravity -->
94
- * <ngt-object3D attractor [options]="{
97
+ * <ngt-object3D [attractor]="{
95
98
  * strength: 1000,
96
99
  * range: 50,
97
100
  * type: 'newtonian',
@@ -107,7 +110,7 @@ declare class NgtrAttractor {
107
110
  linkedCollisionGroups: _angular_core.WritableSignal<number | undefined>;
108
111
  constructor();
109
112
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NgtrAttractor, never>;
110
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgtrAttractor, "ngt-object3D[attractor]", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
113
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NgtrAttractor, "ngt-object3D[attractor]", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; "options": { "alias": "attractor"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
111
114
  }
112
115
 
113
116
  export { NgtrAttractor, applyAttractorForceOnRigidBody };