@needle-tools/engine 4.10.0-beta.2 → 4.10.0-beta.4

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 (55) hide show
  1. package/components.needle.json +1 -1
  2. package/dist/needle-engine.bundle-BFTyp4Pf.min.js +1652 -0
  3. package/dist/{needle-engine.bundle-BTgC7uAm.js → needle-engine.bundle-CsVLA8Ze.js} +6482 -6427
  4. package/dist/{needle-engine.bundle-OTBqjiCd.umd.cjs → needle-engine.bundle-D9nl4ea6.umd.cjs} +139 -137
  5. package/dist/needle-engine.js +106 -106
  6. package/dist/needle-engine.min.js +1 -1
  7. package/dist/needle-engine.umd.cjs +1 -1
  8. package/lib/engine/codegen/register_types.js +2 -2
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/engine_camera.js +5 -5
  11. package/lib/engine/engine_camera.js.map +1 -1
  12. package/lib/engine/engine_gizmos.d.ts +11 -10
  13. package/lib/engine/engine_gizmos.js +24 -10
  14. package/lib/engine/engine_gizmos.js.map +1 -1
  15. package/lib/engine/extensions/extension_utils.js +1 -1
  16. package/lib/engine/extensions/extension_utils.js.map +1 -1
  17. package/lib/engine/xr/NeedleXRController.d.ts +3 -3
  18. package/lib/engine/xr/NeedleXRController.js +28 -0
  19. package/lib/engine/xr/NeedleXRController.js.map +1 -1
  20. package/lib/engine-components/CameraUtils.js +2 -1
  21. package/lib/engine-components/CameraUtils.js.map +1 -1
  22. package/lib/engine-components/codegen/components.d.ts +1 -1
  23. package/lib/engine-components/codegen/components.js +1 -1
  24. package/lib/engine-components/codegen/components.js.map +1 -1
  25. package/lib/engine-components/debug/LogStats.d.ts +1 -0
  26. package/lib/engine-components/debug/LogStats.js +1 -0
  27. package/lib/engine-components/debug/LogStats.js.map +1 -1
  28. package/lib/engine-components/timeline/PlayableDirector.js +1 -1
  29. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  30. package/lib/engine-components/timeline/TimelineTracks.d.ts +2 -1
  31. package/lib/engine-components/timeline/TimelineTracks.js +24 -19
  32. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  33. package/lib/engine-components/web/ScrollFollow.js +36 -34
  34. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  35. package/lib/engine-components/web/ViewBox.d.ts +2 -3
  36. package/lib/engine-components/web/ViewBox.js +99 -50
  37. package/lib/engine-components/web/ViewBox.js.map +1 -1
  38. package/lib/engine-components-experimental/Presentation.d.ts +1 -0
  39. package/lib/engine-components-experimental/Presentation.js +1 -0
  40. package/lib/engine-components-experimental/Presentation.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/engine/codegen/register_types.ts +2 -2
  43. package/src/engine/engine_camera.ts +5 -7
  44. package/src/engine/engine_gizmos.ts +37 -23
  45. package/src/engine/extensions/extension_utils.ts +1 -1
  46. package/src/engine/xr/NeedleXRController.ts +36 -4
  47. package/src/engine-components/CameraUtils.ts +1 -1
  48. package/src/engine-components/codegen/components.ts +1 -1
  49. package/src/engine-components/debug/LogStats.ts +1 -0
  50. package/src/engine-components/timeline/PlayableDirector.ts +1 -1
  51. package/src/engine-components/timeline/TimelineTracks.ts +24 -19
  52. package/src/engine-components/web/ScrollFollow.ts +40 -36
  53. package/src/engine-components/web/ViewBox.ts +101 -47
  54. package/src/engine-components-experimental/Presentation.ts +1 -0
  55. package/dist/needle-engine.bundle-g2_JEHcF.min.js +0 -1650
@@ -1,7 +1,7 @@
1
1
  import { Box3, Object3D } from "three";
2
2
  import { element } from "three/src/nodes/TSL.js";
