@needle-tools/engine 4.9.3 → 4.10.0-beta.1

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 (133) 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-6so_os_w.umd.cjs} +179 -145
  7. package/dist/{needle-engine.bundle-BAsxNKpA.js → needle-engine.bundle-Dj2DYdMY.js} +7699 -7235
  8. package/dist/needle-engine.bundle-Djy6H4lx.min.js +1650 -0
  9. package/dist/needle-engine.js +460 -456
  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 +6 -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.d.ts +7 -1
  36. package/lib/engine/engine_camera.fit.d.ts +68 -0
  37. package/lib/engine/engine_camera.fit.js +166 -0
  38. package/lib/engine/engine_camera.fit.js.map +1 -0
  39. package/lib/engine/engine_camera.js +46 -6
  40. package/lib/engine/engine_camera.js.map +1 -1
  41. package/lib/engine/engine_context.d.ts +6 -0
  42. package/lib/engine/engine_context.js +48 -9
  43. package/lib/engine/engine_context.js.map +1 -1
  44. package/lib/engine/engine_gizmos.d.ts +2 -2
  45. package/lib/engine/engine_gizmos.js +2 -2
  46. package/lib/engine/engine_physics.js +6 -3
  47. package/lib/engine/engine_physics.js.map +1 -1
  48. package/lib/engine/webcomponents/logo-element.d.ts +1 -1
  49. package/lib/engine/webcomponents/logo-element.js +29 -5
  50. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  51. package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -3
  52. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  53. package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
  54. package/lib/engine/webcomponents/needle-engine.js +6 -0
  55. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  56. package/lib/engine/webcomponents/needle-engine.loading.d.ts +0 -1
  57. package/lib/engine/webcomponents/needle-engine.loading.js +62 -59
  58. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  59. package/lib/engine-components/AnimatorController.js +16 -0
  60. package/lib/engine-components/AnimatorController.js.map +1 -1
  61. package/lib/engine-components/CameraUtils.js +8 -9
  62. package/lib/engine-components/CameraUtils.js.map +1 -1
  63. package/lib/engine-components/OrbitControls.d.ts +7 -47
  64. package/lib/engine-components/OrbitControls.js +25 -149
  65. package/lib/engine-components/OrbitControls.js.map +1 -1
  66. package/lib/engine-components/Renderer.d.ts +2 -2
  67. package/lib/engine-components/Renderer.js +10 -5
  68. package/lib/engine-components/Renderer.js.map +1 -1
  69. package/lib/engine-components/api.d.ts +0 -1
  70. package/lib/engine-components/api.js.map +1 -1
  71. package/lib/engine-components/codegen/components.d.ts +3 -0
  72. package/lib/engine-components/codegen/components.js +3 -0
  73. package/lib/engine-components/codegen/components.js.map +1 -1
  74. package/lib/engine-components/timeline/PlayableDirector.d.ts +35 -6
  75. package/lib/engine-components/timeline/PlayableDirector.js +67 -26
  76. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  77. package/lib/engine-components/timeline/TimelineModels.d.ts +11 -0
  78. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  79. package/lib/engine-components/timeline/TimelineTracks.d.ts +7 -0
  80. package/lib/engine-components/timeline/TimelineTracks.js +23 -2
  81. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  82. package/lib/engine-components/utils/LookAt.js +5 -1
  83. package/lib/engine-components/utils/LookAt.js.map +1 -1
  84. package/lib/engine-components/web/Clickthrough.d.ts +3 -0
  85. package/lib/engine-components/web/Clickthrough.js +13 -2
  86. package/lib/engine-components/web/Clickthrough.js.map +1 -1
  87. package/lib/engine-components/web/CursorFollow.d.ts +3 -0
  88. package/lib/engine-components/web/CursorFollow.js +3 -0
  89. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  90. package/lib/engine-components/web/HoverAnimation.d.ts +44 -0
  91. package/lib/engine-components/web/HoverAnimation.js +105 -0
  92. package/lib/engine-components/web/HoverAnimation.js.map +1 -0
  93. package/lib/engine-components/web/ScrollFollow.d.ts +40 -4
  94. package/lib/engine-components/web/ScrollFollow.js +256 -27
  95. package/lib/engine-components/web/ScrollFollow.js.map +1 -1
  96. package/lib/engine-components/web/ViewBox.d.ts +16 -0
  97. package/lib/engine-components/web/ViewBox.js +183 -0
  98. package/lib/engine-components/web/ViewBox.js.map +1 -0
  99. package/lib/engine-components/web/index.d.ts +2 -0
  100. package/lib/engine-components/web/index.js +2 -0
  101. package/lib/engine-components/web/index.js.map +1 -1
  102. package/package.json +1 -1
  103. package/plugins/vite/alias.js +5 -3
  104. package/plugins/vite/poster-client.js +22 -21
  105. package/src/engine/api.ts +2 -1
  106. package/src/engine/codegen/register_types.ts +6 -0
  107. package/src/engine/engine_animation.ts +69 -1
  108. package/src/engine/engine_camera.fit.ts +258 -0
  109. package/src/engine/engine_camera.ts +62 -8
  110. package/src/engine/engine_context.ts +50 -10
  111. package/src/engine/engine_gizmos.ts +2 -2
  112. package/src/engine/engine_physics.ts +6 -3
  113. package/src/engine/webcomponents/logo-element.ts +29 -4
  114. package/src/engine/webcomponents/needle menu/needle-menu.ts +4 -3
  115. package/src/engine/webcomponents/needle-engine.loading.ts +95 -56
  116. package/src/engine/webcomponents/needle-engine.ts +6 -1
  117. package/src/engine-components/AnimatorController.ts +21 -2
  118. package/src/engine-components/CameraUtils.ts +8 -9
  119. package/src/engine-components/OrbitControls.ts +36 -206
  120. package/src/engine-components/Renderer.ts +10 -5
  121. package/src/engine-components/api.ts +0 -1
  122. package/src/engine-components/codegen/components.ts +3 -0
  123. package/src/engine-components/timeline/PlayableDirector.ts +88 -34
  124. package/src/engine-components/timeline/TimelineModels.ts +11 -0
  125. package/src/engine-components/timeline/TimelineTracks.ts +26 -2
  126. package/src/engine-components/utils/LookAt.ts +5 -1
  127. package/src/engine-components/web/Clickthrough.ts +14 -2
  128. package/src/engine-components/web/CursorFollow.ts +3 -0
  129. package/src/engine-components/web/HoverAnimation.ts +99 -0
  130. package/src/engine-components/web/ScrollFollow.ts +316 -25
  131. package/src/engine-components/web/ViewBox.ts +199 -0
  132. package/src/engine-components/web/index.ts +3 -1
  133. package/dist/needle-engine.bundle-ugr1bBtk.min.js +0 -1616
