@needle-tools/engine 4.9.3 → 4.10.0-beta

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 (110) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{gltf-progressive-DhE1A6hX.min.js → gltf-progressive-CoZbSfPR.min.js} +1 -1
  4. package/dist/{gltf-progressive-egsMzRdv.js → gltf-progressive-DUR9TuAH.js} +3 -3
  5. package/dist/{gltf-progressive-DWiyqrwB.umd.cjs → gltf-progressive-Iy7aSAPk.umd.cjs} +1 -1
  6. package/dist/{needle-engine.bundle-C7LSzO5L.umd.cjs → needle-engine.bundle-42AmEGfk.umd.cjs} +160 -137
  7. package/dist/needle-engine.bundle-C6zhyLF5.min.js +1639 -0
  8. package/dist/{needle-engine.bundle-BAsxNKpA.js → needle-engine.bundle-Dj6faVbC.js} +7665 -7380
  9. package/dist/needle-engine.js +447 -444
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/{postprocessing-BZOSD1ln.min.js → postprocessing-BHMVuZQ1.min.js} +1 -1
  13. package/dist/{postprocessing-Bb5StX0o.umd.cjs → postprocessing-BsnRNRRS.umd.cjs} +1 -1
  14. package/dist/{postprocessing-BzFF7i-7.js → postprocessing-DQ2pynXW.js} +2 -2
  15. package/dist/{three-BK56xWDs.umd.cjs → three-B-jwTHao.umd.cjs} +11 -11
  16. package/dist/{three-CsHK73Zc.js → three-CJSAehtG.js} +1 -0
  17. package/dist/{three-examples-Bph291U2.min.js → three-examples-BivkhnvN.min.js} +1 -1
  18. package/dist/{three-examples-C9WfZu-X.umd.cjs → three-examples-Deqc1bNw.umd.cjs} +1 -1
  19. package/dist/{three-examples-BvMpKSun.js → three-examples-Doq0rvFU.js} +1 -1
  20. package/dist/{three-mesh-ui-CN6aRT7i.js → three-mesh-ui-CktOi6oI.js} +1 -1
  21. package/dist/{three-mesh-ui-DnxkZWNA.umd.cjs → three-mesh-ui-CsHwj9cJ.umd.cjs} +1 -1
  22. package/dist/{three-mesh-ui-n_qS2BM-.min.js → three-mesh-ui-DhYXcXZe.min.js} +1 -1
  23. package/dist/{three-TNFQHSFa.min.js → three-qw28ZtTy.min.js} +10 -10
  24. package/dist/{vendor-BtJpSuCj.umd.cjs → vendor-D0Yvltn9.umd.cjs} +1 -1
  25. package/dist/{vendor-k9i6CeGi.js → vendor-DU8tJyl_.js} +1 -1
  26. package/dist/{vendor-XJ9xiwrv.min.js → vendor-JyrX4DVM.min.js} +1 -1
  27. package/lib/engine/api.d.ts +1 -0
  28. package/lib/engine/api.js +1 -0
  29. package/lib/engine/api.js.map +1 -1
  30. package/lib/engine/codegen/register_types.js +4 -0
  31. package/lib/engine/codegen/register_types.js.map +1 -1
  32. package/lib/engine/engine_animation.d.ts +21 -1
  33. package/lib/engine/engine_animation.js +32 -1
  34. package/lib/engine/engine_animation.js.map +1 -1
  35. package/lib/engine/engine_camera.fit.d.ts +68 -0
  36. package/lib/engine/engine_camera.fit.js +193 -0
  37. package/lib/engine/engine_camera.fit.js.map +1 -0
  38. package/lib/engine/engine_gizmos.d.ts +2 -2
  39. package/lib/engine/engine_gizmos.js +2 -2
  40. package/lib/engine/engine_physics.js +6 -3
  41. package/lib/engine/engine_physics.js.map +1 -1
  42. package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
  43. package/lib/engine/webcomponents/needle-engine.js +6 -0
  44. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  45. package/lib/engine/webcomponents/needle-engine.loading.js +59 -23
  46. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  47. package/lib/engine-components/AnimatorController.js +16 -0
  48. package/lib/engine-components/AnimatorController.js.map +1 -1
  49. package/lib/engine-components/CameraUtils.js +8 -9
  50. package/lib/engine-components/CameraUtils.js.map +1 -1
  51. package/lib/engine-components/OrbitControls.d.ts +4 -47
  52. package/lib/engine-components/OrbitControls.js +30 -178
  53. package/lib/engine-components/OrbitControls.js.map +1 -1
  54. package/lib/engine-components/Renderer.d.ts +2 -2
  55. package/lib/engine-components/Renderer.js +6 -4
  56. package/lib/engine-components/Renderer.js.map +1 -1
  57. package/lib/engine-components/api.d.ts +0 -1
  58. package/lib/engine-components/api.js.map +1 -1
  59. package/lib/engine-components/codegen/components.d.ts +2 -0
  60. package/lib/engine-components/codegen/components.js +2 -0
  61. package/lib/engine-components/codegen/components.js.map +1 -1
  62. package/lib/engine-components/timeline/PlayableDirector.d.ts +28 -6
  63. package/lib/engine-components/timeline/PlayableDirector.js +60 -26
  64. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  65. package/lib/engine-components/timeline/TimelineModels.d.ts +3 -0
  66. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  67. package/lib/engine-components/timeline/TimelineTracks.d.ts +7 -0
  68. package/lib/engine-components/timeline/TimelineTracks.js +19 -0
  69. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  70. package/lib/engine-components/web/Clickthrough.d.ts +3 -0
  71. package/lib/engine-components/web/Clickthrough.js +3 -0
  72. package/lib/engine-components/web/Clickthrough.js.map +1 -1
  73. package/lib/engine-components/web/CursorFollow.d.ts +3 -0
  74. package/lib/engine-components/web/CursorFollow.js +3 -0
  75. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  76. package/lib/engine-components/web/HoverAnimation.d.ts +44 -0
  77. package/lib/engine-components/web/HoverAnimation.js +105 -0
  78. package/lib/engine-components/web/HoverAnimation.js.map +1 -0
  79. package/lib/engine-components/web/ScrollFollow.d.ts +18 -4
  80. package/lib/engine-components/web/ScrollFollow.js +143 -25
  81. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  82. package/lib/engine-components/web/index.d.ts +1 -0
  83. package/lib/engine-components/web/index.js +1 -0
  84. package/lib/engine-components/web/index.js.map +1 -1
  85. package/package.json +1 -1
  86. package/plugins/vite/alias.js +5 -3
  87. package/plugins/vite/poster-client.js +22 -21
  88. package/src/engine/api.ts +2 -1
  89. package/src/engine/codegen/register_types.ts +4 -0
  90. package/src/engine/engine_animation.ts +69 -1
  91. package/src/engine/engine_camera.fit.ts +288 -0
  92. package/src/engine/engine_gizmos.ts +2 -2
  93. package/src/engine/engine_physics.ts +6 -3
  94. package/src/engine/webcomponents/needle-engine.loading.ts +63 -24
  95. package/src/engine/webcomponents/needle-engine.ts +6 -1
  96. package/src/engine-components/AnimatorController.ts +21 -2
  97. package/src/engine-components/CameraUtils.ts +8 -9
  98. package/src/engine-components/OrbitControls.ts +30 -239
  99. package/src/engine-components/Renderer.ts +6 -4
  100. package/src/engine-components/api.ts +0 -1
  101. package/src/engine-components/codegen/components.ts +2 -0
  102. package/src/engine-components/timeline/PlayableDirector.ts +79 -34
  103. package/src/engine-components/timeline/TimelineModels.ts +3 -0
  104. package/src/engine-components/timeline/TimelineTracks.ts +22 -0
  105. package/src/engine-components/web/Clickthrough.ts +3 -0
  106. package/src/engine-components/web/CursorFollow.ts +3 -0
  107. package/src/engine-components/web/HoverAnimation.ts +99 -0
  108. package/src/engine-components/web/ScrollFollow.ts +181 -24
  109. package/src/engine-components/web/index.ts +1 -0
  110. package/dist/needle-engine.bundle-ugr1bBtk.min.js +0 -1616
