forgecad 0.9.7 → 0.9.9

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 (47) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/{AdminPage-DX0mpSZT.js → AdminPage-CNEvQM7c.js} +1 -1
  3. package/dist/assets/{BlogPage-CI_P0_Pf.js → BlogPage-Cc41PP4d.js} +1 -1
  4. package/dist/assets/{DocsPage-DLhIIZyJ.js → DocsPage-9U1hGjrg.js} +2 -2
  5. package/dist/assets/{EditorApp-DfFT2Dn8.css → EditorApp-D11wL4Qn.css} +51 -0
  6. package/dist/assets/{EditorApp-BujZvuwX.js → EditorApp-DnddQvBt.js} +151 -9
  7. package/dist/assets/{EmbedViewer-0S0qXKog.js → EmbedViewer-B2lhWTcd.js} +2 -2
  8. package/dist/assets/{LandingPageProofDriven-O_yMtAri.js → LandingPageProofDriven-CFet-l3o.js} +1 -1
  9. package/dist/assets/{PricingPage-DGkX3Ahr.js → PricingPage-CPm8mQx3.js} +1 -1
  10. package/dist/assets/{SettingsPage-DBsqTB_y.js → SettingsPage-BarZonVZ.js} +1 -1
  11. package/dist/assets/__vite-browser-external-Dhvy_jtL.js +4 -0
  12. package/dist/assets/{app-BE2nD6Yz.js → app-BjSEB4sY.js} +1006 -526
  13. package/dist/assets/cli/{render-iP9qh475.js → render-CXVrHY8q.js} +647 -481
  14. package/dist/assets/constructionHistoryWorker-z9_LGiRd.js +42984 -0
  15. package/dist/assets/{evalWorker-Ds5U4xtN.js → evalWorker-CtO7GsJR.js} +42 -9
  16. package/dist/assets/{inspectWorker-Dll4eVyD.js → inspectWorker-BZ2CkQZr.js} +785 -111
  17. package/dist/assets/{manifold-DjYsd7A_.js → manifold-BRdhoQy5.js} +2 -2
  18. package/dist/assets/{manifold-sJ-axdXM.js → manifold-BVi4_OeB.js} +1 -1
  19. package/dist/assets/manifold-Cp_dCC7i.js +3018 -0
  20. package/dist/assets/{manifold-Bk26ViCr.js → manifold-DAzn2Fsa.js} +1 -1
  21. package/dist/assets/{renderSceneState-Bngp5MrQ.js → renderSceneState-CWO8rHlt.js} +1 -1
  22. package/dist/assets/{reportWorker-CU8RZ4O0.js → reportWorker-Bz9tGiHb.js} +42 -9
  23. package/dist/assets/{sectionPlaneMath-BdTjyVfs.js → scalar-sampling-budget-Bmewod18.js} +1339 -215
  24. package/dist/cli/render.html +1 -1
  25. package/dist/docs/index.html +1 -1
  26. package/dist/docs-raw/CLI.md +10 -10
  27. package/dist/docs-raw/coding-best-practices.md +1 -1
  28. package/dist/docs-raw/guides/inspection-bundles.md +77 -19
  29. package/dist/docs-raw/guides/skill-maintenance.md +1 -1
  30. package/dist/docs-raw/runbook.md +2 -2
  31. package/dist/docs-raw/skills/forgecad-make-a-model.md +11 -0
  32. package/dist/docs-raw/skills/forgecad-render-inspect.md +12 -6
  33. package/dist/docs-raw/skills/index.md +1 -1
  34. package/dist/index.html +1 -1
  35. package/dist/sitemap.xml +6 -6
  36. package/dist-cli/forgecad.js +596 -354
  37. package/dist-cli/forgecad.js.map +1 -1
  38. package/dist-skill/CONTEXT.md +77 -19
  39. package/dist-skill/docs/CLI.md +10 -10
  40. package/dist-skill/docs/guides/inspection-bundles.md +77 -19
  41. package/dist-skill/docs-dev/CLI.md +10 -10
  42. package/dist-skill/docs-dev/coding-best-practices.md +1 -1
  43. package/dist-skill/docs-dev/guides/inspection-bundles.md +77 -19
  44. package/dist-skill/docs-dev/guides/skill-maintenance.md +1 -1
  45. package/dist-skill/library/forgecad-make-a-model/SKILL.md +11 -0
  46. package/dist-skill/library/forgecad-render-inspect/SKILL.md +12 -6
  47. package/package.json +6 -3
