@needle-tools/engine 4.9.0-alpha.3 → 4.9.0-next.43185

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 (52) hide show
  1. package/components.needle.json +1 -1
  2. package/dist/{needle-engine.bundle-D3t6rco7.umd.cjs → needle-engine.bundle-Bf4EhG38.umd.cjs} +129 -129
  3. package/dist/{needle-engine.bundle-rZjkMCRy.js → needle-engine.bundle-Bs33m9iI.js} +5015 -4836
  4. package/dist/{needle-engine.bundle-xx2z8elo.min.js → needle-engine.bundle-CZSmogSi.min.js} +128 -128
  5. package/dist/needle-engine.js +556 -552
  6. package/dist/needle-engine.min.js +1 -1
  7. package/dist/needle-engine.umd.cjs +1 -1
  8. package/lib/engine/codegen/register_types.js +8 -0
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/engine_physics_rapier.js +8 -8
  11. package/lib/engine/engine_physics_rapier.js.map +1 -1
  12. package/lib/engine/engine_serialization_builtin_serializer.d.ts +2 -2
  13. package/lib/engine-components/Animation.d.ts +1 -0
  14. package/lib/engine-components/Animation.js +9 -0
  15. package/lib/engine-components/Animation.js.map +1 -1
  16. package/lib/engine-components/Component.d.ts +1 -0
  17. package/lib/engine-components/Component.js.map +1 -1
  18. package/lib/engine-components/EventTrigger.js.map +1 -1
  19. package/lib/engine-components/api.d.ts +1 -0
  20. package/lib/engine-components/api.js +1 -0
  21. package/lib/engine-components/api.js.map +1 -1
  22. package/lib/engine-components/codegen/components.d.ts +4 -0
  23. package/lib/engine-components/codegen/components.js +4 -0
  24. package/lib/engine-components/codegen/components.js.map +1 -1
  25. package/lib/engine-components/physics/Attractor.d.ts +8 -0
  26. package/lib/engine-components/physics/Attractor.js +42 -0
  27. package/lib/engine-components/physics/Attractor.js.map +1 -0
  28. package/lib/engine-components/web/Clickthrough.d.ts +19 -0
  29. package/lib/engine-components/web/Clickthrough.js +57 -0
  30. package/lib/engine-components/web/Clickthrough.js.map +1 -0
  31. package/lib/engine-components/web/CursorFollow.d.ts +12 -0
  32. package/lib/engine-components/web/CursorFollow.js +46 -0
  33. package/lib/engine-components/web/CursorFollow.js.map +1 -0
  34. package/lib/engine-components/web/ScrollFollow.d.ts +45 -0
  35. package/lib/engine-components/web/ScrollFollow.js +132 -0
  36. package/lib/engine-components/web/ScrollFollow.js.map +1 -0
  37. package/lib/engine-components/web/index.d.ts +3 -0
  38. package/lib/engine-components/web/index.js +4 -0
  39. package/lib/engine-components/web/index.js.map +1 -0
  40. package/package.json +3 -3
  41. package/src/engine/codegen/register_types.ts +8 -0
  42. package/src/engine/engine_physics_rapier.ts +11 -11
  43. package/src/engine-components/Animation.ts +9 -0
  44. package/src/engine-components/Component.ts +1 -0
  45. package/src/engine-components/EventTrigger.ts +0 -1
  46. package/src/engine-components/api.ts +1 -0
  47. package/src/engine-components/codegen/components.ts +4 -0
  48. package/src/engine-components/physics/Attractor.ts +35 -0
  49. package/src/engine-components/web/Clickthrough.ts +60 -0
  50. package/src/engine-components/web/CursorFollow.ts +49 -0
  51. package/src/engine-components/web/ScrollFollow.ts +150 -0
  52. package/src/engine-components/web/index.ts +3 -0