@@ -0,0 +1,99 @@
1
+ import { AnimationClip } from "three";
2
+
3
+ import { ScaleClipType } from "../../engine/engine_animation.js";
4
+ import { AnimationUtils } from "../../engine/engine_animation.js";
5
+ import { serializable } from "../../engine/engine_serialization_decorator.js";
6
+ import { registerType } from "../../engine/engine_typestore.js";
7
+ import { Animation } from "../Animation.js";
8
+ import { Behaviour } from "../Component.js";
9
+
10
+
11
+ /**
12
+ * @category Web
13
+ * @group Components
14
+ * @component
15
+ */
16
+ @registerType
17
+ export class HoverAnimation extends Behaviour {
18
+
19
+ /**
20
+ * Default hover animation type if no custom clip is provided.
21
+ * **Node**: This is only used if no custom hover animation clip is provided.
22
+ * @default "linear"
23
+ */
24
+ @serializable()
25
+ type: ScaleClipType = "linear";
26
+
27
+ /**
28
+ * Duration of the hover animation in seconds.
29
+ * **Node**: This is only used if no custom hover animation clip is provided.
30
+ * @default 0.1
31
+ */
32
+ @serializable()
33
+ duration: number = 0.1;
34
+
35
+ /**
36
+ * Scale factor to apply when hovering.
37
+ * **Node**: This is only used if no custom hover animation clip is provided.
38
+ * @default 1.1
39
+ */
40
+ @serializable()
41
+ scaleFactor: number = 1.1;
42
+
43
+
44
+ /**
45
+ * Animation clip to play when hovering. If null, a default scale-up animation is used.
46
+ */
47
+ @serializable(AnimationClip)
48
+ hovered: AnimationClip | null = null;
49
+
50
+ /**
51
+ * Animation clip to play when not hovering. If null, an empty clip is used.
52
+ */
53
+ @serializable(AnimationClip)
54
+ idle: AnimationClip | null = null;
55
+
56
+ private animation: Animation | null = null;
57
+
58
+ start() {
59
+ if (!this.idle) this.idle = AnimationUtils.emptyClip();
60
+
61
+ if (!this.hovered) {
62
+ this.hovered = AnimationUtils.createScaleClip({
63
+ type: "linear",
64
+ duration: this.duration || 0.1,
65
+ scale: this.gameObject.scale,
66
+ scaleFactor: this.scaleFactor || 1.1,
67
+ });
68
+ }
69
+
70
+ this.animation ??= this.gameObject.addComponent(Animation);
71
+ this.animation.playAutomatically = false;
72
+ this.playIdle();
73
+ }
74
+
75
+ onEnable() {
76
+ if (this.animation) this.animation.enabled = true;
77
+ this.playIdle();
78
+ }
79
+ onDisable() {
80
+ if (this.animation) this.animation.enabled = false;
81
+ this.playIdle();
82
+ }
83
+
84
+ onPointerEnter() {
85
+ this.playHover();
86
+ }
87
+
88
+ onPointerExit() {
89
+ this.playIdle();
90
+ }
91
+
92
+ private playIdle() {
93
+ if (this.idle) this.animation?.play(this.idle, { exclusive: true, fadeDuration: .1, loop: true });
94
+ }
95
+ private playHover() {
96
+ if (this.hovered) this.animation?.play(this.hovered, { exclusive: true, fadeDuration: .1, loop: false, clampWhenFinished: true });
97
+ }
98
+
99
+ }
@@ -1,8 +1,11 @@
1
1
  import { Box3, Object3D } from "three";