@@ -806,11 +806,11 @@ function isFinitePositive$3(value) {
806
806
  function isFiniteNonNegative(value) {
807
807
  return Number.isFinite(value) && value >= 0;
808
808
  }
809
- function cloneVec3$5(vec2) {
809
+ function cloneVec3$6(vec2) {
810
810
  return [vec2[0], vec2[1], vec2[2]];
811
811
  }
812
812
  function cloneFaceAxis(vec2) {
813
- return vec2 ? cloneVec3$5(vec2) : void 0;
813
+ return vec2 ? cloneVec3$6(vec2) : void 0;
814
814
  }
815
815
  function cloneSheetMetalModel(model) {
816
816
  if (!model) return null;
@@ -1120,8 +1120,8 @@ function lowerSheetMetalBasePlan(model, output) {
1120
1120
  function descriptor(name, center, normal, planar, uAxis, vAxis, semantic = "face", memberNames = [name], coplanar = planar) {
1121
1121
  return {
1122
1122
  name,
1123
- center: cloneVec3$5(center),
1124
- normal: cloneVec3$5(normal),
1123
+ center: cloneVec3$6(center),
1124
+ normal: cloneVec3$6(normal),
1125
1125
  planar,
1126
1126
  uAxis: cloneFaceAxis(uAxis),
1127
1127
  vAxis: cloneFaceAxis(vAxis),
@@ -1374,10 +1374,10 @@ function describeSheetMetalPlanarRegionFrames(model, output) {
1374
1374
  const size = sheetMetalPlanarRegionSize(derived, face.name);
1375
1375
  return {
1376
1376
  name: face.name,
1377
- center: cloneVec3$5(face.center),
1378
- normal: cloneVec3$5(face.normal),
1379
- uAxis: cloneVec3$5(face.uAxis),
1380
- vAxis: cloneVec3$5(face.vAxis),
1377
+ center: cloneVec3$6(face.center),
1378
+ normal: cloneVec3$6(face.normal),
1379
+ uAxis: cloneVec3$6(face.uAxis),
1380
+ vAxis: cloneVec3$6(face.vAxis),
1381
1381
  width: size.width,
1382
1382
  height: size.height,
1383
1383
  thickness: derived.thickness
@@ -8367,7 +8367,7 @@ function sub$7(a2, b) {
8367
8367
  function cross$8(a2, b) {
8368
8368
  return [a2[1] * b[2] - a2[2] * b[1], a2[2] * b[0] - a2[0] * b[2], a2[0] * b[1] - a2[1] * b[0]];
8369
8369
  }
8370
- function makeEdge(name, start, end, faceName, curve) {
8370
+ function makeEdge$1(name, start, end, faceName, curve) {
8371
8371
  return {
8372
8372
  name,
8373
8373
  start,
@@ -8411,10 +8411,10 @@ function buildSurfaceSheetTopology(boundaries, options = {}) {
8411
8411
  surface: options.surface
8412
8412
  });
8413
8413
  const edges = /* @__PURE__ */ new Map();
8414
- edges.set("u0", makeEdge("u0", u0Start, u0End, faceName, (_a3 = options.edgeCurves) == null ? void 0 : _a3.u0));
8415
- edges.set("u1", makeEdge("u1", u1Start, u1End, faceName, (_b3 = options.edgeCurves) == null ? void 0 : _b3.u1));
8416
- edges.set("v0", makeEdge("v0", v0Start, v0End, faceName, (_c2 = options.edgeCurves) == null ? void 0 : _c2.v0));
8417
- edges.set("v1", makeEdge("v1", v1Start, v1End, faceName, (_d2 = options.edgeCurves) == null ? void 0 : _d2.v1));
8414
+ edges.set("u0", makeEdge$1("u0", u0Start, u0End, faceName, (_a3 = options.edgeCurves) == null ? void 0 : _a3.u0));
8415
+ edges.set("u1", makeEdge$1("u1", u1Start, u1End, faceName, (_b3 = options.edgeCurves) == null ? void 0 : _b3.u1));
8416
+ edges.set("v0", makeEdge$1("v0", v0Start, v0End, faceName, (_c2 = options.edgeCurves) == null ? void 0 : _c2.v0));
8417
+ edges.set("v1", makeEdge$1("v1", v1Start, v1End, faceName, (_d2 = options.edgeCurves) == null ? void 0 : _d2.v1));
8418
8418
  return { faces, edges };
8419
8419
  }
8420
8420
  function attachSurfaceSheetTopology(shape, boundaries, options = {}) {
@@ -8432,7 +8432,7 @@ function attachSurfaceSheetTopology(shape, boundaries, options = {}) {
8432
8432
  });
8433
8433
  return shape;
8434
8434
  }
8435
- function cloneVec3$4(value) {
8435
+ function cloneVec3$5(value) {
8436
8436
  return [value[0], value[1], value[2]];
8437
8437
  }
8438
8438
  function cloneNurbsFaceTrimLoop(loop) {
@@ -8454,38 +8454,38 @@ function cloneFaceSurface(surface) {
8454
8454
  if (!surface) return void 0;
8455
8455
  switch (surface.kind) {
8456
8456
  case "plane":
8457
- return { kind: "plane", normal: cloneVec3$4(surface.normal) };
8457
+ return { kind: "plane", normal: cloneVec3$5(surface.normal) };
8458
8458
  case "cylinder":
8459
8459
  return {
8460
8460
  kind: "cylinder",
8461
- origin: cloneVec3$4(surface.origin),
8462
- axis: cloneVec3$4(surface.axis),
8461
+ origin: cloneVec3$5(surface.origin),
8462
+ axis: cloneVec3$5(surface.axis),
8463
8463
  radius: surface.radius,
8464
8464
  height: surface.height
8465
8465
  };
8466
8466
  case "cone":
8467
8467
  return {
8468
8468
  kind: "cone",
8469
- origin: cloneVec3$4(surface.origin),
8470
- axis: cloneVec3$4(surface.axis),
8469
+ origin: cloneVec3$5(surface.origin),
8470
+ axis: cloneVec3$5(surface.axis),
8471
8471
  radiusBottom: surface.radiusBottom,
8472
8472
  radiusTop: surface.radiusTop,
8473
8473
  height: surface.height
8474
8474
  };
8475
8475
  case "sphere":
8476
- return { kind: "sphere", center: cloneVec3$4(surface.center), radius: surface.radius };
8476
+ return { kind: "sphere", center: cloneVec3$5(surface.center), radius: surface.radius };
8477
8477
  case "torus":
8478
8478
  return {
8479
8479
  kind: "torus",
8480
- center: cloneVec3$4(surface.center),
8481
- axis: cloneVec3$4(surface.axis),
8480
+ center: cloneVec3$5(surface.center),
8481
+ axis: cloneVec3$5(surface.axis),
8482
8482
  majorRadius: surface.majorRadius,
8483
8483
  minorRadius: surface.minorRadius
8484
8484
  };
8485
8485
  case "ruled":
8486
8486
  return {
8487
8487
  kind: "ruled",
8488
- rails: surface.rails.map((rail2) => rail2.map(cloneVec3$4))
8488
+ rails: surface.rails.map((rail2) => rail2.map(cloneVec3$5))
8489
8489
  };
8490
8490
  case "nurbs":
8491
8491
  return {
@@ -8498,9 +8498,9 @@ function cloneEdgeCurve(curve) {
8498
8498
  if (!curve) return void 0;
8499
8499
  switch (curve.kind) {
8500
8500
  case "line":
8501
- return { ...curve, start: cloneVec3$4(curve.start), end: cloneVec3$4(curve.end) };
8501
+ return { ...curve, start: cloneVec3$5(curve.start), end: cloneVec3$5(curve.end) };
8502
8502
  case "circle":
8503
- return { ...curve, center: cloneVec3$4(curve.center), axis: cloneVec3$4(curve.axis) };
8503
+ return { ...curve, center: cloneVec3$5(curve.center), axis: cloneVec3$5(curve.axis) };
8504
8504
  case "surfaceIso":
8505
8505
  return { ...curve, parameterRange: [curve.parameterRange[0], curve.parameterRange[1]] };
8506
8506
  case "nurbsUv":
@@ -8518,7 +8518,7 @@ function cloneEdgeCurve(curve) {
8518
8518
  }
8519
8519
  }
8520
8520
  function makeLineEdgeCurve(start, end, faceName) {
8521
- return faceName ? { kind: "line", start: cloneVec3$4(start), end: cloneVec3$4(end), faceName } : { kind: "line", start: cloneVec3$4(start), end: cloneVec3$4(end) };
8521
+ return faceName ? { kind: "line", start: cloneVec3$5(start), end: cloneVec3$5(end), faceName } : { kind: "line", start: cloneVec3$5(start), end: cloneVec3$5(end) };
8522
8522
  }
8523
8523
  function edgeCurveFaceName(curve) {
8524
8524
  switch (curve.kind) {
@@ -10605,7 +10605,7 @@ async function initManifoldWasm() {
10605
10605
  if (_wasm$1) return _wasm$1;
10606
10606
  performance.mark("manifold:start");
10607
10607
  const Module = (await __vitePreload(async () => {
10608
- const { default: __vite_default__ } = await import("./manifold-DjYsd7A_.js");
10608
+ const { default: __vite_default__ } = await import("./manifold-BRdhoQy5.js");
10609
10609
  return { default: __vite_default__ };
10610
10610
  }, true ? [] : void 0)).default;
10611
10611
  performance.mark("manifold:imported");
@@ -22489,7 +22489,7 @@ function marchingTetrahedra(sdfFn, bounds, edgeLength2) {
22489
22489
  };
22490
22490
  }
22491
22491
  const EPS$8 = 1e-9;
22492
- function finitePositive(value) {
22492
+ function finitePositive$1(value) {
22493
22493
  return Number.isFinite(value) && value > EPS$8;
22494
22494
  }
22495
22495
  function clampNonNegative(value) {
@@ -22508,7 +22508,7 @@ function distancePreservingMatrixScale(matrix) {
22508
22508
  const sx = length4(col0);
22509
22509
  const sy = length4(col1);
22510
22510
  const sz = length4(col2);
22511
- if (!finitePositive(sx) || !finitePositive(sy) || !finitePositive(sz)) return null;
22511
+ if (!finitePositive$1(sx) || !finitePositive$1(sy) || !finitePositive$1(sz)) return null;
22512
22512
  if (Math.abs(sx - sy) > EPS$8 || Math.abs(sx - sz) > EPS$8) return null;
22513
22513
  if (Math.abs(dot2(col0, col1)) > EPS$8 || Math.abs(dot2(col0, col2)) > EPS$8 || Math.abs(dot2(col1, col2)) > EPS$8) return null;
22514
22514
  return sx;
@@ -22525,7 +22525,7 @@ function transformStepDistanceScale(step) {
22525
22525
  const sx = Math.abs(step.x);
22526
22526
  const sy = Math.abs(step.y);
22527
22527
  const sz = Math.abs(step.z);
22528
- if (!finitePositive(sx) || !finitePositive(sy) || !finitePositive(sz)) return null;
22528
+ if (!finitePositive$1(sx) || !finitePositive$1(sy) || !finitePositive$1(sz)) return null;
22529
22529
  return Math.abs(sx - sy) <= EPS$8 && Math.abs(sx - sz) <= EPS$8 ? sx : null;
22530
22530
  }
22531
22531
  }
@@ -22565,7 +22565,7 @@ function translatedPlan(base, z2) {
22565
22565
  };
22566
22566
  }
22567
22567
  function offsetCylinderDimensions(plan, thickness) {
22568
- if (!finitePositive(plan.height)) return null;
22568
+ if (!finitePositive$1(plan.height)) return null;
22569
22569
  const radiusTop = plan.radiusTop ?? plan.radius;
22570
22570
  const slope = (radiusTop - plan.radius) / plan.height;
22571
22571
  const normalScale = Math.hypot(1, slope);
@@ -22574,7 +22574,7 @@ function offsetCylinderDimensions(plan, thickness) {
22574
22574
  const height = zMax - zMin;
22575
22575
  const radiusBottom = plan.radius + thickness * (normalScale - slope);
22576
22576
  const offsetRadiusTop = radiusTop + thickness * (normalScale + slope);
22577
- if (!finitePositive(height) || radiusBottom < -EPS$8 || offsetRadiusTop < -EPS$8) return null;
22577
+ if (!finitePositive$1(height) || radiusBottom < -EPS$8 || offsetRadiusTop < -EPS$8) return null;
22578
22578
  return {
22579
22579
  zMin,
22580
22580
  height,
@@ -22632,7 +22632,7 @@ function rectangleCandidatePointsFromProfile(plan) {
22632
22632
  case "rect": {
22633
22633
  const width = Math.abs(plan.width);
22634
22634
  const height = Math.abs(plan.height);
22635
- if (!finitePositive(width) || !finitePositive(height)) return null;
22635
+ if (!finitePositive$1(width) || !finitePositive$1(height)) return null;
22636
22636
  const halfWidth = width / 2;
22637
22637
  const halfHeight = height / 2;
22638
22638
  const points = [
@@ -22666,7 +22666,7 @@ function rectangleFootprintFromProfile(plan) {
22666
22666
  const [xMin, xMax] = xs;
22667
22667
  const [zMin, zMax] = zs;
22668
22668
  if (xMin == null || xMax == null || zMin == null || zMax == null) return null;
22669
- if (xMin < -EPS$8 || !finitePositive(xMax) || !finitePositive(zMax - zMin)) return null;
22669
+ if (xMin < -EPS$8 || !finitePositive$1(xMax) || !finitePositive$1(zMax - zMin)) return null;
22670
22670
  const hasCorner = (x2, z2) => points.some(([px2, pz2]) => sameScalar$1(px2, x2) && sameScalar$1(pz2, z2));
22671
22671
  if (!hasCorner(xMin, zMin) || !hasCorner(xMax, zMin) || !hasCorner(xMax, zMax) || !hasCorner(xMin, zMax)) return null;
22672
22672
  return {
@@ -22679,7 +22679,7 @@ function rectangleFootprintFromProfile(plan) {
22679
22679
  function circleFootprintFromProfile(plan) {
22680
22680
  if (plan.kind !== "circle") return null;
22681
22681
  const radius = Math.abs(plan.radius);
22682
- if (!finitePositive(radius)) return null;
22682
+ if (!finitePositive$1(radius)) return null;
22683
22683
  const center = transformProfilePointThrough$1([0, 0], plan.transforms);
22684
22684
  const xPoint = transformProfilePointThrough$1([1, 0], plan.transforms);
22685
22685
  const yPoint = transformProfilePointThrough$1([0, 1], plan.transforms);
@@ -22688,7 +22688,7 @@ function circleFootprintFromProfile(plan) {
22688
22688
  const xScale = Math.hypot(xAxis[0], xAxis[1]);
22689
22689
  const yScale = Math.hypot(yAxis[0], yAxis[1]);
22690
22690
  const dot2 = xAxis[0] * yAxis[0] + xAxis[1] * yAxis[1];
22691
- if (!finitePositive(xScale) || !finitePositive(yScale)) return null;
22691
+ if (!finitePositive$1(xScale) || !finitePositive$1(yScale)) return null;
22692
22692
  if (Math.abs(xScale - yScale) > EPS$8 || Math.abs(dot2) > EPS$8 * xScale * yScale) return null;
22693
22693
  return {
22694
22694
  center,
@@ -22701,7 +22701,7 @@ function fullCircleRevolveTorusPlan(plan, minorRadiusOffset = 0) {
22701
22701
  const circle2 = circleFootprintFromProfile(plan.profile);
22702
22702
  if (!circle2 || circle2.center[0] <= EPS$8) return null;
22703
22703
  const minorRadius = circle2.radius + minorRadiusOffset;
22704
- if (!finitePositive(minorRadius) || minorRadius >= circle2.center[0] - EPS$8) return null;
22704
+ if (!finitePositive$1(minorRadius) || minorRadius >= circle2.center[0] - EPS$8) return null;
22705
22705
  return translatedPlan(
22706
22706
  {
22707
22707
  kind: "torus",
@@ -22748,7 +22748,7 @@ function offsetFullRectRevolvePlan(plan, thickness) {
22748
22748
  const innerRadius = rectangle.innerRadius - thickness;
22749
22749
  const outerRadius = rectangle.outerRadius + thickness;
22750
22750
  const height = rectangle.zMax - rectangle.zMin + 2 * thickness;
22751
- if (innerRadius < -EPS$8 || !finitePositive(outerRadius) || !finitePositive(height) || outerRadius <= innerRadius + EPS$8) return null;
22751
+ if (innerRadius < -EPS$8 || !finitePositive$1(outerRadius) || !finitePositive$1(height) || outerRadius <= innerRadius + EPS$8) return null;
22752
22752
  const zCenter = (rectangle.zMin + rectangle.zMax) / 2;
22753
22753
  if (innerRadius <= EPS$8) {
22754
22754
  return translatedPlan(
@@ -22789,11 +22789,11 @@ function offsetSolidAnalyticPrimitivePlan(base, thickness) {
22789
22789
  };
22790
22790
  }
22791
22791
  case "box": {
22792
- if (!finitePositive(base.z)) return null;
22792
+ if (!finitePositive$1(base.z)) return null;
22793
22793
  const x2 = Math.abs(base.x) + 2 * thickness;
22794
22794
  const y2 = Math.abs(base.y) + 2 * thickness;
22795
22795
  const z2 = base.z + 2 * thickness;
22796
- if (!finitePositive(x2) || !finitePositive(y2) || !finitePositive(z2)) return null;
22796
+ if (!finitePositive$1(x2) || !finitePositive$1(y2) || !finitePositive$1(z2)) return null;
22797
22797
  return translatedPlan(
22798
22798
  {
22799
22799
  kind: "box",
@@ -22820,7 +22820,7 @@ function offsetSolidAnalyticPrimitivePlan(base, thickness) {
22820
22820
  }
22821
22821
  case "sphere": {
22822
22822
  const radius = base.radius + thickness;
22823
- if (!finitePositive(radius)) return null;
22823
+ if (!finitePositive$1(radius)) return null;
22824
22824
  return {
22825
22825
  kind: "sphere",
22826
22826
  radius,
@@ -22829,7 +22829,7 @@ function offsetSolidAnalyticPrimitivePlan(base, thickness) {
22829
22829
  }
22830
22830
  case "torus": {
22831
22831
  const minorRadius = base.minorRadius + thickness;
22832
- if (!finitePositive(minorRadius) || minorRadius >= base.majorRadius - EPS$8) return null;
22832
+ if (!finitePositive$1(minorRadius) || minorRadius >= base.majorRadius - EPS$8) return null;
22833
22833
  return {
22834
22834
  kind: "torus",
22835
22835
  majorRadius: base.majorRadius,
@@ -30683,17 +30683,17 @@ function emptyFaceTable() {
30683
30683
  blockedQueries: []
30684
30684
  };
30685
30685
  }
30686
- function cloneVec3$3(vec2) {
30686
+ function cloneVec3$4(vec2) {
30687
30687
  return [vec2[0], vec2[1], vec2[2]];
30688
30688
  }
30689
30689
  function cloneFaceRefValue(face) {
30690
30690
  return {
30691
30691
  ...face,
30692
- normal: cloneVec3$3(face.normal),
30693
- center: cloneVec3$3(face.center),
30692
+ normal: cloneVec3$4(face.normal),
30693
+ center: cloneVec3$4(face.center),
30694
30694
  query: cloneFaceQueryRef(face.query),
30695
- uAxis: face.uAxis ? cloneVec3$3(face.uAxis) : void 0,
30696
- vAxis: face.vAxis ? cloneVec3$3(face.vAxis) : void 0,
30695
+ uAxis: face.uAxis ? cloneVec3$4(face.uAxis) : void 0,
30696
+ vAxis: face.vAxis ? cloneVec3$4(face.vAxis) : void 0,
30697
30697
  surface: cloneFaceSurface(face.surface),
30698
30698
  descendant: face.descendant ? cloneFaceDescendantMetadata(face.descendant) : void 0
30699
30699
  };
@@ -31548,11 +31548,11 @@ function resolveShapeFaceTableInternal(plan, owner) {
31548
31548
  for (const descriptor2 of describeSheetMetalFaces(plan.model, plan.output)) {
31549
31549
  registerFace(table2, {
31550
31550
  name: descriptor2.name,
31551
- normal: cloneVec3$3(descriptor2.normal),
31552
- center: cloneVec3$3(descriptor2.center),
31551
+ normal: cloneVec3$4(descriptor2.normal),
31552
+ center: cloneVec3$4(descriptor2.center),
31553
31553
  planar: descriptor2.planar,
31554
- uAxis: descriptor2.uAxis ? cloneVec3$3(descriptor2.uAxis) : void 0,
31555
- vAxis: descriptor2.vAxis ? cloneVec3$3(descriptor2.vAxis) : void 0,
31554
+ uAxis: descriptor2.uAxis ? cloneVec3$4(descriptor2.uAxis) : void 0,
31555
+ vAxis: descriptor2.vAxis ? cloneVec3$4(descriptor2.vAxis) : void 0,
31556
31556
  query: createTrackedFaceQuery(descriptor2.name, owner),
31557
31557
  descendant: createFaceDescendantMetadata(descriptor2.semantic, descriptor2.memberNames, descriptor2.coplanar)
31558
31558
  });
@@ -31579,7 +31579,7 @@ function resolveShapeFaceTableInternal(plan, owner) {
31579
31579
  baseFace.center[2] - baseFace.normal[2] * plan.thickness
31580
31580
  ],
31581
31581
  normal: [-baseFace.normal[0], -baseFace.normal[1], -baseFace.normal[2]],
31582
- uAxis: baseFace.uAxis ? cloneVec3$3(baseFace.uAxis) : void 0,
31582
+ uAxis: baseFace.uAxis ? cloneVec3$4(baseFace.uAxis) : void 0,
31583
31583
  vAxis: baseFace.vAxis ? [-baseFace.vAxis[0], -baseFace.vAxis[1], -baseFace.vAxis[2]] : void 0,
31584
31584
  query: createdQuery
31585
31585
  });
@@ -31645,15 +31645,15 @@ function resolveShapeFaceTableInternal(plan, owner) {
31645
31645
  if (counterboreFloorQuery && plan.hole.counterbore) {
31646
31646
  registerFace(table2, {
31647
31647
  name: "counterbore-floor",
31648
- normal: cloneVec3$3(workplane.normal),
31648
+ normal: cloneVec3$4(workplane.normal),
31649
31649
  center: [
31650
31650
  origin[0] + inward[0] * plan.hole.counterbore.depth,
31651
31651
  origin[1] + inward[1] * plan.hole.counterbore.depth,
31652
31652
  origin[2] + inward[2] * plan.hole.counterbore.depth
31653
31653
  ],
31654
31654
  planar: true,
31655
- uAxis: cloneVec3$3(workplane.u),
31656
- vAxis: cloneVec3$3(workplane.v),
31655
+ uAxis: cloneVec3$4(workplane.u),
31656
+ vAxis: cloneVec3$4(workplane.v),
31657
31657
  query: counterboreFloorQuery
31658
31658
  });
31659
31659
  }
@@ -31677,11 +31677,11 @@ function resolveShapeFaceTableInternal(plan, owner) {
31677
31677
  if (floorQuery) {
31678
31678
  registerFace(table2, {
31679
31679
  name: "floor",
31680
- normal: cloneVec3$3(workplane.normal),
31680
+ normal: cloneVec3$4(workplane.normal),
31681
31681
  center: [origin[0] + inward[0] * forward.depth, origin[1] + inward[1] * forward.depth, origin[2] + inward[2] * forward.depth],
31682
31682
  planar: true,
31683
- uAxis: cloneVec3$3(workplane.u),
31684
- vAxis: cloneVec3$3(workplane.v),
31683
+ uAxis: cloneVec3$4(workplane.u),
31684
+ vAxis: cloneVec3$4(workplane.v),
31685
31685
  query: floorQuery
31686
31686
  });
31687
31687
  }
@@ -31692,7 +31692,7 @@ function resolveShapeFaceTableInternal(plan, owner) {
31692
31692
  normal: [-workplane.normal[0], -workplane.normal[1], -workplane.normal[2]],
31693
31693
  center: [origin[0] - inward[0] * reverse.depth, origin[1] - inward[1] * reverse.depth, origin[2] - inward[2] * reverse.depth],
31694
31694
  planar: true,
31695
- uAxis: cloneVec3$3(workplane.u),
31695
+ uAxis: cloneVec3$4(workplane.u),
31696
31696
  vAxis: [-workplane.v[0], -workplane.v[1], -workplane.v[2]],
31697
31697
  query: capQuery
31698
31698
  });
@@ -31871,11 +31871,11 @@ function resolveShapeFaceTableInternal(plan, owner) {
31871
31871
  })();
31872
31872
  registerFace(table2, {
31873
31873
  name: "floor",
31874
- normal: cloneVec3$3(placement.workplane.normal),
31874
+ normal: cloneVec3$4(placement.workplane.normal),
31875
31875
  center: floorCenter,
31876
31876
  planar: true,
31877
- uAxis: cloneVec3$3(placement.workplane.u),
31878
- vAxis: cloneVec3$3(placement.workplane.v),
31877
+ uAxis: cloneVec3$4(placement.workplane.u),
31878
+ vAxis: cloneVec3$4(placement.workplane.v),
31879
31879
  query: floorQuery
31880
31880
  });
31881
31881
  }
@@ -31890,7 +31890,7 @@ function resolveShapeFaceTableInternal(plan, owner) {
31890
31890
  origin[2] - depthDir[2] * reverse.depth
31891
31891
  ],
31892
31892
  planar: true,
31893
- uAxis: cloneVec3$3(placement.workplane.u),
31893
+ uAxis: cloneVec3$4(placement.workplane.u),
31894
31894
  vAxis: [-placement.workplane.v[0], -placement.workplane.v[1], -placement.workplane.v[2]],
31895
31895
  query: capQuery
31896
31896
  });
@@ -32076,7 +32076,7 @@ function preservedShapeFaceQueries(basePlan) {
32076
32076
  return listShapeFaceQueries(basePlan);
32077
32077
  }
32078
32078
  const PLACEMENT_REFERENCE_KINDS = ["points", "edges", "surfaces", "objects"];
32079
- function cloneVec3$2(value, label) {
32079
+ function cloneVec3$3(value, label) {
32080
32080
  if (!Array.isArray(value) || value.length < 3) {
32081
32081
  throw new Error(`${label} must be a [x, y, z] tuple`);
32082
32082
  }
@@ -32102,23 +32102,23 @@ function isBoundsObject(value) {
32102
32102
  function toObjectBounds(value, label) {
32103
32103
  if (isBoundsObject(value)) {
32104
32104
  return {
32105
- min: cloneVec3$2(value.min, `${label}.min`),
32106
- max: cloneVec3$2(value.max, `${label}.max`)
32105
+ min: cloneVec3$3(value.min, `${label}.min`),
32106
+ max: cloneVec3$3(value.max, `${label}.max`)
32107
32107
  };
32108
32108
  }
32109
32109
  if (typeof value === "object" && value != null) {
32110
32110
  if ("boundingBox" in value && typeof value.boundingBox === "function") {
32111
32111
  const bounds = value.boundingBox();
32112
32112
  return {
32113
- min: cloneVec3$2(bounds.min, `${label}.min`),
32114
- max: cloneVec3$2(bounds.max, `${label}.max`)
32113
+ min: cloneVec3$3(bounds.min, `${label}.min`),
32114
+ max: cloneVec3$3(bounds.max, `${label}.max`)
32115
32115
  };
32116
32116
  }
32117
32117
  if ("_bbox" in value && typeof value._bbox === "function") {
32118
32118
  const bounds = value._bbox();
32119
32119
  return {
32120
- min: cloneVec3$2(bounds.min, `${label}.min`),
32121
- max: cloneVec3$2(bounds.max, `${label}.max`)
32120
+ min: cloneVec3$3(bounds.min, `${label}.min`),
32121
+ max: cloneVec3$3(bounds.max, `${label}.max`)
32122
32122
  };
32123
32123
  }
32124
32124
  }
@@ -32162,24 +32162,24 @@ function createPlacementReferences() {
32162
32162
  function clonePlacementReferences(refs) {
32163
32163
  const out = createPlacementReferences();
32164
32164
  for (const [name, point2] of Object.entries(refs.points)) {
32165
- out.points[name] = cloneVec3$2(point2, `points.${name}`);
32165
+ out.points[name] = cloneVec3$3(point2, `points.${name}`);
32166
32166
  }
32167
32167
  for (const [name, edge] of Object.entries(refs.edges)) {
32168
32168
  out.edges[name] = {
32169
- start: cloneVec3$2(edge.start, `edges.${name}.start`),
32170
- end: cloneVec3$2(edge.end, `edges.${name}.end`)
32169
+ start: cloneVec3$3(edge.start, `edges.${name}.start`),
32170
+ end: cloneVec3$3(edge.end, `edges.${name}.end`)
32171
32171
  };
32172
32172
  }
32173
32173
  for (const [name, surface] of Object.entries(refs.surfaces)) {
32174
32174
  out.surfaces[name] = {
32175
- center: cloneVec3$2(surface.center, `surfaces.${name}.center`),
32176
- normal: cloneVec3$2(surface.normal, `surfaces.${name}.normal`)
32175
+ center: cloneVec3$3(surface.center, `surfaces.${name}.center`),
32176
+ normal: cloneVec3$3(surface.normal, `surfaces.${name}.normal`)
32177
32177
  };
32178
32178
  }
32179
32179
  for (const [name, objectRef] of Object.entries(refs.objects)) {
32180
32180
  out.objects[name] = {
32181
- min: cloneVec3$2(objectRef.min, `objects.${name}.min`),
32182
- max: cloneVec3$2(objectRef.max, `objects.${name}.max`)
32181
+ min: cloneVec3$3(objectRef.min, `objects.${name}.min`),
32182
+ max: cloneVec3$3(objectRef.max, `objects.${name}.max`)
32183
32183
  };
32184
32184
  }
32185
32185
  return out;
@@ -32187,18 +32187,18 @@ function clonePlacementReferences(refs) {
32187
32187
  function normalizePlacementReferenceInput(input = {}) {
32188
32188
  const out = createPlacementReferences();
32189
32189
  for (const [name, point2] of Object.entries(input.points ?? {})) {
32190
- out.points[name] = cloneVec3$2(point2, `points.${name}`);
32190
+ out.points[name] = cloneVec3$3(point2, `points.${name}`);
32191
32191
  }
32192
32192
  for (const [name, edge] of Object.entries(input.edges ?? {})) {
32193
32193
  out.edges[name] = {
32194
- start: cloneVec3$2(edge.start, `edges.${name}.start`),
32195
- end: cloneVec3$2(edge.end, `edges.${name}.end`)
32194
+ start: cloneVec3$3(edge.start, `edges.${name}.start`),
32195
+ end: cloneVec3$3(edge.end, `edges.${name}.end`)
32196
32196
  };
32197
32197
  }
32198
32198
  for (const [name, surface] of Object.entries(input.surfaces ?? {})) {
32199
32199
  out.surfaces[name] = {
32200
- center: cloneVec3$2(surface.center, `surfaces.${name}.center`),
32201
- normal: normalizeVector$1(cloneVec3$2(surface.normal, `surfaces.${name}.normal`))
32200
+ center: cloneVec3$3(surface.center, `surfaces.${name}.center`),
32201
+ normal: normalizeVector$1(cloneVec3$3(surface.normal, `surfaces.${name}.normal`))
32202
32202
  };
32203
32203
  }
32204
32204
  for (const [name, objectRef] of Object.entries(input.objects ?? {})) {
@@ -32209,23 +32209,23 @@ function normalizePlacementReferenceInput(input = {}) {
32209
32209
  function mergePlacementReferences(...refsList) {
32210
32210
  const out = createPlacementReferences();
32211
32211
  for (const refs of refsList) {
32212
- for (const [name, point2] of Object.entries(refs.points)) out.points[name] = cloneVec3$2(point2, `points.${name}`);
32212
+ for (const [name, point2] of Object.entries(refs.points)) out.points[name] = cloneVec3$3(point2, `points.${name}`);
32213
32213
  for (const [name, edge] of Object.entries(refs.edges)) {
32214
32214
  out.edges[name] = {
32215
- start: cloneVec3$2(edge.start, `edges.${name}.start`),
32216
- end: cloneVec3$2(edge.end, `edges.${name}.end`)
32215
+ start: cloneVec3$3(edge.start, `edges.${name}.start`),
32216
+ end: cloneVec3$3(edge.end, `edges.${name}.end`)
32217
32217
  };
32218
32218
  }
32219
32219
  for (const [name, surface] of Object.entries(refs.surfaces)) {
32220
32220
  out.surfaces[name] = {
32221
- center: cloneVec3$2(surface.center, `surfaces.${name}.center`),
32222
- normal: cloneVec3$2(surface.normal, `surfaces.${name}.normal`)
32221
+ center: cloneVec3$3(surface.center, `surfaces.${name}.center`),
32222
+ normal: cloneVec3$3(surface.normal, `surfaces.${name}.normal`)
32223
32223
  };
32224
32224
  }
32225
32225
  for (const [name, objectRef] of Object.entries(refs.objects)) {
32226
32226
  out.objects[name] = {
32227
- min: cloneVec3$2(objectRef.min, `objects.${name}.min`),
32228
- max: cloneVec3$2(objectRef.max, `objects.${name}.max`)
32227
+ min: cloneVec3$3(objectRef.min, `objects.${name}.min`),
32228
+ max: cloneVec3$3(objectRef.max, `objects.${name}.max`)
32229
32229
  };
32230
32230
  }
32231
32231
  }
@@ -32269,7 +32269,7 @@ function resolvePointFromKind(refs, kind, name, selector, originalRef) {
32269
32269
  const point2 = refs.points[name];
32270
32270
  if (!point2) return null;
32271
32271
  if (selector != null) placementRefSelectorError(originalRef, "does not support selectors");
32272
- return cloneVec3$2(point2, `points.${name}`);
32272
+ return cloneVec3$3(point2, `points.${name}`);
32273
32273
  }
32274
32274
  case "edges": {
32275
32275
  const edge = refs.edges[name];
@@ -32277,8 +32277,8 @@ function resolvePointFromKind(refs, kind, name, selector, originalRef) {
32277
32277
  if (selector == null || selector === "midpoint" || selector === "center") {
32278
32278
  return midpoint$2(edge.start, edge.end);
32279
32279
  }
32280
- if (selector === "start") return cloneVec3$2(edge.start, `edges.${name}.start`);
32281
- if (selector === "end") return cloneVec3$2(edge.end, `edges.${name}.end`);
32280
+ if (selector === "start") return cloneVec3$3(edge.start, `edges.${name}.start`);
32281
+ if (selector === "end") return cloneVec3$3(edge.end, `edges.${name}.end`);
32282
32282
  placementRefSelectorError(originalRef, "supports only .start, .end, or .midpoint");
32283
32283
  }
32284
32284
  case "surfaces": {
@@ -32287,7 +32287,7 @@ function resolvePointFromKind(refs, kind, name, selector, originalRef) {
32287
32287
  if (selector != null && selector !== "center") {
32288
32288
  placementRefSelectorError(originalRef, "supports only .center");
32289
32289
  }
32290
- return cloneVec3$2(surface.center, `surfaces.${name}.center`);
32290
+ return cloneVec3$3(surface.center, `surfaces.${name}.center`);
32291
32291
  }
32292
32292
  case "objects": {
32293
32293
  const objectRef = refs.objects[name];
@@ -35372,7 +35372,7 @@ function attachTopologyRewritePropagation(plan, propagation) {
35372
35372
  }
35373
35373
  const DEFAULT_TOLERANCE$2 = 1;
35374
35374
  const DEFAULT_ANGLE_TOLERANCE = 10;
35375
- function distSq(a2, b) {
35375
+ function distSq$1(a2, b) {
35376
35376
  const dx = a2[0] - b[0], dy = a2[1] - b[1], dz = a2[2] - b[2];
35377
35377
  return dx * dx + dy * dy + dz * dz;
35378
35378
  }
@@ -35464,7 +35464,7 @@ function applyFilters(edges, query) {
35464
35464
  }
35465
35465
  if (query.near) {
35466
35466
  const pt = query.near;
35467
- result = result.slice().sort((a2, b) => distSq(a2.midpoint, pt) - distSq(b.midpoint, pt));
35467
+ result = result.slice().sort((a2, b) => distSq$1(a2.midpoint, pt) - distSq$1(b.midpoint, pt));
35468
35468
  }
35469
35469
  return result;
35470
35470
  }
@@ -35528,10 +35528,10 @@ function coalesceEdges(segments, tolerance = 0.01) {
35528
35528
  }
35529
35529
  function minEndpointGap(a2, b) {
35530
35530
  return Math.min(
35531
- Math.sqrt(distSq(a2.start, b.start)),
35532
- Math.sqrt(distSq(a2.start, b.end)),
35533
- Math.sqrt(distSq(a2.end, b.start)),
35534
- Math.sqrt(distSq(a2.end, b.end))
35531
+ Math.sqrt(distSq$1(a2.start, b.start)),
35532
+ Math.sqrt(distSq$1(a2.start, b.end)),
35533
+ Math.sqrt(distSq$1(a2.end, b.start)),
35534
+ Math.sqrt(distSq$1(a2.end, b.end))
35535
35535
  );
35536
35536
  }
35537
35537
  function mergeCollinearGroup(group2, index2) {
@@ -53237,11 +53237,11 @@ function inverseLerp(x2, y2, value) {
53237
53237
  return 0;
53238
53238
  }
53239
53239
  }
53240
- function lerp$5(x2, y2, t) {
53240
+ function lerp$6(x2, y2, t) {
53241
53241
  return (1 - t) * x2 + t * y2;
53242
53242
  }
53243
53243
  function damp(x2, y2, lambda, dt) {
53244
- return lerp$5(x2, y2, 1 - Math.exp(-lambda * dt));
53244
+ return lerp$6(x2, y2, 1 - Math.exp(-lambda * dt));
53245
53245
  }
53246
53246
  function pingpong(x2, length4 = 1) {
53247
53247
  return length4 - Math.abs(euclideanModulo(x2, length4 * 2) - length4);
@@ -53434,7 +53434,7 @@ const MathUtils = {
53434
53434
  * @param {number} t - The interpolation factor in the closed interval `[0, 1]`.
53435
53435
  * @return {number} The interpolated value.
53436
53436
  */
53437
- lerp: lerp$5,
53437
+ lerp: lerp$6,
53438
53438
  /**
53439
53439
  * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta
53440
53440
  * time to maintain frame rate independent movement. For details, see
@@ -62388,9 +62388,9 @@ class Color {
62388
62388
  lerpHSL(color, alpha) {
62389
62389
  this.getHSL(_hslA);
62390
62390
  color.getHSL(_hslB);
62391
- const h = lerp$5(_hslA.h, _hslB.h, alpha);
62392
- const s = lerp$5(_hslA.s, _hslB.s, alpha);
62393
- const l = lerp$5(_hslA.l, _hslB.l, alpha);
62391
+ const h = lerp$6(_hslA.h, _hslB.h, alpha);
62392
+ const s = lerp$6(_hslA.s, _hslB.s, alpha);
62393
+ const l = lerp$6(_hslA.l, _hslB.l, alpha);
62394
62394
  this.setHSL(h, s, l);
62395
62395
  return this;
62396
62396
  }
@@ -94501,6 +94501,19 @@ const Viewport = {
94501
94501
  collectRenderLabel(text, at, options);
94502
94502
  }
94503
94503
  };
94504
+ const NO_SURFACE_FIELD = {
94505
+ enabled: false,
94506
+ kind: "precision",
94507
+ baseColor: "#000000",
94508
+ darkColor: "#000000",
94509
+ lineColor: "#000000",
94510
+ nodeColor: "#000000",
94511
+ accentColor: "#000000",
94512
+ spacing: 1,
94513
+ lineWidth: 0.01,
94514
+ glow: 0,
94515
+ objectColorMix: 0
94516
+ };
94504
94517
  const DEFAULT_RENDER_STYLE = "classic";
94505
94518
  const RENDER_STYLE_OPTIONS = [
94506
94519
  {
@@ -94522,6 +94535,16 @@ const RENDER_STYLE_OPTIONS = [
94522
94535
  id: "glass",
94523
94536
  label: "Glass",
94524
94537
  description: "Showcase lighting for authored transparent materials."
94538
+ },
94539
+ {
94540
+ id: "precision",
94541
+ label: "Precision",
94542
+ description: "Dense, thin surface-field contours for technical inspection."
94543
+ },
94544
+ {
94545
+ id: "hybrid",
94546
+ label: "Hybrid",
94547
+ description: "Topo-led surface contours with a quiet orthogonal field."
94525
94548
  }
94526
94549
  ];
94527
94550
  const RENDER_STYLE_IDS = new Set(RENDER_STYLE_OPTIONS.map((option) => option.id));
@@ -94577,7 +94600,8 @@ const PRESETS = {
94577
94600
  color: "#ffffff",
94578
94601
  opacity: 0,
94579
94602
  scale: 1
94580
- }
94603
+ },
94604
+ surfaceField: NO_SURFACE_FIELD
94581
94605
  },
94582
94606
  studio: {
94583
94607
  id: "studio",
@@ -94630,7 +94654,8 @@ const PRESETS = {
94630
94654
  color: "#f7fffb",
94631
94655
  opacity: 0.055,
94632
94656
  scale: 1.006
94633
- }
94657
+ },
94658
+ surfaceField: NO_SURFACE_FIELD
94634
94659
  },
94635
94660
  fast: {
94636
94661
  id: "fast",
@@ -94683,7 +94708,8 @@ const PRESETS = {
94683
94708
  color: "#fff6df",
94684
94709
  opacity: 0,
94685
94710
  scale: 1
94686
- }
94711
+ },
94712
+ surfaceField: NO_SURFACE_FIELD
94687
94713
  },
94688
94714
  glass: {
94689
94715
  id: "glass",
@@ -94736,6 +94762,139 @@ const PRESETS = {
94736
94762
  color: "#e8fff8",
94737
94763
  opacity: 0.13,
94738
94764
  scale: 1.012
94765
+ },
94766
+ surfaceField: NO_SURFACE_FIELD
94767
+ },
94768
+ precision: {
94769
+ id: "precision",
94770
+ label: "Precision",
94771
+ background: "#0c1011",
94772
+ toneMappingExposure: 1.06,
94773
+ environmentIntensity: 0.35,
94774
+ canvasDpr: { live: 1, idleMax: 1.45 },
94775
+ lights: {
94776
+ ambientIntensity: 0.36,
94777
+ keyIntensity: 1.25,
94778
+ keyColor: "#f2fff9",
94779
+ keyPosition: [95, -120, 145],
94780
+ fillIntensity: 0.32,
94781
+ fillColor: "#cbeee8",
94782
+ fillPosition: [-80, 70, 80],
94783
+ rimIntensity: 0.28,
94784
+ rimColor: "#d1fff7",
94785
+ rimPosition: [-105, -75, 120],
94786
+ hemisphereSky: "#d1fff7",
94787
+ hemisphereGround: "#111616",
94788
+ hemisphereIntensity: 0.3
94789
+ },
94790
+ material: {
94791
+ metalness: 0,
94792
+ roughness: 0.68,
94793
+ clearcoat: 0,
94794
+ clearcoatRoughness: 0.6,
94795
+ reflectivity: 0.18,
94796
+ specularIntensity: 0.62,
94797
+ opacity: 1,
94798
+ transmission: 0,
94799
+ thickness: 0,
94800
+ authoredTransparent: {
94801
+ roughness: 0.42,
94802
+ clearcoat: 0.08,
94803
+ clearcoatRoughness: 0.46,
94804
+ reflectivity: 0.24,
94805
+ specularIntensity: 0.72,
94806
+ transmission: 0,
94807
+ thickness: 0.2
94808
+ }
94809
+ },
94810
+ edge: {
94811
+ color: "#d1fff7",
94812
+ opacity: 0.26
94813
+ },
94814
+ glassShell: {
94815
+ enabled: false,
94816
+ color: "#d1fff7",
94817
+ opacity: 0,
94818
+ scale: 1
94819
+ },
94820
+ surfaceField: {
94821
+ enabled: true,
94822
+ kind: "precision",
94823
+ baseColor: "#3d5659",
94824
+ darkColor: "#070b0c",
94825
+ lineColor: "#d1fff7",
94826
+ nodeColor: "#fff4bc",
94827
+ accentColor: "#ffb66f",
94828
+ spacing: 0.22,
94829
+ lineWidth: 36e-4,
94830
+ glow: 0.2,
94831
+ objectColorMix: 0.35
94832
+ }
94833
+ },
94834
+ hybrid: {
94835
+ id: "hybrid",
94836
+ label: "Hybrid",
94837
+ background: "#0b1312",
94838
+ toneMappingExposure: 1.08,
94839
+ environmentIntensity: 0.42,
94840
+ canvasDpr: { live: 1, idleMax: 1.45 },
94841
+ lights: {
94842
+ ambientIntensity: 0.38,
94843
+ keyIntensity: 1.32,
94844
+ keyColor: "#f2fff9",
94845
+ keyPosition: [100, -125, 145],
94846
+ fillIntensity: 0.34,
94847
+ fillColor: "#c9fff2",
94848
+ fillPosition: [-80, 78, 85],
94849
+ rimIntensity: 0.34,
94850
+ rimColor: "#d7ff86",
94851
+ rimPosition: [-105, -80, 125],
94852
+ hemisphereSky: "#bfffee",
94853
+ hemisphereGround: "#101810",
94854
+ hemisphereIntensity: 0.32
94855
+ },
94856
+ material: {
94857
+ metalness: 0,
94858
+ roughness: 0.66,
94859
+ clearcoat: 0,
94860
+ clearcoatRoughness: 0.6,
94861
+ reflectivity: 0.2,
94862
+ specularIntensity: 0.66,
94863
+ opacity: 1,
94864
+ transmission: 0,
94865
+ thickness: 0,
94866
+ authoredTransparent: {
94867
+ roughness: 0.4,
94868
+ clearcoat: 0.08,
94869
+ clearcoatRoughness: 0.46,
94870
+ reflectivity: 0.24,
94871
+ specularIntensity: 0.74,
94872
+ transmission: 0,
94873
+ thickness: 0.2
94874
+ }
94875
+ },
94876
+ edge: {
94877
+ color: "#defdf7",
94878
+ opacity: 0.28
94879
+ },
94880
+ glassShell: {
94881
+ enabled: false,
94882
+ color: "#defdf7",
94883
+ opacity: 0,
94884
+ scale: 1
94885
+ },
94886
+ surfaceField: {
94887
+ enabled: true,
94888
+ kind: "hybrid",
94889
+ baseColor: "#32645e",
94890
+ darkColor: "#07100f",
94891
+ lineColor: "#95fff0",
94892
+ nodeColor: "#ffe098",
94893
+ accentColor: "#d7ff86",
94894
+ spacing: 0.3,
94895
+ lineWidth: 5e-3,
94896
+ glow: 0.4,
94897
+ objectColorMix: 0.28
94739
94898
  }
94740
94899
  }
94741
94900
  };
@@ -96566,7 +96725,7 @@ function scale$1(v, s) {
96566
96725
  function dot$2(a2, b) {
96567
96726
  return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
96568
96727
  }
96569
- function lerp$4(a2, b, t) {
96728
+ function lerp$5(a2, b, t) {
96570
96729
  return a2 + (b - a2) * t;
96571
96730
  }
96572
96731
  function frameMatrix$1(x2, y2, z2, p2) {
@@ -96642,9 +96801,9 @@ function interpolateQuery(a2, b, t) {
96642
96801
  }
96643
96802
  return {
96644
96803
  side: sideA,
96645
- u: lerp$4(a2.u ?? 0.5, b.u ?? 0.5, t),
96646
- v: lerp$4(a2.v ?? 0.5, b.v ?? 0.5, t),
96647
- offset: lerp$4(a2.offset ?? 0, b.offset ?? 0, t)
96804
+ u: lerp$5(a2.u ?? 0.5, b.u ?? 0.5, t),
96805
+ v: lerp$5(a2.v ?? 0.5, b.v ?? 0.5, t),
96806
+ offset: lerp$5(a2.offset ?? 0, b.offset ?? 0, t)
96648
96807
  };
96649
96808
  }
96650
96809
  function resolvePathQueries(points) {
@@ -96769,7 +96928,7 @@ class ProductSkin {
96769
96928
  }
96770
96929
  /** Interpolate center, width, and depth at a normalized v or absolute axis value. */
96771
96930
  stationAt(vOrAxis) {
96772
- const axisValue = vOrAxis >= 0 && vOrAxis <= 1 ? lerp$4(this.axisMin, this.axisMax, vOrAxis) : clamp$5(vOrAxis, this.axisMin, this.axisMax);
96931
+ const axisValue = vOrAxis >= 0 && vOrAxis <= 1 ? lerp$5(this.axisMin, this.axisMax, vOrAxis) : clamp$5(vOrAxis, this.axisMin, this.axisMax);
96773
96932
  const sorted = this.stations;
96774
96933
  for (let index2 = 0; index2 < sorted.length - 1; index2 += 1) {
96775
96934
  const a2 = sorted[index2];
@@ -96781,12 +96940,12 @@ class ProductSkin {
96781
96940
  const t = clamp$5((axisValue - aAxis) / span, 0, 1);
96782
96941
  return {
96783
96942
  axisValue,
96784
- center: [lerp$4(a2.center[0], b.center[0], t), lerp$4(a2.center[1], b.center[1], t), lerp$4(a2.center[2], b.center[2], t)],
96785
- width: lerp$4(a2.profile.width, b.profile.width, t),
96786
- depth: lerp$4(a2.profile.depth, b.profile.depth, t),
96943
+ center: [lerp$5(a2.center[0], b.center[0], t), lerp$5(a2.center[1], b.center[1], t), lerp$5(a2.center[2], b.center[2], t)],
96944
+ width: lerp$5(a2.profile.width, b.profile.width, t),
96945
+ depth: lerp$5(a2.profile.depth, b.profile.depth, t),
96787
96946
  dWidth: (b.profile.width - a2.profile.width) / span,
96788
96947
  dDepth: (b.profile.depth - a2.profile.depth) / span,
96789
- exponent: lerp$4(profileExponent(a2), profileExponent(b), t),
96948
+ exponent: lerp$5(profileExponent(a2), profileExponent(b), t),
96790
96949
  kind: a2.profile.kind === b.profile.kind ? a2.profile.kind : "custom"
96791
96950
  };
96792
96951
  }
@@ -97619,7 +97778,7 @@ function requirePositive$3(value, label) {
97619
97778
  function clamp$4(value, min2, max2) {
97620
97779
  return Math.max(min2, Math.min(max2, value));
97621
97780
  }
97622
- function lerp$3(a2, b, t) {
97781
+ function lerp$4(a2, b, t) {
97623
97782
  return a2 + (b - a2) * t;
97624
97783
  }
97625
97784
  function add(a2, b) {
@@ -97669,19 +97828,19 @@ function transformLocal(point2, tangentAcross, normal, tangentAlong, x2, y2, z2
97669
97828
  function interpolateCylinder(a2, b, t, mode) {
97670
97829
  let delta = b.angle - a2.angle;
97671
97830
  if (mode === "shortest" && Math.abs(delta) > 180) delta -= Math.sign(delta) * 360;
97672
- return { kind: "cylinder", angle: a2.angle + delta * t, z: lerp$3(a2.z, b.z, t), offset: lerp$3(a2.offset ?? 0, b.offset ?? 0, t) };
97831
+ return { kind: "cylinder", angle: a2.angle + delta * t, z: lerp$4(a2.z, b.z, t), offset: lerp$4(a2.offset ?? 0, b.offset ?? 0, t) };
97673
97832
  }
97674
97833
  function interpolatePlane(a2, b, t) {
97675
- return { kind: "plane", x: lerp$3(a2.x, b.x, t), y: lerp$3(a2.y, b.y, t), offset: lerp$3(a2.offset ?? 0, b.offset ?? 0, t) };
97834
+ return { kind: "plane", x: lerp$4(a2.x, b.x, t), y: lerp$4(a2.y, b.y, t), offset: lerp$4(a2.offset ?? 0, b.offset ?? 0, t) };
97676
97835
  }
97677
97836
  function interpolateProductSkin(a2, b, t) {
97678
97837
  if ((a2.side ?? b.side) !== (b.side ?? a2.side)) throw new Error("SurfacePath on ProductSkin currently supports one side per path; split side transitions into separate members.");
97679
97838
  return {
97680
97839
  kind: "productSkin",
97681
97840
  side: a2.side ?? b.side,
97682
- u: lerp$3(a2.u ?? 0.5, b.u ?? 0.5, t),
97683
- v: lerp$3(a2.v ?? 0.5, b.v ?? 0.5, t),
97684
- offset: lerp$3(a2.offset ?? 0, b.offset ?? 0, t)
97841
+ u: lerp$4(a2.u ?? 0.5, b.u ?? 0.5, t),
97842
+ v: lerp$4(a2.v ?? 0.5, b.v ?? 0.5, t),
97843
+ offset: lerp$4(a2.offset ?? 0, b.offset ?? 0, t)
97685
97844
  };
97686
97845
  }
97687
97846
  class SurfacePath {
@@ -98779,7 +98938,7 @@ function counterboresForPlate(spec2, width, height, thickness, diagnostics) {
98779
98938
  function minWidthAcrossAlongRange(widthAtT, length4, minAlong, maxAlong) {
98780
98939
  let minWidth = Number.POSITIVE_INFINITY;
98781
98940
  for (let index2 = 0; index2 <= 8; index2 += 1) {
98782
- const along = lerp$3(minAlong, maxAlong, index2 / 8);
98941
+ const along = lerp$4(minAlong, maxAlong, index2 / 8);
98783
98942
  const t = Math.max(0, Math.min(1, (along + length4 / 2) / Math.max(length4, 1e-8)));
98784
98943
  minWidth = Math.min(minWidth, widthAtT(t));
98785
98944
  }
@@ -99079,7 +99238,7 @@ function pathParameterAtDistance(samples, distance2) {
99079
99238
  const segmentLength = Math.hypot(b.point[0] - a2.point[0], b.point[1] - a2.point[1], b.point[2] - a2.point[2]);
99080
99239
  if (traveled + segmentLength >= distance2) {
99081
99240
  const localT = segmentLength <= 1e-8 ? 0 : (distance2 - traveled) / segmentLength;
99082
- return lerp$3(a2.t, b.t, localT);
99241
+ return lerp$4(a2.t, b.t, localT);
99083
99242
  }
99084
99243
  traveled += segmentLength;
99085
99244
  }
@@ -99132,7 +99291,7 @@ function compileBandFootprintMesh(path2, input) {
99132
99291
  const width = input.widthAt(t);
99133
99292
  const along = distance2 - length4 / 2;
99134
99293
  for (let acrossIndex = 0; acrossIndex <= acrossSegments; acrossIndex += 1) {
99135
- const across = lerp$3(-width / 2, width / 2, acrossIndex / acrossSegments);
99294
+ const across = lerp$4(-width / 2, width / 2, acrossIndex / acrossSegments);
99136
99295
  mesh.vertices.push(pointAtProfile([across, along], false));
99137
99296
  }
99138
99297
  }
@@ -99142,7 +99301,7 @@ function compileBandFootprintMesh(path2, input) {
99142
99301
  const width = input.widthAt(t);
99143
99302
  const along = distance2 - length4 / 2;
99144
99303
  for (let acrossIndex = 0; acrossIndex <= acrossSegments; acrossIndex += 1) {
99145
- const across = lerp$3(-width / 2, width / 2, acrossIndex / acrossSegments);
99304
+ const across = lerp$4(-width / 2, width / 2, acrossIndex / acrossSegments);
99146
99305
  mesh.vertices.push(pointAtProfile([across, along], true));
99147
99306
  }
99148
99307
  }
@@ -99154,7 +99313,7 @@ function compileBandFootprintMesh(path2, input) {
99154
99313
  const width = input.widthAt(t);
99155
99314
  const along = distance2 - length4 / 2;
99156
99315
  for (let acrossIndex = 0; acrossIndex < acrossSegments; acrossIndex += 1) {
99157
- const across = lerp$3(-width / 2, width / 2, (acrossIndex + 0.5) / acrossSegments);
99316
+ const across = lerp$4(-width / 2, width / 2, (acrossIndex + 0.5) / acrossSegments);
99158
99317
  filled[alongIndex][acrossIndex] = !holes.some((hole2) => pointInProfileLoop([across, along], hole2));
99159
99318
  }
99160
99319
  }
@@ -101354,7 +101513,7 @@ function midpoint$1(a2, b) {
101354
101513
  requireVec3$1(b, "b");
101355
101514
  return [(a2[0] + b[0]) / 2, (a2[1] + b[1]) / 2, (a2[2] + b[2]) / 2];
101356
101515
  }
101357
- function lerp$2(a2, b, t) {
101516
+ function lerp$3(a2, b, t) {
101358
101517
  requireVec3$1(a2, "a");
101359
101518
  requireVec3$1(b, "b");
101360
101519
  requireFiniteNumber(t, "t");
@@ -101384,7 +101543,7 @@ const Points2 = {
101384
101543
  /** Center point between two 3D points. */
101385
101544
  midpoint: midpoint$1,
101386
101545
  /** Linearly interpolate between two 3D points. t=0 returns a, t=1 returns b. */
101387
- lerp: lerp$2,
101546
+ lerp: lerp$3,
101388
101547
  /** Unit direction vector from a to b. Throws if a and b are the same point. */
101389
101548
  direction,
101390
101549
  /** Move a point along a direction vector by a given amount. */
@@ -121920,7 +122079,7 @@ function railCrossAt(rail2, position) {
121920
122079
  const b = points[index2 + 1];
121921
122080
  if (position >= a2.position - LOFT_GUIDE_EPS && position <= b.position + LOFT_GUIDE_EPS) {
121922
122081
  const t = (position - a2.position) / (b.position - a2.position);
121923
- return [lerp$1(a2.cross[0], b.cross[0], t), lerp$1(a2.cross[1], b.cross[1], t)];
122082
+ return [lerp$2(a2.cross[0], b.cross[0], t), lerp$2(a2.cross[1], b.cross[1], t)];
121924
122083
  }
121925
122084
  }
121926
122085
  throw new Error("Loft guide rail does not cover requested station position");
@@ -121958,7 +122117,7 @@ function crossPointForAxis(axis, point2) {
121958
122117
  if (axis === "Y") return [point2[0], -point2[2]];
121959
122118
  return [point2[0], point2[1]];
121960
122119
  }
121961
- function lerp$1(a2, b, t) {
122120
+ function lerp$2(a2, b, t) {
121962
122121
  return a2 + (b - a2) * t;
121963
122122
  }
121964
122123
  function loftWithGuideRails(stations, rails, options = {}) {
@@ -122082,13 +122241,13 @@ function sketchBounds(profile) {
122082
122241
  }
122083
122242
  function lerpBounds(a2, b, t) {
122084
122243
  return {
122085
- minX: lerp(a2.minX, b.minX, t),
122086
- maxX: lerp(a2.maxX, b.maxX, t),
122087
- minY: lerp(a2.minY, b.minY, t),
122088
- maxY: lerp(a2.maxY, b.maxY, t)
122244
+ minX: lerp$1(a2.minX, b.minX, t),
122245
+ maxX: lerp$1(a2.maxX, b.maxX, t),
122246
+ minY: lerp$1(a2.minY, b.minY, t),
122247
+ maxY: lerp$1(a2.maxY, b.maxY, t)
122089
122248
  };
122090
122249
  }
122091
- function lerp(a2, b, t) {
122250
+ function lerp$1(a2, b, t) {
122092
122251
  return a2 + (b - a2) * t;
122093
122252
  }
122094
122253
  function mapLoftPath2D(path2, label, mapper) {
@@ -339496,6 +339655,14 @@ function createForgeRuntimeModule(bindings) {
339496
339655
  runtime.default = runtime;
339497
339656
  return runtime;
339498
339657
  }
339658
+ function finalizeForgeJsImport(moduleExports, importedDims) {
339659
+ if (moduleExports instanceof Assembly) {
339660
+ return new ImportedAssembly(moduleExports, moduleExports.getReferences());
339661
+ }
339662
+ if (!(moduleExports instanceof Shape$1)) return moduleExports;
339663
+ if (importedDims.length === 0) return moduleExports;
339664
+ return setShapeDimensions(moduleExports, [...getShapeDimensions(moduleExports), ...importedDims]);
339665
+ }
339499
339666
  const DEFAULT_RAYMARCH_STEPS = 360;
339500
339667
  const MIN_RAYMARCH_STEP = 0.012;
339501
339668
  function classifySdfPreviewNode(node) {
@@ -340417,7 +340584,7 @@ function isRenderableEntryResult(value) {
340417
340584
  return containsRenderableLeaf(value, /* @__PURE__ */ new WeakSet());
340418
340585
  }
340419
340586
  function containsRenderableLeaf(value, seen2) {
340420
- if (value instanceof Shape$1 || value instanceof Sketch || value instanceof SdfShape || value instanceof ShapeGroup || value instanceof GCodeBuilder || value instanceof Assembly || value instanceof SolvedAssembly) {
340587
+ if (value instanceof Shape$1 || value instanceof Sketch || value instanceof SdfShape || value instanceof ShapeGroup || value instanceof GCodeBuilder || value instanceof Assembly || value instanceof ImportedAssembly || value instanceof SolvedAssembly) {
340421
340588
  return true;
340422
340589
  }
340423
340590
  if (!value || typeof value !== "object") return false;
@@ -340439,11 +340606,6 @@ function hasExplicitModuleExports(exportsValue, initialExportsRef) {
340439
340606
  const keys = Object.keys(exportsValue);
340440
340607
  return keys.some((key) => key !== "__esModule");
340441
340608
  }
340442
- function finalizeForgeJsImport(moduleExports, importedDims) {
340443
- if (!(moduleExports instanceof Shape$1)) return moduleExports;
340444
- if (importedDims.length === 0) return moduleExports;
340445
- return setShapeDimensions(moduleExports, [...getShapeDimensions(moduleExports), ...importedDims]);
340446
- }
340447
340609
  function mapScriptResultToScene(args) {
340448
340610
  var _a3;
340449
340611
  const objects = [];
@@ -340571,6 +340733,19 @@ function mapScriptResultToScene(args) {
340571
340733
  value.solve().toSceneObjects().forEach((item, index2) => processNamedItem(item, `${name}.${index2 + 1}`, `${index2 + 1}`, name, treePath, inheritedTags));
340572
340734
  return;
340573
340735
  }
340736
+ if (value instanceof ImportedAssembly) {
340737
+ const group2 = value.toGroup();
340738
+ group2.children.forEach((child, index2) => {
340739
+ flattenGroupChild(
340740
+ child,
340741
+ groupChildLabel(group2, name, index2),
340742
+ name,
340743
+ [...treePath, shapeGroupChildSegment(group2, index2)],
340744
+ mergeSceneTags(inheritedTags, group2.tagsForChild(index2))
340745
+ );
340746
+ });
340747
+ return;
340748
+ }
340574
340749
  if (value instanceof SolvedAssembly) {
340575
340750
  value.toSceneObjects().forEach((item, index2) => processNamedItem(item, `${name}.${index2 + 1}`, `${index2 + 1}`, name, treePath, inheritedTags));
340576
340751
  return;
@@ -340726,6 +340901,12 @@ function mapScriptResultToScene(args) {
340726
340901
  const label = `Object ${index2 + 1}`;
340727
340902
  processNamedItem(item, label, label);
340728
340903
  });
340904
+ } else if (result instanceof ImportedAssembly) {
340905
+ const group2 = result.toGroup();
340906
+ group2.children.forEach((child, index2) => {
340907
+ const label = rootGroupChildLabel(group2, index2);
340908
+ flattenGroupChild(child, label, void 0, [label], group2.tagsForChild(index2));
340909
+ });
340729
340910
  } else if (result instanceof ShapeGroup) {
340730
340911
  result.children.forEach((child, i) => {
340731
340912
  const label = rootGroupChildLabel(result, i);
@@ -340764,7 +340945,7 @@ function mapScriptResultToScene(args) {
340764
340945
  }
340765
340946
  processRenderableTree(item, label, label);
340766
340947
  });
340767
- } else if (result !== null && typeof result === "object" && !Array.isArray(result) && !(result instanceof Shape$1) && !(result instanceof Sketch) && !(result instanceof SdfShape) && !(result instanceof ShapeGroup) && !(result instanceof GCodeBuilder) && !(result instanceof Assembly) && !(result instanceof SolvedAssembly)) {
340948
+ } else if (result !== null && typeof result === "object" && !Array.isArray(result) && !(result instanceof Shape$1) && !(result instanceof Sketch) && !(result instanceof SdfShape) && !(result instanceof ShapeGroup) && !(result instanceof GCodeBuilder) && !(result instanceof Assembly) && !(result instanceof ImportedAssembly) && !(result instanceof SolvedAssembly)) {
340768
340949
  const obj = result;
340769
340950
  const defaultValue = obj.default;
340770
340951
  if (defaultValue && isRenderableEntryResult(defaultValue)) {
@@ -340852,7 +341033,7 @@ Fix one:
340852
341033
  sketch: objects.length === 1 ? objects[0].sketch : null,
340853
341034
  objects,
340854
341035
  extraDimensions: shapeDimensions,
340855
- error: objects.length > 0 || args.allowEmptyResult ? null : "No renderable objects found. Return a Shape, Sketch, SdfShape, array, or object tree containing renderable values."
341036
+ error: objects.length > 0 || args.allowEmptyResult ? null : "No renderable objects found. Return a Shape, Sketch, SdfShape, Assembly, ImportedAssembly, array, or object tree containing renderable values."
340856
341037
  };
340857
341038
  }
340858
341039
  const FORGE_RUNTIME_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["forgecad", "@forge/runtime", "@forgecad/runtime"]);
@@ -341149,6 +341330,7 @@ function executeFile(code, fileName, allFiles, visited, scope = {}, options, exe
341149
341330
  composeChain,
341150
341331
  assembly,
341151
341332
  Assembly,
341333
+ ImportedAssembly,
341152
341334
  port: () => {
341153
341335
  throw new Error("port() has been renamed to connector(). Update your script.");
341154
341336
  },
@@ -341550,7 +341732,7 @@ function runScript(code, fileName = "main.forge.js", allFiles = {}, options = {}
341550
341732
  }
341551
341733
  }
341552
341734
  const DEFAULT_LEAF_SIZE = 8;
341553
- function cloneVec3$1(value) {
341735
+ function cloneVec3$2(value) {
341554
341736
  return [value[0], value[1], value[2]];
341555
341737
  }
341556
341738
  function emptyBounds() {
@@ -341618,14 +341800,14 @@ class AabbSpatialIndex {
341618
341800
  nodeCount += 1;
341619
341801
  const bounds = boundsFor(entries, indexes);
341620
341802
  if (indexes.length <= this.leafSize) {
341621
- return { min: cloneVec3$1(bounds.min), max: cloneVec3$1(bounds.max), left: null, right: null, indexes };
341803
+ return { min: cloneVec3$2(bounds.min), max: cloneVec3$2(bounds.max), left: null, right: null, indexes };
341622
341804
  }
341623
341805
  const axis = longestAxis(bounds);
341624
341806
  indexes.sort((a2, b) => centerOnAxis(entries[a2], axis) - centerOnAxis(entries[b], axis) || a2 - b);
341625
341807
  const mid = Math.max(1, Math.floor(indexes.length / 2));
341626
341808
  return {
341627
- min: cloneVec3$1(bounds.min),
341628
- max: cloneVec3$1(bounds.max),
341809
+ min: cloneVec3$2(bounds.min),
341810
+ max: cloneVec3$2(bounds.max),
341629
341811
  left: build(indexes.slice(0, mid)),
341630
341812
  right: build(indexes.slice(mid)),
341631
341813
  indexes: null
@@ -341691,7 +341873,7 @@ class AabbSpatialIndex {
341691
341873
  const DEFAULT_COLLISION_INSPECTION_OPTIONS = {
341692
341874
  minOverlapVolume: 0.1
341693
341875
  };
341694
- function cloneVec3(value) {
341876
+ function cloneVec3$1(value) {
341695
341877
  return [value[0], value[1], value[2]];
341696
341878
  }
341697
341879
  function isIdentityTransform(matrix) {
@@ -341733,8 +341915,8 @@ function prepareEntry(entry) {
341733
341915
  if (isIdentityTransform(entry.transform)) {
341734
341916
  return {
341735
341917
  ...entry,
341736
- min: cloneVec3(entry.min),
341737
- max: cloneVec3(entry.max)
341918
+ min: cloneVec3$1(entry.min),
341919
+ max: cloneVec3$1(entry.max)
341738
341920
  };
341739
341921
  }
341740
341922
  const bbox = transformBBox(entry.min, entry.max, entry.transform);
@@ -341753,7 +341935,7 @@ function shouldSkipPair(a2, b, options) {
341753
341935
  if (options.skipMockPairs && a2.mock && b.mock) return true;
341754
341936
  return false;
341755
341937
  }
341756
- function collectCandidatePairs(entries, options) {
341938
+ function collectCandidatePairs$1(entries, options) {
341757
341939
  const index2 = new AabbSpatialIndex(entries, 1);
341758
341940
  const result = index2.overlapPairs({
341759
341941
  padding: options.bboxPadding,
@@ -341794,11 +341976,17 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341794
341976
  const warnings = [];
341795
341977
  const collisions = [];
341796
341978
  const preparedEntries = entries.map((entry) => prepareEntry(entry));
341797
- const { pairs: candidatePairs, bboxPairChecks } = collectCandidatePairs(preparedEntries, options);
341798
- const limitedCandidatePairs = options.maxCandidatePairs === null ? candidatePairs : candidatePairs.slice(0, options.maxCandidatePairs);
341799
- const pairLimitSkippedPairCount = candidatePairs.length - limitedCandidatePairs.length;
341979
+ const { pairs: candidatePairs, bboxPairChecks } = collectCandidatePairs$1(preparedEntries, options);
341980
+ const exactCandidatePairs = candidatePairs.filter((pair) => pair.bboxOverlapVolume > options.minOverlapVolume);
341981
+ const bboxVolumePrunedPairCount = candidatePairs.length - exactCandidatePairs.length;
341982
+ const limitedCandidatePairs = options.maxCandidatePairs === null ? exactCandidatePairs : exactCandidatePairs.slice(0, options.maxCandidatePairs);
341983
+ const pairLimitSkippedPairCount = exactCandidatePairs.length - limitedCandidatePairs.length;
341800
341984
  let testedPairCount = 0;
341801
341985
  let timeBudgetStopped = false;
341986
+ const exactCheckedKeys = /* @__PURE__ */ new Set();
341987
+ const pairKey = (pair) => `${pair.sourceIndex}:${pair.targetIndex}`;
341988
+ const exactCandidateKeys = new Set(exactCandidatePairs.map(pairKey));
341989
+ const limitedCandidateKeys = new Set(limitedCandidatePairs.map(pairKey));
341802
341990
  const exactStarted = performance.now();
341803
341991
  for (const pair of limitedCandidatePairs) {
341804
341992
  if (options.maxElapsedMs !== null && (options.maxElapsedMs <= 0 || performance.now() - exactStarted >= options.maxElapsedMs)) {
@@ -341806,6 +341994,7 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341806
341994
  break;
341807
341995
  }
341808
341996
  testedPairCount += 1;
341997
+ exactCheckedKeys.add(pairKey(pair));
341809
341998
  const a2 = preparedEntries[pair.sourceIndex];
341810
341999
  const b = preparedEntries[pair.targetIndex];
341811
342000
  try {
@@ -341836,10 +342025,11 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341836
342025
  const bboxCandidates = options.includeBBoxCandidates ? candidatePairs.map((pair, index2) => {
341837
342026
  const source = preparedEntries[pair.sourceIndex];
341838
342027
  const target = preparedEntries[pair.targetIndex];
341839
- const exactChecked = index2 < testedPairCount;
342028
+ const exactChecked = exactCheckedKeys.has(pairKey(pair));
341840
342029
  let skippedBy;
341841
342030
  if (!exactChecked) {
341842
- skippedBy = index2 >= limitedCandidatePairs.length ? "pair-limit" : "time-budget";
342031
+ const key = pairKey(pair);
342032
+ skippedBy = !exactCandidateKeys.has(key) ? "bbox-volume-threshold" : limitedCandidateKeys.has(key) ? "time-budget" : "pair-limit";
341843
342033
  }
341844
342034
  return {
341845
342035
  index: index2 + 1,
@@ -341872,8 +342062,8 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341872
342062
  treePath: entry.treePath,
341873
342063
  mock: entry.mock === true,
341874
342064
  bbox: {
341875
- min: cloneVec3(entry.min),
341876
- max: cloneVec3(entry.max)
342065
+ min: cloneVec3$1(entry.min),
342066
+ max: cloneVec3$1(entry.max)
341877
342067
  }
341878
342068
  }));
341879
342069
  return {
@@ -341883,10 +342073,12 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341883
342073
  method: "aabb-bvh",
341884
342074
  allPairCount: preparedEntries.length * (preparedEntries.length - 1) / 2,
341885
342075
  bboxPairChecks,
342076
+ bboxVolumePrunedPairCount,
341886
342077
  booleanPairChecks: testedPairCount
341887
342078
  },
341888
342079
  objectCount: objects.length,
341889
342080
  candidatePairCount: candidatePairs.length,
342081
+ bboxVolumePrunedPairCount,
341890
342082
  testedPairCount,
341891
342083
  skippedPairCount,
341892
342084
  pairLimitSkippedPairCount,
@@ -341899,6 +342091,892 @@ function analyzeCollisionIntersections(entries, rawOptions = {}) {
341899
342091
  warnings
341900
342092
  };
341901
342093
  }
342094
+ const SURFACE_FIELD_VERTEX_SHADER = `
342095
+ varying vec3 vWorldPos;
342096
+ varying vec3 vNormalW;
342097
+
342098
+ void main() {
342099
+ vec4 world = modelMatrix * vec4(position, 1.0);
342100
+ vWorldPos = world.xyz;
342101
+ vNormalW = normalize(mat3(modelMatrix) * normal);
342102
+ gl_Position = projectionMatrix * viewMatrix * world;
342103
+ }
342104
+ `;
342105
+ const SURFACE_FIELD_FRAGMENT_SHADER = `
342106
+ uniform float uGlow;
342107
+ uniform float uLineWidth;
342108
+ uniform float uObjectColorMix;
342109
+ uniform float uFieldScale;
342110
+ uniform float uSpacing;
342111
+ uniform int uFieldKind;
342112
+ uniform vec3 uAccentColor;
342113
+ uniform vec3 uBaseColor;
342114
+ uniform vec3 uDarkColor;
342115
+ uniform vec3 uLineColor;
342116
+ uniform vec3 uNodeColor;
342117
+ uniform vec3 uObjectColor;
342118
+
342119
+ varying vec3 vNormalW;
342120
+ varying vec3 vWorldPos;
342121
+
342122
+ float gridLine(float coord, float spacing, float width) {
342123
+ float distanceToLine = abs(fract(coord / spacing + 0.5) - 0.5) * spacing;
342124
+ return 1.0 - smoothstep(width, width * 2.7, distanceToLine);
342125
+ }
342126
+
342127
+ float intersectionFade(float axisNormal) {
342128
+ return 1.0 - smoothstep(0.72, 0.98, abs(axisNormal));
342129
+ }
342130
+
342131
+ void main() {
342132
+ vec3 normalW = normalize(vNormalW);
342133
+ vec3 viewDir = normalize(cameraPosition - vWorldPos);
342134
+ vec3 lightDir = normalize(vec3(-0.38, 0.72, 0.58));
342135
+ float lit = max(dot(normalW, lightDir), 0.0);
342136
+ float rim = pow(1.0 - max(dot(normalW, viewDir), 0.0), 2.35);
342137
+ vec3 fieldPos = vWorldPos / uFieldScale;
342138
+
342139
+ float xFade = intersectionFade(normalW.x);
342140
+ float yFade = intersectionFade(normalW.y);
342141
+ float zFade = intersectionFade(normalW.z);
342142
+
342143
+ float lx = gridLine(fieldPos.x, uSpacing, uLineWidth) * xFade;
342144
+ float ly = gridLine(fieldPos.y, uSpacing, uLineWidth) * yFade;
342145
+ float lz = gridLine(fieldPos.z, uSpacing, uLineWidth) * zFade;
342146
+ float mx = gridLine(fieldPos.x, uSpacing * 0.5, uLineWidth * 0.52) * xFade * 0.34;
342147
+ float my = gridLine(fieldPos.y, uSpacing * 0.5, uLineWidth * 0.52) * yFade * 0.34;
342148
+ float mz = gridLine(fieldPos.z, uSpacing * 0.5, uLineWidth * 0.52) * zFade * 0.34;
342149
+ float majorX = gridLine(fieldPos.x, uSpacing * 4.0, uLineWidth * 1.25) * xFade;
342150
+ float majorY = gridLine(fieldPos.y, uSpacing * 4.0, uLineWidth * 1.25) * yFade;
342151
+ float majorZ = gridLine(fieldPos.z, uSpacing * 4.0, uLineWidth * 1.25) * zFade;
342152
+
342153
+ float contour = max(max(lx, ly), lz);
342154
+ float minorContour = max(max(mx, my), mz);
342155
+ float majorContour = max(max(majorX, majorY), majorZ);
342156
+ float pairNode = max(max(min(lx, ly), min(lx, lz)), min(ly, lz));
342157
+ float topoScale = max(max(lz, mz), majorZ);
342158
+ float lineMask = max(max(contour * 0.74, minorContour), majorContour * 0.54);
342159
+ float nodeMask = pairNode * 0.035;
342160
+
342161
+ if (uFieldKind == 1) {
342162
+ lineMask = max(topoScale, max(mx, my) * 0.42);
342163
+ nodeMask = pairNode * 0.06;
342164
+ }
342165
+
342166
+ vec3 body = mix(uBaseColor, uObjectColor, uObjectColorMix);
342167
+ vec3 base = mix(uDarkColor, body, 0.34 + lit * 0.66) + rim * uAccentColor * 0.14;
342168
+ vec3 color = mix(base, uLineColor, clamp(lineMask * 0.58, 0.0, 1.0));
342169
+ color += uLineColor * lineMask * uGlow * 0.22;
342170
+ color += uNodeColor * nodeMask * uGlow * 0.28;
342171
+ color += sin(gl_FragCoord.y * 3.14159) * 0.008;
342172
+
342173
+ gl_FragColor = vec4(color, 1.0);
342174
+ }
342175
+ `;
342176
+ const ZEBRA_STRIPE_SCALE = 18;
342177
+ const ZEBRA_STRIPE_SOFTNESS = 0.16;
342178
+ const ZEBRA_DARK_COLOR = "#05070a";
342179
+ const ZEBRA_LIGHT_COLOR = "#f2f4ec";
342180
+ const ZEBRA_ACCENT_COLOR = "#3bd6ff";
342181
+ const ZEBRA_STRIPE_VERTEX_SHADER = `
342182
+ varying vec3 vViewNormal;
342183
+ varying vec3 vViewPosition;
342184
+
342185
+ void main() {
342186
+ vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
342187
+ vViewPosition = viewPosition.xyz;
342188
+ vViewNormal = normalize(normalMatrix * normal);
342189
+ gl_Position = projectionMatrix * viewPosition;
342190
+ }
342191
+ `;
342192
+ const ZEBRA_STRIPE_FRAGMENT_SHADER = `
342193
+ precision highp float;
342194
+
342195
+ uniform vec3 uAccentColor;
342196
+ uniform vec3 uDarkColor;
342197
+ uniform vec3 uLightColor;
342198
+ uniform float uStripeScale;
342199
+ uniform float uStripeSoftness;
342200
+
342201
+ varying vec3 vViewNormal;
342202
+ varying vec3 vViewPosition;
342203
+
342204
+ void main() {
342205
+ vec3 normal = normalize(vViewNormal);
342206
+ if (!gl_FrontFacing) {
342207
+ normal = -normal;
342208
+ }
342209
+
342210
+ vec3 eyeDirection = normalize(-vViewPosition);
342211
+ vec3 reflection = normalize(reflect(-eyeDirection, normal));
342212
+ float stripePhase = reflection.x * 0.92 + reflection.y * 0.28 + reflection.z * 0.18;
342213
+ float stripeWave = sin(stripePhase * uStripeScale);
342214
+ float stripeMask = smoothstep(-uStripeSoftness, uStripeSoftness, stripeWave);
342215
+
342216
+ float grazing = pow(1.0 - clamp(dot(normal, eyeDirection), 0.0, 1.0), 1.8);
342217
+ float secondaryWave = sin((reflection.y - reflection.z * 0.45) * uStripeScale * 0.45);
342218
+ float secondary = smoothstep(0.72, 1.0, secondaryWave) * 0.12;
342219
+
342220
+ vec3 bands = mix(uDarkColor, uLightColor, stripeMask);
342221
+ vec3 color = mix(bands, uAccentColor, grazing * 0.18);
342222
+ color += uLightColor * secondary * (0.35 + grazing * 0.4);
342223
+
342224
+ gl_FragColor = vec4(color, 1.0);
342225
+ }
342226
+ `;
342227
+ function isVisibleColor(colors, vertexIndex) {
342228
+ const offset2 = vertexIndex * 3;
342229
+ return colors[offset2] > 1e-6 || colors[offset2 + 1] > 1e-6 || colors[offset2 + 2] > 1e-6;
342230
+ }
342231
+ function copyAttribute(attribute, vertexIndexes) {
342232
+ const itemSize = attribute.itemSize;
342233
+ const source = attribute.array;
342234
+ const out = new Float32Array(vertexIndexes.length * itemSize);
342235
+ vertexIndexes.forEach((vertexIndex, outIndex) => {
342236
+ const sourceOffset = vertexIndex * itemSize;
342237
+ const outOffset = outIndex * itemSize;
342238
+ for (let component = 0; component < itemSize; component += 1) {
342239
+ out[outOffset + component] = source[sourceOffset + component];
342240
+ }
342241
+ });
342242
+ return new BufferAttribute(out, itemSize, attribute.normalized);
342243
+ }
342244
+ function selectedTriangleVertexIndexes(geometry, colors) {
342245
+ const position = geometry.getAttribute("position");
342246
+ if (!position || colors.length !== position.count * 3) return [];
342247
+ const selected = [];
342248
+ const index2 = geometry.getIndex();
342249
+ if (index2) {
342250
+ const values = index2.array;
342251
+ for (let triangle = 0; triangle + 2 < index2.count; triangle += 3) {
342252
+ const a2 = values[triangle];
342253
+ const b = values[triangle + 1];
342254
+ const c2 = values[triangle + 2];
342255
+ if (isVisibleColor(colors, a2) || isVisibleColor(colors, b) || isVisibleColor(colors, c2)) {
342256
+ selected.push(a2, b, c2);
342257
+ }
342258
+ }
342259
+ return selected;
342260
+ }
342261
+ for (let vertex2 = 0; vertex2 + 2 < position.count; vertex2 += 3) {
342262
+ if (isVisibleColor(colors, vertex2) || isVisibleColor(colors, vertex2 + 1) || isVisibleColor(colors, vertex2 + 2)) {
342263
+ selected.push(vertex2, vertex2 + 1, vertex2 + 2);
342264
+ }
342265
+ }
342266
+ return selected;
342267
+ }
342268
+ function geometryWithVisibleVertexColors(geometry, colors) {
342269
+ const vertexIndexes = selectedTriangleVertexIndexes(geometry, colors);
342270
+ if (vertexIndexes.length === 0) return null;
342271
+ const out = new BufferGeometry();
342272
+ for (const name of ["position", "normal"]) {
342273
+ const attribute = geometry.getAttribute(name);
342274
+ if (attribute) out.setAttribute(name, copyAttribute(attribute, vertexIndexes));
342275
+ }
342276
+ const colorAttribute = copyAttribute(new BufferAttribute(colors, 3), vertexIndexes);
342277
+ out.setAttribute("color", colorAttribute);
342278
+ return out;
342279
+ }
342280
+ const DEFAULT_ROUGHNESS_INSPECTION_OPTIONS = {
342281
+ smoothAngleDeg: 5,
342282
+ sharpAngleDeg: 30,
342283
+ harshAngleDeg: 90,
342284
+ maxSamplesPerObject: 5e3
342285
+ };
342286
+ const ROUGHNESS_COLORS = {
342287
+ smooth: [62, 72, 84],
342288
+ moderate: [255, 214, 0],
342289
+ sharp: [255, 124, 34],
342290
+ harsh: [255, 42, 96]
342291
+ };
342292
+ function resolveRoughnessInspectionOptions(raw = {}) {
342293
+ const options = {
342294
+ smoothAngleDeg: raw.smoothAngleDeg ?? DEFAULT_ROUGHNESS_INSPECTION_OPTIONS.smoothAngleDeg,
342295
+ sharpAngleDeg: raw.sharpAngleDeg ?? DEFAULT_ROUGHNESS_INSPECTION_OPTIONS.sharpAngleDeg,
342296
+ harshAngleDeg: raw.harshAngleDeg ?? DEFAULT_ROUGHNESS_INSPECTION_OPTIONS.harshAngleDeg,
342297
+ maxSamplesPerObject: raw.maxSamplesPerObject ?? DEFAULT_ROUGHNESS_INSPECTION_OPTIONS.maxSamplesPerObject
342298
+ };
342299
+ if (!Number.isFinite(options.smoothAngleDeg) || options.smoothAngleDeg < 0) {
342300
+ throw new Error(`smoothAngleDeg must be a finite non-negative angle (got ${options.smoothAngleDeg}).`);
342301
+ }
342302
+ if (!Number.isFinite(options.sharpAngleDeg) || options.sharpAngleDeg <= options.smoothAngleDeg) {
342303
+ throw new Error(`sharpAngleDeg must be greater than smoothAngleDeg (got ${options.sharpAngleDeg}).`);
342304
+ }
342305
+ if (!Number.isFinite(options.harshAngleDeg) || options.harshAngleDeg <= options.sharpAngleDeg || options.harshAngleDeg > 180) {
342306
+ throw new Error(`harshAngleDeg must be greater than sharpAngleDeg and <= 180 (got ${options.harshAngleDeg}).`);
342307
+ }
342308
+ if (!Number.isFinite(options.maxSamplesPerObject) || options.maxSamplesPerObject <= 0) {
342309
+ throw new Error(`maxSamplesPerObject must be a positive finite number (got ${options.maxSamplesPerObject}).`);
342310
+ }
342311
+ return {
342312
+ ...options,
342313
+ maxSamplesPerObject: Math.max(1, Math.floor(options.maxSamplesPerObject))
342314
+ };
342315
+ }
342316
+ function roughnessClassForAngle(angleDeg, options) {
342317
+ if (angleDeg >= options.harshAngleDeg) return "harsh";
342318
+ if (angleDeg >= options.sharpAngleDeg) return "sharp";
342319
+ if (angleDeg >= options.smoothAngleDeg) return "moderate";
342320
+ return "smooth";
342321
+ }
342322
+ function roughnessScoreForAngle(angleDeg, options) {
342323
+ if (angleDeg < options.sharpAngleDeg) return 0;
342324
+ if (angleDeg < options.harshAngleDeg) {
342325
+ return MathUtils.lerp(0.48, 0.82, (angleDeg - options.sharpAngleDeg) / (options.harshAngleDeg - options.sharpAngleDeg));
342326
+ }
342327
+ return 1;
342328
+ }
342329
+ function roughnessColorForAngle(angleDeg, options) {
342330
+ const cls = roughnessClassForAngle(angleDeg, options);
342331
+ if (cls === "smooth" || cls === "harsh") return ROUGHNESS_COLORS[cls];
342332
+ if (cls === "moderate") {
342333
+ return lerpRgb(
342334
+ ROUGHNESS_COLORS.moderate,
342335
+ ROUGHNESS_COLORS.sharp,
342336
+ (angleDeg - options.smoothAngleDeg) / (options.sharpAngleDeg - options.smoothAngleDeg)
342337
+ );
342338
+ }
342339
+ return lerpRgb(
342340
+ ROUGHNESS_COLORS.sharp,
342341
+ ROUGHNESS_COLORS.harsh,
342342
+ (angleDeg - options.sharpAngleDeg) / (options.harshAngleDeg - options.sharpAngleDeg)
342343
+ );
342344
+ }
342345
+ function lerpRgb(a2, b, t) {
342346
+ const clamped = MathUtils.clamp(t, 0, 1);
342347
+ return [
342348
+ Math.round(MathUtils.lerp(a2[0], b[0], clamped)),
342349
+ Math.round(MathUtils.lerp(a2[1], b[1], clamped)),
342350
+ Math.round(MathUtils.lerp(a2[2], b[2], clamped))
342351
+ ];
342352
+ }
342353
+ const AXIS_NAMES = ["x", "y", "z"];
342354
+ function nearestBoundaryGap(a2, b, axis) {
342355
+ return Math.min(Math.abs(a2.max[axis] - b.min[axis]), Math.abs(b.max[axis] - a2.min[axis]));
342356
+ }
342357
+ function hasPositiveGap(gaps) {
342358
+ return gaps[0] > 0 || gaps[1] > 0 || gaps[2] > 0;
342359
+ }
342360
+ function contactFromBBoxes(a2, b, tolerance) {
342361
+ const gaps = aabbGaps(a2, b);
342362
+ const largestGap = Math.max(gaps[0], gaps[1], gaps[2]);
342363
+ if (largestGap > tolerance) return { touching: false, gap: largestGap };
342364
+ const separatedAxes = gaps.map((gap, axis) => ({ gap, axis })).filter((entry) => entry.gap > 0);
342365
+ if (separatedAxes.length > 0) {
342366
+ const nearest2 = separatedAxes.reduce((best, entry) => entry.gap > best.gap ? entry : best, separatedAxes[0]);
342367
+ return { touching: true, gap: nearest2.gap, axis: AXIS_NAMES[nearest2.axis] };
342368
+ }
342369
+ const boundaryAxes = AXIS_NAMES.map((axisName, axis) => ({
342370
+ axis,
342371
+ axisName,
342372
+ gap: nearestBoundaryGap(a2, b, axis)
342373
+ })).filter((entry) => entry.gap <= tolerance);
342374
+ if (boundaryAxes.length === 0) return { touching: false, gap: 0 };
342375
+ const nearest = boundaryAxes.reduce((best, entry) => entry.gap < best.gap ? entry : best, boundaryAxes[0]);
342376
+ return { touching: true, gap: nearest.gap, axis: nearest.axisName };
342377
+ }
342378
+ function isFiniteTriangle(positions, offset2) {
342379
+ for (let index2 = 0; index2 < 9; index2 += 1) {
342380
+ if (!Number.isFinite(positions[offset2 + index2])) return false;
342381
+ }
342382
+ return true;
342383
+ }
342384
+ function triangleRef(positions, offset2) {
342385
+ if (!isFiniteTriangle(positions, offset2)) return null;
342386
+ const ax = positions[offset2];
342387
+ const ay = positions[offset2 + 1];
342388
+ const az = positions[offset2 + 2];
342389
+ const bx = positions[offset2 + 3];
342390
+ const by = positions[offset2 + 4];
342391
+ const bz = positions[offset2 + 5];
342392
+ const cx = positions[offset2 + 6];
342393
+ const cy = positions[offset2 + 7];
342394
+ const cz = positions[offset2 + 8];
342395
+ return {
342396
+ offset: offset2,
342397
+ min: [Math.min(ax, bx, cx), Math.min(ay, by, cy), Math.min(az, bz, cz)],
342398
+ max: [Math.max(ax, bx, cx), Math.max(ay, by, cy), Math.max(az, bz, cz)]
342399
+ };
342400
+ }
342401
+ function meshContactDataFor(entry) {
342402
+ const positions = entry.positions;
342403
+ if (!positions || positions.length < 9) return null;
342404
+ const triangleCount = Math.floor(positions.length / 9);
342405
+ const triangles = [];
342406
+ for (let triangleIndex = 0; triangleIndex < triangleCount; triangleIndex += 1) {
342407
+ const triangle = triangleRef(positions, triangleIndex * 9);
342408
+ if (triangle) triangles.push(triangle);
342409
+ }
342410
+ if (triangles.length === 0) return null;
342411
+ return {
342412
+ positions,
342413
+ vertexCount: triangleCount * 3,
342414
+ triangles
342415
+ };
342416
+ }
342417
+ function distSq(px2, py2, pz2, qx, qy, qz) {
342418
+ const dx = px2 - qx;
342419
+ const dy = py2 - qy;
342420
+ const dz = pz2 - qz;
342421
+ return dx * dx + dy * dy + dz * dz;
342422
+ }
342423
+ function pointSegmentDistanceSq(point2, start, end) {
342424
+ const dx = end[0] - start[0];
342425
+ const dy = end[1] - start[1];
342426
+ const dz = end[2] - start[2];
342427
+ const lengthSq = dx * dx + dy * dy + dz * dz;
342428
+ if (lengthSq <= 1e-20) return distSq(point2[0], point2[1], point2[2], start[0], start[1], start[2]);
342429
+ const t = Math.max(0, Math.min(1, ((point2[0] - start[0]) * dx + (point2[1] - start[1]) * dy + (point2[2] - start[2]) * dz) / lengthSq));
342430
+ return distSq(point2[0], point2[1], point2[2], start[0] + t * dx, start[1] + t * dy, start[2] + t * dz);
342431
+ }
342432
+ function pointTriangleDistanceSq(px2, py2, pz2, ax, ay, az, bx, by, bz, cx, cy, cz) {
342433
+ const abx = bx - ax;
342434
+ const aby = by - ay;
342435
+ const abz = bz - az;
342436
+ const acx = cx - ax;
342437
+ const acy = cy - ay;
342438
+ const acz = cz - az;
342439
+ const apx = px2 - ax;
342440
+ const apy = py2 - ay;
342441
+ const apz = pz2 - az;
342442
+ const d1 = abx * apx + aby * apy + abz * apz;
342443
+ const d2 = acx * apx + acy * apy + acz * apz;
342444
+ if (d1 <= 0 && d2 <= 0) return distSq(px2, py2, pz2, ax, ay, az);
342445
+ const bpx = px2 - bx;
342446
+ const bpy = py2 - by;
342447
+ const bpz = pz2 - bz;
342448
+ const d3 = abx * bpx + aby * bpy + abz * bpz;
342449
+ const d4 = acx * bpx + acy * bpy + acz * bpz;
342450
+ if (d3 >= 0 && d4 <= d3) return distSq(px2, py2, pz2, bx, by, bz);
342451
+ const vc = d1 * d4 - d3 * d2;
342452
+ if (vc <= 0 && d1 >= 0 && d3 <= 0) {
342453
+ const v22 = d1 / (d1 - d3);
342454
+ return distSq(px2, py2, pz2, ax + v22 * abx, ay + v22 * aby, az + v22 * abz);
342455
+ }
342456
+ const cpx = px2 - cx;
342457
+ const cpy = py2 - cy;
342458
+ const cpz = pz2 - cz;
342459
+ const d5 = abx * cpx + aby * cpy + abz * cpz;
342460
+ const d6 = acx * cpx + acy * cpy + acz * cpz;
342461
+ if (d6 >= 0 && d5 <= d6) return distSq(px2, py2, pz2, cx, cy, cz);
342462
+ const vb = d5 * d2 - d1 * d6;
342463
+ if (vb <= 0 && d2 >= 0 && d6 <= 0) {
342464
+ const w22 = d2 / (d2 - d6);
342465
+ return distSq(px2, py2, pz2, ax + w22 * acx, ay + w22 * acy, az + w22 * acz);
342466
+ }
342467
+ const va = d3 * d6 - d5 * d4;
342468
+ if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0) {
342469
+ const bcx = cx - bx;
342470
+ const bcy = cy - by;
342471
+ const bcz = cz - bz;
342472
+ const w22 = (d4 - d3) / (d4 - d3 + d5 - d6);
342473
+ return distSq(px2, py2, pz2, bx + w22 * bcx, by + w22 * bcy, bz + w22 * bcz);
342474
+ }
342475
+ const barycentricTotal = va + vb + vc;
342476
+ if (!Number.isFinite(barycentricTotal) || Math.abs(barycentricTotal) < 1e-20) {
342477
+ return Math.min(distSq(px2, py2, pz2, ax, ay, az), distSq(px2, py2, pz2, bx, by, bz), distSq(px2, py2, pz2, cx, cy, cz));
342478
+ }
342479
+ const denom = 1 / barycentricTotal;
342480
+ const v = vb * denom;
342481
+ const w2 = vc * denom;
342482
+ return distSq(px2, py2, pz2, ax + abx * v + acx * w2, ay + aby * v + acy * w2, az + abz * v + acz * w2);
342483
+ }
342484
+ function segmentSegmentDistanceSq(a0, a1, b0, b1) {
342485
+ const ux = a1[0] - a0[0];
342486
+ const uy = a1[1] - a0[1];
342487
+ const uz = a1[2] - a0[2];
342488
+ const vx = b1[0] - b0[0];
342489
+ const vy = b1[1] - b0[1];
342490
+ const vz = b1[2] - b0[2];
342491
+ const wx = a0[0] - b0[0];
342492
+ const wy = a0[1] - b0[1];
342493
+ const wz = a0[2] - b0[2];
342494
+ const a2 = ux * ux + uy * uy + uz * uz;
342495
+ const b = ux * vx + uy * vy + uz * vz;
342496
+ const c2 = vx * vx + vy * vy + vz * vz;
342497
+ const d2 = ux * wx + uy * wy + uz * wz;
342498
+ const e = vx * wx + vy * wy + vz * wz;
342499
+ const denom = a2 * c2 - b * b;
342500
+ let sNumerator = denom;
342501
+ let sDenominator = denom;
342502
+ let tNumerator = denom;
342503
+ let tDenominator = denom;
342504
+ if (a2 <= 1e-20) return pointSegmentDistanceSq(a0, b0, b1);
342505
+ if (c2 <= 1e-20) return pointSegmentDistanceSq(b0, a0, a1);
342506
+ if (denom < 1e-20) {
342507
+ sNumerator = 0;
342508
+ sDenominator = 1;
342509
+ tNumerator = e;
342510
+ tDenominator = c2;
342511
+ } else {
342512
+ sNumerator = b * e - c2 * d2;
342513
+ tNumerator = a2 * e - b * d2;
342514
+ if (sNumerator < 0) {
342515
+ sNumerator = 0;
342516
+ tNumerator = e;
342517
+ tDenominator = c2;
342518
+ } else if (sNumerator > sDenominator) {
342519
+ sNumerator = sDenominator;
342520
+ tNumerator = e + b;
342521
+ tDenominator = c2;
342522
+ }
342523
+ }
342524
+ if (tNumerator < 0) {
342525
+ tNumerator = 0;
342526
+ if (-d2 < 0) {
342527
+ sNumerator = 0;
342528
+ } else if (-d2 > a2) {
342529
+ sNumerator = sDenominator;
342530
+ } else {
342531
+ sNumerator = -d2;
342532
+ sDenominator = a2;
342533
+ }
342534
+ } else if (tNumerator > tDenominator) {
342535
+ tNumerator = tDenominator;
342536
+ if (-d2 + b < 0) {
342537
+ sNumerator = 0;
342538
+ } else if (-d2 + b > a2) {
342539
+ sNumerator = sDenominator;
342540
+ } else {
342541
+ sNumerator = -d2 + b;
342542
+ sDenominator = a2;
342543
+ }
342544
+ }
342545
+ const s = Math.abs(sNumerator) < 1e-20 ? 0 : sNumerator / sDenominator;
342546
+ const t = Math.abs(tNumerator) < 1e-20 ? 0 : tNumerator / tDenominator;
342547
+ const dx = wx + s * ux - t * vx;
342548
+ const dy = wy + s * uy - t * vy;
342549
+ const dz = wz + s * uz - t * vz;
342550
+ return dx * dx + dy * dy + dz * dz;
342551
+ }
342552
+ function trianglePoint(positions, triangle, corner) {
342553
+ const offset2 = triangle.offset + corner * 3;
342554
+ return [positions[offset2], positions[offset2 + 1], positions[offset2 + 2]];
342555
+ }
342556
+ function bboxDistanceSq(a2, b) {
342557
+ let total = 0;
342558
+ for (let axis = 0; axis < 3; axis += 1) {
342559
+ const gap = Math.max(0, a2.min[axis] - b.max[axis], b.min[axis] - a2.max[axis]);
342560
+ total += gap * gap;
342561
+ }
342562
+ return total;
342563
+ }
342564
+ function triangleDistanceSq(aPositions, a2, bPositions, b) {
342565
+ const a0 = trianglePoint(aPositions, a2, 0);
342566
+ const a1 = trianglePoint(aPositions, a2, 1);
342567
+ const a22 = trianglePoint(aPositions, a2, 2);
342568
+ const b0 = trianglePoint(bPositions, b, 0);
342569
+ const b1 = trianglePoint(bPositions, b, 1);
342570
+ const b22 = trianglePoint(bPositions, b, 2);
342571
+ return Math.min(
342572
+ pointTriangleDistanceSq(a0[0], a0[1], a0[2], b0[0], b0[1], b0[2], b1[0], b1[1], b1[2], b22[0], b22[1], b22[2]),
342573
+ pointTriangleDistanceSq(a1[0], a1[1], a1[2], b0[0], b0[1], b0[2], b1[0], b1[1], b1[2], b22[0], b22[1], b22[2]),
342574
+ pointTriangleDistanceSq(a22[0], a22[1], a22[2], b0[0], b0[1], b0[2], b1[0], b1[1], b1[2], b22[0], b22[1], b22[2]),
342575
+ pointTriangleDistanceSq(b0[0], b0[1], b0[2], a0[0], a0[1], a0[2], a1[0], a1[1], a1[2], a22[0], a22[1], a22[2]),
342576
+ pointTriangleDistanceSq(b1[0], b1[1], b1[2], a0[0], a0[1], a0[2], a1[0], a1[1], a1[2], a22[0], a22[1], a22[2]),
342577
+ pointTriangleDistanceSq(b22[0], b22[1], b22[2], a0[0], a0[1], a0[2], a1[0], a1[1], a1[2], a22[0], a22[1], a22[2]),
342578
+ segmentSegmentDistanceSq(a0, a1, b0, b1),
342579
+ segmentSegmentDistanceSq(a0, a1, b1, b22),
342580
+ segmentSegmentDistanceSq(a0, a1, b22, b0),
342581
+ segmentSegmentDistanceSq(a1, a22, b0, b1),
342582
+ segmentSegmentDistanceSq(a1, a22, b1, b22),
342583
+ segmentSegmentDistanceSq(a1, a22, b22, b0),
342584
+ segmentSegmentDistanceSq(a22, a0, b0, b1),
342585
+ segmentSegmentDistanceSq(a22, a0, b1, b22),
342586
+ segmentSegmentDistanceSq(a22, a0, b22, b0)
342587
+ );
342588
+ }
342589
+ function meshEntriesContactDistance(a2, b, tolerance) {
342590
+ const toleranceSq = tolerance * tolerance;
342591
+ let bestDistanceSq = Infinity;
342592
+ for (const aTriangle of a2.triangles) {
342593
+ for (const bTriangle of b.triangles) {
342594
+ if (bboxDistanceSq(aTriangle, bTriangle) > toleranceSq) continue;
342595
+ const distanceSq = triangleDistanceSq(a2.positions, aTriangle, b.positions, bTriangle);
342596
+ if (distanceSq > toleranceSq) continue;
342597
+ if (distanceSq <= 1e-20) return 0;
342598
+ bestDistanceSq = Math.min(bestDistanceSq, distanceSq);
342599
+ }
342600
+ }
342601
+ return Number.isFinite(bestDistanceSq) ? Math.sqrt(bestDistanceSq) : null;
342602
+ }
342603
+ function intersectionVolume(a2, b) {
342604
+ try {
342605
+ const hit = a2.shape.intersect(b.shape);
342606
+ if (hit.isEmpty()) return { volume: 0 };
342607
+ const volume = hit.volume();
342608
+ return { volume: Number.isFinite(volume) ? volume : 0 };
342609
+ } catch (err2) {
342610
+ const message = err2 instanceof Error ? err2.message : String(err2);
342611
+ return { volume: null, warning: `Could not boolean-test ${a2.name} against ${b.name}: ${message}` };
342612
+ }
342613
+ }
342614
+ function detectPhysicalContact(a2, b, options, meshCache = {}) {
342615
+ const gaps = aabbGaps(a2, b);
342616
+ const largestGap = Math.max(gaps[0], gaps[1], gaps[2]);
342617
+ if (largestGap > options.contactTolerance) return { contact: null };
342618
+ const sourceMesh = meshCache.sourceMesh !== void 0 ? meshCache.sourceMesh : meshContactDataFor(a2);
342619
+ const targetMesh = meshCache.targetMesh !== void 0 ? meshCache.targetMesh : meshContactDataFor(b);
342620
+ if (sourceMesh && targetMesh) {
342621
+ const distance2 = meshEntriesContactDistance(sourceMesh, targetMesh, options.contactTolerance);
342622
+ if (distance2 != null) {
342623
+ return {
342624
+ contact: {
342625
+ kind: "touching",
342626
+ method: "mesh-surface-distance",
342627
+ gap: distance2
342628
+ }
342629
+ };
342630
+ }
342631
+ }
342632
+ const bboxOverlaps = !hasPositiveGap(gaps) && aabbInteriorOverlaps(a2, b);
342633
+ if (options.exactGeometry && bboxOverlaps) {
342634
+ if (aabbOverlapVolume(a2, b) <= options.minOverlapVolume) return { contact: null };
342635
+ const overlap = intersectionVolume(a2, b);
342636
+ if (overlap.volume != null && overlap.volume > options.minOverlapVolume) {
342637
+ return {
342638
+ contact: {
342639
+ kind: "overlap",
342640
+ method: "boolean-intersection",
342641
+ gap: 0,
342642
+ overlapVolume: overlap.volume
342643
+ },
342644
+ warning: overlap.warning
342645
+ };
342646
+ }
342647
+ return { contact: null, warning: overlap.warning };
342648
+ }
342649
+ if (bboxOverlaps && options.mergeOverlappingBBoxes) {
342650
+ return {
342651
+ contact: {
342652
+ kind: "overlap",
342653
+ method: "bbox-overlap",
342654
+ gap: 0,
342655
+ overlapVolume: aabbOverlapVolume(a2, b)
342656
+ }
342657
+ };
342658
+ }
342659
+ if (options.mergeTouchingBBoxes) {
342660
+ const contact = contactFromBBoxes(a2, b, options.contactTolerance);
342661
+ if (contact.touching) {
342662
+ return {
342663
+ contact: {
342664
+ kind: "touching",
342665
+ method: "bbox-contact",
342666
+ gap: contact.gap,
342667
+ axis: contact.axis
342668
+ }
342669
+ };
342670
+ }
342671
+ }
342672
+ return { contact: null };
342673
+ }
342674
+ const DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS = {
342675
+ contactTolerance: 0.05,
342676
+ minOverlapVolume: 0.1,
342677
+ exactGeometry: true
342678
+ };
342679
+ class UnionFind {
342680
+ constructor(size) {
342681
+ __publicField(this, "parent");
342682
+ __publicField(this, "rank");
342683
+ this.parent = Array.from({ length: size }, (_2, index2) => index2);
342684
+ this.rank = Array.from({ length: size }, () => 0);
342685
+ }
342686
+ find(value) {
342687
+ const parent = this.parent[value];
342688
+ if (parent === value) return value;
342689
+ const root = this.find(parent);
342690
+ this.parent[value] = root;
342691
+ return root;
342692
+ }
342693
+ union(a2, b) {
342694
+ const rootA = this.find(a2);
342695
+ const rootB = this.find(b);
342696
+ if (rootA === rootB) return;
342697
+ if (this.rank[rootA] < this.rank[rootB]) {
342698
+ this.parent[rootA] = rootB;
342699
+ return;
342700
+ }
342701
+ if (this.rank[rootA] > this.rank[rootB]) {
342702
+ this.parent[rootB] = rootA;
342703
+ return;
342704
+ }
342705
+ this.parent[rootB] = rootA;
342706
+ this.rank[rootA] += 1;
342707
+ }
342708
+ }
342709
+ function cloneVec3(value) {
342710
+ return [value[0], value[1], value[2]];
342711
+ }
342712
+ function emptyBBox() {
342713
+ return {
342714
+ min: [Infinity, Infinity, Infinity],
342715
+ max: [-Infinity, -Infinity, -Infinity]
342716
+ };
342717
+ }
342718
+ function expandBBox(target, min2, max2) {
342719
+ for (let axis = 0; axis < 3; axis += 1) {
342720
+ target.min[axis] = Math.min(target.min[axis], min2[axis]);
342721
+ target.max[axis] = Math.max(target.max[axis], max2[axis]);
342722
+ }
342723
+ }
342724
+ function collectCandidatePairs(entries, tolerance) {
342725
+ if (entries.length < 2) return [];
342726
+ const index2 = new AabbSpatialIndex(entries);
342727
+ const pairs = index2.overlapPairs({ padding: tolerance }).pairs.map((pair) => ({
342728
+ sourceIndex: pair.sourceIndex,
342729
+ targetIndex: pair.targetIndex,
342730
+ gaps: aabbGaps(entries[pair.sourceIndex], entries[pair.targetIndex])
342731
+ })).filter((pair) => Math.max(pair.gaps[0], pair.gaps[1], pair.gaps[2]) <= tolerance);
342732
+ pairs.sort((a2, b) => a2.sourceIndex - b.sourceIndex || a2.targetIndex - b.targetIndex);
342733
+ return pairs;
342734
+ }
342735
+ function bodyCountForEntry(entry) {
342736
+ if (typeof entry.bodyCount === "number" && Number.isFinite(entry.bodyCount)) {
342737
+ return Math.max(0, Math.round(entry.bodyCount));
342738
+ }
342739
+ return 1;
342740
+ }
342741
+ function makeEdge(entries, sourceIndex, targetIndex, edge) {
342742
+ const source = entries[sourceIndex];
342743
+ const target = entries[targetIndex];
342744
+ return {
342745
+ sourceIndex,
342746
+ targetIndex,
342747
+ sourceId: source.id,
342748
+ targetId: target.id,
342749
+ sourceName: source.name,
342750
+ targetName: target.name,
342751
+ ...edge
342752
+ };
342753
+ }
342754
+ function analyzePhysicalConnectivity(entries, rawOptions = {}) {
342755
+ const exactGeometry = rawOptions.exactGeometry ?? DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS.exactGeometry;
342756
+ const options = {
342757
+ contactTolerance: rawOptions.contactTolerance ?? DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS.contactTolerance,
342758
+ minOverlapVolume: rawOptions.minOverlapVolume ?? DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS.minOverlapVolume,
342759
+ exactGeometry,
342760
+ mergeOverlappingBBoxes: rawOptions.mergeOverlappingBBoxes ?? !exactGeometry,
342761
+ mergeTouchingBBoxes: rawOptions.mergeTouchingBBoxes ?? !exactGeometry
342762
+ };
342763
+ const warnings = [];
342764
+ const edges = [];
342765
+ const unionFind = new UnionFind(entries.length);
342766
+ const meshDataByIndex = /* @__PURE__ */ new Map();
342767
+ entries.forEach((entry, index2) => {
342768
+ const meshData = meshContactDataFor(entry);
342769
+ if (meshData) meshDataByIndex.set(index2, meshData);
342770
+ });
342771
+ for (const pair of collectCandidatePairs(entries, options.contactTolerance)) {
342772
+ const i = pair.sourceIndex;
342773
+ const j = pair.targetIndex;
342774
+ const detection = detectPhysicalContact(entries[i], entries[j], options, {
342775
+ sourceMesh: meshDataByIndex.get(i) ?? null,
342776
+ targetMesh: meshDataByIndex.get(j) ?? null
342777
+ });
342778
+ if (detection.warning) warnings.push(detection.warning);
342779
+ if (!detection.contact) continue;
342780
+ unionFind.union(i, j);
342781
+ edges.push(makeEdge(entries, i, j, detection.contact));
342782
+ }
342783
+ const objects = entries.map((entry, index2) => ({
342784
+ index: index2,
342785
+ id: entry.id,
342786
+ name: entry.name,
342787
+ groupName: entry.groupName,
342788
+ treePath: entry.treePath,
342789
+ mock: entry.mock === true,
342790
+ bodyCount: bodyCountForEntry(entry),
342791
+ bbox: {
342792
+ min: cloneVec3(entry.min),
342793
+ max: cloneVec3(entry.max)
342794
+ },
342795
+ componentIndex: 0
342796
+ }));
342797
+ const componentByRoot = /* @__PURE__ */ new Map();
342798
+ const rootToComponentIndex = /* @__PURE__ */ new Map();
342799
+ for (let objectIndex = 0; objectIndex < objects.length; objectIndex += 1) {
342800
+ const root = unionFind.find(objectIndex);
342801
+ let component = componentByRoot.get(root);
342802
+ if (!component) {
342803
+ component = {
342804
+ index: componentByRoot.size + 1,
342805
+ objectIndexes: [],
342806
+ objectIds: [],
342807
+ objectNames: [],
342808
+ objectCount: 0,
342809
+ bodyCount: 0,
342810
+ bbox: emptyBBox()
342811
+ };
342812
+ componentByRoot.set(root, component);
342813
+ rootToComponentIndex.set(root, component.index);
342814
+ }
342815
+ const object = objects[objectIndex];
342816
+ object.componentIndex = rootToComponentIndex.get(root) ?? component.index;
342817
+ component.objectIndexes.push(object.index);
342818
+ component.objectIds.push(object.id);
342819
+ component.objectNames.push(object.name);
342820
+ component.objectCount += 1;
342821
+ component.bodyCount += object.bodyCount;
342822
+ expandBBox(component.bbox, object.bbox.min, object.bbox.max);
342823
+ }
342824
+ const components = [...componentByRoot.values()];
342825
+ return {
342826
+ method: options.exactGeometry ? "mesh-contact-plus-boolean-overlap" : "bbox-neighborhood",
342827
+ options,
342828
+ objectCount: objects.length,
342829
+ componentCount: components.length,
342830
+ objects,
342831
+ components,
342832
+ edges,
342833
+ warnings
342834
+ };
342835
+ }
342836
+ const DEFAULT_THICKNESS_INSPECTION_OPTIONS = {
342837
+ minThickness: 1.2,
342838
+ warnThickness: 2,
342839
+ maxThickness: 6,
342840
+ maxSamplesPerObject: 5e3,
342841
+ contactTolerance: DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS.contactTolerance
342842
+ };
342843
+ const THICKNESS_COLORS = {
342844
+ critical: [255, 28, 28],
342845
+ warning: [255, 150, 0],
342846
+ ok: [60, 220, 90],
342847
+ thick: [70, 145, 255],
342848
+ unknown: [90, 90, 90]
342849
+ };
342850
+ function finitePositive(value, fallback, label) {
342851
+ if (value === void 0) return fallback;
342852
+ if (!Number.isFinite(value) || value <= 0) {
342853
+ throw new Error(`${label} must be a positive finite number.`);
342854
+ }
342855
+ return value;
342856
+ }
342857
+ function finiteNonNegative(value, fallback, label) {
342858
+ if (value === void 0) return fallback;
342859
+ if (!Number.isFinite(value) || value < 0) {
342860
+ throw new Error(`${label} must be a non-negative finite number.`);
342861
+ }
342862
+ return value;
342863
+ }
342864
+ function resolveThicknessInspectionOptions(raw = {}) {
342865
+ const minThickness = finitePositive(raw.minThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.minThickness, "minThickness");
342866
+ const warnThickness = finitePositive(raw.warnThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.warnThickness, "warnThickness");
342867
+ const maxThickness = finitePositive(raw.maxThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.maxThickness, "maxThickness");
342868
+ const maxSamplesPerObject = finitePositive(
342869
+ raw.maxSamplesPerObject,
342870
+ DEFAULT_THICKNESS_INSPECTION_OPTIONS.maxSamplesPerObject,
342871
+ "maxSamplesPerObject"
342872
+ );
342873
+ const contactTolerance = finiteNonNegative(
342874
+ raw.contactTolerance,
342875
+ DEFAULT_THICKNESS_INSPECTION_OPTIONS.contactTolerance,
342876
+ "contactTolerance"
342877
+ );
342878
+ if (minThickness > warnThickness) {
342879
+ throw new Error("minThickness must be less than or equal to warnThickness.");
342880
+ }
342881
+ if (warnThickness > maxThickness) {
342882
+ throw new Error("warnThickness must be less than or equal to maxThickness.");
342883
+ }
342884
+ return {
342885
+ minThickness,
342886
+ warnThickness,
342887
+ maxThickness,
342888
+ maxSamplesPerObject: Math.max(1, Math.floor(maxSamplesPerObject)),
342889
+ contactTolerance
342890
+ };
342891
+ }
342892
+ function lerp(a2, b, t) {
342893
+ return a2 + (b - a2) * Math.max(0, Math.min(1, t));
342894
+ }
342895
+ function lerpColor(a2, b, t) {
342896
+ return [Math.round(lerp(a2[0], b[0], t)), Math.round(lerp(a2[1], b[1], t)), Math.round(lerp(a2[2], b[2], t))];
342897
+ }
342898
+ function thicknessClass(thickness, options) {
342899
+ if (thickness == null || !Number.isFinite(thickness) || thickness <= 0) return "unknown";
342900
+ if (thickness <= options.minThickness) return "critical";
342901
+ if (thickness <= options.warnThickness) return "warning";
342902
+ if (thickness <= options.maxThickness) return "ok";
342903
+ return "thick";
342904
+ }
342905
+ function thicknessColor(thickness, options) {
342906
+ const cls = thicknessClass(thickness, options);
342907
+ if (cls === "unknown") return THICKNESS_COLORS.unknown;
342908
+ if (cls === "critical") return THICKNESS_COLORS.critical;
342909
+ if (cls === "warning") {
342910
+ const span = Math.max(1e-9, options.warnThickness - options.minThickness);
342911
+ return lerpColor(THICKNESS_COLORS.critical, THICKNESS_COLORS.warning, ((thickness ?? 0) - options.minThickness) / span);
342912
+ }
342913
+ if (cls === "ok") {
342914
+ const span = Math.max(1e-9, options.maxThickness - options.warnThickness);
342915
+ return lerpColor(THICKNESS_COLORS.ok, THICKNESS_COLORS.thick, ((thickness ?? 0) - options.warnThickness) / span);
342916
+ }
342917
+ return THICKNESS_COLORS.thick;
342918
+ }
342919
+ function sampleArea(sample) {
342920
+ const area2 = sample.area ?? 1;
342921
+ return Number.isFinite(area2) && area2 > 0 ? area2 : 1;
342922
+ }
342923
+ function weightedQuantile(samples, q) {
342924
+ if (samples.length === 0) return null;
342925
+ const sorted = [...samples].sort((a2, b) => a2.thickness - b.thickness);
342926
+ const totalArea = sorted.reduce((sum2, sample) => sum2 + sample.area, 0);
342927
+ const target = totalArea * Math.max(0, Math.min(1, q));
342928
+ let cumulative = 0;
342929
+ for (const sample of sorted) {
342930
+ cumulative += sample.area;
342931
+ if (cumulative >= target) return sample.thickness;
342932
+ }
342933
+ return sorted[sorted.length - 1].thickness;
342934
+ }
342935
+ function percent(part, total) {
342936
+ if (total <= 0) return 0;
342937
+ return part / total * 100;
342938
+ }
342939
+ function summarizeThicknessSamples(samples, options) {
342940
+ const resolved = [];
342941
+ let totalArea = 0;
342942
+ let resolvedArea = 0;
342943
+ let unresolvedArea = 0;
342944
+ let criticalArea = 0;
342945
+ let warningArea = 0;
342946
+ let weightedSum = 0;
342947
+ for (const sample of samples) {
342948
+ const area2 = sampleArea(sample);
342949
+ totalArea += area2;
342950
+ const value = sample.thickness;
342951
+ if (value == null || !Number.isFinite(value) || value <= 0) {
342952
+ unresolvedArea += area2;
342953
+ continue;
342954
+ }
342955
+ resolved.push({ thickness: value, area: area2 });
342956
+ resolvedArea += area2;
342957
+ weightedSum += value * area2;
342958
+ if (value <= options.minThickness) {
342959
+ criticalArea += area2;
342960
+ } else if (value <= options.warnThickness) {
342961
+ warningArea += area2;
342962
+ }
342963
+ }
342964
+ const values = resolved.map((sample) => sample.thickness);
342965
+ return {
342966
+ sampleCount: samples.length,
342967
+ resolvedCount: resolved.length,
342968
+ unresolvedCount: samples.length - resolved.length,
342969
+ minThickness: values.length > 0 ? Math.min(...values) : null,
342970
+ p05Thickness: weightedQuantile(resolved, 0.05),
342971
+ medianThickness: weightedQuantile(resolved, 0.5),
342972
+ meanThickness: resolvedArea > 0 ? weightedSum / resolvedArea : null,
342973
+ maxThickness: values.length > 0 ? Math.max(...values) : null,
342974
+ criticalAreaPercent: percent(criticalArea, resolvedArea),
342975
+ warningAreaPercent: percent(warningArea, resolvedArea),
342976
+ belowWarnAreaPercent: percent(criticalArea + warningArea, resolvedArea),
342977
+ unresolvedAreaPercent: percent(unresolvedArea, totalArea)
342978
+ };
342979
+ }
341902
342980
  const VECTOR_KEYS = /* @__PURE__ */ new Set(["pos", "position", "target", "lookat", "aim", "up"]);
341903
342981
  const roundNumber = (value, digits) => {
341904
342982
  const scale2 = 10 ** digits;
@@ -342070,6 +343148,28 @@ function localAabbPlaneRelation(min2, max2, plane, eps = 1e-7) {
342070
343148
  if (minDistance > -eps) return "positive";
342071
343149
  return "crossing";
342072
343150
  }
343151
+ const DEFAULT_SCALAR_SCENE_BUDGET_OBJECTS = 15;
343152
+ const DEFAULT_SCALAR_SCENE_MIN_SAMPLES_PER_OBJECT = 100;
343153
+ function resolveScalarSceneSampleBudget(args) {
343154
+ const objectCount = Math.max(0, Math.floor(args.objectCount));
343155
+ const requestedMaxSamplesPerObject = Math.max(1, Math.floor(args.maxSamplesPerObject));
343156
+ const sceneBudgetObjectCount = Math.max(1, Math.floor(args.sceneBudgetObjectCount ?? DEFAULT_SCALAR_SCENE_BUDGET_OBJECTS));
343157
+ const minSamplesPerObject = Math.max(1, Math.floor(args.minSamplesPerObject ?? DEFAULT_SCALAR_SCENE_MIN_SAMPLES_PER_OBJECT));
343158
+ const explicitMaxSamplesPerObject = args.explicitMaxSamplesPerObject === true;
343159
+ const sceneMaxSamples = requestedMaxSamplesPerObject * sceneBudgetObjectCount;
343160
+ const budgeted = objectCount <= 0 || objectCount <= sceneBudgetObjectCount || explicitMaxSamplesPerObject ? requestedMaxSamplesPerObject : Math.max(minSamplesPerObject, Math.floor(sceneMaxSamples / objectCount));
343161
+ const effectiveMaxSamplesPerObject = Math.min(requestedMaxSamplesPerObject, budgeted);
343162
+ return {
343163
+ objectCount,
343164
+ requestedMaxSamplesPerObject,
343165
+ effectiveMaxSamplesPerObject,
343166
+ sceneBudgetObjectCount,
343167
+ sceneMaxSamples,
343168
+ minSamplesPerObject,
343169
+ explicitMaxSamplesPerObject,
343170
+ capped: effectiveMaxSamplesPerObject < requestedMaxSamplesPerObject
343171
+ };
343172
+ }
342073
343173
  export {
342074
343174
  Matrix4 as $,
342075
343175
  ACESFilmicToneMapping as A,
@@ -342165,7 +343265,7 @@ export {
342165
343265
  DEFAULT_ACTIVE_BACKEND as ay,
342166
343266
  isConstraintSketch as az,
342167
343267
  PCFShadowMap as b,
342168
- initKernelManifoldOnly as b$,
343268
+ analyzePhysicalConnectivity as b$,
342169
343269
  PointLight as b0,
342170
343270
  DirectionalLight as b1,
342171
343271
  analyzeCollisionIntersections as b2,
@@ -342176,61 +343276,85 @@ export {
342176
343276
  runScript as b7,
342177
343277
  MeshPhysicalMaterial as b8,
342178
343278
  LineSegments as b9,
342179
- findJointAnimationClip as bA,
342180
- resolveJointAnimation as bB,
342181
- resolveJointViewValues as bC,
342182
- getShapePorts as bD,
342183
- getShapeUsedPorts as bE,
342184
- DEFAULT_VIEW_CONFIG as bF,
342185
- getKernelFaceNameForTriangle as bG,
342186
- initKernel as bH,
342187
- initSolverWasm as bI,
342188
- BoxGeometry as bJ,
342189
- localAabbPlaneRelation as bK,
342190
- ShapeUtils as bL,
342191
- aabbInteriorOverlaps as bM,
342192
- aabbOverlapVolume as bN,
342193
- AabbSpatialIndex as bO,
342194
- aabbGaps as bP,
342195
- Group as bQ,
342196
- intersectWithPlane as bR,
342197
- parseCameraCliSpec as bS,
342198
- PMREMGenerator as bT,
342199
- PointsMaterial as bU,
342200
- Points$1 as bV,
342201
- serializeCollisionFinding as bW,
342202
- worldAuthorPlaneToLocal as bX,
342203
- generateCuttingLayoutPdf as bY,
342204
- getCameraForwardVector as bZ,
342205
- RENDER_STYLE_OPTIONS as b_,
342206
- getRenderStylePreset as ba,
342207
- AdditiveBlending as bb,
342208
- CatmullRomCurve3 as bc,
342209
- TubeGeometry as bd,
342210
- MeshStandardMaterial as be,
342211
- compileSdfNode3 as bf,
342212
- buildSdfRaymarchFragmentShader as bg,
342213
- SDF_RAYMARCH_PROXY_VERTEX_SHADER as bh,
342214
- Shape2 as bi,
342215
- ShapeGeometry as bj,
342216
- ShaderLib as bk,
342217
- CylinderGeometry as bl,
342218
- parseViewportCameraState as bm,
342219
- createResolvedExplodeConfig as bn,
342220
- explodeBoundsCenter as bo,
342221
- explodeMergeBounds as bp,
342222
- resolveExplodeDirective as bq,
342223
- computeExplodeMotion as br,
342224
- getSketchWorldMatrix as bs,
342225
- explodeAdd as bt,
342226
- hasExplodeOverride as bu,
342227
- resolveExplodeLocalFanDirection as bv,
342228
- explodeMul as bw,
342229
- explodeLeafFanStage as bx,
342230
- normalizeCutPlane as by,
342231
- toClippingPlane as bz,
343279
+ parseViewportCameraState as bA,
343280
+ createResolvedExplodeConfig as bB,
343281
+ explodeBoundsCenter as bC,
343282
+ explodeMergeBounds as bD,
343283
+ resolveExplodeDirective as bE,
343284
+ computeExplodeMotion as bF,
343285
+ getSketchWorldMatrix as bG,
343286
+ explodeAdd as bH,
343287
+ hasExplodeOverride as bI,
343288
+ resolveExplodeLocalFanDirection as bJ,
343289
+ explodeMul as bK,
343290
+ explodeLeafFanStage as bL,
343291
+ normalizeCutPlane as bM,
343292
+ toClippingPlane as bN,
343293
+ findJointAnimationClip as bO,
343294
+ resolveJointAnimation as bP,
343295
+ resolveJointViewValues as bQ,
343296
+ getShapePorts as bR,
343297
+ getShapeUsedPorts as bS,
343298
+ DEFAULT_VIEW_CONFIG as bT,
343299
+ getKernelFaceNameForTriangle as bU,
343300
+ resolveScalarSceneSampleBudget as bV,
343301
+ initKernel as bW,
343302
+ initSolverWasm as bX,
343303
+ BoxGeometry as bY,
343304
+ localAabbPlaneRelation as bZ,
343305
+ ShapeUtils as b_,
343306
+ geometryWithVisibleVertexColors as ba,
343307
+ getRenderStylePreset as bb,
343308
+ AdditiveBlending as bc,
343309
+ ZEBRA_STRIPE_SOFTNESS as bd,
343310
+ ZEBRA_STRIPE_SCALE as be,
343311
+ ZEBRA_LIGHT_COLOR as bf,
343312
+ ZEBRA_DARK_COLOR as bg,
343313
+ ZEBRA_ACCENT_COLOR as bh,
343314
+ ZEBRA_STRIPE_FRAGMENT_SHADER as bi,
343315
+ ZEBRA_STRIPE_VERTEX_SHADER as bj,
343316
+ SURFACE_FIELD_FRAGMENT_SHADER as bk,
343317
+ SURFACE_FIELD_VERTEX_SHADER as bl,
343318
+ CatmullRomCurve3 as bm,
343319
+ TubeGeometry as bn,
343320
+ ROUGHNESS_COLORS as bo,
343321
+ DEFAULT_ROUGHNESS_INSPECTION_OPTIONS as bp,
343322
+ DEFAULT_THICKNESS_INSPECTION_OPTIONS as bq,
343323
+ THICKNESS_COLORS as br,
343324
+ MeshStandardMaterial as bs,
343325
+ compileSdfNode3 as bt,
343326
+ buildSdfRaymarchFragmentShader as bu,
343327
+ SDF_RAYMARCH_PROXY_VERTEX_SHADER as bv,
343328
+ Shape2 as bw,
343329
+ ShapeGeometry as bx,
343330
+ ShaderLib as by,
343331
+ CylinderGeometry as bz,
342232
343332
  SRGBColorSpace as c,
342233
- __viteBrowserExternal$1 as c0,
343333
+ meshContactDataFor as c0,
343334
+ AabbSpatialIndex as c1,
343335
+ detectPhysicalContact as c2,
343336
+ resolveThicknessInspectionOptions as c3,
343337
+ thicknessColor as c4,
343338
+ thicknessClass as c5,
343339
+ roughnessClassForAngle as c6,
343340
+ resolveRoughnessInspectionOptions as c7,
343341
+ roughnessColorForAngle as c8,
343342
+ roughnessScoreForAngle as c9,
343343
+ Group as ca,
343344
+ intersectWithPlane as cb,
343345
+ setActiveBackend as cc,
343346
+ parseCameraCliSpec as cd,
343347
+ PMREMGenerator as ce,
343348
+ PointsMaterial as cf,
343349
+ Points$1 as cg,
343350
+ serializeCollisionFinding as ch,
343351
+ summarizeThicknessSamples as ci,
343352
+ worldAuthorPlaneToLocal as cj,
343353
+ generateCuttingLayoutPdf as ck,
343354
+ getCameraForwardVector as cl,
343355
+ RENDER_STYLE_OPTIONS as cm,
343356
+ initKernelManifoldOnly as cn,
343357
+ __viteBrowserExternal$1 as co,
342234
343358
  Layers as d,
342235
343359
  Color as e,
342236
343360
  RGBAFormat as f,