@needle-tools/engine 4.10.0-next.f0ec242 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +7 -3
  2. package/README.md +2 -1
  3. package/components.needle.json +1 -1
  4. package/dist/needle-engine.bundle-BSq-d_16.min.js +1652 -0
  5. package/dist/{needle-engine.bundle-dgNq9Vsa.umd.cjs → needle-engine.bundle-C2kVfQq6.umd.cjs} +153 -140
  6. package/dist/{needle-engine.bundle-BC-0Ex9m.js → needle-engine.bundle-CIuhf7-t.js} +7388 -7113
  7. package/dist/needle-engine.d.ts +15 -15
  8. package/dist/needle-engine.js +259 -257
  9. package/dist/needle-engine.min.js +1 -1
  10. package/dist/needle-engine.umd.cjs +1 -1
  11. package/dist/vendor-CPuBPspY.umd.cjs +1121 -0
  12. package/dist/vendor-DPCU8cUF.min.js +1121 -0
  13. package/dist/vendor-MBoqSyFm.js +16240 -0
  14. package/lib/engine/codegen/register_types.js +2 -0
  15. package/lib/engine/codegen/register_types.js.map +1 -1
  16. package/lib/engine/engine_camera.d.ts +7 -1
  17. package/lib/engine/engine_camera.js +46 -6
  18. package/lib/engine/engine_camera.js.map +1 -1
  19. package/lib/engine/engine_context.d.ts +6 -0
  20. package/lib/engine/engine_context.js +48 -9
  21. package/lib/engine/engine_context.js.map +1 -1
  22. package/lib/engine/engine_gizmos.d.ts +11 -10
  23. package/lib/engine/engine_gizmos.js +24 -10
  24. package/lib/engine/engine_gizmos.js.map +1 -1
  25. package/lib/engine/engine_license.js +1 -1
  26. package/lib/engine/engine_license.js.map +1 -1
  27. package/lib/engine/engine_lightdata.d.ts +3 -3
  28. package/lib/engine/engine_lightdata.js +10 -10
  29. package/lib/engine/engine_lightdata.js.map +1 -1
  30. package/lib/engine/engine_physics_rapier.js +4 -0
  31. package/lib/engine/engine_physics_rapier.js.map +1 -1
  32. package/lib/engine/engine_scenelighting.d.ts +1 -1
  33. package/lib/engine/engine_scenelighting.js +4 -5
  34. package/lib/engine/engine_scenelighting.js.map +1 -1
  35. package/lib/engine/engine_utils.d.ts +3 -1
  36. package/lib/engine/engine_utils.js +11 -0
  37. package/lib/engine/engine_utils.js.map +1 -1
  38. package/lib/engine/extensions/NEEDLE_lightmaps.js +1 -1
  39. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  40. package/lib/engine/extensions/extension_utils.js +1 -1
  41. package/lib/engine/extensions/extension_utils.js.map +1 -1
  42. package/lib/engine/webcomponents/logo-element.d.ts +1 -1
  43. package/lib/engine/webcomponents/logo-element.js +29 -5
  44. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  45. package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -3
  46. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  47. package/lib/engine/webcomponents/needle-engine.js +22 -0
  48. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  49. package/lib/engine/webcomponents/needle-engine.loading.d.ts +0 -1
  50. package/lib/engine/webcomponents/needle-engine.loading.js +3 -36
  51. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  52. package/lib/engine/xr/NeedleXRController.d.ts +3 -3
  53. package/lib/engine/xr/NeedleXRController.js +28 -0
  54. package/lib/engine/xr/NeedleXRController.js.map +1 -1
  55. package/lib/engine-components/CameraUtils.js +2 -1
  56. package/lib/engine-components/CameraUtils.js.map +1 -1
  57. package/lib/engine-components/Renderer.js +6 -1
  58. package/lib/engine-components/Renderer.js.map +1 -1
  59. package/lib/engine-components/Skybox.js +22 -4
  60. package/lib/engine-components/Skybox.js.map +1 -1
  61. package/lib/engine-components/codegen/components.d.ts +1 -0
  62. package/lib/engine-components/codegen/components.js +1 -0
  63. package/lib/engine-components/codegen/components.js.map +1 -1
  64. package/lib/engine-components/debug/LogStats.d.ts +1 -0
  65. package/lib/engine-components/debug/LogStats.js +1 -0
  66. package/lib/engine-components/debug/LogStats.js.map +1 -1
  67. package/lib/engine-components/timeline/PlayableDirector.d.ts +7 -0
  68. package/lib/engine-components/timeline/PlayableDirector.js +8 -1
  69. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  70. package/lib/engine-components/timeline/TimelineModels.d.ts +11 -1
  71. package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -1
  72. package/lib/engine-components/timeline/TimelineTracks.js +30 -25
  73. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  74. package/lib/engine-components/utils/LookAt.js +5 -1
  75. package/lib/engine-components/utils/LookAt.js.map +1 -1
  76. package/lib/engine-components/web/Clickthrough.js +10 -2
  77. package/lib/engine-components/web/Clickthrough.js.map +1 -1
  78. package/lib/engine-components/web/ScrollFollow.d.ts +24 -0
  79. package/lib/engine-components/web/ScrollFollow.js +169 -42
  80. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  81. package/lib/engine-components/web/ViewBox.d.ts +43 -0
  82. package/lib/engine-components/web/ViewBox.js +258 -0
  83. package/lib/engine-components/web/ViewBox.js.map +1 -0
  84. package/lib/engine-components/web/index.d.ts +1 -0
  85. package/lib/engine-components/web/index.js +1 -0
  86. package/lib/engine-components/web/index.js.map +1 -1
  87. package/lib/engine-components-experimental/Presentation.d.ts +1 -0
  88. package/lib/engine-components-experimental/Presentation.js +1 -0
  89. package/lib/engine-components-experimental/Presentation.js.map +1 -1
  90. package/package.json +3 -2
  91. package/src/engine/codegen/register_types.ts +2 -0
  92. package/src/engine/engine_camera.ts +61 -9
  93. package/src/engine/engine_context.ts +50 -10
  94. package/src/engine/engine_gizmos.ts +37 -23
  95. package/src/engine/engine_license.ts +1 -1
  96. package/src/engine/engine_lightdata.ts +11 -11
  97. package/src/engine/engine_physics_rapier.ts +3 -0
  98. package/src/engine/engine_scenelighting.ts +5 -6
  99. package/src/engine/engine_utils.ts +12 -0
  100. package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
  101. package/src/engine/extensions/extension_utils.ts +1 -1
  102. package/src/engine/webcomponents/logo-element.ts +29 -4
  103. package/src/engine/webcomponents/needle menu/needle-menu.ts +4 -3
  104. package/src/engine/webcomponents/needle-engine.loading.ts +32 -32
  105. package/src/engine/webcomponents/needle-engine.ts +33 -6
  106. package/src/engine/xr/NeedleXRController.ts +36 -4
  107. package/src/engine-components/CameraUtils.ts +1 -1
  108. package/src/engine-components/Renderer.ts +6 -1
  109. package/src/engine-components/Skybox.ts +26 -7
  110. package/src/engine-components/codegen/components.ts +1 -0
  111. package/src/engine-components/debug/LogStats.ts +1 -0
  112. package/src/engine-components/timeline/PlayableDirector.ts +10 -1
  113. package/src/engine-components/timeline/TimelineModels.ts +11 -1
  114. package/src/engine-components/timeline/TimelineTracks.ts +30 -25
  115. package/src/engine-components/utils/LookAt.ts +5 -1
  116. package/src/engine-components/web/Clickthrough.ts +11 -2
  117. package/src/engine-components/web/ScrollFollow.ts +205 -51
  118. package/src/engine-components/web/ViewBox.ts +278 -0
  119. package/src/engine-components/web/index.ts +2 -1
  120. package/src/engine-components-experimental/Presentation.ts +1 -0
  121. package/dist/needle-engine.bundle-BSh7dSEx.min.js +0 -1639
  122. package/dist/vendor-D0Yvltn9.umd.cjs +0 -1121
  123. package/dist/vendor-DU8tJyl_.js +0 -14366
  124. package/dist/vendor-JyrX4DVM.min.js +0 -1121