3
3
 
4
- import { Context } from "../../engine/engine_context.js";
4
+ import { isDevEnvironment } from "../../engine/debug/debug.js";
5
5
  import { Mathf } from "../../engine/engine_math.js";
6
6
  import { serializable } from "../../engine/engine_serialization.js";
7
7
  import { getBoundingBox, setVisibleInCustomShadowRendering } from "../../engine/engine_three_utils.js";
@@ -174,8 +174,8 @@ export class ScrollFollow extends Behaviour {
174
174
 
175
175
  const value = this.invert ? 1 - this._current_value : this._current_value;
176
176
 
177
- const height = this._rangeEndValue - this._rangeStartValue;
178
- const pixelValue = this._rangeStartValue + value * height;
177
+ // const height = this._rangeEndValue - this._rangeStartValue;
178
+ // const pixelValue = this._rangeStartValue + value * height;
179
179
 
180
180
  // apply scroll to target(s)
181
181
  if (Array.isArray(this.target)) {
@@ -186,7 +186,7 @@ export class ScrollFollow extends Behaviour {
186
186
  }
187
187
 
188
188
  if (debug && this.context.time.frame % 30 === 0) {
189
- console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%`);
189
+ console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%, targets [${Array.isArray(this.target) ? this.target.length : 1}]`);
190
190
  }
191
191
  }
192
192
  }