@@ -592,7 +592,7 @@ namespace NEMeshBVH {
592
592
  const timeSinceLastUpdate = now - skinnedMesh.staticGeometryLastUpdate!;
593
593
  const interval = skinnedMesh.autoUpdateMeshBvhInterval ?? 100;
594
594
  if (skinnedMeshBVHNeedsUpdate || timeSinceLastUpdate > interval) {
595
- if(debugPhysics) console.warn(`Physics: updating skinned mesh bvh for ${mesh.name} after ${timeSinceLastUpdate.toFixed(2)}ms`);
595
+ if (debugPhysics) console.warn(`Physics: updating skinned mesh bvh for ${mesh.name} after ${timeSinceLastUpdate.toFixed(2)}ms`);
596
596
  skinnedMesh.bvhNeedsUpdate = false;
597
597
  skinnedMesh.staticGeometryLastUpdate = now;
598
598
  skinnedMesh.staticGenerator?.generate(skinnedMesh.staticGeometry);
@@ -709,8 +709,11 @@ namespace NEMeshBVH {
709
709
  else {
710
710
  if (debugPhysics) console.warn("No bounds tree found for mesh", mesh.name, { workerTask: geom[workerTaskSymbol], hasAcceleratedRaycast: _acceleratedRaycast != null });
711
711
  if (options.allowSlowRaycastFallback === false) {
712
- if (debugPhysics) console.warn("Skipping raycast because no bounds tree is available and allowSlowRaycastFallback is false");
713
- return false;
712
+ const vertices = geom.getAttribute("position")?.array?.length ?? 0;
713
+ if (vertices > 2000) {
714
+ if (debugPhysics) console.warn("Skipping raycast because no bounds tree is available and allowSlowRaycastFallback is false");
715
+ return false;
716
+ }
714
717
  }
715
718
  }
716
719
  const prevFirstHitOnly = raycaster.firstHitOnly;
@@ -32,10 +32,22 @@ export class NeedleLogoElement extends HTMLElement {
32
32
  cursor: pointer;
33
33
  }
34
34
  img {
35
- width: 95px;
36
35
  height: 100%;
37
36
  align-self: end;
38
37
  margin-left: 0.6rem;
38
+ transition: transform 0.2s;
39
+ }
40
+ img.with-text {
41
+ width: 11.5ch;
42
+ &:hover {
43
+ transform: scale(1.02);
44
+ }
45
+ }
46
+ img.compact {
47
+ width: 1.7em;
48
+ &:hover {
49
+ transform: scale(1.1);
50
+ }
39
51
  }
40
52
  span {
41
53
  font-size: 1rem;
@@ -43,12 +55,14 @@ export class NeedleLogoElement extends HTMLElement {
43
55
  }
44
56
  </style>
45
57
  <div class="wrapper">
46
- <img class="logo" src=${needleLogoSVG} />
58
+ <img class="logo with-text" src=${needleLogoSVG} />
47
59
  </div>
48
60
  `;
49
61
  this._root.appendChild(template.content.cloneNode(true));
50
62
  this.wrapper = this._root.querySelector(".wrapper") as HTMLDivElement;
51
63
  this._root.appendChild(this.wrapper);
64
+ this.logoElement = this._root.querySelector("img.logo") as HTMLImageElement;
65
+
52
66
  // this.wrapper.classList.add("wrapper");
53
67
 
54
68
  // this.wrapper.appendChild(this.logoElement);
@@ -67,13 +81,24 @@ export class NeedleLogoElement extends HTMLElement {
67
81
 
68
82
  private readonly _root: ShadowRoot;
69
83
  private readonly wrapper: HTMLDivElement;
70
- private readonly logoElement: HTMLImageElement = document.createElement("img");
71
- private readonly textElement: HTMLSpanElement = document.createElement("span");
84
+ private readonly logoElement: HTMLImageElement;
72
85
 
73
86
  setLogoVisible(val: boolean) {
74
87
  this.logoElement.style.display = val ? "block" : "none";
75
88
  }
76
89
 
90
+ setType(type: "full" | "compact") {
91
+ if (type === "full") {
92
+ this.logoElement.src = needleLogoSVG;
93
+ this.logoElement.classList.remove("with-text");
94
+ this.logoElement.classList.remove("compact");
95
+ } else {
96
+ this.logoElement.src = needleLogoOnlySVG;
97
+ this.logoElement.classList.add("with-text");
98
+ this.logoElement.classList.add("compact");
99
+ }
100
+ }
101
+
77
102
  }
78
103
  if (!customElements.get(elementName))
79
104
  customElements.define(elementName, NeedleLogoElement);
@@ -459,7 +459,7 @@ export class NeedleMenuElement extends HTMLElement {
459
459
 
460
460
  .logo {
461
461
  cursor: pointer;
462
- padding-left: 0.6rem;
462
+ padding-left: 0.0rem;
463
463
  padding-bottom: .02rem;
464
464
  margin-right: 0.5rem;
465
465
  }
@@ -664,8 +664,8 @@ export class NeedleMenuElement extends HTMLElement {
664
664
  <slot name="end"></slot>
665
665
  </div>
666
666
  </div>
667
- <div style="user-select:none" class="logo">
668
- <span class="madewith notranslate">powered by</span>
667
+ <div style="user-select:none;" class="logo">
668
+ <span class="madewith notranslate" style="display:none;">powered by</span>
669
669
  </div>
670
670
  </div>
671
671
  <button class="compact-menu-button">
@@ -698,6 +698,7 @@ export class NeedleMenuElement extends HTMLElement {
698
698
  this.wrapper.classList.add("wrapper");
699
699
 
700
700
  const logo = NeedleLogoElement.create();
701
+ logo.setType("compact");
701
702
  logo.style.minHeight = "1rem";
702
703
  this.logoContainer.append(logo);
703
704
  this.logoContainer.addEventListener("click", () => {
@@ -158,8 +158,18 @@ export class EngineLoadingView implements ILoadingViewHandler {
158
158
  private onDoneLoading() {
159
159
  if (this._loadingElement) {
160
160
  if (debug) console.log("Hiding loading element");
161
- this._loadingElement.style.display = "none";
162
- this._loadingElement.remove();
161
+ // animate alpha to 0
162
+ const element = this._loadingElement;
163
+ element.animate([
164
+ { opacity: 1 },
165
+ { opacity: 0 }
166
+ ], {
167
+ duration: 200,
168
+ easing: 'ease-in-out',
169
+ }).addEventListener('finish', () => {
170
+ element.style.display = "none";
171
+ element.remove();
172
+ });
163
173
  }
164
174
  if (this._progressLoop)
165
175
  clearInterval(this._progressLoop);
@@ -190,6 +200,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
190
200
  loadingStyle = "light";
191
201
  }
192
202
 
203
+
193
204
  const hasLicense = hasProLicense();
194
205
  if (!existing) {
195
206
  this._loadingElement.style.position = "absolute";
@@ -197,6 +208,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
197
208
  this._loadingElement.style.height = "100%";
198
209
  this._loadingElement.style.left = "0";
199
210
  this._loadingElement.style.top = "0";
211
+ this._loadingElement.style.overflow = "hidden";
200
212
  const loadingBackgroundColor = this._element.getAttribute("loading-background");
201
213
  if (loadingBackgroundColor) {
202
214
  this._loadingElement.style.background = loadingBackgroundColor;
@@ -227,24 +239,48 @@ export class EngineLoadingView implements ILoadingViewHandler {
227
239
  }
228
240
 
229
241
  const content = document.createElement("div");
242
+ content.style.cssText = `
243
+ position: relative;
244
+ display: flex;
245
+ flex-direction: column;
246
+ align-items: center;
247
+ justify-content: center;
248
+ width: 100%;
249
+ height: 100%;
250
+ pointer-events: none;
251
+ `
230
252
  this._loadingElement.appendChild(content);
231
253
 
254
+ const poster = this._element.getAttribute("poster");
255
+ if (poster !== null && poster !== "0") {
256
+ const backgroundImage = document.createElement("div");
257
+ const backgroundBlur = poster?.length ? "0px" : "50px";
258
+ backgroundImage.style.cssText = `
259
+ position: absolute;
260
+ left: 0;
261
+ top: 0;
262
+ bottom: 0;
263
+ right: 0;
264
+ z-index: -1;
265
+ overflow: hidden;
266
+
267
+ margin: -${backgroundBlur};
268
+ background: url('${poster?.length ? poster : "/include/poster.webp"}') center center no-repeat;
269
+ background-size: cover;
270
+ filter: blur(${backgroundBlur});
271
+ `;
272
+ this._loadingElement.appendChild(backgroundImage);
273
+ }
274
+
232
275
  const logo = document.createElement("img");
233
- const logoSize = 120;
234
- logo.style.width = `${logoSize}px`;
235
- logo.style.height = `${logoSize}px`;
236
- logo.style.paddingTop = "20px";
237
- logo.style.paddingBottom = "10px";
238
- logo.style.margin = "0px";
276
+ const logoWidth = "80%";
277
+ const logoHeight = "15%";
278
+ const logoDelay = ".2s";
239
279
  logo.style.userSelect = "none";
240
280
  logo.style.objectFit = "contain";
241
- logo.style.transition = "transform 1.5s ease-out, opacity .3s ease-in-out";
242
281
  logo.style.transform = "translateY(30px)";
243
- logo.style.opacity = "0.05";
244
- setTimeout(() => {
245
- logo.style.opacity = "1";
246
- logo.style.transform = "translateY(0px)";
247
- }, 1);
282
+ logo.style.opacity = "0.0000001";
283
+ logo.style.transition = `transform 1s ease-out ${logoDelay}, opacity .3s ease-in-out ${logoDelay}`;
248
284
  logo.src = needleLogoOnlySVG;
249
285
  let isUsingCustomLogo = false;
250
286
  if (hasLicense && this._element) {
@@ -252,8 +288,15 @@ export class EngineLoadingView implements ILoadingViewHandler {
252
288
  if (customLogo) {
253
289
  isUsingCustomLogo = true;
254
290
  logo.src = customLogo;
291
+ setTimeout(() => {
292
+ logo.style.opacity = "1";
293
+ logo.style.transform = "translateY(0px)";
294
+ }, 1);
255
295
  }
256
296
  }
297
+
298
+ logo.style.width = `${logoWidth}`;
299
+ logo.style.height = `min(1000px, max(${logoHeight}, 50px))`;
257
300
  content.appendChild(logo);
258
301
 
259
302
  const details = document.createElement("div");
@@ -273,18 +316,14 @@ export class EngineLoadingView implements ILoadingViewHandler {
273
316
  const maxWidth = 100;
274
317
  loadingBarContainer.style.display = "flex";
275
318
  loadingBarContainer.style.width = maxWidth + "%";
276
- loadingBarContainer.style.height = "3px";
319
+ loadingBarContainer.style.height = "5px";
277
320
  loadingBarContainer.style.position = "absolute";
278
321
  loadingBarContainer.style.left = "0";
279
- loadingBarContainer.style.bottom = "0px";
322
+ loadingBarContainer.style.top = "0px";
280
323
  loadingBarContainer.style.opacity = "0";
281
- loadingBarContainer.style.transition = "opacity 1s ease-in-out 2s";
324
+ loadingBarContainer.style.transition = "opacity 1s ease-in-out";
325
+ loadingBarContainer.style.backgroundColor = "rgba(240,240,240,.5)"
282
326
  setTimeout(() => { loadingBarContainer.style.opacity = "1"; }, 1);
283
- if (loadingStyle === "light")
284
- loadingBarContainer.style.backgroundColor = "rgba(0,0,0,.2)"
285
- else
286
- loadingBarContainer.style.backgroundColor = "rgba(255,255,255,.2)"
287
- // loadingBarContainer.style.alignItems = "center";
288
327
 
289
328
  this._loadingElement.appendChild(loadingBarContainer);
290
329
 
@@ -294,9 +333,9 @@ export class EngineLoadingView implements ILoadingViewHandler {
294
333
  const getGradientPos = function (t: number): string {
295
334
  return Mathf.lerp(0, maxWidth, t) + "%";
296
335
  }
297
- this._loadingBar.style.background = "#66A22F";
298
- // `linear-gradient(90deg, #204f49 ${getGradientPos(0)}, #0BA398 ${getGradientPos(.3)}, #66A22F ${getGradientPos(.6)}, #D7DB0A ${getGradientPos(1)})`;
336
+ // `linear-gradient(90deg, #204f49 ${getGradientPos(0)}, #0BA398 ${getGradientPos(.3)}, #66A22F ${getGradientPos(.6)}, #D7DB0A ${getGradientPos(1)})`;
299
337
  this._loadingBar.style.backgroundAttachment = "fixed";
338
+ this._loadingBar.style.background = "#c4c4c4ab";
300
339
  this._loadingBar.style.width = "0%";
301
340
  this._loadingBar.style.height = "100%";
302
341
  if (hasLicense && this._element) {
@@ -335,40 +374,40 @@ export class EngineLoadingView implements ILoadingViewHandler {
335
374
  // }
336
375
  // }
337
376
 
338
- this.handleRuntimeLicense(this._loadingElement);
377
+ // this.handleRuntimeLicense(this._loadingElement);
339
378
 
340
379
  return this._loadingElement;
341
380
  }
342
381
 
343
- private async handleRuntimeLicense(loadingElement: HTMLElement) {
344
- // First check if we have a commercial license
345
- let commercialLicense = hasCommercialLicense();
346
- // if it's the case then we don't need to perform a runtime check
347
- if (commercialLicense) return;
348
-
349
- // If we don't have a commercial license, then we need to display our message
350
- if (debugLicense) console.log("Loading UI has commercial license?", commercialLicense);
351
- const nonCommercialContainer = document.createElement("div");
352
- nonCommercialContainer.style.paddingTop = ".6em";
353
- nonCommercialContainer.style.fontSize = ".8em";
354
- nonCommercialContainer.style.textTransform = "uppercase";
355
- nonCommercialContainer.innerText = "NEEDLE ENGINE NON COMMERCIAL VERSION\nCLICK HERE TO GET A LICENSE";
356
- nonCommercialContainer.style.cursor = "pointer";
357
- nonCommercialContainer.style.userSelect = "none";
358
- nonCommercialContainer.style.textAlign = "center";
359
- nonCommercialContainer.style.pointerEvents = "all";
360
- nonCommercialContainer.addEventListener("click", () => window.open("https://needle.tools/pricing", "_self"));
361
- nonCommercialContainer.style.opacity = "0";
362
- loadingElement.appendChild(nonCommercialContainer);
363
-
364
- // Use the runtime license check
365
- if (!isDevEnvironment() && runtimeLicenseCheckPromise) {
366
- if (debugLicense) console.log("Waiting for runtime license check");
367
- await runtimeLicenseCheckPromise;
368
- commercialLicense = hasCommercialLicense();
369
- }
370
- if (commercialLicense) return;
371
- nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
372
- nonCommercialContainer.style.opacity = "1";
373
- }
382
+ // private async handleRuntimeLicense(loadingElement: HTMLElement) {
383
+ // // First check if we have a commercial license
384
+ // let commercialLicense = hasCommercialLicense();
385
+ // // if it's the case then we don't need to perform a runtime check
386
+ // if (commercialLicense) return;
387
+
388
+ // // If we don't have a commercial license, then we need to display our message
389
+ // if (debugLicense) console.log("Loading UI has commercial license?", commercialLicense);
390
+ // const nonCommercialContainer = document.createElement("div");
391
+ // nonCommercialContainer.style.paddingTop = ".6em";
392
+ // nonCommercialContainer.style.fontSize = ".8em";
393
+ // nonCommercialContainer.style.textTransform = "uppercase";
394
+ // nonCommercialContainer.innerText = "NEEDLE ENGINE NON COMMERCIAL VERSION\nCLICK HERE TO GET A LICENSE";
395
+ // nonCommercialContainer.style.cursor = "pointer";
396
+ // nonCommercialContainer.style.userSelect = "none";
397
+ // nonCommercialContainer.style.textAlign = "center";
398
+ // nonCommercialContainer.style.pointerEvents = "all";
399
+ // nonCommercialContainer.addEventListener("click", () => window.open("https://needle.tools/pricing", "_self"));
400
+ // nonCommercialContainer.style.opacity = "0";
401
+ // loadingElement.appendChild(nonCommercialContainer);
402
+
403
+ // // Use the runtime license check
404
+ // if (!isDevEnvironment() && runtimeLicenseCheckPromise) {
405
+ // if (debugLicense) console.log("Waiting for runtime license check");
406
+ // await runtimeLicenseCheckPromise;
407
+ // commercialLicense = hasCommercialLicense();
408
+ // }
409
+ // if (commercialLicense) return;
410
+ // nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
411
+ // nonCommercialContainer.style.opacity = "1";
412
+ // }
374
413
  }
@@ -85,12 +85,17 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
85
85
  * <needle-engine></needle-engine>
86
86
  * @returns {boolean | null} if the attribute is not set it returns null
87
87
  */
88
- public get cameraControls(): boolean | null {
88
+ get cameraControls(): boolean | null {
89
89
  const attr = this.getAttribute("camera-controls") as NeedleEngineAttributes["camera-controls"] | ({} & string)
90
90
  if (attr == null) return null;
91
91
  if (attr === null || attr === "False" || attr === "false" || attr === "0" || attr === "none") return false;
92
92
  return true;
93
93
  }
94
+ set cameraControls(value: boolean | null) {
95
+ if (value === null) this.removeAttribute("camera-controls");
96
+ else this.setAttribute("camera-controls", value ? "true" : "false");
97
+ }
98
+
94
99
 
95
100
  /**
96
101
  * Get the current context for this web component instance. The context is created when the src attribute is set and the loading has finished.
@@ -276,7 +276,7 @@ export class AnimatorController {
276
276
  * @returns The found state or null if not found
277
277
  */
278
278
  FindState(name: string | number | undefined | null): State | null { return this.findState(name); }
279
-
279
+
280
280
  /**
281
281
  * Finds an animation state by name or hash.
282
282
  *
@@ -321,6 +321,25 @@ export class AnimatorController {
321
321
  return action;
322
322
  }
323
323
 
324
+ // addState(state: State, layerIndex: number = 0) {
325
+ // if (!this.model) throw new Error("AnimatorController model is missing");
326
+ // if (layerIndex < 0 || layerIndex >= this.model.layers.length) {
327
+ // throw new Error(`Invalid layer index: ${layerIndex}`);
328
+ // }
329
+ // const layer = this.model.layers[layerIndex];
330
+ // if (!layer.stateMachine) {
331
+ // layer.stateMachine = { states: [], defaultState: 0 };
332
+ // }
333
+ // if (!layer.stateMachine.states) {
334
+ // layer.stateMachine.states = [];
335
+ // }
336
+ // if (state.hash === undefined) {
337
+ // state.hash = stringToHash(state.name || "state" + layer.stateMachine.states.length);
338
+ // }
339
+
340
+ // }
341
+
342
+
324
343
  /**
325
344
  * The normalized time (0-1) to start playing the first state at.
326
345
  * This affects the initial state when the animator is first enabled.
@@ -331,7 +350,7 @@ export class AnimatorController {
331
350
  * The Animator component this controller is bound to.
332
351
  */
333
352
  animator?: Animator;
334
-
353
+
335
354
  /**
336
355
  * The data model describing the animation states and transitions.
337
356
  */
@@ -117,16 +117,15 @@ function createDefaultCameraControls(context: IContext, cam?: ICamera) {
117
117
  if (cameraObject) {
118
118
  const orbit = getOrAddComponent(cameraObject, OrbitControls) as OrbitControls;
119
119
  orbit.sourceId = cam?.sourceId ?? "unknown";
120
+ // /enable auto-rotate if the auto-rotate attribute is provided
120
121
  const autoRotate = context.domElement.getAttribute("auto-rotate");
121
- orbit.autoRotate = autoRotate !== undefined && autoRotate !== null && (autoRotate != "0" && autoRotate?.toLowerCase() != "false");
122
- orbit.autoRotateSpeed = 0.5;
123
- orbit.autoFit = true;
124
- if (orbit.autoRotate && autoRotate) {
125
- const autoRotateValue = parseFloat(autoRotate);
126
- if (!isNaN(autoRotateValue)) {
127
- orbit.autoRotateSpeed = autoRotateValue;
128
- }
129
- }
122
+ orbit.autoRotate = autoRotate != "0" && autoRotate?.toLowerCase() != "false";
123
+ const autoRotateSpeed = Number.parseFloat(autoRotate || ".5");
124
+ orbit.autoRotateSpeed = !isNaN(autoRotateSpeed) ? autoRotateSpeed : .5;
125
+ console.log("Auto-rotate", orbit.autoRotate, "speed:", orbit.autoRotateSpeed);
126
+ const autoFit = context.domElement.getAttribute("auto-fit");
127
+ orbit.autoFit = autoFit !== "0" && autoFit?.toLowerCase() != "false";
128
+ orbit.autoTarget = true;
130
129
  }
131
130
  else {
132
131
  console.warn("Missing camera object, can not add orbit controls")