@@ -0,0 +1,42 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Behaviour } from "../Component.js";
8
+ import { Rigidbody } from "../RigidBody.js";
9
+ import { serializable } from "../../engine/engine_serialization_decorator.js";
10
+ export class Attractor extends Behaviour {
11
+ strength = 1;
12
+ radius = 2;
13
+ targets = [];
14
+ update() {
15
+ const wp = this.gameObject.worldPosition;
16
+ const factor = -this.strength * this.context.time.deltaTime;
17
+ this.targets.forEach(t => {
18
+ if (!t)
19
+ return;
20
+ const dir = t.gameObject.worldPosition.sub(wp);
21
+ const length = dir.length();
22
+ if (length > this.radius)
23
+ return;
24
+ let _factor = factor;
25
+ if (length > 1)
26
+ _factor /= length * length;
27
+ else
28
+ _factor /= Math.max(.05, length);
29
+ t.applyImpulse(dir.multiplyScalar(_factor));
30
+ });
31
+ }
32
+ }
33
+ __decorate([
34
+ serializable()
35
+ ], Attractor.prototype, "strength", void 0);
36
+ __decorate([
37
+ serializable()
38
+ ], Attractor.prototype, "radius", void 0);
39
+ __decorate([
40
+ serializable(Rigidbody)
41
+ ], Attractor.prototype, "targets", void 0);
42
+ //# sourceMappingURL=Attractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Attractor.js","sourceRoot":"","sources":["../../../src/engine-components/physics/Attractor.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAI9E,MAAM,OAAO,SAAU,SAAQ,SAAS;IAGpC,QAAQ,GAAW,CAAC,CAAC;IAGrB,MAAM,GAAW,CAAC,CAAC;IAGnB,OAAO,GAAgB,EAAE,CAAC;IAG1B,MAAM;QACF,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QACzC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACrB,IAAG,CAAC,CAAC;gBAAE,OAAO;YACd,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM;gBAAE,OAAO;YACjC,IAAI,OAAO,GAAG,MAAM,CAAC;YACrB,IAAI,MAAM,GAAG,CAAC;gBAAE,OAAO,IAAI,MAAM,GAAG,MAAM,CAAC;;gBACtC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAA;IACN,CAAC;CAGJ;AAzBG;IADC,YAAY,EAAE;2CACM;AAGrB;IADC,YAAY,EAAE;yCACI;AAGnB;IADC,YAAY,CAAC,SAAS,CAAC;0CACE"}
@@ -0,0 +1,19 @@
1
+ import { Behaviour } from "../Component.js";
2
+ /**
3
+ * ClickThrough component allows pointer events to "click through" the 3D canvas to HTML elements behind it.
4
+ *
5
+ * This is useful if you have a transparent canvas overlaying HTML content and want to interact with the HTML content through the transparent areas of the canvas.
6
+ *
7
+ * Usage Options:
8
+ * - Add the ClickThrough component to any GameObject in your scene.
9
+ * - Alternatively, add the `clickthrough` attribute to the `<needle-engine>` HTML element (e.g. `<needle-engine clickthrough></needle-engine>`).
10
+ *
11
+ * @link Example https://stackblitz.com/~/github.com/needle-engine/sample-3d-over-html
12
+ */
13
+ export declare class ClickThrough extends Behaviour {
14
+ onEnable(): void;
15
+ onDisable(): void;
16
+ onPointerEnter(): void;
17
+ private onPointerEvent;
18
+ private onTouchEnd;
19
+ }
@@ -0,0 +1,57 @@
1
+ import { Behaviour } from "../Component.js";
2
+ import { onStart } from "../../engine/engine_lifecycle_api.js";
3
+ // Automatically add ClickThrough component if "clickthrough" attribute is present on the needle-engine element
4
+ onStart(ctx => {
5
+ const attribute = ctx.domElement.getAttribute("clickthrough");
6
+ if (attribute !== null && attribute !== "0" && attribute !== "false") {
7
+ ctx.scene.addComponent(ClickThrough);
8
+ }
9
+ });
10
+ /**
11
+ * ClickThrough component allows pointer events to "click through" the 3D canvas to HTML elements behind it.
12
+ *
13
+ * This is useful if you have a transparent canvas overlaying HTML content and want to interact with the HTML content through the transparent areas of the canvas.
14
+ *
15
+ * Usage Options:
16
+ * - Add the ClickThrough component to any GameObject in your scene.
17
+ * - Alternatively, add the `clickthrough` attribute to the `<needle-engine>` HTML element (e.g. `<needle-engine clickthrough></needle-engine>`).
18
+ *
19
+ * @link Example https://stackblitz.com/~/github.com/needle-engine/sample-3d-over-html
20
+ */
21
+ export class ClickThrough extends Behaviour {
22
+ onEnable() {
23
+ // Register for pointer down and pointer move event
24
+ this.context.input.addEventListener('pointerdown', this.onPointerEvent);
25
+ this.context.input.addEventListener('pointermove', this.onPointerEvent, {
26
+ queue: 100,
27
+ });
28
+ window.addEventListener("touchend", this.onTouchEnd, { passive: true });
29
+ }
30
+ onDisable() {
31
+ this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
32
+ this.context.input.removeEventListener('pointermove', this.onPointerEvent);
33
+ window.removeEventListener("touchend", this.onTouchEnd);
34
+ this.context.domElement.style.pointerEvents = 'all';
35
+ }
36
+ onPointerEnter() {
37
+ /** do nothing, necessary to raycast children */
38
+ }
39
+ onPointerEvent = (evt) => {
40
+ if (evt.pointerId > 0)
41
+ return;
42
+ const intersections = evt.intersections;
43
+ // If we don't had any intersections during the 3D raycasting then we disable pointer events for the needle-engine element so that content BEHIND the 3D element can receive pointer events
44
+ if (intersections?.length <= 0) {
45
+ this.context.domElement.style.pointerEvents = 'none';
46
+ }
47
+ else {
48
+ this.context.domElement.style.pointerEvents = 'all';
49
+ }
50
+ };
51
+ onTouchEnd = (_evt) => {
52
+ setTimeout(() => {
53
+ this.context.domElement.style.pointerEvents = 'all';
54
+ }, 100);
55
+ };
56
+ }
57
+ //# sourceMappingURL=Clickthrough.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Clickthrough.js","sourceRoot":"","sources":["../../../src/engine-components/web/Clickthrough.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAE/D,+GAA+G;AAC/G,OAAO,CAAC,GAAG,CAAC,EAAE;IACV,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;IAC9D,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,OAAO,EAAE;QAClE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;KACxC;AACL,CAAC,CAAC,CAAC;AAGH;;;;;;;;;;GAUG;AACH,MAAM,OAAO,YAAa,SAAQ,SAAS;IACvC,QAAQ;QACJ,mDAAmD;QACnD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACxE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,EAAE;YACpE,KAAK,EAAE,GAAG;SACb,CAAC,CAAC;QACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,SAAS;QACL,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3E,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC;IACxD,CAAC;IACD,cAAc;QACV,gDAAgD;IACpD,CAAC;IAEO,cAAc,GAAG,CAAC,GAAmB,EAAE,EAAE;QAC7C,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC;YAAE,OAAO;QAC9B,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;QACxC,2LAA2L;QAC3L,IAAI,aAAa,EAAE,MAAM,IAAI,CAAC,EAAE;YAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;SACxD;aAAM;YACH,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC;SACvD;IACL,CAAC,CAAC;IAEM,UAAU,GAAG,CAAC,IAAgB,EAAE,EAAE;QACtC,UAAU,CAAC,GAAG,EAAE;YACZ,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC;QACxD,CAAC,EAAE,GAAG,CAAC,CAAC;IACZ,CAAC,CAAA;CACJ"}
@@ -0,0 +1,12 @@
1
+ import { Behaviour } from "../Component.js";
2
+ export declare class CursorFollow extends Behaviour {
3
+ /**
4
+ * Damping for the movement, set to 0 for instant movement
5
+ * @default 0
6
+ */
7
+ damping: number;
8
+ private _distance;
9
+ updateDistance(): void;
10
+ /** @internal */
11
+ update(): void;
12
+ }
@@ -0,0 +1,46 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { serializable } from "../../engine/engine_serialization_decorator.js";
8
+ import { getTempVector } from "../../engine/engine_three_utils.js";
9
+ import { Behaviour } from "../Component.js";
10
+ export class CursorFollow extends Behaviour {
11
+ /**
12
+ * Damping for the movement, set to 0 for instant movement
13
+ * @default 0
14
+ */
15
+ damping = 0;
16
+ _distance = -1;
17
+ updateDistance() {
18
+ this._distance = this.gameObject.worldPosition.distanceTo(this.context.mainCamera.worldPosition);
19
+ }
20
+ /** @internal */
21
+ update() {
22
+ // continuously update distance in case camera or object moves
23
+ this.updateDistance();
24
+ // follow cursor in screenspace but maintain initial distance from camera
25
+ const cursor = this.context.input.mousePositionRC;
26
+ const camera = this.context.mainCamera;
27
+ const cameraPosition = camera.worldPosition;
28
+ // create ray from camera through cursor position
29
+ const rayDirection = getTempVector(cursor.x, cursor.y, 1).unproject(camera);
30
+ rayDirection.sub(cameraPosition).normalize();
31
+ // position object at initial distance along the ray
32
+ const newPosition = rayDirection.multiplyScalar(this._distance).add(cameraPosition);
33
+ if (this.damping > 0) {
34
+ const pos = this.gameObject.worldPosition;
35
+ pos.lerp(newPosition, this.context.time.deltaTime / this.damping);
36
+ this.gameObject.worldPosition = pos;
37
+ }
38
+ else {
39
+ this.gameObject.worldPosition = newPosition;
40
+ }
41
+ }
42
+ }
43
+ __decorate([
44
+ serializable()
45
+ ], CursorFollow.prototype, "damping", void 0);
46
+ //# sourceMappingURL=CursorFollow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CursorFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/CursorFollow.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,YAAa,SAAQ,SAAS;IAEvC;;;OAGG;IAEH,OAAO,GAAW,CAAC,CAAC;IAGZ,SAAS,GAAW,CAAC,CAAC,CAAC;IAC/B,cAAc;QACV,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACrG,CAAC;IAGD,gBAAgB;IAChB,MAAM;QACF,8DAA8D;QAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,yEAAyE;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACvC,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;QAE5C,iDAAiD;QACjD,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5E,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,SAAS,EAAE,CAAC;QAE7C,oDAAoD;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpF,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YAClE,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC;SACvC;aACI;YACD,IAAI,CAAC,UAAU,CAAC,aAAa,GAAG,WAAW,CAAC;SAC/C;IAEL,CAAC;CAEJ;AApCG;IADC,YAAY,EAAE;6CACK"}
@@ -0,0 +1,45 @@
1
+ import { Behaviour } from "../Component.js";
2
+ import { EventList } from "../EventList.js";
3
+ type ScrollFollowEvent = {
4
+ /** Event type */
5
+ type: "change";
6
+ /** Current scroll value */
7
+ value: number;
8
+ /** ScrollFollow component that raised the event */
9
+ component: ScrollFollow;
10
+ /** Call to prevent invocation of default (e.g. updating targets) */
11
+ preventDefault: () => void;
12
+ defaultPrevented: boolean;
13
+ };
14
+ export declare class ScrollFollow extends Behaviour {
15
+ /**
16
+ * Target object(s) to follow the scroll position of the page. If null, the main camera is used.
17
+ */
18
+ target: object[] | object | null;
19
+ /**
20
+ * Damping for the movement, set to 0 for instant movement
21
+ * @default 0
22
+ */
23
+ damping: number;
24
+ mode: "window";
25
+ /**
26
+ * Event fired when the scroll position changes
27
+ */
28
+ changed: EventList<ScrollFollowEvent>;
29
+ /**
30
+ * Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
31
+ */
32
+ get currentValue(): number;
33
+ private current_value;
34
+ private target_value;
35
+ private applied_value;
36
+ /** @internal */
37
+ onEnable(): void;
38
+ /** @internal */
39
+ onDisable(): void;
40
+ /** @internal */
41
+ lateUpdate(): void;
42
+ private updateCurrentScroll;
43
+ private applyScroll;
44
+ }
45
+ export {};
@@ -0,0 +1,132 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Object3D } from "three";
8
+ import { serializable } from "../../engine/engine_serialization.js";
9
+ import { Mathf } from "../../engine/engine_math.js";
10
+ import { Behaviour } from "../Component.js";
11
+ import { PlayableDirector } from "../timeline/PlayableDirector.js";
12
+ import { EventList } from "../EventList.js";
13
+ import { Animation } from "../Animation.js";
14
+ import { AudioSource } from "../AudioSource.js";
15
+ export class ScrollFollow extends Behaviour {
16
+ /**
17
+ * Target object(s) to follow the scroll position of the page. If null, the main camera is used.
18
+ */
19
+ target = null;
20
+ /**
21
+ * Damping for the movement, set to 0 for instant movement
22
+ * @default 0
23
+ */
24
+ damping = 0;
25
+ mode = "window";
26
+ /**
27
+ * Event fired when the scroll position changes
28
+ */
29
+ changed = new EventList();
30
+ /**
31
+ * Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
32
+ */
33
+ get currentValue() {
34
+ return this.current_value;
35
+ }
36
+ current_value = 0;
37
+ target_value = 0;
38
+ applied_value = -1;
39
+ /** @internal */
40
+ onEnable() {
41
+ window.addEventListener("wheel", this.updateCurrentScroll, { passive: true });
42
+ this.applied_value = -1;
43
+ this.updateCurrentScroll();
44
+ }
45
+ /** @internal */
46
+ onDisable() {
47
+ window.removeEventListener("wheel", this.updateCurrentScroll);
48
+ }
49
+ /** @internal */
50
+ lateUpdate() {
51
+ // apply damping if any
52
+ if (this.damping > 0) {
53
+ this.current_value = Mathf.lerp(this.current_value, this.target_value, this.context.time.deltaTime / this.damping);
54
+ }
55
+ if (this.current_value !== this.applied_value) {
56
+ this.applied_value = this.current_value;
57
+ let defaultPrevented = false;
58
+ if (this.changed.listenerCount > 0) {
59
+ // fire change event
60
+ const event = {
61
+ type: "change",
62
+ value: this.current_value,
63
+ component: this,
64
+ preventDefault: () => { event.defaultPrevented = true; },
65
+ defaultPrevented: false,
66
+ };
67
+ this.changed.invoke(event);
68
+ defaultPrevented = event.defaultPrevented;
69
+ }
70
+ // if not prevented apply scroll
71
+ if (!defaultPrevented) {
72
+ // apply scroll to target(s)
73
+ if (Array.isArray(this.target)) {
74
+ this.target.forEach(t => t && this.applyScroll(t));
75
+ }
76
+ else if (this.target) {
77
+ this.applyScroll(this.target);
78
+ }
79
+ }
80
+ }
81
+ }
82
+ updateCurrentScroll = () => {
83
+ switch (this.mode) {
84
+ case "window":
85
+ this.target_value = window.scrollY / (document.body.scrollHeight - window.innerHeight);
86
+ if (isNaN(this.target_value) || !isFinite(this.target_value))
87
+ this.target_value = 0;
88
+ break;
89
+ }
90
+ if (this.damping <= 0) {
91
+ this.current_value = this.target_value;
92
+ }
93
+ };
94
+ applyScroll(target) {
95
+ if (!target)
96
+ return;
97
+ if (target instanceof PlayableDirector) {
98
+ target.time = this.current_value * target.duration;
99
+ if (!target.isPlaying)
100
+ target.evaluate();
101
+ }
102
+ else if (target instanceof Animation) {
103
+ target.time = this.current_value * target.duration;
104
+ }
105
+ else if (target instanceof AudioSource) {
106
+ if (!target.duration)
107
+ return;
108
+ target.time = this.current_value * target.duration;
109
+ }
110
+ else if ("scroll" in target) {
111
+ if (typeof target.scroll === "number") {
112
+ target.scroll = this.current_value;
113
+ }
114
+ else if (typeof target.scroll === "function") {
115
+ target.scroll(this.current_value);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ __decorate([
121
+ serializable([Behaviour, Object3D])
122
+ ], ScrollFollow.prototype, "target", void 0);
123
+ __decorate([
124
+ serializable()
125
+ ], ScrollFollow.prototype, "damping", void 0);
126
+ __decorate([
127
+ serializable()
128
+ ], ScrollFollow.prototype, "mode", void 0);
129
+ __decorate([
130
+ serializable(EventList)
131
+ ], ScrollFollow.prototype, "changed", void 0);
132
+ //# sourceMappingURL=ScrollFollow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScrollFollow.js","sourceRoot":"","sources":["../../../src/engine-components/web/ScrollFollow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from "./Clickthrough.js";
2
+ export * from "./CursorFollow.js";
3
+ export * from "./ScrollFollow.js";
@@ -0,0 +1,4 @@
1
+ export * from "./Clickthrough.js";
2
+ export * from "./CursorFollow.js";
3
+ export * from "./ScrollFollow.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine-components/web/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "4.9.0-alpha.3",
3
+ "version": "4.9.0-next.43185",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
5
5
  "main": "dist/needle-engine.min.js",
6
6
  "exports": {
@@ -93,7 +93,7 @@
93
93
  ],
94
94
  "dependencies": {
95
95
  "@dimforge/rapier3d-compat": "^0.19.0",
96
- "@needle-tools/gltf-progressive": "3.3.3",
96
+ "@needle-tools/gltf-progressive": "3.3.4",
97
97
  "@needle-tools/three-animation-pointer": "1.0.2",
98
98
  "@webxr-input-profiles/motion-controllers": "^1.0.0",
99
99
  "flatbuffers": "2.0.4",
@@ -168,4 +168,4 @@
168
168
  "module": "lib/needle-engine.js",
169
169
  "typings": "lib/needle-engine.d.ts",
170
170
  "types": "lib/needle-engine.d.ts"
171
- }
171
+ }
@@ -67,6 +67,7 @@ import { CameraTargetReachedEvent } from "../../engine-components/OrbitControls.
67
67
  import { OrbitControls } from "../../engine-components/OrbitControls.js";
68
68
  import { ParticleSystemRenderer } from "../../engine-components/particlesystem/ParticleSystem.js";
69
69
  import { ParticleSystem } from "../../engine-components/particlesystem/ParticleSystem.js";
70
+ import { Attractor } from "../../engine-components/physics/Attractor.js";
70
71
  import { PlayerColor } from "../../engine-components/PlayerColor.js";
71
72
  import { Antialiasing } from "../../engine-components/postprocessing/Effects/Antialiasing.js";
72
73
  import { BloomEffect } from "../../engine-components/postprocessing/Effects/BloomEffect.js";
@@ -136,6 +137,9 @@ import { LookAt } from "../../engine-components/utils/LookAt.js";
136
137
  import { OpenURL } from "../../engine-components/utils/OpenURL.js";
137
138
  import { VideoPlayer } from "../../engine-components/VideoPlayer.js";
138
139
  import { Voip } from "../../engine-components/Voip.js";
140
+ import { ClickThrough } from "../../engine-components/web/Clickthrough.js";
141
+ import { CursorFollow } from "../../engine-components/web/CursorFollow.js";
142
+ import { ScrollFollow } from "../../engine-components/web/ScrollFollow.js";
139
143
  import { Avatar } from "../../engine-components/webxr/Avatar.js";
140
144
  import { XRControllerFollow } from "../../engine-components/webxr/controllers/XRControllerFollow.js";
141
145
  import { XRControllerModel } from "../../engine-components/webxr/controllers/XRControllerModel.js";
@@ -219,6 +223,7 @@ TypeStore.add("CameraTargetReachedEvent", CameraTargetReachedEvent);
219
223
  TypeStore.add("OrbitControls", OrbitControls);
220
224
  TypeStore.add("ParticleSystemRenderer", ParticleSystemRenderer);
221
225
  TypeStore.add("ParticleSystem", ParticleSystem);
226
+ TypeStore.add("Attractor", Attractor);
222
227
  TypeStore.add("PlayerColor", PlayerColor);
223
228
  TypeStore.add("Antialiasing", Antialiasing);
224
229
  TypeStore.add("BloomEffect", BloomEffect);
@@ -288,6 +293,9 @@ TypeStore.add("LookAt", LookAt);
288
293
  TypeStore.add("OpenURL", OpenURL);
289
294
  TypeStore.add("VideoPlayer", VideoPlayer);
290
295
  TypeStore.add("Voip", Voip);
296
+ TypeStore.add("ClickThrough", ClickThrough);
297
+ TypeStore.add("CursorFollow", CursorFollow);
298
+ TypeStore.add("ScrollFollow", ScrollFollow);
291
299
  TypeStore.add("Avatar", Avatar);
292
300
  TypeStore.add("XRControllerFollow", XRControllerFollow);
293
301
  TypeStore.add("XRControllerModel", XRControllerModel);
@@ -164,13 +164,13 @@ export class RapierPhysics implements IPhysicsEngine {
164
164
  this.validate();
165
165
  const body = this.internal_getRigidbody(rigidbody);
166
166
  if (body) body.addForce(force, wakeup)
167
- else console.warn("Rigidbody doesn't exist: can not apply force (does your object with the Rigidbody have a collider?)");
167
+ else if (this._isInitialized) console.warn("Physics Body doesn't exist: can not apply force (does your object with the Rigidbody have a collider?)");
168
168
  }
169
169
  addImpulse(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
170
170
  this.validate();
171
171
  const body = this.internal_getRigidbody(rigidbody);
172
172
  if (body) body.applyImpulse(force, wakeup);
173
- else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
173
+ else if (this._isInitialized) console.warn("Physics Body doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
174
174
  }
175
175
  getLinearVelocity(comp: IRigidbody | ICollider): Vec3 | null {
176
176
  this.validate();
@@ -206,14 +206,14 @@ export class RapierPhysics implements IPhysicsEngine {
206
206
  this.validate();
207
207
  const body = this.internal_getRigidbody(rb);
208
208
  if (body) body.applyImpulse(vec, wakeup);
209
- else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
209
+ else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
210
210
  }
211
211
 
212
212
  wakeup(rb: IRigidbody) {
213
213
  this.validate();
214
214
  const body = this.internal_getRigidbody(rb);
215
215
  if (body) body.wakeUp();
216
- else console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
216
+ else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
217
217
  }
218
218
  isSleeping(rb: IRigidbody) {
219
219
  this.validate();
@@ -224,13 +224,13 @@ export class RapierPhysics implements IPhysicsEngine {
224
224
  this.validate();
225
225
  const body = this.internal_getRigidbody(rb);
226
226
  if (body) body.setAngvel(vec, wakeup);
227
- else console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
227
+ else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
228
228
  }
229
229
  setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
230
230
  this.validate();
231
231
  const body = this.internal_getRigidbody(rb);
232
232
  if (body) body.setLinvel(vec, wakeup);
233
- else console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
233
+ else if (this._isInitialized) console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
234
234
  }
235
235
 
236
236
  private readonly context?: IContext;
@@ -273,7 +273,7 @@ export class RapierPhysics implements IPhysicsEngine {
273
273
  if (debugPhysics) console.trace("Loading rapier physics engine");
274
274
  const module = await MODULES.RAPIER_PHYSICS.load();
275
275
  // https://github.com/dimforge/rapier/issues/811
276
- await module.init();
276
+ await module.init();
277
277
  }
278
278
  if (debugPhysics) console.log("Physics engine initialized, creating world...");
279
279
  this._world = new MODULES.RAPIER_PHYSICS.MODULE.World(this._gravity);
@@ -673,7 +673,7 @@ export class RapierPhysics implements IPhysicsEngine {
673
673
  }
674
674
 
675
675
  async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, extraScale?: Vector3) {
676
-
676
+
677
677
  // capture the geometry before waiting for phyiscs engine
678
678
  let geo = mesh.geometry;
679
679
  if (!geo) {
@@ -714,13 +714,13 @@ export class RapierPhysics implements IPhysicsEngine {
714
714
  }
715
715
 
716
716
  if (!collider.activeAndEnabled) return;
717
-
717
+
718
718
 
719
719
  // let positions = geo.getAttribute("position").array as Float32Array;
720
720
  const indices = geo.index?.array as Uint32Array;
721
-
721
+
722
722
  const scale = collider.gameObject.worldScale.clone();
723
- if(extraScale) scale.multiply(extraScale);
723
+ if (extraScale) scale.multiply(extraScale);
724
724
 
725
725
  // scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
726
726
  if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
@@ -130,6 +130,15 @@ export class Animation extends Behaviour implements IAnimationComponent {
130
130
  }
131
131
  }
132
132
 
133
+ get duration() {
134
+ if (this.actions) {
135
+ for (const action of this.actions) {
136
+ if (action.isRunning()) return action.getClip().duration;
137
+ }
138
+ }
139
+ return 0;
140
+ }
141
+
133
142
  private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
134
143
  /**
135
144
  * Get the first animation clip in the animations array
@@ -147,6 +147,7 @@ export abstract class GameObject extends Object3D implements Object3D, IGameObje
147
147
  * The forward direction vector of this GameObject in world space
148
148
  */
149
149
  abstract get worldForward(): Vector3;
150
+ abstract set worldForward(val: Vector3);
150
151
 
151
152
  /**
152
153
  * The right direction vector of this GameObject in world space
@@ -1,5 +1,4 @@
1
1
  import { serializable } from "../engine/engine_serialization.js";
2
- import { EventSystem } from "./api.js";
3
2
  import { Behaviour } from "./Component.js"
4
3
  import { EventList } from "./EventList.js";
5
4
  import { EventType } from "./EventType.js"
@@ -56,6 +56,7 @@ export type { DropListenerNetworkEventArguments, DropListenerOnDropArguments } f
56
56
  export { type FitCameraOptions } from "./OrbitControls.js";
57
57
  export * from "./particlesystem/api.js"
58
58
  export * from "./splines/index.js";
59
+ export * from "./web/index.js";
59
60
 
60
61
  // for correct type resolution in JSDoc
61
62
  import type { PhysicsMaterial } from "../engine/engine_physics.types.js";
@@ -115,6 +115,7 @@ export { InheritVelocityModule } from "../particlesystem/ParticleSystemModules.j
115
115
  export { SizeBySpeedModule } from "../particlesystem/ParticleSystemModules.js";
116
116
  export { ColorBySpeedModule } from "../particlesystem/ParticleSystemModules.js";
117
117
  export { ParticleSubEmitter } from "../particlesystem/ParticleSystemSubEmitter.js";
118
+ export { Attractor } from "../physics/Attractor.js";
118
119
  export { PlayerColor } from "../PlayerColor.js";
119
120
  export { Antialiasing } from "../postprocessing/Effects/Antialiasing.js";
120
121
  export { BloomEffect } from "../postprocessing/Effects/BloomEffect.js";
@@ -202,6 +203,9 @@ export { LookAt } from "../utils/LookAt.js";
202
203
  export { OpenURL } from "../utils/OpenURL.js";
203
204
  export { VideoPlayer } from "../VideoPlayer.js";
204
205
  export { Voip } from "../Voip.js";
206
+ export { ClickThrough } from "../web/Clickthrough.js";
207
+ export { CursorFollow } from "../web/CursorFollow.js";
208
+ export { ScrollFollow } from "../web/ScrollFollow.js";
205
209
  export { Avatar } from "../webxr/Avatar.js";
206
210
  export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
207
211
  export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
@@ -0,0 +1,35 @@
1
+ import { Behaviour } from "../Component.js";
2
+ import { Rigidbody } from "../RigidBody.js";
3
+ import { serializable } from "../../engine/engine_serialization_decorator.js";
4
+
5
+
6
+
7
+ export class Attractor extends Behaviour {
8
+
9
+ @serializable()
10
+ strength: number = 1;
11
+
12
+ @serializable()
13
+ radius: number = 2;
14
+
15
+ @serializable(Rigidbody)
16
+ targets: Rigidbody[] = [];
17
+
18
+
19
+ update() {
20
+ const wp = this.gameObject.worldPosition;
21
+ const factor = -this.strength * this.context.time.deltaTime;
22
+ this.targets.forEach(t => {
23
+ if(!t) return;
24
+ const dir = t.gameObject.worldPosition.sub(wp);
25
+ const length = dir.length();
26
+ if (length > this.radius) return;
27
+ let _factor = factor;
28
+ if (length > 1) _factor /= length * length;
29
+ else _factor /= Math.max(.05, length);
30
+ t.applyImpulse(dir.multiplyScalar(_factor));
31
+ })
32
+ }
33
+
34
+
35
+ }