@needle-tools/engine 4.10.0-next.2abafea → 4.10.0-next.55c0bf9
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.
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-p_i5rc9e.js → needle-engine.bundle-CUo74dPe.js} +7011 -7222
- package/dist/{needle-engine.bundle-7QhMyR9L.umd.cjs → needle-engine.bundle-Cf5H9Zy9.umd.cjs} +141 -152
- package/dist/{needle-engine.bundle-COzW_KEf.min.js → needle-engine.bundle-DlAVTipB.min.js} +159 -170
- package/dist/needle-engine.js +257 -259
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/codegen/register_types.js +0 -2
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.d.ts +1 -7
- package/lib/engine/engine_camera.fit.d.ts +1 -1
- package/lib/engine/engine_camera.fit.js +30 -3
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_camera.js +6 -46
- package/lib/engine/engine_camera.js.map +1 -1
- package/lib/engine/engine_context.d.ts +0 -6
- package/lib/engine/engine_context.js +9 -48
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_lightdata.d.ts +3 -3
- package/lib/engine/engine_lightdata.js +10 -10
- package/lib/engine/engine_lightdata.js.map +1 -1
- package/lib/engine/engine_physics_rapier.js +0 -4
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_scenelighting.d.ts +1 -1
- package/lib/engine/engine_scenelighting.js +5 -4
- package/lib/engine/engine_scenelighting.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -3
- package/lib/engine/engine_utils.js +0 -11
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js +1 -1
- package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
- package/lib/engine/webcomponents/logo-element.d.ts +1 -1
- package/lib/engine/webcomponents/logo-element.js +5 -29
- package/lib/engine/webcomponents/logo-element.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +3 -4
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +0 -4
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.d.ts +1 -0
- package/lib/engine/webcomponents/needle-engine.loading.js +36 -3
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +1 -4
- package/lib/engine-components/OrbitControls.js +6 -30
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.js +1 -6
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/Skybox.js +4 -22
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +0 -1
- package/lib/engine-components/codegen/components.js +0 -1
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +0 -7
- package/lib/engine-components/timeline/PlayableDirector.js +0 -7
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineModels.d.ts +1 -9
- package/lib/engine-components/timeline/TimelineTracks.js +2 -4
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/utils/LookAt.js +1 -5
- package/lib/engine-components/utils/LookAt.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.js +2 -10
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +0 -22
- package/lib/engine-components/web/ScrollFollow.js +38 -159
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/index.d.ts +0 -1
- package/lib/engine-components/web/index.js +0 -1
- package/lib/engine-components/web/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/codegen/register_types.ts +0 -2
- package/src/engine/engine_camera.fit.ts +32 -2
- package/src/engine/engine_camera.ts +8 -62
- package/src/engine/engine_context.ts +10 -50
- package/src/engine/engine_lightdata.ts +11 -11
- package/src/engine/engine_physics_rapier.ts +0 -3
- package/src/engine/engine_scenelighting.ts +6 -5
- package/src/engine/engine_utils.ts +0 -12
- package/src/engine/extensions/NEEDLE_lightmaps.ts +1 -1
- package/src/engine/webcomponents/logo-element.ts +4 -29
- package/src/engine/webcomponents/needle menu/needle-menu.ts +3 -4
- package/src/engine/webcomponents/needle-engine.loading.ts +32 -32
- package/src/engine/webcomponents/needle-engine.ts +0 -4
- package/src/engine-components/OrbitControls.ts +1 -40
- package/src/engine-components/Renderer.ts +1 -6
- package/src/engine-components/Skybox.ts +7 -26
- package/src/engine-components/codegen/components.ts +0 -1
- package/src/engine-components/timeline/PlayableDirector.ts +0 -9
- package/src/engine-components/timeline/TimelineModels.ts +1 -9
- package/src/engine-components/timeline/TimelineTracks.ts +2 -4
- package/src/engine-components/utils/LookAt.ts +1 -5
- package/src/engine-components/web/Clickthrough.ts +2 -11
- package/src/engine-components/web/ScrollFollow.ts +44 -190
- package/src/engine-components/web/index.ts +1 -2
- package/lib/engine-components/web/ViewBox.d.ts +0 -16
- package/lib/engine-components/web/ViewBox.js +0 -186
- package/lib/engine-components/web/ViewBox.js.map +0 -1
- package/src/engine-components/web/ViewBox.ts +0 -202
|
@@ -358,11 +358,8 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
358
358
|
//@ts-ignore
|
|
359
359
|
get sharedMaterials(): SharedMaterialArray {
|
|
360
360
|
|
|
361
|
-
// @ts-ignore (original materials will be set during deserialization)
|
|
362
|
-
if(this._originalMaterials === undefined) return null;
|
|
363
|
-
|
|
364
361
|
// @ts-ignore during deserialization code might access this property *before* the setter and then create an empty array
|
|
365
|
-
if (this.
|
|
362
|
+
if (!this.__didAwake) return null;
|
|
366
363
|
|
|
367
364
|
if (!this._sharedMaterials || !this._sharedMaterials.is(this)) {
|
|
368
365
|
if (!this._originalMaterials) this._originalMaterials = [];
|
|
@@ -728,8 +725,6 @@ export class Renderer extends Behaviour implements IRenderer {
|
|
|
728
725
|
// If the material has a envMap and is NOT using a reflection probe we set the envMap to the scene environment
|
|
729
726
|
if (mat && "envMap" in mat && "envMapIntensity" in mat && !ReflectionProbe.isUsingReflectionProbe(mat)) {
|
|
730
727
|
mat.envMap = this.context.scene.environment;
|
|
731
|
-
mat.envMapIntensity = this.context.scene.environmentIntensity;
|
|
732
|
-
mat.envMapRotation = this.context.scene.environmentRotation;
|
|
733
728
|
}
|
|
734
729
|
}
|
|
735
730
|
}
|
|
@@ -8,7 +8,7 @@ import { syncField } from "../engine/engine_networking_auto.js";
|
|
|
8
8
|
import { loadPMREM } from "../engine/engine_pmrem.js";
|
|
9
9
|
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
10
10
|
import { type IContext } from "../engine/engine_types.js";
|
|
11
|
-
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback
|
|
11
|
+
import { addAttributeChangeCallback, getParam, PromiseAllWithErrors, removeAttributeChangeCallback } from "../engine/engine_utils.js";
|
|
12
12
|
import { registerObservableAttribute } from "../engine/webcomponents/needle-engine.extras.js";
|
|
13
13
|
import { Camera, ClearFlags } from "./Camera.js";
|
|
14
14
|
import { Behaviour, GameObject } from "./Component.js";
|
|
@@ -27,34 +27,15 @@ function createRemoteSkyboxComponent(context: IContext, url: string, skybox: boo
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const remote = new RemoteSkybox();
|
|
30
|
-
remote.sourceId = toSourceId(url);
|
|
31
30
|
remote.allowDrop = false;
|
|
32
31
|
remote.allowNetworking = false;
|
|
33
32
|
remote.background = skybox;
|
|
34
33
|
remote.environment = environment;
|
|
35
34
|
GameObject.addComponent(context.scene, remote);
|
|
36
35
|
const urlChanged = newValue => {
|
|
37
|
-
if (
|
|
38
|
-
if (newValue)
|
|
39
|
-
|
|
40
|
-
console.warn("Invalid attribute value for " + attribute);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
remote.setSkybox(newValue);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
if (remote.sourceId) {
|
|
47
|
-
if (environment) {
|
|
48
|
-
if (!context.sceneLighting.internalEnableReflection(remote.sourceId)) {
|
|
49
|
-
context.scene.environment = null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (skybox) {
|
|
53
|
-
const skybox = context.lightmaps.tryGetSkybox(remote.sourceId);
|
|
54
|
-
context.scene.background = skybox;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
36
|
+
if (typeof newValue !== "string") return;
|
|
37
|
+
if (debug) console.log(attribute, "CHANGED TO", newValue)
|
|
38
|
+
remote.setSkybox(newValue);
|
|
58
39
|
};
|
|
59
40
|
addAttributeChangeCallback(context.domElement, attribute, urlChanged);
|
|
60
41
|
remote.addEventListener("destroy", () => {
|
|
@@ -69,7 +50,7 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, (args) => {
|
|
|
69
50
|
const context = args.context;
|
|
70
51
|
const backgroundImage = context.domElement.getAttribute("background-image");
|
|
71
52
|
const environmentImage = context.domElement.getAttribute("environment-image");
|
|
72
|
-
|
|
53
|
+
|
|
73
54
|
if (backgroundImage) {
|
|
74
55
|
if (debug) console.log("Creating RemoteSkybox to load background " + backgroundImage);
|
|
75
56
|
// if the user is loading a GLB without a camera then the CameraUtils (which creates the default camera)
|
|
@@ -265,8 +246,8 @@ export class RemoteSkybox extends Behaviour {
|
|
|
265
246
|
envMap.needsUpdate = true;
|
|
266
247
|
}
|
|
267
248
|
|
|
268
|
-
if
|
|
269
|
-
if
|
|
249
|
+
if(this.destroyed) return;
|
|
250
|
+
if(!this.context) {
|
|
270
251
|
console.warn("RemoteSkybox: Context is not available - can not apply skybox.");
|
|
271
252
|
return;
|
|
272
253
|
}
|
|
@@ -208,7 +208,6 @@ export { ClickThrough } from "../web/Clickthrough.js";
|
|
|
208
208
|
export { CursorFollow } from "../web/CursorFollow.js";
|
|
209
209
|
export { HoverAnimation } from "../web/HoverAnimation.js";
|
|
210
210
|
export { ScrollFollow } from "../web/ScrollFollow.js";
|
|
211
|
-
export { ViewBox } from "../web/ViewBox.js";
|
|
212
211
|
export { Avatar } from "../webxr/Avatar.js";
|
|
213
212
|
export { XRControllerFollow } from "../webxr/controllers/XRControllerFollow.js";
|
|
214
213
|
export { XRControllerModel } from "../webxr/controllers/XRControllerModel.js";
|
|
@@ -66,19 +66,10 @@ export class PlayableDirector extends Behaviour {
|
|
|
66
66
|
this.createTrackFunctions[type] = fn;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/**
|
|
70
|
-
* The timeline asset that is played by this director.
|
|
71
|
-
*/
|
|
72
69
|
playableAsset?: Models.TimelineAssetModel;
|
|
73
|
-
|
|
74
70
|
/** Set to true to start playing the timeline when the scene starts */
|
|
75
71
|
@serializable()
|
|
76
72
|
playOnAwake?: boolean;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Determines how the timeline behaves when it reaches the end of its duration.
|
|
80
|
-
* @default DirectorWrapMode.Loop
|
|
81
|
-
*/
|
|
82
73
|
@serializable()
|
|
83
74
|
extrapolationMode: DirectorWrapMode = DirectorWrapMode.Loop;
|
|
84
75
|
|
|
@@ -92,12 +92,4 @@ export declare class SignalMarkerModel extends MarkerModel {
|
|
|
92
92
|
asset: string;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
* Marker with a name, used for scroll-driven timelines. It is used together with elements in your HTML to define what time in the timeline should be active when the element is in the scroll view.
|
|
97
|
-
*
|
|
98
|
-
* @example Mark html elements to define scroll positions
|
|
99
|
-
* ```html
|
|
100
|
-
* <div data-timeline-marker>...</div>
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
export type ScrollMarkerModel = MarkerModel & { name: string };
|
|
95
|
+
export type ScrollMarkerModel = MarkerModel & { selector: string };
|
|
@@ -175,10 +175,8 @@ export class AnimationTrackHandler extends TrackHandler {
|
|
|
175
175
|
// which means we want to notify the object that it's not animated anymore
|
|
176
176
|
// and the animator can then take over
|
|
177
177
|
onStateChanged() {
|
|
178
|
-
if (this._animator)
|
|
179
|
-
|
|
180
|
-
setObjectAnimated(this._animator.gameObject, this, this.director.enabled && this.director.weight > 0);
|
|
181
|
-
}
|
|
178
|
+
if (this._animator)
|
|
179
|
+
setObjectAnimated(this._animator.gameObject, this, this.director.isPlaying);
|
|
182
180
|
}
|
|
183
181
|
|
|
184
182
|
createHooks(clipModel: Models.AnimationClipModel, clip) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Matrix4, Object3D, Quaternion, Vector3 } from "three";
|
|
2
2
|
|
|
3
|
-
import { isDevEnvironment } from "../../engine/debug/index.js";
|
|
4
3
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
5
4
|
import { lookAtObject } from "../../engine/engine_three_utils.js";
|
|
6
5
|
import { type UsdzBehaviour } from "../../engine-components/export/usdz/extensions/behavior/Behaviour.js";
|
|
@@ -43,10 +42,7 @@ export class LookAt extends Behaviour implements UsdzBehaviour {
|
|
|
43
42
|
/** @internal */
|
|
44
43
|
onBeforeRender(): void {
|
|
45
44
|
let target: Object3D | null | undefined = this.target;
|
|
46
|
-
if (!target)
|
|
47
|
-
target = this.context.mainCamera;
|
|
48
|
-
if (isDevEnvironment()) console.warn(`[LookAt] No target set on ${this.name}, using main camera as target.`);
|
|
49
|
-
}
|
|
45
|
+
if (!target) target = this.context.mainCamera;
|
|
50
46
|
if (!target) return;
|
|
51
47
|
|
|
52
48
|
let copyTargetRotation = this.copyTargetRotation;
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
2
|
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
3
|
-
import { addAttributeChangeCallback } from "../../engine/engine_utils.js";
|
|
4
3
|
import { Behaviour } from "../Component.js";
|
|
5
4
|
|
|
6
5
|
// Automatically add ClickThrough component if "clickthrough" attribute is present on the needle-engine element
|
|
7
6
|
onStart(ctx => {
|
|
8
7
|
const attribute = ctx.domElement.getAttribute("clickthrough");
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
addAttributeChangeCallback(ctx.domElement, "clickthrough", () => {
|
|
12
|
-
const attribute = ctx.domElement.getAttribute("clickthrough");
|
|
13
|
-
comp.enabled = clickthroughEnabled(attribute);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function clickthroughEnabled(val: string | null) {
|
|
18
|
-
return val !== null && val !== "0" && val !== "false";
|
|
8
|
+
if (attribute !== null && attribute !== "0" && attribute !== "false") {
|
|
9
|
+
ctx.scene.addComponent(ClickThrough);
|
|
19
10
|
}
|
|
20
11
|
});
|
|
21
12
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Box3, Object3D } from "three";
|
|
2
2
|
import { element } from "three/src/nodes/TSL.js";
|
|
3
|
-
|
|
4
3
|
import { Context } from "../../engine/engine_context.js";
|
|
4
|
+
|
|
5
5
|
import { Mathf } from "../../engine/engine_math.js";
|
|
6
6
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
7
|
-
import { getBoundingBox
|
|
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";
|
|
@@ -151,8 +150,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
151
150
|
}
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
{
|
|
153
|
+
if (this._current_value !== this._appliedValue) {
|
|
156
154
|
this._appliedValue = this._current_value;
|
|
157
155
|
|
|
158
156
|
let defaultPrevented = false;
|
|
@@ -244,8 +242,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
244
242
|
|
|
245
243
|
if (target instanceof PlayableDirector) {
|
|
246
244
|
this.handleTimelineTarget(target, value);
|
|
247
|
-
if (target.isPlaying) target.
|
|
248
|
-
target.evaluate();
|
|
245
|
+
if (!target.isPlaying) target.evaluate();
|
|
249
246
|
}
|
|
250
247
|
else if (target instanceof Animator) {
|
|
251
248
|
target.setFloat("scroll", value);
|
|
@@ -295,35 +292,18 @@ export class ScrollFollow extends Behaviour {
|
|
|
295
292
|
let scrollRegionEnd = 0;
|
|
296
293
|
markersArray.length = 0;
|
|
297
294
|
|
|
298
|
-
|
|
299
|
-
let markerIndex = 0;
|
|
300
|
-
|
|
301
|
-
// https://scroll-driven-animations.style/tools/view-timeline/ranges
|
|
302
|
-
for (const marker of director.foreachMarker<ScrollMarkerModel & { element?: HTMLElement | null, needsUpdate?: boolean, timeline?: ViewTimeline }>("ScrollMarker")) {
|
|
303
|
-
|
|
304
|
-
const index = markerIndex++;
|
|
295
|
+
for (const marker of director.foreachMarker<ScrollMarkerModel & { element?: HTMLElement | null, needsUpdate?: boolean }>("ScrollMarker")) {
|
|
305
296
|
|
|
306
297
|
// Get marker elements from DOM
|
|
307
|
-
if ((marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (!marker.element?.parentNode))) {
|
|
298
|
+
if (marker.selector?.length && (marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (!marker.element?.parentNode))) {
|
|
308
299
|
marker.needsUpdate = false;
|
|
309
300
|
try {
|
|
310
|
-
marker.element =
|
|
311
|
-
if (debug) console.debug("ScrollMarker found on page", marker.element, marker.
|
|
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
|
-
}
|
|
301
|
+
marker.element = document.querySelector<HTMLElement>(marker.selector) || null;
|
|
302
|
+
if (debug) console.debug("ScrollMarker found on page", marker.element, marker.selector);
|
|
323
303
|
}
|
|
324
304
|
catch (error) {
|
|
325
305
|
marker.element = null;
|
|
326
|
-
console.error("ScrollMarker selector is not valid: " + marker.
|
|
306
|
+
console.error("ScrollMarker selector is not valid: " + marker.selector + "\n", error);
|
|
327
307
|
}
|
|
328
308
|
}
|
|
329
309
|
|
|
@@ -350,74 +330,41 @@ export class ScrollFollow extends Behaviour {
|
|
|
350
330
|
|
|
351
331
|
weightsArray.length = 0;
|
|
352
332
|
let sum = 0;
|
|
353
|
-
const oneFrameTime = 1 / 60;
|
|
354
333
|
|
|
355
|
-
// 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
334
|
let markerCount = 0;
|
|
357
|
-
for (
|
|
358
|
-
|
|
335
|
+
for (const marker of markersArray) {
|
|
336
|
+
|
|
359
337
|
if (!marker.element) continue;
|
|
360
|
-
const nextMarker = markersArray[i + 1];
|
|
361
338
|
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
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
|
+
}
|
|
365
361
|
|
|
366
362
|
markerCount += 1;
|
|
367
363
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
}
|
|
364
|
+
if (overlap > 0) {
|
|
365
|
+
weightsArray.push({ time: marker.time, weight: overlap });
|
|
366
|
+
sum += overlap;
|
|
388
367
|
}
|
|
389
|
-
continue;
|
|
390
|
-
// if(this.context.time.frame % 10 === 0) console.log(marker.element?.className, timeline, calculateTimelinePositionNormalized(timeline!));
|
|
391
|
-
|
|
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;
|
|
396
|
-
|
|
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
|
|
398
|
-
|
|
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
|
-
// }
|
|
414
|
-
|
|
415
|
-
// // if(this.context.time.frame % 20 === 0) console.log(overlap)
|
|
416
|
-
|
|
417
|
-
// if (overlap > 0) {
|
|
418
|
-
// weightsArray.push({ time: marker.time, weight: overlap });
|
|
419
|
-
// sum += overlap;
|
|
420
|
-
// }
|
|
421
368
|
}
|
|
422
369
|
|
|
423
370
|
if (weightsArray.length <= 0 && markerCount <= 0) {
|
|
@@ -425,118 +372,25 @@ export class ScrollFollow extends Behaviour {
|
|
|
425
372
|
}
|
|
426
373
|
else if (weightsArray.length > 0) {
|
|
427
374
|
// normalize and calculate weighted time
|
|
428
|
-
let time = weightsArray[0].time;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const diff = Math.abs(entry.time - time);
|
|
435
|
-
time += diff * weight;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (this.context.time.frame % 20 === 0) console.log(time.toFixed(3), [...weightsArray])
|
|
439
|
-
if (this.damping <= 0) {
|
|
440
|
-
director.time = time;
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
director.time = Mathf.lerp(director.time, time, this.context.time.deltaTime / this.damping);
|
|
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;
|
|
444
381
|
}
|
|
382
|
+
director.time = time;
|
|
445
383
|
}
|
|
446
384
|
}
|
|
447
385
|
|
|
448
386
|
}
|
|
449
387
|
|
|
450
|
-
|
|
451
|
-
|
|
452
388
|
const weightsArray: OverlapInfo[] = [];
|
|
453
|
-
const markersArray: (ScrollMarkerModel & { element?: HTMLElement | null
|
|
389
|
+
const markersArray: (ScrollMarkerModel & { element?: HTMLElement | null })[] = [];
|
|
454
390
|
|
|
455
391
|
type OverlapInfo = {
|
|
456
392
|
/** Marker time */
|
|
457
393
|
time: number,
|
|
458
394
|
/** Overlap in pixels */
|
|
459
395
|
weight: number,
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// type SelectorCache = {
|
|
464
|
-
// /** The selector used to query the *elements */
|
|
465
|
-
// selector: string,
|
|
466
|
-
// elements: Element[] | null,
|
|
467
|
-
// usedElementCount: number,
|
|
468
|
-
// }
|
|
469
|
-
// const querySelectorResults: Array<SelectorCache> = [];
|
|
470
|
-
|
|
471
|
-
const needleScrollMarkerCacheKey = "data-timeline-marker";
|
|
472
|
-
const needleScrollMarkerIndexCache = new Map<number, Element | null>();
|
|
473
|
-
const needleScrollMarkerNameCache = new Map<string, Element | null>();
|
|
474
|
-
let needsScrollMarkerRefresh = true;
|
|
475
|
-
|
|
476
|
-
function tryGetElementsForSelector(index: number, name: string): Element | null {
|
|
477
|
-
|
|
478
|
-
if (!needsScrollMarkerRefresh) {
|
|
479
|
-
let element = name?.length ? needleScrollMarkerNameCache.get(name) : null;
|
|
480
|
-
if (element) return element;
|
|
481
|
-
element = needleScrollMarkerIndexCache.get(index) || null;
|
|
482
|
-
return element;
|
|
483
|
-
}
|
|
484
|
-
needsScrollMarkerRefresh = false;
|
|
485
|
-
needleScrollMarkerIndexCache.clear();
|
|
486
|
-
const markers = document.querySelectorAll(`[data-timeline-marker]`);
|
|
487
|
-
markers.forEach((m, i) => {
|
|
488
|
-
needleScrollMarkerIndexCache.set(i, m);
|
|
489
|
-
const name = m.getAttribute("data-timeline-marker");
|
|
490
|
-
if (name?.length) needleScrollMarkerNameCache.set(name, m);
|
|
491
|
-
});
|
|
492
|
-
const element = needleScrollMarkerIndexCache.get(index) || null;
|
|
493
|
-
return element;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
/* e.g.
|
|
497
|
-
<div class="section behind start" data-needle-scroll-marker>
|
|
498
|
-
*/
|
|
499
|
-
// console.log(index, element)
|
|
500
|
-
if (element) return element;
|
|
501
|
-
|
|
502
|
-
// for (const entry of querySelectorResults) {
|
|
503
|
-
// if (entry.selector === selector) {
|
|
504
|
-
// const index = entry.usedElementCount++;
|
|
505
|
-
// return entry.elements && index < entry.elements.length ? entry.elements[index] : null;
|
|
506
|
-
// }
|
|
507
|
-
// }
|
|
508
|
-
// const elements = document.querySelectorAll(selector);
|
|
509
|
-
// querySelectorResults.push({ selector, elements: Array.from(elements), usedElementCount: 1 });
|
|
510
|
-
// if (elements.length > 0) return elements[0];
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
// #region ScrollTimeline
|
|
516
|
-
|
|
517
|
-
function calculateTimelinePositionNormalized(timeline: ViewTimeline) {
|
|
518
|
-
if (!timeline.source) return 0;
|
|
519
|
-
const currentTime = timeline.currentTime;
|
|
520
|
-
const duration = timeline.duration;
|
|
521
|
-
let durationValue = 1;
|
|
522
|
-
if (duration.unit === "seconds") {
|
|
523
|
-
durationValue = duration.value;
|
|
524
|
-
}
|
|
525
|
-
else if (duration.unit === "percent") {
|
|
526
|
-
durationValue = duration.value;
|
|
527
|
-
}
|
|
528
|
-
const t01 = currentTime.unit === "seconds" ? (currentTime.value / durationValue) : (currentTime.value / 100);
|
|
529
|
-
return t01;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
declare global {
|
|
534
|
-
interface ViewTimeline {
|
|
535
|
-
axis: 'block' | 'inline';
|
|
536
|
-
currentTime: { unit: 'seconds' | 'percent', value: number };
|
|
537
|
-
duration: { unit: 'seconds' | 'percent', value: number };
|
|
538
|
-
source: Element | null;
|
|
539
|
-
startOffset: { unit: 'px', value: number };
|
|
540
|
-
endOffset: { unit: 'px', value: number };
|
|
541
|
-
}
|
|
542
396
|
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Behaviour } from "../Component.js";
|
|
2
|
-
export declare class ViewBox extends Behaviour {
|
|
3
|
-
static instances: ViewBox[];
|
|
4
|
-
referenceFieldOfView: number;
|
|
5
|
-
debug: boolean;
|
|
6
|
-
awake(): void;
|
|
7
|
-
onEnable(): void;
|
|
8
|
-
onDisable(): void;
|
|
9
|
-
onBeforeRender(): void;
|
|
10
|
-
/**
|
|
11
|
-
* Cover fit
|
|
12
|
-
*/
|
|
13
|
-
private fit;
|
|
14
|
-
private projectBoxIntoCamera;
|
|
15
|
-
private _projectedBoxElement;
|
|
16
|
-
}
|