@needle-tools/engine 4.11.0 → 4.11.1

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 (31) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +3 -1
  3. package/dist/{needle-engine.bundle-Dh4X0Qy5.js → needle-engine.bundle-6yF8G5KJ.js} +2646 -2575
  4. package/dist/{needle-engine.bundle-IPerDSpg.min.js → needle-engine.bundle-BSk8yk3v.min.js} +100 -100
  5. package/dist/{needle-engine.bundle-DhRclTK5.umd.cjs → needle-engine.bundle-DPVYipMl.umd.cjs} +97 -97
  6. package/dist/needle-engine.js +2 -2
  7. package/dist/needle-engine.min.js +1 -1
  8. package/dist/needle-engine.umd.cjs +1 -1
  9. package/lib/engine/engine_physics.js +2 -1
  10. package/lib/engine/engine_physics.js.map +1 -1
  11. package/lib/engine-components/OrbitControls.js +2 -0
  12. package/lib/engine-components/OrbitControls.js.map +1 -1
  13. package/lib/engine-components/splines/SplineWalker.d.ts +43 -4
  14. package/lib/engine-components/splines/SplineWalker.js +88 -12
  15. package/lib/engine-components/splines/SplineWalker.js.map +1 -1
  16. package/lib/engine-components/web/Clickthrough.d.ts +2 -0
  17. package/lib/engine-components/web/Clickthrough.js +23 -1
  18. package/lib/engine-components/web/Clickthrough.js.map +1 -1
  19. package/lib/engine-components/web/ScrollFollow.d.ts +4 -9
  20. package/lib/engine-components/web/ScrollFollow.js +26 -30
  21. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  22. package/lib/engine-components/web/ViewBox.d.ts +16 -0
  23. package/lib/engine-components/web/ViewBox.js +35 -3
  24. package/lib/engine-components/web/ViewBox.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/engine/engine_physics.ts +3 -3
  27. package/src/engine-components/OrbitControls.ts +5 -2
  28. package/src/engine-components/splines/SplineWalker.ts +99 -14
  29. package/src/engine-components/web/Clickthrough.ts +28 -1
  30. package/src/engine-components/web/ScrollFollow.ts +31 -33
  31. package/src/engine-components/web/ViewBox.ts +35 -5
@@ -37,24 +37,47 @@ const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
37
37
  * @component
38
38
  */
39
39
  let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
40
+ /**
41
+ * All active ViewBox instances. The last one in the array is the currently active one.
42
+ */
40
43
  static instances = [];
41
44
  /**
42
45
  * The reference field of view is used to calculate the box size. This should usually be the same as your camera's fov.
43
46
  * @default -1 (meaning it will use the camera fov on the first frame)
44
47
  */
45
48
  referenceFieldOfView = -1;
49
+ /**
50
+ * The mode determines if the viewbox should be applied once or continuously while it is the active viewbox.
51
+ * Options:
52
+ * - "once": The viewbox will be applied once when it becomes the active viewbox. This is useful if you want to fit the view once and then allow the user to zoom or pan freely.
53
+ * - "continuous": The viewbox will be applied continuously while it is the active viewbox. This is useful if you animate or scale the viewbox over time.
54
+ */
55
+ get mode() { return this._mode; }
56
+ set mode(v) {
57
+ if (v === this._mode)
58
+ return;
59
+ this._mode = v;
60
+ if (v === "once")
61
+ this._applyCount = 0;
62
+ if (debugParam || this.debug)
63
+ console.debug("[ViewBox] Set mode:", v);
64
+ }
65
+ _mode = "continuous";
46
66
  /**
47
67
  * Enable debug logs and rendering for this component instance
48
68
  */
49
69
  debug = false;
70
+ /** @internal */
50
71
  onEnable() {
51
72
  if (debugParam || this.debug || isDevEnvironment())
52
73
  console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
53
74
  // register instance
54
75
  ViewBox_1.instances.push(this);
76
+ this._applyCount = 0;
55
77
  this.removeUpdateCallback();
56
78
  this.context.pre_render_callbacks.push(this.internalUpdate);
57
79
  }
