@needle-tools/engine 4.10.0-beta.3 → 4.10.0-next.4f9d92a

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 (39) hide show
  1. package/dist/{needle-engine.bundle-Ddybtee9.js → needle-engine.bundle-BeZ_xmJa.js} +6422 -6480
  2. package/dist/needle-engine.bundle-C3bpSNYu.min.js +1650 -0
  3. package/dist/{needle-engine.bundle-Ckr5KE6m.umd.cjs → needle-engine.bundle-D4dO0t5I.umd.cjs} +134 -134
  4. package/dist/needle-engine.js +14 -15
  5. package/dist/needle-engine.min.js +1 -1
  6. package/dist/needle-engine.umd.cjs +1 -1
  7. package/lib/engine/engine_lightdata.d.ts +3 -3
  8. package/lib/engine/engine_lightdata.js +10 -10
  9. package/lib/engine/engine_lightdata.js.map +1 -1
  10. package/lib/engine/engine_physics_rapier.js +0 -4
  11. package/lib/engine/engine_physics_rapier.js.map +1 -1
  12. package/lib/engine/engine_scenelighting.d.ts +1 -1
  13. package/lib/engine/engine_scenelighting.js +5 -4
  14. package/lib/engine/engine_scenelighting.js.map +1 -1
  15. package/lib/engine/engine_utils.d.ts +1 -3
  16. package/lib/engine/engine_utils.js +0 -11
  17. package/lib/engine/engine_utils.js.map +1 -1
  18. package/lib/engine/webcomponents/needle-engine.js +0 -22
  19. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  20. package/lib/engine-components/CameraUtils.js +1 -2
  21. package/lib/engine-components/CameraUtils.js.map +1 -1
  22. package/lib/engine-components/Skybox.js +4 -22
  23. package/lib/engine-components/Skybox.js.map +1 -1
  24. package/lib/engine-components/web/ScrollFollow.js +70 -80
  25. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  26. package/lib/engine-components/web/ViewBox.d.ts +1 -0
  27. package/lib/engine-components/web/ViewBox.js +27 -67
  28. package/lib/engine-components/web/ViewBox.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/engine/engine_lightdata.ts +11 -11
  31. package/src/engine/engine_physics_rapier.ts +0 -3
  32. package/src/engine/engine_scenelighting.ts +6 -5
  33. package/src/engine/engine_utils.ts +0 -12
  34. package/src/engine/webcomponents/needle-engine.ts +6 -33
  35. package/src/engine-components/CameraUtils.ts +1 -1
  36. package/src/engine-components/Skybox.ts +7 -26
  37. package/src/engine-components/web/ScrollFollow.ts +70 -82
  38. package/src/engine-components/web/ViewBox.ts +29 -71
  39. package/dist/needle-engine.bundle-CLzMgxkO.min.js +0 -1650
@@ -4,11 +4,10 @@ import { element } from "three/src/nodes/TSL.js";
4
4
  import { Context } from "../../engine/engine_context.js";
5
5
  import { Mathf } from "../../engine/engine_math.js";
6
6
  import { serializable } from "../../engine/engine_serialization.js";
7
- import { getBoundingBox, setVisibleInCustomShadowRendering } from "../../engine/engine_three_utils.js";
7
+ import { getBoundingBox } from "../../engine/engine_three_utils.js";
8
8
  import { getParam } from "../../engine/engine_utils.js";
9
9
  import { Animation } from "../Animation.js";
10
10
  import { Animator } from "../Animator.js";
11
- import { MarkerTrackHandler } from "../api.js";
12
11
  import { AudioSource } from "../AudioSource.js";
13
12
  import { Behaviour } from "../Component.js";
14
13
  import { EventList } from "../EventList.js";
