@lovelace_lol/embody 0.0.10 → 0.0.11

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/README.md CHANGED
@@ -87,6 +87,11 @@ spent. Each native mesh raycast is indivisible; a large mesh can still cause a
87
87
  frame drop, and slicing does not reduce total raycast CPU time. Interactive
88
88
  annotation changes retain synchronous queries so a marker samples one pose.
89
89
  Replacement, clearing and disposal cancel stale loads before scene commits.
90
+ New 3D markers and separated endpoints invalidate the cached camera layout.
91
+ Visible markers receive the current zoom sizing and Rust viewport constraints
92
+ before paint; hidden markers receive that layout before reveal captures label
93
+ scales. Viewport clipping also follows the animated label size during reveal
94
+ overshoot. Markers added during a reveal stay hidden until its layout pass resumes.
90
95
 
91
96
  For first reveal, call `controller.prepareModelForRender(model, { signal })`
92
97
  from the existing `beforeReveal` callback (or directly before attaching the
package/dist/index.js CHANGED
@@ -1207,6 +1207,7 @@ var DPthree3DMarkers = class {
1207
1207
  // Calculated from model size - collapse expanded regions when zoomed out
1208
1208
  __publicField(this, "lastCameraDistance", -1);
1209
1209
  // Cache to avoid unnecessary checks
1210
+ __publicField(this, "markerLayoutDirty", false);
1210
1211
  __publicField(this, "visibilityAnimationActive", false);
1211
1212
  __publicField(this, "visibilityAnimationScheduler", new AnimationFrameTaskScheduler());
1212
1213
  __publicField(this, "visibilityAnimationStates", []);
@@ -1370,6 +1371,8 @@ var DPthree3DMarkers = class {
1370
1371
  return;
1371
1372
  }
1372
1373
  this.separateOverlappingMarkers(annotationCameraCore);
1374
+ this.markerLayoutDirty = true;
1375
+ this.update();
1373
1376
  console.log(`[3DMarkers] loadRegions complete. Created markers for:`, Array.from(this.markerMeshes.keys()));
1374
1377
  console.log(`[3DMarkers] lineEndpoints:`, Array.from(this.lineEndpoints.keys()));
1375
1378
  console.log(`[3DMarkers] resolvedStyles:`, Array.from(this.resolvedStyles.keys()));
@@ -1841,6 +1844,12 @@ var DPthree3DMarkers = class {
1841
1844
  this.markerTargetVisibility.set(region.name, !startHidden && !region.isFallback);
1842
1845
  this.markerAngleGateVisibility.delete(region.name);
1843
1846
  this.markerViewportVisibility.set(region.name, true);
1847
+ this.markerLayoutDirty = true;
1848
+ if (this.visibilityAnimationActive) {
1849
+ this.setMarkerObjectsVisible(region.name, false, false);
1850
+ } else {
1851
+ this.update();
1852
+ }
1844
1853
  }
1845
1854
  /**
1846
1855
  * Embody Rust owns endpoint layout; the Three adapter applies the returned positions
@@ -2456,7 +2465,7 @@ var DPthree3DMarkers = class {
2456
2465
  const dy = this.camera.position.y - this.modelCenter.y;
2457
2466
  const dz = this.camera.position.z - this.modelCenter.z;
2458
2467
  const cameraDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
2459
- const distanceChanged = this.lastCameraDistance < 0 || Math.abs(cameraDistance - this.lastCameraDistance) > this.lastCameraDistance * 0.02;
2468
+ const distanceChanged = this.markerLayoutDirty || this.lastCameraDistance < 0 || Math.abs(cameraDistance - this.lastCameraDistance) > this.lastCameraDistance * 0.02;
2460
2469
  if (distanceChanged) {
2461
2470
  const previousDistance = this.lastCameraDistance;
2462
2471
  this.lastCameraDistance = cameraDistance;
@@ -2467,22 +2476,27 @@ var DPthree3DMarkers = class {
2467
2476
  sphere.scale.setScalar(clampedScale);
2468
2477
  }
2469
2478
  const shouldBeZoomedIn = cameraDistance < this.zoomThreshold;
2470
- if (shouldBeZoomedIn !== this.isZoomedIn) {
2479
+ const zoomChanged = shouldBeZoomedIn !== this.isZoomedIn;
2480
+ if (this.markerLayoutDirty || zoomChanged) {
2471
2481
  this.isZoomedIn = shouldBeZoomedIn;
2472
- this.applyZoomScale(shouldBeZoomedIn ? ZOOMED_IN_LINE_SCALE : 1);
2482
+ this.applyZoomScale(
2483
+ shouldBeZoomedIn ? ZOOMED_IN_LINE_SCALE : 1,
2484
+ zoomChanged || shouldBeZoomedIn
2485
+ );
2473
2486
  }
2474
2487
  const crossedAutoCollapseThreshold = previousDistance >= 0 && previousDistance <= this.autoCollapseThreshold && cameraDistance > this.autoCollapseThreshold;
2475
2488
  if (crossedAutoCollapseThreshold) {
2476
2489
  this.collapseAllRegions();
2477
2490
  }
2478
2491
  }
2479
- const cameraMoved = !this.hasCameraAngleUpdateSnapshot || this.lastCameraAngleUpdatePosition.distanceToSquared(this.camera.position) > 1e-4 || 1 - Math.abs(this.lastCameraAngleUpdateQuaternion.dot(this.camera.quaternion)) > 1e-5;
2492
+ const cameraMoved = this.markerLayoutDirty || !this.hasCameraAngleUpdateSnapshot || this.lastCameraAngleUpdatePosition.distanceToSquared(this.camera.position) > 1e-4 || 1 - Math.abs(this.lastCameraAngleUpdateQuaternion.dot(this.camera.quaternion)) > 1e-5;
2480
2493
  if (!cameraMoved) {
2481
2494
  return;
2482
2495
  }
2483
2496
  this.lastCameraAngleUpdatePosition.copy(this.camera.position);
2484
2497
  this.lastCameraAngleUpdateQuaternion.copy(this.camera.quaternion);
2485
2498
  this.hasCameraAngleUpdateSnapshot = true;
2499
+ this.markerLayoutDirty = false;
2486
2500
  const cameraAngle = getModelLocalOrbitAngle(this.model, this.modelCenter, this.camera.position);
2487
2501
  for (const [name, sphere] of this.markerMeshes) {
2488
2502
  const markerAngle = sphere.userData.cameraAngle;
@@ -2520,14 +2534,16 @@ var DPthree3DMarkers = class {
2520
2534
  }
2521
2535
  /**
2522
2536
  * Apply zoom-based scaling to all markers, lines, and labels.
2523
- * Only called when crossing the zoom threshold (not every frame).
2537
+ * Runs on zoom threshold crossings and when marker geometry changes.
2524
2538
  */
2525
- applyZoomScale(scaleFactor) {
2539
+ applyZoomScale(scaleFactor, scaleSpheres = true) {
2526
2540
  const isZoomed = scaleFactor < 1;
2527
2541
  const sphereScaleFactor = isZoomed ? ZOOMED_IN_SPHERE_SCALE : 1;
2528
2542
  const labelScaleFactor = isZoomed ? ZOOMED_IN_LABEL_SCALE : 1;
2529
- for (const sphere of this.markerMeshes.values()) {
2530
- sphere.scale.setScalar(sphereScaleFactor);
2543
+ if (scaleSpheres) {
2544
+ for (const sphere of this.markerMeshes.values()) {
2545
+ sphere.scale.setScalar(sphereScaleFactor);
2546
+ }
2531
2547
  }
2532
2548
  for (const line of this.lineMeshes.values()) {
2533
2549
  const material = line.material;
@@ -2631,6 +2647,10 @@ var DPthree3DMarkers = class {
2631
2647
  object.visible = true;
2632
2648
  this.setObjectOpacity(object, opacity * itemOpacityFactor);
2633
2649
  }
2650
+ const name = state.label?.object.userData.annotation;
2651
+ if (typeof name === "string" && !this.updateMarkerLineLayout(name)) {
2652
+ this.setMarkerObjectsVisible(name, false, false);
2653
+ }
2634
2654
  }
2635
2655
  }
2636
2656
  restoreVisibilityAnimationStates(states) {
@@ -2816,6 +2836,8 @@ var DPthree3DMarkers = class {
2816
2836
  this.stopVisibilityAnimation(true);
2817
2837
  if (visible) {
2818
2838
  this.markerGroup.visible = true;
2839
+ this.markerLayoutDirty = true;
2840
+ this.update();
2819
2841
  }
2820
2842
  this.visibilityAnimationStates = this.captureVisibilityAnimationStates();
2821
2843
  if (this.visibilityAnimationStates.length === 0) {
@@ -2878,6 +2900,7 @@ var DPthree3DMarkers = class {
2878
2900
  this.markerAngleGateVisibility.clear();
2879
2901
  this.markerViewportVisibility.clear();
2880
2902
  this.soloedMarker = null;
2903
+ this.markerLayoutDirty = false;
2881
2904
  this.hasCameraAngleUpdateSnapshot = false;
2882
2905
  }
2883
2906
  // ============ SOLO MODE ============