@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.
- package/dist/{needle-engine.bundle-Ddybtee9.js → needle-engine.bundle-BeZ_xmJa.js} +6422 -6480
- package/dist/needle-engine.bundle-C3bpSNYu.min.js +1650 -0
- package/dist/{needle-engine.bundle-Ckr5KE6m.umd.cjs → needle-engine.bundle-D4dO0t5I.umd.cjs} +134 -134
- 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 -22
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +1 -2
- package/lib/engine-components/CameraUtils.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/lib/engine-components/web/ViewBox.d.ts +1 -0
- package/lib/engine-components/web/ViewBox.js +27 -67
- package/lib/engine-components/web/ViewBox.js.map +1 -1
- package/package.json +2 -2
- 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 +6 -33
- package/src/engine-components/CameraUtils.ts +1 -1
- package/src/engine-components/Skybox.ts +7 -26
- package/src/engine-components/web/ScrollFollow.ts +70 -82
- package/src/engine-components/web/ViewBox.ts +29 -71
- 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
|
|
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 {
|
|
@@ -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 {
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
//
|
|
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,
|
|
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
|
|
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,
|
|
193
|
-
|
|
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
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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 };
|