2
+ import { element } from "three/src/nodes/TSL.js";
3
+ import { Context } from "../../engine/engine_context.js";
2
4
 
3
5
  import { Mathf } from "../../engine/engine_math.js";
4
6
  import { serializable } from "../../engine/engine_serialization.js";
5
7
  import { getBoundingBox } from "../../engine/engine_three_utils.js";
8
+ import { getParam } from "../../engine/engine_utils.js";
6
9
  import { Animation } from "../Animation.js";
7
10
  import { Animator } from "../Animator.js";
8
11
  import { AudioSource } from "../AudioSource.js";
@@ -11,6 +14,9 @@ import { EventList } from "../EventList.js";
11
14
  import { Light } from "../Light.js";
12
15
  import { SplineWalker } from "../splines/SplineWalker.js";
13
16
  import { PlayableDirector } from "../timeline/PlayableDirector.js";
17
+ import { ScrollMarkerModel } from "../timeline/TimelineModels.js";
18
+
19
+ const debug = getParam("debugscroll");
14
20
 
15
21
  type ScrollFollowEvent = {
16
22
  /** Event type */
@@ -44,6 +50,10 @@ type ScrollFollowEvent = {
44
50
  * 2. Add a ScrollFollow component to the same GameObject or another GameObject in the scene.
45
51
  * 3. Assign the PlayableDirector component to the ScrollFollow's target property.
46
52
  * 4. The timeline will now scrub based on the scroll position of the page.
53
+ *
54
+ * @category Web
55
+ * @group Components
56
+ * @component
47
57
  */
48
58
  export class ScrollFollow extends Behaviour {
49
59
 
@@ -77,7 +87,8 @@ export class ScrollFollow extends Behaviour {
77
87
  @serializable()
78
88
  invert: boolean = false;
79
89
 
80
- /**
90
+ /**
91
+ * **Experimental - might change in future updates**
81
92
  * If set, the scroll position will be read from the specified element instead of the window.
82
93
  * Use a CSS selector to specify the element, e.g. `#my-scrollable-div` or `.scroll-container`.
83
94
  * @default null
@@ -98,17 +109,23 @@ export class ScrollFollow extends Behaviour {
98
109
  * Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
99
110
  */
100
111
  get currentValue() {
101
- return this.current_value;
112
+ return this._current_value;
102
113
  }
103
114
 
104
- private current_value: number = 0;
105
- private target_value: number = 0;
106
- private applied_value: number = -1;
115
+ private _current_value: number = 0;
116
+ private _target_value: number = 0;
117
+ private _appliedValue: number = -1;
118
+
119
+
120
+ private _scrollStart: number = 0;
121
+ private _scrollEnd: number = 0;
122
+ private _scrollValue: number = 0;
123
+ private _scrollContainerHeight: number = 0;
107
124
 
108
125
  /** @internal */
109
126
  onEnable() {
110
127
  window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
111
- this.applied_value = -1;
128
+ this._appliedValue = -1;
112
129
  }
113
130
 
114
131
  /** @internal */
@@ -121,23 +138,27 @@ export class ScrollFollow extends Behaviour {
121
138
 
122
139
  this.updateCurrentScrollValue();
123
140
 
124
- // apply damping if any
125
- if (this.damping > 0) {
126
- this.current_value = Mathf.lerp(this.current_value, this.target_value, this.context.time.deltaTime / this.damping);
127
- }
128
- else {
129
- this.current_value = this.target_value;
141
+ if (this._target_value >= 0) {
142
+ if (this.damping > 0) { // apply damping
143
+ this._current_value = Mathf.lerp(this._current_value, this._target_value, this.context.time.deltaTime / this.damping);
144
+ if (Math.abs(this._current_value - this._target_value) < 0.001) {
145
+ this._current_value = this._target_value;
146
+ }
147
+ }
148
+ else {
149
+ this._current_value = this._target_value;
150
+ }
130
151
  }
131
152
 
132
- if (this.current_value !== this.applied_value) {
133
- this.applied_value = this.current_value;
153
+ if (this._current_value !== this._appliedValue) {
154
+ this._appliedValue = this._current_value;
134
155
 
135
156
  let defaultPrevented = false;
136
157
  if (this.changed.listenerCount > 0) {
137
158
  // fire change event
138
159
  const event: ScrollFollowEvent = {
139
160
  type: "change",
140
- value: this.current_value,
161
+ value: this._current_value,
141
162
  component: this,
142
163
  preventDefault: () => { event.defaultPrevented = true; },
143
164
  defaultPrevented: false,
@@ -149,14 +170,21 @@ export class ScrollFollow extends Behaviour {
149
170
  // if not prevented apply scroll
150
171
  if (!defaultPrevented) {
151
172
 
152
- const value = this.invert ? 1 - this.current_value : this.current_value;
173
+ const value = this.invert ? 1 - this._current_value : this._current_value;
174
+
175
+ const height = this._rangeEndValue - this._rangeStartValue;
176
+ const pixelValue = this._rangeStartValue + value * height;
153
177
 
154
178
  // apply scroll to target(s)
155
179
  if (Array.isArray(this.target)) {
156
- this.target.forEach(t => t && ScrollFollow.applyScroll(t, value));
180
+ this.target.forEach(t => t && this.applyScroll(t, value));
157
181
  }
158
182
  else if (this.target) {
159
- ScrollFollow.applyScroll(this.target, value);
183
+ this.applyScroll(this.target, value);
184
+ }
185
+
186
+ if (debug && this.context.time.frame % 30 === 0) {
187
+ console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%`);
160
188
  }
161
189
  }
162
190
  }
@@ -164,11 +192,16 @@ export class ScrollFollow extends Behaviour {
164
192
 
165
193
  private _lastSelectorValue: string | null = null;
166
194
  private _lastSelectorElement: Element | null = null;
195
+ /** Top y */
196
+ private _rangeStartValue: number = 0;
197
+ /** Bottom y */
198
+ private _rangeEndValue: number = 0;
167
199
 
168
200
  private updateCurrentScrollValue = () => {
169
201
 
170
202
  switch (this.mode) {
171
203
  case "window":
204
+
172
205
  if (this.htmlSelector?.length) {
173
206
  if (this.htmlSelector !== this._lastSelectorValue) {
174
207
  this._lastSelectorElement = document.querySelector(this.htmlSelector);
@@ -176,27 +209,39 @@ export class ScrollFollow extends Behaviour {
176
209
  }
177
210
  if (this._lastSelectorElement) {
178
211
  const rect = this._lastSelectorElement.getBoundingClientRect();
179
- this.target_value = -rect.top / (rect.height - window.innerHeight);
180
- if (isNaN(this.target_value) || !isFinite(this.target_value)) this.target_value = 0;
212
+
213
+ this._scrollStart = rect.top + window.scrollY;
214
+ this._scrollEnd = rect.height - window.innerHeight;
215
+ this._scrollValue = -rect.top;
216
+ this._target_value = -rect.top / (rect.height - window.innerHeight);
217
+ this._rangeStartValue = rect.top + window.scrollY;
218
+ this._rangeEndValue = this._rangeStartValue + rect.height - window.innerHeight;
219
+ this._scrollContainerHeight = rect.height;
181
220
  break;
182
221
  }
183
222
  }
184
223
  else {
185
- this.target_value = window.scrollY / (document.body.scrollHeight - window.innerHeight);
224
+ this._scrollStart = 0;
225
+ this._scrollEnd = window.document.body.scrollHeight - window.innerHeight;
226
+ this._scrollValue = window.scrollY;
227
+ this._target_value = this._scrollValue / (this._scrollEnd || 1);
228
+ this._rangeStartValue = 0;
229
+ this._rangeEndValue = document.body.scrollHeight;
230
+ this._scrollContainerHeight = window.innerHeight;
186
231
  }
187
- if (isNaN(this.target_value) || !isFinite(this.target_value)) this.target_value = 0;
188
232
  break;
189
233
  }
190
234
 
235
+ if (isNaN(this._target_value) || !isFinite(this._target_value)) this._target_value = -1;
191
236
  }
192
237
 
193
238
 
194
- private static applyScroll(target: object, value: number) {
239
+ private applyScroll(target: object, value: number) {
195
240
 
196
241
  if (!target) return;
197
242
 
198
243
  if (target instanceof PlayableDirector) {
199
- target.time = value * target.duration;
244
+ this.handleTimelineTarget(target, value);
200
245
  if (!target.isPlaying) target.evaluate();
201
246
  }
202
247
  else if (target instanceof Animator) {
@@ -236,4 +281,116 @@ export class ScrollFollow extends Behaviour {
236
281
  }
237
282
  }
238
283
 
284
+
285
+
286
+ private handleTimelineTarget(director: PlayableDirector, value: number) {
287
+
288
+ const duration = director.duration;
289
+
290
+
291
+ let scrollRegionStart = Infinity;
292
+ let scrollRegionEnd = 0;
293
+ markersArray.length = 0;
294
+
295
+ for (const marker of director.foreachMarker<ScrollMarkerModel & { element?: HTMLElement | null, needsUpdate?: boolean }>("ScrollMarker")) {
296
+
297
+ // Get marker elements from DOM
298
+ if (marker.selector?.length && (marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (!marker.element?.parentNode))) {
299
+ marker.needsUpdate = false;
300
+ try {
301
+ marker.element = document.querySelector<HTMLElement>(marker.selector) || null;
302
+ if (debug) console.debug("ScrollMarker found on page", marker.element, marker.selector);
303
+ }
304
+ catch (error) {
305
+ marker.element = null;
306
+ console.error("ScrollMarker selector is not valid: " + marker.selector + "\n", error);
307
+ }
308
+ }
309
+
310
+ // skip markers without element (e.g. if the selector didn't return any element)
311
+ if (!marker.element) continue;
312
+
313
+ markersArray.push(marker);
314
+
315
+ const top = marker.element.offsetTop;
316
+ const height = marker.element.offsetHeight;
317
+ const bottom = top + height;
318
+ if (top < scrollRegionStart) {
319
+ scrollRegionStart = top;
320
+ }
321
+ if (bottom > scrollRegionEnd) {
322
+ scrollRegionEnd = bottom;
323
+ }
324
+ }
325
+
326
+
327
+
328
+ const currentTop = this._scrollValue;
329
+ const currentBottom = currentTop + this._scrollContainerHeight;
330
+
331
+ weightsArray.length = 0;
332
+ let sum = 0;
333
+
334
+ let markerCount = 0;
335
+ for (const marker of markersArray) {
336
+
337
+ if (!marker.element) continue;
338
+
339
+ const top = marker.element.offsetTop;
340
+ const height = marker.element.offsetHeight;
341
+ const bottom = top + height;
342
+ let overlap = 0;
343
+
344
+ // 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
345
+
346
+ if (bottom < currentTop) {
347
+ // marker is above scroll region
348
+ overlap = 0;
349
+ }
350
+ else if (top > currentBottom) {
351
+ // marker is below scroll region
352
+ overlap = 0;
353
+ }
354
+ else {
355
+ // calculate overlap in pixels
356
+ const overlapTop = Math.max(top, currentTop);
357
+ const overlapBottom = Math.min(bottom, currentBottom);
358
+ overlap = Math.max(0, overlapBottom - overlapTop);
359
+ // console.log(marker.element.className, overlap)
360
+ }
361
+
362
+ markerCount += 1;
363
+
364
+ if (overlap > 0) {
365
+ weightsArray.push({ time: marker.time, weight: overlap });
366
+ sum += overlap;
367
+ }
368
+ }
369
+
370
+ if (weightsArray.length <= 0 && markerCount <= 0) {
371
+ director.time = value * duration;
372
+ }
373
+ else if (weightsArray.length > 0) {
374
+ // normalize and calculate weighted time
375
+ let time = weightsArray[0].time;
376
+ for (const o of weightsArray) {
377
+ const weight = o.weight / Math.max(0.00001, sum);
378
+ // lerp time based on weight
379
+ const diff = Math.abs(o.time - time);
380
+ time += diff * weight;
381
+ }
382
+ director.time = time;
383
+ }
384
+ }
385
+
386
+ }
387
+
388
+ const weightsArray: OverlapInfo[] = [];
389
+ const markersArray: (ScrollMarkerModel & { element?: HTMLElement | null })[] = [];
390
+
391
+ type OverlapInfo = {
392
+ /** Marker time */
393
+ time: number,
394
+ /** Overlap in pixels */
395
+ weight: number,
239
396
  }
@@ -1,3 +1,4 @@
1
1
  export * from "./Clickthrough.js";
2
2
  export * from "./CursorFollow.js";
3
+ export * from "./HoverAnimation.js";
3
4
  export * from "./ScrollFollow.js";