angular-three-rapier 4.0.0-next.12 → 4.0.0-next.121

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
@@ -1,7 +1,409 @@
1
- # rapier
1
+ # `angular-three-rapier`
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ This library provides Rapier physics integration for Angular Three. [Rapier](https://rapier.rs/) is a fast, cross-platform physics engine written in Rust with JavaScript bindings.
4
4
 
5
- ## Running unit tests
5
+ ## Documentation
6
6
 
7
- Run `nx test rapier` to execute the unit tests.
7
+ All public APIs are documented with JSDoc comments. Your IDE will provide inline documentation, parameter hints, and examples as you code.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install angular-three-rapier @dimforge/rapier3d-compat
13
+ # yarn add angular-three-rapier @dimforge/rapier3d-compat
14
+ # pnpm add angular-three-rapier @dimforge/rapier3d-compat
15
+ ```
16
+
17
+ > Make sure to already have `angular-three` installed
18
+
19
+ ## Usage
20
+
21
+ ```typescript
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);
28
+
29
+ @Component({
30
+ selector: 'app-box',
31
+ template: `
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>
38
+ `,
39
+ imports: [NgtrRigidBody],
40
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
41
+ })
42
+ export class Box {}
43
+
44
+ @Component({
45
+ selector: 'app-ground',
46
+ template: `
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>
53
+ `,
54
+ imports: [NgtrRigidBody, NgtArgs],
55
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
56
+ })
57
+ export class Ground {}
58
+
59
+ @Component({
60
+ template: `
61
+ <ngtr-physics [options]="{ gravity: [0, -9.81, 0] }">
62
+ <ng-template>
63
+ <app-box />
64
+ <app-ground />
65
+ </ng-template>
66
+ </ngtr-physics>
67
+ `,
68
+ imports: [NgtrPhysics, Box, Ground],
69
+ })
70
+ export class SceneGraph {}
71
+ ```
72
+
73
+ ## Physics Options
74
+
75
+ | Property | Description | Default |
76
+ | ------------- | ----------------------------------------------- | --------------- |
77
+ | `gravity` | Gravity vector `[x, y, z]` | `[0, -9.81, 0]` |
78
+ | `colliders` | Default collider type for rigid bodies | `'cuboid'` |
79
+ | `paused` | Whether physics simulation is paused | `false` |
80
+ | `timeStep` | Fixed timestep for physics simulation | `1/60` |
81
+ | `debug` | Enable debug visualization | `false` |
82
+ | `interpolate` | Enable transform interpolation | `true` |
83
+ | `updateLoop` | Update loop type: `'follow'` or `'independent'` | `'follow'` |
84
+
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
+ ```
105
+
106
+ ### Rigid Body Types
107
+
108
+ - `''` or `'dynamic'` - Affected by forces and collisions
109
+ - `'fixed'` - Static, immovable body
110
+ - `'kinematicPosition'` - Controlled by position, affects dynamic bodies
111
+ - `'kinematicVelocity'` - Controlled by velocity, affects dynamic bodies
112
+
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
148
+
149
+ Colliders use `ngt-object3D` with specific collider attributes. By default, rigid bodies auto-generate colliders from child meshes.
150
+
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
+ ```
209
+
210
+ ## Joints
211
+
212
+ Create joints between rigid bodies using injectable functions:
213
+
214
+ ```typescript
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';
225
+
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
+ }
366
+ ```
367
+
368
+ ## Debug Visualization
369
+
370
+ Enable debug rendering via physics options:
371
+
372
+ ```html
373
+ <ngtr-physics [options]="{ debug: true }">
374
+ <ng-template>
375
+ <!-- your physics objects -->
376
+ </ng-template>
377
+ </ngtr-physics>
378
+ ```
379
+
380
+ ## Addons
381
+
382
+ ### Attractor
383
+
384
+ Apply gravitational or magnetic forces:
385
+
386
+ ```typescript
387
+ import { NgtrAttractor } from 'angular-three-rapier/addons';
388
+ ```
389
+
390
+ ```html
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
+ />
409
+ ```
@@ -0,0 +1,112 @@
1
+ # angular-three-rapier/addons
2
+
3
+ Secondary entry point of `angular-three-rapier`. It can be used by importing from `angular-three-rapier/addons`.
4
+
5
+ ## Installation
6
+
7
+ This package requires `angular-three-rapier` as a peer dependency.
8
+
9
+ ```bash
10
+ npm install angular-three-rapier @dimforge/rapier3d-compat
11
+ ```
12
+
13
+ ## NgtrAttractor
14
+
15
+ A directive that creates a gravitational attractor point in the physics world. All dynamic rigid bodies within range will be attracted (or repelled) towards this point.
16
+
17
+ ### Basic Usage
18
+
19
+ ```html
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 }" />
25
+
26
+ <!-- Repeller (negative strength) -->
27
+ <ngt-object3D [attractor]="{ strength: -10, range: 15 }" [position]="[5, 0, 0]" />
28
+ ```
29
+
30
+ ### Gravity Types
31
+
32
+ The attractor supports three different gravity calculation models:
33
+
34
+ ```html
35
+ <!-- Static: Constant force regardless of distance -->
36
+ <ngt-object3D [attractor]="{ type: 'static', strength: 5, range: 20 }" />
37
+
38
+ <!-- Linear: Force increases as objects get closer -->
39
+ <ngt-object3D [attractor]="{ type: 'linear', strength: 5, range: 20 }" />
40
+
41
+ <!-- Newtonian: Realistic inverse-square law (like real gravity) -->
42
+ <ngt-object3D
43
+ [attractor]="{
44
+ type: 'newtonian',
45
+ strength: 1000,
46
+ range: 50,
47
+ gravitationalConstant: 0.01
48
+ }"
49
+ />
50
+ ```
51
+
52
+ ### Options
53
+
54
+ | Option | Type | Default | Description |
55
+ | ----------------------- | ------------------------------------- | ----------- | ----------------------------------------------------------------------------- |
56
+ | `strength` | `number` | `1` | Force strength. Positive attracts, negative repels. |
57
+ | `range` | `number` | `10` | Effective range in world units. Objects outside this range are unaffected. |
58
+ | `type` | `'static' \| 'linear' \| 'newtonian'` | `'static'` | Gravity calculation model. |
59
+ | `gravitationalConstant` | `number` | `6.673e-11` | Gravitational constant for newtonian type. |
60
+ | `collisionGroups` | `InteractionGroups` | `undefined` | Limits which rigid bodies are affected. If unset, affects all dynamic bodies. |
61
+
62
+ ### Gravity Type Details
63
+
64
+ - **static**: Constant force regardless of distance. Good for simple push/pull effects.
65
+ - **linear**: Force scales linearly with distance (closer = stronger). Provides smooth attraction.
66
+ - **newtonian**: Force follows Newton's law of universal gravitation (`F = G * m1 * m2 / r²`). Most realistic but can cause extreme forces at close range.
67
+
68
+ ## applyAttractorForceOnRigidBody
69
+
70
+ A utility function for manually applying attractor forces to rigid bodies. Useful for custom physics behavior.
71
+
72
+ ### Usage
73
+
74
+ ```typescript
75
+ import { applyAttractorForceOnRigidBody } from 'angular-three-rapier/addons';
76
+ import { beforePhysicsStep } from 'angular-three-rapier';
77
+
78
+ // In your component
79
+ beforePhysicsStep((world) => {
80
+ world.bodies.forEach((body) => {
81
+ if (body.isDynamic()) {
82
+ applyAttractorForceOnRigidBody(body, {
83
+ object: attractorMesh, // THREE.Object3D position reference
84
+ strength: 10,
85
+ range: 20,
86
+ type: 'newtonian',
87
+ gravitationalConstant: 0.01,
88
+ });
89
+ }
90
+ });
91
+ });
92
+ ```
93
+
94
+ ### Parameters
95
+
96
+ | Parameter | Type | Description |
97
+ | ------------------------------- | -------------------------- | ------------------------------------------------------ |
98
+ | `rigidBody` | `RigidBody` | The Rapier rigid body to apply force to. |
99
+ | `options.object` | `THREE.Object3D` | Object3D whose world position is the attractor center. |
100
+ | `options.strength` | `number` | Force strength (positive attracts, negative repels). |
101
+ | `options.range` | `number` | Maximum distance for the force to apply. |
102
+ | `options.type` | `NgtrAttractorGravityType` | Gravity calculation type. |
103
+ | `options.gravitationalConstant` | `number` | Gravitational constant for newtonian calculations. |
104
+ | `options.collisionGroups` | `InteractionGroups` | Optional collision group filter. |
105
+
106
+ ## Debug Visualization
107
+
108
+ When physics debug mode is enabled on `NgtrPhysics`, attractors automatically display debug visualization:
109
+
110
+ - Blue sphere with normals for attractors (positive strength)
111
+ - Red sphere with normals for repellers (negative strength)
112
+ - Normal length indicates the range