80
+ /** @internal */
58
81
  onDisable() {
59
82
  if (debugParam || this.debug)
60
83
  console.debug("[ViewBox] Disabled");
@@ -73,6 +96,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
73
96
  }
74
97
  static _tempProjectionMatrix = new Matrix4();
75
98
  static _tempProjectionMatrixInverse = new Matrix4();
99
+ _applyCount = 0;
76
100
  internalUpdate = () => {
77
101
  if (this.context.isInXR)
78
102
  return;
@@ -104,6 +128,10 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
104
128
  console.warn("[ViewBox] No valid referenceFieldOfView set, cannot adjust box size:", this.referenceFieldOfView);
105
129
  return;
106
130
  }
131
+ if (this._applyCount >= 1 && this.mode === "once") {
132
+ return;
133
+ }
134
+ this._applyCount++;
107
135
  const domWidth = this.context.domWidth;
108
136
  const domHeight = this.context.domHeight;
109
137
  let rectWidth = domWidth;
@@ -122,7 +150,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
122
150
  ViewBox_1._tempProjectionMatrix.copy(camera.projectionMatrix);
123
151
  ViewBox_1._tempProjectionMatrixInverse.copy(camera.projectionMatrixInverse);
124
152
  const view = camera.view;
125
- const zoom = camera.zoom;
153
+ const cameraZoom = camera.zoom;
126
154
  const aspect = camera.aspect;
127
155
  const fov = camera.fov;
128
156
  // Set values to default so we can calculate the box size correctly
@@ -173,6 +201,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
173
201
  const boxWidth = (projectedBox.maxX - projectedBox.minX);
174
202
  const boxHeight = (projectedBox.maxY - projectedBox.minY);
175
203
  const scale = this.fit(boxWidth * camera.aspect, boxHeight, width / diffWidth, height / diffHeight);
204
+ const zoom = scale / (height * .5);
176
205
  // console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
177
206
  // this.context.focusRectSettings.zoom = 1.39;
178
207
  // if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
@@ -181,13 +210,13 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
181
210
  vec.project(camera);
182
211
  this.context.focusRectSettings.offsetX = vec.x;
183
212
  this.context.focusRectSettings.offsetY = vec.y;
184
- this.context.focusRectSettings.zoom = scale / (height * .5);
213
+ this.context.focusRectSettings.zoom = zoom;
185
214
  // if we don't have a focus rect yet, set it to the dom element
186
215
  if (!this.context.focusRect)
187
216
  this.context.setCameraFocusRect(this.context.domElement);
188
217
  // Reset values
189
218
  camera.view = view;
190
- camera.zoom = zoom;
219
+ camera.zoom = cameraZoom;
191
220
  camera.aspect = aspect;
192
221
  camera.fov = fov;
193
222
  camera.projectionMatrix.copy(ViewBox_1._tempProjectionMatrix);
@@ -259,6 +288,9 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
259
288
  __decorate([
260
289
  serializable()
261
290
  ], ViewBox.prototype, "referenceFieldOfView", void 0);