@@ -304,13 +304,15 @@ export class ScrollFollow extends Behaviour {
304
304
  const index = markerIndex++;
305
305
 
306
306
  // Get marker elements from DOM
307
- if ((marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (!marker.element?.parentNode))) {
307
+ if ((marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (marker.element && !marker.element?.parentNode))) {
308
308
  marker.needsUpdate = false;
309
309
  try {
310
+ // TODO: with this it's currently not possible to remap markers from HTML. For example if I have two sections and I want to now use the marker["center"] multiple times to stay at that marker for a longer time
310
311
  marker.element = tryGetElementsForSelector(index, marker.name) as HTMLElement | null;
311
- if (debug) console.debug("ScrollMarker found on page", marker.element, marker.name);
312
+ if (debug) console.debug(`ScrollMarker #${index} "${marker.name}" (${marker.time.toFixed(2)}) found`, marker.element);
312
313
  if (!marker.element) {
313
314
  marker.timeline = undefined;
315
+ if (debug || isDevEnvironment()) console.warn(`No HTML element found for ScrollMarker: ${marker.name} (index ${index})`);
314
316
  continue;
315
317
  }
316
318
  else {
@@ -370,19 +372,20 @@ export class ScrollFollow extends Behaviour {
370
372
  const time01 = calculateTimelinePositionNormalized(timeline);
371
373
  // remap 0-1 to 0 - 1 - 0 (full weight at center)
372
374
  const weight = 1 - Math.abs(time01 - 0.5) * 2;
375
+ const name = marker.name || `marker${i}`;
373
376
  if (time01 > 0 && time01 <= 1) {
374
377
  const lerpTime = marker.time + (nextTime - marker.time) * time01;
375
- weightsArray.push({ time: lerpTime, weight: weight });
378
+ weightsArray.push({ name, time: lerpTime, weight: weight });
376
379
  sum += weight;
377
380
  }
378
381
  // Before the first marker is reached
379
382
  else if (i === 0 && time01 <= 0) {
380
- weightsArray.push({ time: 0, weight: 1 });
383
+ weightsArray.push({ name, time: 0, weight: 1 });
381
384
  sum += 1;
382
385
  }
383
386
  // After the last marker is reached
384
387
  else if (i === markersArray.length - 1 && time01 >= 1) {
385
- weightsArray.push({ time: duration, weight: 1 });
388
+ weightsArray.push({ name, time: duration, weight: 1 });
386
389
  sum += 1;
387
390
  }
388
391
  }
@@ -435,13 +438,16 @@ export class ScrollFollow extends Behaviour {
435
438
  time += diff * weight;
436
439
  }
437
440
  }
438
- if (debug && this.context.time.frame % 20 === 0) console.log(time.toFixed(3), [...weightsArray])
439
441
  if (this.damping <= 0) {
440
442
  director.time = time;
441
443
  }
442
444
  else {
443
445
  director.time = Mathf.lerp(director.time, time, this.context.time.deltaTime / this.damping);
444
446
  }
447
+
448
+ if (debug && this.context.time.frame % 30 === 0) {
449
+ console.log(`[ScrollFollow ] Timeline ${director.name}: ${time.toFixed(3)}`, weightsArray.map(w => `[${w.name} ${(w.weight * 100).toFixed(0)}%]`).join(", "));
450
+ }
445
451
  }
446
452
  }
447
453
 
@@ -450,9 +456,13 @@ export class ScrollFollow extends Behaviour {
450
456
 
451
457
 
452
458
  const weightsArray: OverlapInfo[] = [];
453
- const markersArray: (ScrollMarkerModel & { element?: HTMLElement | null, timeline?: ViewTimeline })[] = [];
459
+ const markersArray: Array<ScrollMarkerModel & {
460
+ element?: HTMLElement | null,
461
+ timeline?: ViewTimeline,
462
+ }> = [];
454
463
 
455
464
  type OverlapInfo = {
465
+ name: string,
456
466
  /** Marker time */
457
467
  time: number,
458
468
  /** Overlap in pixels */
@@ -468,17 +478,29 @@ type OverlapInfo = {
468
478
  // }
469
479
  // const querySelectorResults: Array<SelectorCache> = [];
470
480
 
471
- const needleScrollMarkerCacheKey = "data-timeline-marker";
472
481
  const needleScrollMarkerIndexCache = new Map<number, Element | null>();
473
482
  const needleScrollMarkerNameCache = new Map<string, Element | null>();
474
483
  let needsScrollMarkerRefresh = true;
475
484
 
476
- function tryGetElementsForSelector(index: number, name: string): Element | null {
485
+ function tryGetElementsForSelector(index: number, name: string, _cycle: number = 0): Element | null {
477
486
 
478
487
  if (!needsScrollMarkerRefresh) {
479
- let element = name?.length ? needleScrollMarkerNameCache.get(name) : null;
480
- if (element) return element;
481
- element = needleScrollMarkerIndexCache.get(index) || null;
488
+ if (name?.length) {
489
+ const element = needleScrollMarkerNameCache.get(name) || null;
490
+ if (element) return element;
491
+ // const isNumber = !isNaN(Number(name));
492
+ // if (!isNumber) {
493
+ // }
494
+ }
495
+ const element = needleScrollMarkerIndexCache.get(index) || null;
496
+ const value = element?.getAttribute("data-timeline-marker");
497
+ // if (value?.length) {
498
+ // if (cycle === 0) {
499
+ // // if the HTML marker we found by index does define a different marker name we try to find the correct HTML element by name
500
+ // return tryGetElementsForSelector(index, value, 1);
501
+ // }
502
+ // if (isDevEnvironment()) console.warn(`ScrollMarker name mismatch: expected "${name}", got "${value}"`);
503
+ // }
482
504
  return element;
483
505
  }
484
506
  needsScrollMarkerRefresh = false;
@@ -489,26 +511,8 @@ function tryGetElementsForSelector(index: number, name: string): Element | null
489
511
  const name = m.getAttribute("data-timeline-marker");
490
512
  if (name?.length) needleScrollMarkerNameCache.set(name, m);
491
513
  });
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;
514
+ needsScrollMarkerRefresh = false;
515
+ return tryGetElementsForSelector(index, name);
512
516
  }
513
517
 
514
518
 
@@ -1,4 +1,4 @@
1
- import { Camera, PerspectiveCamera, Vector2, Vector3 } from "three";
1
+ import { Camera, PerspectiveCamera, Quaternion, Vector2, Vector3 } from "three";
2
2
 
3
3
  import { isDevEnvironment } from "../../engine/debug/debug.js";
4
4
  import { Gizmos } from "../../engine/engine_gizmos.js";
@@ -6,14 +6,17 @@ import { serializable } from "../../engine/engine_serialization_decorator.js";
6
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
+ import { RGBAColor } from "../../engine/js-extensions/RGBAColor.js";
9
10
  import { Behaviour } from "../Component.js";
10
11
 
12
+
11
13
  const debugParam = getParam("debugviewbox");
14
+ const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
12
15
 
13
16
  @registerType
14
- export class ViewBox extends Behaviour {
17
+ export class ResponsiveBox extends Behaviour {
15
18
 
16
- static instances: ViewBox[] = [];
19
+ static instances: ResponsiveBox[] = [];
17
20
 
18
21
  @serializable()
19
22
  referenceFieldOfView: number = 60;
@@ -21,30 +24,41 @@ export class ViewBox extends Behaviour {
21
24
  @serializable()
22
25
  debug: boolean = false;
23
26
 
24
- awake() {
25
- // this.referenceFieldOfView = (this.context.mainCamera as PerspectiveCamera)?.fov || 60;
26
- // setInterval(()=>{
27
- // this.enabled = !this.enabled
28
- // }, 1000)
29
- }
27
+ // awake() {
28
+ // // this.referenceFieldOfView = (this.context.mainCamera as PerspectiveCamera)?.fov || 60;
29
+ // setInterval(()=>{
30
+ // if(Math.random() > .5)
31
+ // this.enabled = !this.enabled
32
+ // }, 1000)
33
+ // }
34
+
30
35
  onEnable(): void {
31
36
  if (debugParam || this.debug || isDevEnvironment()) console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
32
- ViewBox.instances.push(this);
37
+ ResponsiveBox.instances.push(this);
38
+ // this.context.pre_render_callbacks.push(this.internalUpdate);
33
39
  }
34
40
 
35
41
  onDisable(): void {
36
- const idx = ViewBox.instances.indexOf(this);
37
- if (idx !== -1) ViewBox.instances.splice(idx, 1);
42
+ if (debugParam || this.debug) console.debug("[ViewBox] Disabled");
43
+ const idx = ResponsiveBox.instances.indexOf(this);
44
+ if (idx !== -1) ResponsiveBox.instances.splice(idx, 1);
45
+ this._projectedBoxElement?.remove();
46
+
47
+ // const cb_idx = this.context.pre_render_callbacks.indexOf(this.internalUpdate);
48
+ // if (cb_idx !== -1) this.context.pre_render_callbacks.splice(cb_idx, 1);
38
49
  }
39
50
 
40
- onBeforeRender() {
51
+ onBeforeRender(): void {
41
52
  if (this.context.isInXR) return;
42
- const isActive = ViewBox.instances[ViewBox.instances.length - 1] === this;
53
+ if(this.destroyed) return;
54
+ const isActive = ResponsiveBox.instances[ResponsiveBox.instances.length - 1] === this;
43
55
  if (!isActive) {
44
- if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, 0x333333);
56
+ if (debugParam || this.debug) {
57
+ Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, disabledGizmoColor);
58
+ }
45
59
  return;
46
60
  }
47
- if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, 0xdddd00);
61
+ if (debugParam || this.debug) Gizmos.DrawWireBox(this.gameObject.worldPosition, this.gameObject.worldScale, 0xdddd00, 0, true, this.gameObject.worldQuaternion);
48
62
 
49
63
  // calculate box size to fit the camera frustrum size at the current position (just scale)
50
64
  const camera = this.context.mainCamera;
@@ -80,44 +94,81 @@ export class ViewBox extends Behaviour {
80
94
  diffHeight = domHeight / rectHeight;
81
95
  }
82
96
 
83
- // const view = camera.view;
97
+
84
98
  const view = camera.view;
85
99
  const zoom = camera.zoom;
86
100
  const aspect = camera.aspect;
87
101
  const fov = camera.fov;
88
102
  camera.view = null;
89
103
  camera.zoom = 1;
90
- // camera.aspect = rectWidth / rectHeight;
91
104
  camera.fov = this.referenceFieldOfView;
92
105
  camera.updateProjectionMatrix();
93
106
 
107
+
94
108
  const boxPosition = this.gameObject.worldPosition;
95
109
  const boxScale = this.gameObject.worldScale;
96
110
 
111
+ const cameraPosition = camera.worldPosition;
112
+ const distance = cameraPosition.distanceTo(boxPosition);
113
+
114
+
115
+ // #region camera fixes
116
+ // If the camera is inside the box, move it out
117
+ const boxSizeMax = Math.max(boxScale.x, boxScale.y, boxScale.z);
118
+ const direction = getTempVector(cameraPosition).sub(boxPosition);
119
+ if (distance < boxSizeMax) {
120
+ // move camera out of bounds
121
+ if (this.debug || debugParam) console.warn("[ViewBox] Moving camera out of bounds", distance, "<", boxSizeMax);
122
+ const positionDirection = getTempVector(direction);
123
+ positionDirection.y *= .00000001; // stay on horizontal plane mostly
124
+ positionDirection.normalize();
125
+ const lengthToMove = (boxSizeMax - distance) * 10; // move a bit more than needed
126
+ const newPosition = cameraPosition.add(positionDirection.multiplyScalar(lengthToMove));
127
+ camera.worldPosition = newPosition.lerp(cameraPosition, 1 - this.context.time.deltaTime);
128
+ }
129
+
130
+ // Ensure the camera looks at the ViewBox
131
+ // TOOD: smooth lookat over multiple frames if we have multiple viewboxes
132
+ // const dot = direction.normalize().dot(camera.worldForward);
133
+ // if (dot < .9) {
134
+ // console.log(dot);
135
+ // const targetRotation = direction;
136
+ // const rotation = getTempQuaternion();
137
+ // rotation.setFromUnitVectors(camera.worldForward.multiplyScalar(-1), targetRotation);
138
+ // camera.worldQuaternion = rotation;
139
+ // camera.updateMatrixWorld();
140
+ // }
141
+ const boxPositionInCameraSpace = getTempVector(boxPosition);
142
+ camera.worldToLocal(boxPositionInCameraSpace);
143
+ camera.lookAt(boxPosition);
144
+ camera.updateMatrixWorld();
97
145
 
98
146
 
99
- // const fov = this.referenceFieldOfView
100
- const distance = camera.worldPosition.distanceTo(boxPosition);
147
+ // #region calculate fit
101
148
  const vFOV = this.referenceFieldOfView * Math.PI / 180; // convert vertical fov to radians
102
149
  const height = 2 * Math.tan(vFOV / 2) * distance; // visible height
103
150
  const width = height * camera.aspect; // visible width
104
151
 
105
- const projectedBox = this.projectBoxIntoCamera(boxPosition, boxScale, camera, height * .5);
152
+ const projectedBox = this.projectBoxIntoCamera(camera, 1);
153
+ // return
106
154
  const boxWidth = (projectedBox.maxX - projectedBox.minX);
107
155
  const boxHeight = (projectedBox.maxY - projectedBox.minY);
108
156
 
109
- // TODO: take the rect size different into account
110
157
  const scale = this.fit(
111
158
  boxWidth * camera.aspect,
112
159
  boxHeight,
113
160
  width / diffWidth,
114
161
  height / diffHeight
115
162
  );
163
+ // console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
164
+ // this.context.focusRectSettings.zoom = 1.39;
165
+ // if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
166
+ // return
116
167
  const vec = getTempVector(boxPosition);
117
168
  vec.project(camera);
118
169
  this.context.focusRectSettings.offsetX = vec.x;
119
170
  this.context.focusRectSettings.offsetY = vec.y;
120
- this.context.focusRectSettings.zoom = scale;
171
+ this.context.focusRectSettings.zoom = scale / (height * .5);
121
172
  // if we don't have a focus rect yet, set it to the dom element
122
173
  if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
123
174
 
@@ -149,19 +200,18 @@ export class ViewBox extends Behaviour {
149
200
 
150
201
 
151
202
 
152
- private projectBoxIntoCamera(position: Vector3, scale: Vector3, camera: Camera, diff: number) {
153
-
154
- const factor = .5 * diff;
203
+ private projectBoxIntoCamera(camera: Camera, _factor: number) {
204
+ const factor = .5 * _factor;
155
205
 
156
206
  const corners = [
157
- getTempVector(-scale.x * factor, -scale.y * factor, -scale.z * factor),
158
- getTempVector(scale.x * factor, -scale.y * factor, -scale.z * factor),
159
- getTempVector(-scale.x * factor, scale.y * factor, -scale.z * factor),
160
- getTempVector(scale.x * factor, scale.y * factor, -scale.z * factor),
161
- getTempVector(-scale.x * factor, -scale.y * factor, scale.z * factor),
162
- getTempVector(scale.x * factor, -scale.y * factor, scale.z * factor),
163
- getTempVector(-scale.x * factor, scale.y * factor, scale.z * factor),
164
- getTempVector(scale.x * factor, scale.y * factor, scale.z * factor),
207
+ getTempVector(-factor, -factor, -factor),
208
+ getTempVector(factor, -factor, -factor),
209
+ getTempVector(-factor, factor, -factor),
210
+ getTempVector(factor, factor, -factor),
211
+ getTempVector(-factor, -factor, factor),
212
+ getTempVector(factor, -factor, factor),
213
+ getTempVector(-factor, factor, factor),
214
+ getTempVector(factor, factor, factor),
165
215
  ];
166
216
  let minX = Number.POSITIVE_INFINITY;
167
217
  let maxX = Number.NEGATIVE_INFINITY;
@@ -169,7 +219,7 @@ export class ViewBox extends Behaviour {
169
219
  let maxY = Number.NEGATIVE_INFINITY;
170
220
  for (let i = 0; i < corners.length; i++) {
171
221
  const c = corners[i];
172
- c.add(position);
222
+ c.applyMatrix4(this.gameObject.matrixWorld);
173
223
  c.project(camera);
174
224
  if (c.x < minX) minX = c.x;
175
225
  if (c.x > maxX) maxX = c.x;
@@ -177,18 +227,22 @@ export class ViewBox extends Behaviour {
177
227
  if (c.y > maxY) maxY = c.y;
178
228
  }
179
229
 
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";
230
+ if (debugParam) {
231
+ if (!this._projectedBoxElement) {
232
+ this._projectedBoxElement = document.createElement("div");
233
+ }
234
+ if (this._projectedBoxElement.parentElement !== this.context.domElement)
235
+ this.context.domElement.appendChild(this._projectedBoxElement);
236
+ this._projectedBoxElement.style.position = "fixed";
237
+ // dotted but with larger gaps
238
+ this._projectedBoxElement.style.outline = "2px dashed rgba(255,0,0,.5)";
239
+ this._projectedBoxElement.style.left = ((minX * .5 + .5) * this.context.domWidth) + "px";
240
+ this._projectedBoxElement.style.top = ((-maxY * .5 + .5) * this.context.domHeight) + "px";
241
+ this._projectedBoxElement.style.width = ((maxX - minX) * .5 * this.context.domWidth) + "px";
242
+ this._projectedBoxElement.style.height = ((maxY - minY) * .5 * this.context.domHeight) + "px";
243
+ this._projectedBoxElement.style.pointerEvents = "none";
244
+ this._projectedBoxElement.style.zIndex = "1000";
245
+ }
192
246
 
193
247
 
194
248
  return { minX, maxX, minY, maxY };
@@ -1,6 +1,7 @@
1
1
  import type { KeyCode } from "../engine/engine_input.js";
2
2
  import { Behaviour } from "../engine-components/Component.js";
3
3
 
4
+ /** @internal */
4
5
  export class PresentationMode extends Behaviour {
5
6
 
6
7
  toggleKey: KeyCode = "KeyP";