@@ -309,17 +308,17 @@ export class ScrollFollow extends Behaviour {
309
308
  try {
310
309
  marker.element = tryGetElementsForSelector(index, marker.name) as HTMLElement | null;
311
310
  if (debug) console.debug("ScrollMarker found on page", marker.element, marker.name);
312
- if (!marker.element) {
313
- marker.timeline = undefined;
314
- continue;
315
- }
316
- else {
317
- /** @ts-ignore */
318
- marker.timeline = new ViewTimeline({
319
- subject: marker.element,
320
- axis: 'block', // https://drafts.csswg.org/scroll-animations/#scroll-notation
321
- });
322
- }
311
+ // if (!marker.element) {
312
+ // marker.timeline = undefined;
313
+ // continue;
314
+ // }
315
+ // else {
316
+ // /** @ts-ignore */
317
+ // marker.timeline = new ViewTimeline({
318
+ // subject: marker.element,
319
+ // axis: 'block', // https://drafts.csswg.org/scroll-animations/#scroll-notation
320
+ // });
321
+ // }
323
322
  }
324
323
  catch (error) {
325
324
  marker.element = null;
@@ -350,74 +349,57 @@ export class ScrollFollow extends Behaviour {
350
349
 
351
350
  weightsArray.length = 0;
352
351
  let sum = 0;
353
- const oneFrameTime = 1 / 60;
354
352
 
355
353
  // We keep a separate count here in case there are some markers that could not be resolved so point to *invalid* elements - the timeline should fallback to 0-1 scroll behaviour then
356
354
  let markerCount = 0;
357
- for (let i = 0; i < markersArray.length; i++) {
358
- const marker = markersArray[i];
359
- if (!marker.element) continue;
360
- const nextMarker = markersArray[i + 1];
355
+ for (const marker of markersArray) {
361
356
 
362
- const nextTime = nextMarker
363
- ? (nextMarker.time - oneFrameTime)
364
- : duration;
357
+ if (!marker.element) continue;
365
358
 
366
359
  markerCount += 1;
367
360
 
368
- const timeline = marker.timeline;
369
- if (timeline) {
370
- const time01 = calculateTimelinePositionNormalized(timeline);
371
- // remap 0-1 to 0 - 1 - 0 (full weight at center)
372
- const weight = 1 - Math.abs(time01 - 0.5) * 2;
373
- if (time01 > 0 && time01 <= 1) {
374
- const lerpTime = marker.time + (nextTime - marker.time) * time01;
375
- weightsArray.push({ time: lerpTime, weight: weight });
376
- sum += weight;
377
- }
378
- // Before the first marker is reached
379
- else if (i === 0 && time01 <= 0) {
380
- weightsArray.push({ time: 0, weight: 1 });
381
- sum += 1;
382
- }
383
- // After the last marker is reached
384
- else if (i === markersArray.length - 1 && time01 >= 1) {
385
- weightsArray.push({ time: duration, weight: 1 });
386
- sum += 1;
387
- }
388
- }
389
- continue;
361
+ // const timeline = marker.timeline;
362
+ // if (timeline) {
363
+ // const time01 = calculateTimelinePositionNormalized(timeline);
364
+ // if (time01 > 0 && time01 <= 1) {
365
+ // const overlap = calculateTimelinePositionNormalized(timeline!);
366
+ // const weight = overlap;
367
+ // // console.log(marker.element.className, time01)
368
+ // weightsArray.push({ time: marker.time, weight: weight });
369
+ // sum += weight;
370
+ // }
371
+ // }
372
+ // continue;
390
373
  // if(this.context.time.frame % 10 === 0) console.log(marker.element?.className, timeline, calculateTimelinePositionNormalized(timeline!));
391
374
 
392
- // const top = marker.element.offsetTop - this._scrollContainerHeight;
393
- // const height = marker.element.offsetHeight + this._scrollContainerHeight;
394
- // const bottom = top + height;
395
- // let overlap = 0;
375
+ const top = marker.element.offsetTop;
376
+ const height = marker.element.offsetHeight;
377
+ const bottom = top + height;
378
+ let overlap = 0;
396
379
 
397
- // // TODO: if we have two marker sections where no HTML overlaps (vor example because some large section is between them) we probably want to still virtually interpolate between them slowly in that region
380
+ // TODO: if we have two marker sections where no HTML overlaps (vor example because some large section is between them) we probably want to still virtually interpolate between them slowly in that region
398
381
 
399
- // if (bottom < currentTop) {
400
- // // marker is above scroll region
401
- // overlap = 0;
402
- // }
403
- // else if (top > currentBottom) {
404
- // // marker is below scroll region
405
- // overlap = 0;
406
- // }
407
- // else {
408
- // // calculate overlap in pixels
409
- // const overlapTop = Math.max(top, currentTop);
410
- // const overlapBottom = Math.min(bottom, currentBottom);
411
- // const height = Math.max(1, currentBottom - currentTop);
412
- // overlap = Math.max(0, overlapBottom - overlapTop);
413
- // }
382
+ if (bottom < currentTop) {
383
+ // marker is above scroll region
384
+ overlap = 0;
385
+ }
386
+ else if (top > currentBottom) {
387
+ // marker is below scroll region
388
+ overlap = 0;
389
+ }
390
+ else {
391
+ // calculate overlap in pixels
392
+ const overlapTop = Math.max(top, currentTop);
393
+ const overlapBottom = Math.min(bottom, currentBottom);
394
+ overlap = Math.max(0, overlapBottom - overlapTop);
395
+ }
414
396
 
415
- // // if(this.context.time.frame % 20 === 0) console.log(overlap)
397
+ markerCount += 1;
416
398
 
417
- // if (overlap > 0) {
418
- // weightsArray.push({ time: marker.time, weight: overlap });
419
- // sum += overlap;
420
- // }
399
+ if (overlap > 0) {
400
+ weightsArray.push({ time: marker.time, weight: overlap });
401
+ sum += overlap;
402
+ }
421
403
  }
422
404
 
423
405
  if (weightsArray.length <= 0 && markerCount <= 0) {
@@ -425,23 +407,19 @@ export class ScrollFollow extends Behaviour {
425
407
  }
426
408
  else if (weightsArray.length > 0) {
427
409
  // normalize and calculate weighted time
428
- let time = weightsArray[0].time; // fallback to first time
429
- if (weightsArray.length > 1) {
430
- for (const entry of weightsArray) {
431
- const weight = entry.weight / Math.max(0.00001, sum);
432
- // console.log(weight.toFixed(2))
433
- // lerp time based on weight
434
- const diff = Math.abs(entry.time - time);
435
- time += diff * weight;
436
- }
410
+ let time = 0;
411
+ for (const entry of weightsArray) {
412
+ const weight = entry.weight / Math.max(0.00001, sum);
413
+ // console.log(weight.toFixed(2))
414
+ // lerp time based on weight
415
+ const diff = Math.abs(entry.time - time);
416
+ time += diff * weight;
437
417
  }
438
- if (debug && this.context.time.frame % 20 === 0) console.log(time.toFixed(3), [...weightsArray])
439
- if (this.damping <= 0) {
418
+ // console.log(time.toFixed(2), [...weightsArray])
419
+ if (this.damping <= 0)
440
420
  director.time = time;
441
- }
442
- else {
421
+ else
443
422
  director.time = Mathf.lerp(director.time, time, this.context.time.deltaTime / this.damping);
444
- }
445
423
  }
446
424
  }
447
425
 
@@ -528,6 +506,16 @@ function calculateTimelinePositionNormalized(timeline: ViewTimeline) {
528
506
  const t01 = currentTime.unit === "seconds" ? (currentTime.value / durationValue) : (currentTime.value / 100);
529
507
  return t01;
530
508
  }
509
+ function calculateNormalizedOverlap(timeline: ViewTimeline) {
510
+ if (!timeline.source) return 0;
511
+ const start = timeline.startOffset;
512
+ const end = timeline.endOffset;
513
+ const total = start.value + end.value;
514
+ if (total <= 0) return 1;
515
+ const startNorm = start.value / total;
516
+ const endNorm = end.value / total;
517
+ return 1 - (startNorm + endNorm);
518
+ }
531
519
 
532
520
 
533
521
  declare global {
@@ -3,7 +3,7 @@ import { Camera, PerspectiveCamera, Vector2, Vector3 } from "three";
3
3
  import { isDevEnvironment } from "../../engine/debug/debug.js";
4
4
  import { Gizmos } from "../../engine/engine_gizmos.js";
5
5
  import { serializable } from "../../engine/engine_serialization_decorator.js";
6
- import { getTempQuaternion, getTempVector } from "../../engine/engine_three_utils.js";
6
+ import { getTempVector } from "../../engine/engine_three_utils.js";
7
7
  import { registerType } from "../../engine/engine_typestore.js";
8
8
  import { getParam } from "../../engine/engine_utils.js";
9
9
  import { Behaviour } from "../Component.js";
@@ -21,24 +21,20 @@ export class ViewBox extends Behaviour {
21
21
  @serializable()
22
22
  debug: boolean = false;
23
23
 
24
- // awake() {
25
- // // this.referenceFieldOfView = (this.context.mainCamera as PerspectiveCamera)?.fov || 60;
26
- // setInterval(()=>{
27
- // if(Math.random() > .5)
28
- // this.enabled = !this.enabled
29
- // }, 1000)
30
- // }
31
-
24
+ awake() {
25
+ // this.referenceFieldOfView = (this.context.mainCamera as PerspectiveCamera)?.fov || 60;
26
+ // setInterval(()=>{
27
+ // this.enabled = !this.enabled
28
+ // }, 1000)
29
+ }
32
30
  onEnable(): void {
33
31
  if (debugParam || this.debug || isDevEnvironment()) console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
34
32
  ViewBox.instances.push(this);
35
33
  }
36
34
 
37
35
  onDisable(): void {
38
- if (debugParam || this.debug) console.debug("[ViewBox] Disabled");
39
36
  const idx = ViewBox.instances.indexOf(this);
40
37
  if (idx !== -1) ViewBox.instances.splice(idx, 1);
41
- this._projectedBoxElement?.remove();
42
38
  }
43
39
 
44
40
  onBeforeRender() {
@@ -84,80 +80,44 @@ export class ViewBox extends Behaviour {
84
80
  diffHeight = domHeight / rectHeight;
85
81
  }
86
82
 
87
-
83
+ // const view = camera.view;
88
84
  const view = camera.view;
89
85
  const zoom = camera.zoom;
90
86
  const aspect = camera.aspect;
91
87
  const fov = camera.fov;
92
88
  camera.view = null;
93
89
  camera.zoom = 1;
90
+ // camera.aspect = rectWidth / rectHeight;
94
91
  camera.fov = this.referenceFieldOfView;
95
92
  camera.updateProjectionMatrix();
96
93
 
97
94
  const boxPosition = this.gameObject.worldPosition;
98
95
  const boxScale = this.gameObject.worldScale;
99
96
 
100
- const cameraPosition = camera.worldPosition;
101
- const distance = cameraPosition.distanceTo(boxPosition);
102
-
103
-
104
- // #region camera fixes
105
- // If the camera is inside the box, move it out
106
- const boxSizeMax = Math.max(boxScale.x, boxScale.y, boxScale.z);
107
- const direction = getTempVector(cameraPosition).sub(boxPosition);
108
- if (distance < boxSizeMax) {
109
- // move camera out of bounds
110
- if (this.debug || debugParam) console.warn("[ViewBox] Moving camera out of bounds", distance, "<", boxSizeMax);
111
- const positionDirection = getTempVector(direction);
112
- positionDirection.y *= .00000001; // stay on horizontal plane mostly
113
- positionDirection.normalize();
114
- const lengthToMove = (boxSizeMax - distance) * 10; // move a bit more than needed
115
- const newPosition = cameraPosition.add(positionDirection.multiplyScalar(lengthToMove));
116
- camera.worldPosition = newPosition.lerp(cameraPosition, 1 - this.context.time.deltaTime);
117
- }
118
-
119
- // Ensure the camera looks at the ViewBox
120
- // TOOD: smooth lookat over multiple frames if we have multiple viewboxes
121
- // const dot = direction.normalize().dot(camera.worldForward);
122
- // if (dot < .9) {
123
- // console.log(dot);
124
- // const targetRotation = direction;
125
- // const rotation = getTempQuaternion();
126
- // rotation.setFromUnitVectors(camera.worldForward.multiplyScalar(-1), targetRotation);
127
- // camera.worldQuaternion = rotation;
128
- // camera.updateMatrixWorld();
129
- // }
130
- const boxPositionInCameraSpace = getTempVector(boxPosition);
131
- camera.worldToLocal(boxPositionInCameraSpace);
132
- camera.lookAt(boxPosition);
133
- camera.updateMatrixWorld();
134
97
 
135
98
 
136
- // #region calculate fit
99
+ // const fov = this.referenceFieldOfView
100
+ const distance = camera.worldPosition.distanceTo(boxPosition);
137
101
  const vFOV = this.referenceFieldOfView * Math.PI / 180; // convert vertical fov to radians
138
102
  const height = 2 * Math.tan(vFOV / 2) * distance; // visible height
139
103
  const width = height * camera.aspect; // visible width
140
104
 
141
- const projectedBox = this.projectBoxIntoCamera(boxPosition, boxScale, camera, 1);
142
- // return
105
+ const projectedBox = this.projectBoxIntoCamera(boxPosition, boxScale, camera, height * .5);
143
106
  const boxWidth = (projectedBox.maxX - projectedBox.minX);
144
107
  const boxHeight = (projectedBox.maxY - projectedBox.minY);
145
108
 
109
+ // TODO: take the rect size different into account
146
110
  const scale = this.fit(
147
111
  boxWidth * camera.aspect,
148
112
  boxHeight,
149
113
  width / diffWidth,
150
114
  height / diffHeight
151
115
  );
152
- // console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
153
- // this.context.focusRectSettings.zoom = 1.39;
154
- // if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
155
- // return
156
116
  const vec = getTempVector(boxPosition);
157
117
  vec.project(camera);
158
118
  this.context.focusRectSettings.offsetX = vec.x;
159
119
  this.context.focusRectSettings.offsetY = vec.y;
160
- this.context.focusRectSettings.zoom = scale / (height * .5);
120
+ this.context.focusRectSettings.zoom = scale;
161
121
  // if we don't have a focus rect yet, set it to the dom element
162
122
  if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
163
123
 
@@ -189,8 +149,9 @@ export class ViewBox extends Behaviour {
189
149
 
190
150
 
191
151
 
192
- private projectBoxIntoCamera(position: Vector3, scale: Vector3, camera: Camera, _factor: number) {
193
- const factor = .5 * _factor;
152
+ private projectBoxIntoCamera(position: Vector3, scale: Vector3, camera: Camera, diff: number) {
153
+
154
+ const factor = .5 * diff;
194
155
 
195
156
  const corners = [
196
157
  getTempVector(-scale.x * factor, -scale.y * factor, -scale.z * factor),
@@ -216,21 +177,18 @@ export class ViewBox extends Behaviour {
216
177
  if (c.y > maxY) maxY = c.y;
217
178
  }
218
179
 
219
- if (debugParam) {
220
- if (!this._projectedBoxElement) {
221
- this._projectedBoxElement = document.createElement("div");
222
- }
223
- if (this._projectedBoxElement.parentElement !== this.context.domElement)
224
- this.context.domElement.appendChild(this._projectedBoxElement);
225
- this._projectedBoxElement.style.position = "fixed";
226
- this._projectedBoxElement.style.outline = "5px dotted red";
227
- this._projectedBoxElement.style.left = ((minX * .5 + .5) * this.context.domWidth) + "px";
228
- this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * this.context.domHeight) + "px";
229
- this._projectedBoxElement.style.width = ((maxX - minX) * .5 * this.context.domWidth) + "px";
230
- this._projectedBoxElement.style.height = ((maxY - minY) * .5 * this.context.domHeight) + "px";
231
- this._projectedBoxElement.style.pointerEvents = "none";
232
- this._projectedBoxElement.style.zIndex = "1000";
233
- }
180
+ // if(!this._projectedBoxElement) {
181
+ // this._projectedBoxElement = document.createElement("div");
182
+ // this.context.domElement.appendChild(this._projectedBoxElement);
183
+ // }
184
+ // this._projectedBoxElement.style.position = "fixed";
185
+ // this._projectedBoxElement.style.outline = "10px solid red";
186
+ // this._projectedBoxElement.style.left = ((minX * .5 + .5) * this.context.domWidth) + "px";
187
+ // this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * this.context.domHeight) + "px";
188
+ // this._projectedBoxElement.style.width = ((maxX - minX) * .5 * this.context.domWidth) + "px";
189
+ // this._projectedBoxElement.style.height = ((maxY - minY) * .5 * this.context.domHeight) + "px";
190
+ // this._projectedBoxElement.style.pointerEvents = "none";
191
+ // this._projectedBoxElement.style.zIndex = "1000";
234
192
 
235
193
 
236
194
  return { minX, maxX, minY, maxY };