@@ -0,0 +1,278 @@
1
+ import { Camera, PerspectiveCamera, Quaternion, Scene, Vector2, Vector3 } from "three";
2
+
3
+ import { isDevEnvironment } from "../../engine/debug/debug.js";
4
+ import { Gizmos } from "../../engine/engine_gizmos.js";
5
+ import { serializable } from "../../engine/engine_serialization_decorator.js";
6
+ import { getTempVector } from "../../engine/engine_three_utils.js";
7
+ import { registerType } from "../../engine/engine_typestore.js";
8
+ import { getParam } from "../../engine/engine_utils.js";
9
+ import { RGBAColor } from "../../engine/js-extensions/RGBAColor.js";
10
+ import { Behaviour } from "../Component.js";
11
+
12
+
13
+ const debugParam = getParam("debugviewbox");
14
+ const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
15
+
16
+ /**
17
+ * This component can be used to automatically fit a certain box area into the camera view - no matter your screen size or aspect ratio.
18
+ *
19
+ * Add the ViewBox to an object into your scene
20
+ *
21
+ * @link [Example on needle.run](https://viewbox-demo-z23hmxbz2gkayo-z1nyzm6.needle.run/)
22
+ * @link [Scrollytelling Demo using animated Viewbox](https://scrollytelling-bike-z23hmxb2gnu5a.needle.run/)
23
+ * @link [Example on Stackblitz](https://stackblitz.com/edit/needle-engine-view-box-example)
24
+ *
25
+ * @example Add a Viewbox component to an object in your scene
26
+ * ```ts
27
+ const viewBox = new Object3D();
28
+ viewBox.scale.set(0, 0, 0);
29
+ viewBox.addComponent(ViewBox, { debug: true });
30
+ scene.add(viewBox);
31
+
32
+ * @category Web
33
+ * @group Components
34
+ * @component
35
+ * ```
36
+ */
37
+ @registerType
38
+ export class ViewBox extends Behaviour {
39
+
40
+ static readonly instances: ViewBox[] = [];
41
+
42
+ /**
43
+ * The reference field of view is used to calculate the box size. This should usually be the same as your camera's fov.
44
+ * @default undefined (meaning it will use the camera fov on the first frame)
45
+ */
46
+ @serializable()
47
+ referenceFieldOfView: number | undefined = undefined;
48
+
49
+ /**
50
+ * Enable debug logs and rendering for this component instance
51
+ */
52
+ @serializable()
53
+ debug: boolean = false;
54
+
55
+ onEnable(): void {
56
+ if (debugParam || this.debug || isDevEnvironment()) console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
57
+ // register instance
58
+ ViewBox.instances.push(this);
59
+ }
60
+
61
+ onDisable(): void {
62
+ if (debugParam || this.debug) console.debug("[ViewBox] Disabled");
63
+ // unregister instance
64
+ const idx = ViewBox.instances.indexOf(this);
65
+ if (idx !== -1) ViewBox.instances.splice(idx, 1);
66
+ this._projectedBoxElement?.remove();
67
+ }
68
+
69
+ onBeforeRender(): void {
70
+ if (this.context.isInXR) return;
71
+ if (this.destroyed) return;
72
+ const isActive = ViewBox.instances[ViewBox.instances.length - 1] === this;
73
+ if (!isActive) {
74
+ if (debugParam || this.debug) {
75
+ Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, disabledGizmoColor);
76
+ }
77
+ return;
78
+ }
79
+ if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, 0xdddd00, 0, true, this.gameObject.worldQuaternion);
80
+
81
+ // calculate box size to fit the camera frustrum size at the current position (just scale)
82
+ const camera = this.context.mainCamera;
83
+ if (!camera) return;
84
+ if (!(camera instanceof PerspectiveCamera)) {
85
+ // TODO: support orthographic camera
86
+ return;
87
+ }
88
+
89
+ if (this.referenceFieldOfView === undefined) {
90
+ this.referenceFieldOfView = camera.fov;
91
+ }
92
+
93
+ if (this.referenceFieldOfView === undefined || this.referenceFieldOfView <= 0) {
94
+ if (debugParam || this.debug) console.warn("[ViewBox] No valid referenceFieldOfView set, cannot adjust box size:", this.referenceFieldOfView);
95
+ return;
96
+ }
97
+
98
+ const domWidth = this.context.domWidth;
99
+ const domHeight = this.context.domHeight;
100
+
101
+ let rectPosX = 0;
102
+ let rectPosY = 0;
103
+ let rectWidth = domWidth;
104
+ let rectHeight = domHeight;
105
+ let diffWidth = 1;
106
+ let diffHeight = 1;
107
+ // use focus rect if available
108
+ const focusRectSize = this.context.focusRectSize;
109
+ if (focusRectSize) {
110
+ // console.log(focusRectSize)
111
+ rectPosX = focusRectSize.x;
112
+ rectPosY = focusRectSize.y;
113
+ rectWidth = focusRectSize.width;
114
+ rectHeight = focusRectSize.height;
115
+ diffWidth = domWidth / rectWidth;
116
+ diffHeight = domHeight / rectHeight;
117
+ }
118
+
119
+
120
+ const view = camera.view;
121
+ const zoom = camera.zoom;
122
+ const aspect = camera.aspect;
123
+ const fov = camera.fov;
124
+ camera.view = null;
125
+ camera.zoom = 1;
126
+ camera.fov = this.referenceFieldOfView;
127
+ camera.updateProjectionMatrix();
128
+
129
+
130
+ const boxPosition = this.gameObject.worldPosition;
131
+ const boxScale = this.gameObject.worldScale;
132
+
133
+ const cameraPosition = camera.worldPosition;
134
+ const distance = cameraPosition.distanceTo(boxPosition);
135
+
136
+
137
+ // #region camera fixes
138
+ // If the camera is inside the box, move it out
139
+ const boxSizeMax = Math.max(boxScale.x, boxScale.y, boxScale.z);
140
+ const direction = getTempVector(cameraPosition).sub(boxPosition);
141
+ if (distance < boxSizeMax) {
142
+ // move camera out of bounds
143
+ if (this.debug || debugParam) console.warn("[ViewBox] Moving camera out of bounds", distance, "<", boxSizeMax);
144
+ const positionDirection = getTempVector(direction);
145
+ positionDirection.y *= .00000001; // stay on horizontal plane mostly
146
+ positionDirection.normalize();
147
+ const lengthToMove = (boxSizeMax - distance);
148
+ const newPosition = cameraPosition.add(positionDirection.multiplyScalar(lengthToMove));
149
+ camera.worldPosition = newPosition.lerp(cameraPosition, 1 - this.context.time.deltaTime);
150
+ }
151
+
152
+ // Ensure the camera looks at the ViewBox
153
+ // TOOD: smooth lookat over multiple frames if we have multiple viewboxes
154
+ // const dot = direction.normalize().dot(camera.worldForward);
155
+ // if (dot < .9) {
156
+ // console.log(dot);
157
+ // const targetRotation = direction;
158
+ // const rotation = getTempQuaternion();
159
+ // rotation.setFromUnitVectors(camera.worldForward.multiplyScalar(-1), targetRotation);
160
+ // camera.worldQuaternion = rotation;
161
+ // camera.updateMatrixWorld();
162
+ // }
163
+ const boxPositionInCameraSpace = getTempVector(boxPosition);
164
+ camera.worldToLocal(boxPositionInCameraSpace);
165
+ camera.lookAt(boxPosition);
166
+ camera.updateMatrixWorld();
167
+
168
+
169
+ // #region calculate fit
170
+ const vFOV = this.referenceFieldOfView * Math.PI / 180; // convert vertical fov to radians
171
+ const height = 2 * Math.tan(vFOV / 2) * distance; // visible height
172
+ const width = height * camera.aspect; // visible width
173
+
174
+ const projectedBox = this.projectBoxIntoCamera(camera, 1);
175
+ // return
176
+ const boxWidth = (projectedBox.maxX - projectedBox.minX);
177
+ const boxHeight = (projectedBox.maxY - projectedBox.minY);
178
+
179
+ const scale = this.fit(
180
+ boxWidth * camera.aspect,
181
+ boxHeight,
182
+ width / diffWidth,
183
+ height / diffHeight
184
+ );
185
+ // console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
186
+ // this.context.focusRectSettings.zoom = 1.39;
187
+ // if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
188
+ // return
189
+ const vec = getTempVector(boxPosition);
190
+ vec.project(camera);
191
+ this.context.focusRectSettings.offsetX = vec.x;
192
+ this.context.focusRectSettings.offsetY = vec.y;
193
+ this.context.focusRectSettings.zoom = scale / (height * .5);
194
+ // if we don't have a focus rect yet, set it to the dom element
195
+ if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
196
+
197
+ // Reset values
198
+ camera.view = view;
199
+ camera.zoom = zoom;
200
+ camera.aspect = aspect;
201
+ camera.fov = fov;
202
+ // camera.updateProjectionMatrix();
203
+
204
+
205
+ // BACKLOG: some code for box scale of an object (different component)
206
+ // this.gameObject.worldScale = getTempVector(width, height, worldscale.z);
207
+ // this.gameObject.scale.multiplyScalar(.98)
208
+ // const minscale = Math.min(width, height);
209
+ // console.log(width, height);
210
+ // this.gameObject.worldScale = getTempVector(scale, scale, scale);
211
+ }
212
+
213
+
214
+ /**
215
+ * Cover fit
216
+ */
217
+ private fit(width1: number, height1: number, width2: number, height2: number) {
218
+ const scaleX = width2 / width1;
219
+ const scaleY = height2 / height1;
220
+ return Math.min(scaleX, scaleY);
221
+ }
222
+
223
+
224
+
225
+ private projectBoxIntoCamera(camera: Camera, _factor: number) {
226
+ const factor = .5 * _factor;
227
+
228
+ const corners = [
229
+ getTempVector(-factor, -factor, -factor),
230
+ getTempVector(factor, -factor, -factor),
231
+ getTempVector(-factor, factor, -factor),
232
+ getTempVector(factor, factor, -factor),
233
+ getTempVector(-factor, -factor, factor),
234
+ getTempVector(factor, -factor, factor),
235
+ getTempVector(-factor, factor, factor),
236
+ getTempVector(factor, factor, factor),
237
+ ];
238
+ let minX = Number.POSITIVE_INFINITY;
239
+ let maxX = Number.NEGATIVE_INFINITY;
240
+ let minY = Number.POSITIVE_INFINITY;
241
+ let maxY = Number.NEGATIVE_INFINITY;
242
+ for (let i = 0; i < corners.length; i++) {
243
+ const c = corners[i];
244
+ c.applyMatrix4(this.gameObject.matrixWorld);
245
+ c.project(camera);
246
+ if (c.x < minX) minX = c.x;
247
+ if (c.x > maxX) maxX = c.x;
248
+ if (c.y < minY) minY = c.y;
249
+ if (c.y > maxY) maxY = c.y;
250
+ }
251
+
252
+ if (debugParam) {
253
+ if (!this._projectedBoxElement) {
254
+ this._projectedBoxElement = document.createElement("div");
255
+ }
256
+ if (this._projectedBoxElement.parentElement !== this.context.domElement)
257
+ this.context.domElement.appendChild(this._projectedBoxElement);
258
+ this._projectedBoxElement.style.position = "fixed";
259
+ // dotted but with larger gaps
260
+ this._projectedBoxElement.style.outline = "2px dashed rgba(255,0,0,.5)";
261
+ this._projectedBoxElement.style.left = ((minX * .5 + .5) * this.context.domWidth) + "px";
262
+ this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * this.context.domHeight) + "px";
263
+ this._projectedBoxElement.style.width = ((maxX - minX) * .5 * this.context.domWidth) + "px";
264
+ this._projectedBoxElement.style.height = ((maxY - minY) * .5 * this.context.domHeight) + "px";
265
+ this._projectedBoxElement.style.pointerEvents = "none";
266
+ this._projectedBoxElement.style.zIndex = "1000";
267
+ }
268
+
269
+
270
+ return { minX, maxX, minY, maxY };
271
+
272
+ }
273
+ private _projectedBoxElement: HTMLElement | null = null;
274
+
275
+
276
+
277
+
278
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./Clickthrough.js";
2
2
  export * from "./CursorFollow.js";
3
3
  export * from "./HoverAnimation.js";
4
- export * from "./ScrollFollow.js";
4
+ export * from "./ScrollFollow.js";
5
+ export * from "./ViewBox.js";
@@ -1,6 +1,7 @@
1
1
  import type { KeyCode } from "../engine/engine_input.js";
2
2
  import { Behaviour } from "../engine-components/Component.js";
3
3
 
4
+ /** @internal */
4
5
  export class PresentationMode extends Behaviour {
5
6
 
6
7
  toggleKey: KeyCode = "KeyP";