291
+ __decorate([
292
+ serializable()
293
+ ], ViewBox.prototype, "mode", null);
262
294
  __decorate([
263
295
  serializable()
264
296
  ], ViewBox.prototype, "debug", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"ViewBox.js","sourceRoot":"","sources":["../../../src/engine-components/web/ViewBox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ViewBox.js","sourceRoot":"","sources":["../../../src/engine-components/web/ViewBox.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "4.11.0",
3
+ "version": "4.11.1",
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": {
@@ -323,7 +323,7 @@ export class Physics {
323
323
 
324
324
  let shouldIntersectObject = true;
325
325
  const mesh = obj as Mesh | SkinnedMesh;
326
- const geo = mesh.geometry;
326
+ const geo = mesh.geometry as BufferGeometry | null | undefined;
327
327
 
328
328
  if (obj.raycastAllowed === false) {
329
329
  shouldIntersectObject = false;
@@ -356,7 +356,7 @@ export class Physics {
356
356
 
357
357
  let usePrecise = preference !== "bounds";
358
358
  if (options.precise === false) usePrecise = false;
359
- usePrecise ||= geo.getAttribute("position")?.array?.length < 64;
359
+ if (geo) usePrecise ||= geo.getAttribute("position")?.array?.length < 64;
360
360
  if (mesh instanceof GroundedSkybox) {
361
361
  usePrecise = false;
362
362
  }
@@ -379,7 +379,7 @@ export class Physics {
379
379
  }
380
380
 
381
381
  // Restore
382
- mesh.geometry = geo;
382
+ mesh.geometry = geo as any;
383
383
 
384
384
  // Debug
385
385
  if (debugPhysics && results.length != lastResultsCount) {
@@ -711,8 +711,10 @@ export class OrbitControls extends Behaviour implements ICameraController {
711
711
 
712
712
 
713
713
  if (this._controls) {
714
- if (this.debugLog)
715
- this._controls.domElement = this.context.renderer.domElement;
714
+ if (this.debugLog) this._controls.domElement = this.context.renderer.domElement;
715
+
716
+ const viewZoomFactor = 1 / (this.context.focusRectSettings?.zoom || 1);
717
+
716
718
  this._controls.enabled = !this._shouldDisable && this._camera === this.context.mainCameraComponent && !this.context.isInXR && !this._activePointerEvents.some(e => e.used);
717
719
  this._controls.keys = this.enableKeys ? defaultKeys : disabledKeys;
718
720
  this._controls.autoRotate = this.autoRotate;
@@ -723,6 +725,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
723
725
  this._controls.enableDamping = this.enableDamping;
724
726
  this._controls.dampingFactor = this.dampingFactor;
725
727
  this._controls.enablePan = this.enablePan;
728
+ this._controls.panSpeed = viewZoomFactor;
726
729
  this._controls.enableRotate = this.enableRotate;
727
730
  this._controls.minAzimuthAngle = this.minAzimuthAngle;
728
731
  this._controls.maxAzimuthAngle = this.maxAzimuthAngle;
@@ -1,5 +1,5 @@
1
1
 
2
- import { Object3D } from "three"
2
+ import { Object3D, Vector3 } from "three"
3
3
 
4
4
  import { Mathf } from "../../engine/engine_math.js";
5
5
  import { serializeable } from "../../engine/engine_serialization_decorator.js";
@@ -7,7 +7,10 @@ import { Behaviour } from "../Component.js";
7
7
  import { SplineContainer } from "./Spline.js";
8
8
 
9
9
  /**
10
- * Moves an object along a spline. Use this with a SplineContainer component.
10
+ * Moves an object along a spline.
11
+ * Use this with a SplineContainer component.
12
+ *
13
+ * - Example http://samples.needle.tools/splines
11
14
  */
12
15
  export class SplineWalker extends Behaviour {
13
16
 
@@ -17,18 +20,35 @@ export class SplineWalker extends Behaviour {
17
20
  @serializeable(SplineContainer)
18
21
  spline: SplineContainer | null = null;
19
22
 
20
- /** The object to move along the spline. If object is undefined then the spline walker will use the gameObject the component has been added to
23
+ /**
24
+ * The object to move along the spline.
25
+ * If object is undefined then the spline walker will use it's own object (gameObject).
26
+ * If object is null the spline walker will not move any object.
21
27
  * @default undefined
22
28
  */
23
29
  @serializeable(Object3D)
24
30
  object?: Object3D | null = undefined;
25
31
 
26
- /** The object to look at while moving along the spline
32
+
33
+
34
+ /**
35
+ * If true the object will rotate to look in the direction of the spline while moving along it.
36
+ * @default true
37
+ */
38
+ @serializeable()
39
+ useLookAt = true;
40
+
41
+ /**
42
+ * The object to look at while moving along the spline.
43
+ * If null the object will look in the direction of the spline.
44
+ * This can be disabled by setting useLookAt to false.
27
45
  * @default null
28
46
  */
29
47
  @serializeable(Object3D)
30
48
  lookAt: Object3D | null = null;
31
-
49
+
50
+
51
+
32
52
  /**
33
53
  * When clamp is set to true, the position01 value will be clamped between 0 and 1 and the object will not loop the spline.
34
54
  * @default false
@@ -36,7 +56,10 @@ export class SplineWalker extends Behaviour {
36
56
  @serializeable()
37
57
  clamp: boolean = false;
38
58
 
39
- /** The current position on the spline. The value ranges from 0 (start of the spline curve) to 1 (end of the spline curve)
59
+ /**
60
+ * The current position on the spline. The value ranges from 0 (start of the spline curve) to 1 (end of the spline curve)
61
+ *
62
+ * When setting this value, the position will be updated in the next frame.
40
63
  * @default 0
41
64
  */
42
65
  // @type float
@@ -46,7 +69,7 @@ export class SplineWalker extends Behaviour {
46
69
  }
47
70
  set position01(v: number) {
48
71
  this._position01 = v;
49
- this.updateFromPosition();
72
+ this._needsUpdate = true;
50
73
  }
51
74
 
52
75
  /** Resets the position to 0 */
@@ -68,25 +91,60 @@ export class SplineWalker extends Behaviour {
68
91
  @serializeable()
69
92
  duration: number = 10;
70
93
 
94
+ /**
95
+ * The strength with which the object is pulled to the spline.
96
+ * This can be used to create a "rubber band" effect when the object is moved away from the spline by other forces.
97
+ * A value of 0 means no pull, a value of 1 means the object is always on the spline.
98
+ * @default 1
99
+ */
100
+ pullStrength: number = 1;
101
+
71
102
 
72
103
  // #region internal
73
104
 
74
105
  private _position01: number = 0;
106
+ private _needsUpdate = false;
75
107
 
76
108
  /** @internal */
77
109
  start() {
78
- if(this.object === undefined) this.object = this.gameObject;
110
+ if (this.object === undefined) this.object = this.gameObject;
79
111
  this.updateFromPosition();
80
112
  }
81
113
 
114
+ /** @internal */
115
+ onEnable(): void {
116
+ window.addEventListener("pointerdown", this.onUserInput, { passive: true });
117
+ window.addEventListener("wheel", this.onUserInput, { passive: true });
118
+ }
119
+ /** @internal */
120
+ onDisable(): void {
121
+ window.removeEventListener("pointerdown", this.onUserInput);
122
+ window.removeEventListener("wheel", this.onUserInput);
123
+ }
124
+ private onUserInput = () => {
125
+ if (this.object?.contains(this.context.mainCamera)) {
126
+ this._needsUpdate = false;
127
+ this._performedUpdates += 999;
128
+ }
129
+ }
130
+
131
+ /** @internal */
82
132
  update() {
83
133
  if (this.autoRun) {
134
+ this._needsUpdate = true;
84
135
  this._position01 += this.context.time.deltaTime / this.duration;
136
+ }
137
+
138
+ if (this._needsUpdate) {
139
+ this._needsUpdate = false;
85
140
  this.updateFromPosition();
86
141
  }
87
142
  }
88
143
 
89
-
144
+ /**
145
+ * Updates the position of the object based on the current position01 value.
146
+ * @internal
147
+ */
90
148
  private updateFromPosition() {
91
149
  if (!this.spline || !this.spline.curve) return;
92
150
  if (!this.object) return;
@@ -96,11 +154,38 @@ export class SplineWalker extends Behaviour {
96
154
 
97
155
  const t = this._position01 >= 1 ? 1 : this._position01 % 1;
98
156
  const pt = this.spline.getPointAt(t);
99
- this.object.worldPosition = pt;
100
- if (!this.lookAt) {
101
- const tan = this.spline.getTangentAt(t);
102
- this.object.lookAt(pt.add(tan));
157
+
158
+ if (this.pullStrength >= 1) {
159
+ this.object.worldPosition = pt;
160
+ }
161
+ else {
162
+ if (this._position01 !== this._lastPosition01) {
163
+ this._performedUpdates = 0;
164
+ }
165
+ this._requiredUpdates = Math.round(100 / this.pullStrength);
166
+ if (this._performedUpdates < this._requiredUpdates) {
167
+ const wp = this.object.worldPosition;
168
+ this._performedUpdates++;
169
+ const pull = Mathf.clamp01(this.pullStrength);
170
+ const newPosition = this.object.worldPosition = wp.lerp(pt, pull * (this.context.time.deltaTime / .3));
171
+ this._lastPositionVector.copy(newPosition);
172
+ this._needsUpdate = true;
173
+ }
103
174
  }
104
- else this.object.lookAt(this.lookAt.worldPosition);
175
+
176
+ if (this.useLookAt) {
177
+ if (!this.lookAt) {
178
+ const tan = this.spline.getTangentAt(t);
179
+ this.object.lookAt(pt.add(tan));
180
+ }
181
+ else this.object.lookAt(this.lookAt.worldPosition);
182
+ }
183
+
184
+ this._lastPosition01 = this._position01;
105
185
  }
186
+
187
+ private _lastPosition01 = 0;
188
+ private _requiredUpdates: number = 0;
189
+ private _performedUpdates: number = 0;
190
+ private _lastPositionVector = new Vector3();
106
191
  }
@@ -1,3 +1,4 @@
1
+ import { Vector2 } from "three";
1
2
  import { NEPointerEvent } from "../../engine/engine_input.js";
2
3
  import { onStart } from "../../engine/engine_lifecycle_api.js";
3
4
  import { addAttributeChangeCallback } from "../../engine/engine_utils.js";
@@ -45,12 +46,14 @@ export class ClickThrough extends Behaviour {
45
46
  this.context.input.addEventListener('pointermove', this.onPointerEvent, {
46
47
  queue: 100,
47
48
  });
49
+ window.addEventListener("touchstart", this.onTouchStart, { passive: true });
48
50
  window.addEventListener("touchend", this.onTouchEnd, { passive: true });
49
51
  this._previousPointerEvents = this.context.domElement.style.pointerEvents;
50
52
  }
51
53
  onDisable() {
52
54
  this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
53
55
  this.context.input.removeEventListener('pointermove', this.onPointerEvent);
56
+ window.removeEventListener("touchstart", this.onTouchStart);
54
57
  window.removeEventListener("touchend", this.onTouchEnd);
55
58
  this.context.domElement.style.pointerEvents = this._previousPointerEvents;
56
59
  }
@@ -69,9 +72,33 @@ export class ClickThrough extends Behaviour {
69
72
  }
70
73
  };
71
74
 
75
+
76
+
77
+ // #region Touch hack
78
+
79
+ private _touchDidHitAnything = false;
80
+
81
+ private onTouchStart = (_evt: TouchEvent) => {
82
+
83
+ const touch = _evt.touches[0];
84
+ if (!touch) return;
85
+
86
+ const ndx = touch.clientX / window.innerWidth * 2 - 1;
87
+ const ndy = -(touch.clientY / window.innerHeight) * 2 + 1;
88
+ // console.log(ndx, ndy);
89
+ const hits = this.context.physics.raycast({
90
+ screenPoint: new Vector2(ndx, ndy),
91
+ })
92
+ if (hits.length > 0) {
93
+ this._touchDidHitAnything = true;
94
+ }
95
+ }
96
+
72
97
  private onTouchEnd = (_evt: TouchEvent) => {
98
+ const _didHit = this._touchDidHitAnything;
99
+ this._touchDidHitAnything = false;
73
100
  setTimeout(() => {
74
- this.context.domElement.style.pointerEvents = 'all';
101
+ if (_didHit) this.context.domElement.style.pointerEvents = 'all';
75
102
  }, 100);
76
103
  }
77
104
  }
@@ -96,6 +96,7 @@ export class ScrollFollow extends Behaviour {
96
96
  @serializable()
97
97
  invert: boolean = false;
98
98
 
99
+
99
100
  /**
100
101
  * **Experimental - might change in future updates**
101
102
  * If set, the scroll position will be read from the specified element instead of the window.
@@ -106,7 +107,7 @@ export class ScrollFollow extends Behaviour {
106
107
  htmlSelector: string | null = null;
107
108
 
108
109
  @serializable()
109
- private mode: "window" = "window";
110
+ mode: "window" = "window";
110
111
 
111
112
  /**
112
113
  * Event fired when the scroll position changes
@@ -124,17 +125,19 @@ export class ScrollFollow extends Behaviour {
124
125
  private _current_value: number = 0;
125
126
  private _target_value: number = 0;
126
127
  private _appliedValue: number = -1;
128
+ private _needsUpdate = false;
129
+ private _firstUpdate = false;
127
130
 
131
+ awake() {
132
+ this._firstUpdate = true;
133
+ }
128
134
 
129
- private _scrollStart: number = 0;
130
- private _scrollEnd: number = 0;
131
- private _scrollValue: number = 0;
132
- private _scrollContainerHeight: number = 0;
133
135
 
134
136
  /** @internal */
135
137
  onEnable() {
136
138
  window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
137
139
  this._appliedValue = -1;
140
+ this._needsUpdate = true;
138
141
  }
139
142
 
140
143
  /** @internal */
@@ -148,7 +151,7 @@ export class ScrollFollow extends Behaviour {
148
151
  this.updateCurrentScrollValue();
149
152
 
150
153
  if (this._target_value >= 0) {
151
- if (this.damping > 0) { // apply damping
154
+ if (this.damping > 0 && !this._firstUpdate) { // apply damping
152
155
  this._current_value = Mathf.lerp(this._current_value, this._target_value, this.context.time.deltaTime / this.damping);
153
156
  if (Math.abs(this._current_value - this._target_value) < 0.001) {
154
157
  this._current_value = this._target_value;
@@ -159,9 +162,10 @@ export class ScrollFollow extends Behaviour {
159
162
  }
160
163
  }
161
164
 
162
- // if (this._current_value !== this._appliedValue)
165
+ if (this._needsUpdate || this._current_value !== this._appliedValue)
163
166
  {
164
167
  this._appliedValue = this._current_value;
168
+ this._needsUpdate = false;
165
169
 
166
170
  let defaultPrevented = false;
167
171
  if (this.changed.listenerCount > 0) {
@@ -182,9 +186,6 @@ export class ScrollFollow extends Behaviour {
182
186
 
183
187
  const value = this.invert ? 1 - this._current_value : this._current_value;
184
188
 
185
- // const height = this._rangeEndValue - this._rangeStartValue;
186
- // const pixelValue = this._rangeStartValue + value * height;
187
-
188
189
  // apply scroll to target(s)
189
190
  if (Array.isArray(this.target)) {
190
191
  this.target.forEach(t => t && this.applyScroll(t, value));
@@ -197,21 +198,18 @@ export class ScrollFollow extends Behaviour {
197
198
  console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%, targets [${Array.isArray(this.target) ? this.target.length : 1}]`);
198
199
  }
199
200
  }
201
+
202
+ this._firstUpdate = false;
200
203
  }
201
204
  }
202
205
 
203
206
  private _lastSelectorValue: string | null = null;
204
207
  private _lastSelectorElement: Element | null = null;
205
- /** Top y */
206
- private _rangeStartValue: number = 0;
207
- /** Bottom y */
208
- private _rangeEndValue: number = 0;
209
208
 
210
209
  private updateCurrentScrollValue = () => {
211
210
 
212
211
  switch (this.mode) {
213
212
  case "window":
214
-
215
213
  if (this.htmlSelector?.length) {
216
214
  if (this.htmlSelector !== this._lastSelectorValue) {
217
215
  this._lastSelectorElement = document.querySelector(this.htmlSelector);
@@ -219,26 +217,20 @@ export class ScrollFollow extends Behaviour {
219
217
  }
220
218
  if (this._lastSelectorElement) {
221
219
  const rect = this._lastSelectorElement.getBoundingClientRect();
222
-
223
- this._scrollStart = rect.top + window.scrollY;
224
- this._scrollEnd = rect.height - window.innerHeight;
225
- this._scrollValue = -rect.top;
226
220
  this._target_value = -rect.top / (rect.height - window.innerHeight);
227
- this._rangeStartValue = rect.top + window.scrollY;
228
- this._rangeEndValue = this._rangeStartValue + rect.height - window.innerHeight;
229
- this._scrollContainerHeight = rect.height;
230
221
  break;
231
222
  }
232
223
  }
233
224
  else {
234
- this._scrollStart = 0;
235
- this._scrollEnd = window.document.body.scrollHeight - window.innerHeight;
236
- this._scrollValue = window.scrollY;
237
- this._target_value = this._scrollValue / (this._scrollEnd || 1);
238
- this._rangeStartValue = 0;
239
- this._rangeEndValue = document.body.scrollHeight;
240
- this._scrollContainerHeight = window.innerHeight;
225
+ if (window.document.body.scrollHeight <= window.innerHeight) {
226
+ // If the page is not scrollable we can still increment the scroll value to allow triggering timelines etc.
227
+ }
228
+ else {
229
+ const diff = window.document.body.scrollHeight - window.innerHeight;
230
+ this._target_value = window.scrollY / (diff || 1);
231
+ }
241
232
  }
233
+
242
234
  break;
243
235
  }
244
236
 
@@ -272,11 +264,12 @@ export class ScrollFollow extends Behaviour {
272
264
  target.intensity = value;
273
265
  }
274
266
  else if (target instanceof Object3D) {
267
+ const t = target as any;
275
268
  // When objects are assigned they're expected to move vertically based on scroll
276
- if (target["needle:scrollbounds"] === undefined) {
277
- target["needle:scrollbounds"] = getBoundingBox(target) || null;
269
+ if (t["needle:scrollbounds"] === undefined) {
270
+ t["needle:scrollbounds"] = getBoundingBox(target) || null;
278
271
  }
279
- const bounds = target["needle:scrollbounds"] as Box3;
272
+ const bounds = t["needle:scrollbounds"] as Box3;
280
273
  if (bounds) {
281
274
  // TODO: remap position to use upper screen edge and lower edge instead of center
282
275
  target.position.y = -bounds.min.y - value * (bounds.max.y - bounds.min.y);
@@ -422,13 +415,18 @@ export class ScrollFollow extends Behaviour {
422
415
  time += diff * weight;
423
416
  }
424
417
  }
425
- if (this.damping <= 0) {
418
+ if (this.damping <= 0 || this._firstUpdate) {
426
419
  director.time = time;
427
420
  }
428
421
  else {
429
422
  director.time = Mathf.lerp(director.time, time, this.context.time.deltaTime / this.damping);
430
423
  }
431
424
 
425
+ const delta = Math.abs(director.time - time);
426
+ if (delta > .001) { // if the time is > 1/100th of a second off we need another update
427
+ this._needsUpdate = true;
428
+ }
429
+
432
430
  if (debug && this.context.time.frame % 30 === 0) {
433
431
  console.log(`[ScrollFollow ] Timeline ${director.name}: ${time.toFixed(3)}`, weightsArray.map(w => `[${w.name} ${(w.weight * 100).toFixed(0)}%]`).join(", "));
434
432
  }