@needle-tools/engine 4.10.0-next.2abafea → 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.
- package/dist/{needle-engine.bundle-p_i5rc9e.js → needle-engine.bundle-BeZ_xmJa.js} +5346 -5375
- package/dist/{needle-engine.bundle-COzW_KEf.min.js → needle-engine.bundle-C3bpSNYu.min.js} +132 -132
- package/dist/{needle-engine.bundle-7QhMyR9L.umd.cjs → needle-engine.bundle-D4dO0t5I.umd.cjs} +128 -128
- package/dist/needle-engine.js +14 -15
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +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/webcomponents/needle-engine.js +0 -4
- package/lib/engine/webcomponents/needle-engine.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/web/ScrollFollow.js +70 -80
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/package.json +1 -1
- 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/webcomponents/needle-engine.ts +0 -4
- package/src/engine-components/Skybox.ts +7 -26
- package/src/engine-components/web/ScrollFollow.ts +70 -82
|
@@ -381,14 +381,6 @@ export function resolveUrl(source: SourceIdentifier | undefined, uri: string): s
|
|
|
381
381
|
}
|
|
382
382
|
return uri;
|
|
383
383
|
}
|
|
384
|
-
|
|
385
|
-
export function toSourceId(src: string | null): SourceIdentifier | undefined {
|
|
386
|
-
if (!src) return undefined;
|
|
387
|
-
src = src.trim();
|
|
388
|
-
src = src.split("?")[0]?.split("#")[0];
|
|
389
|
-
return src;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
384
|
// export function getPath(glbLocation: SourceIdentifier | undefined, path: string) {
|
|
393
385
|
// if (path && glbLocation && !path.includes("/")) {
|
|
394
386
|
// // get directory of glb and prepend it to the audio file path
|
|
@@ -801,7 +793,6 @@ const mutationObserverMap = new WeakMap<HTMLElement, HtmlElementExtra>();
|
|
|
801
793
|
/**
|
|
802
794
|
* Register a callback when an {@link HTMLElement} attribute changes.
|
|
803
795
|
* This is used, for example, by the Skybox component to watch for changes to the environment-* and skybox-* attributes.
|
|
804
|
-
* @returns A function that can be used to unregister the callback
|
|
805
796
|
*/
|
|
806
797
|
export function addAttributeChangeCallback(domElement: HTMLElement, name: string, callback: AttributeChangeCallback) {
|
|
807
798
|
if (!mutationObserverMap.get(domElement)) {
|
|
@@ -820,9 +811,6 @@ export function addAttributeChangeCallback(domElement: HTMLElement, name: string
|
|
|
820
811
|
listeners.set(name, []);
|
|
821
812
|
}
|
|
822
813
|
listeners.get(name)!.push(callback);
|
|
823
|
-
return () => {
|
|
824
|
-
removeAttributeChangeCallback(domElement, name, callback);
|
|
825
|
-
}
|
|
826
814
|
};
|
|
827
815
|
|
|
828
816
|
/**
|
|
@@ -570,10 +570,6 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
|
|
|
570
570
|
this._context.renderer.setClearColor(rgbaColor, rgbaColor.alpha);
|
|
571
571
|
this.context.scene.background = null;
|
|
572
572
|
}
|
|
573
|
-
// HACK: if we set background-color to a color and then back to null we want the background-image attribute to re-apply
|
|
574
|
-
else if(this.getAttribute("background-image")) {
|
|
575
|
-
this.setAttribute("background-image", this.getAttribute("background-image")!);
|
|
576
|
-
}
|
|
577
573
|
}
|
|
578
574
|
}
|
|
579
575
|
|
|
@@ -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
|
}
|
|
@@ -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
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
375
|
+
const top = marker.element.offsetTop;
|
|
376
|
+
const height = marker.element.offsetHeight;
|
|
377
|
+
const bottom = top + height;
|
|
378
|
+
let overlap = 0;
|
|
396
379
|
|
|
397
|
-
//
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
397
|
+
markerCount += 1;
|
|
416
398
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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 =
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
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 {
|