forgecad 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AdminPage-Da6hhpJx.js → AdminPage-DX0mpSZT.js} +1 -1
- package/dist/assets/{BlogPage-Bl_sKeWb.js → BlogPage-CI_P0_Pf.js} +1 -1
- package/dist/assets/{DocsPage-Blz3Tp4j.js → DocsPage-DLhIIZyJ.js} +3 -3
- package/dist/assets/{EditorApp-CuiPbtn5.js → EditorApp-BujZvuwX.js} +140 -20
- package/dist/assets/{EditorApp-DS0AIUrZ.css → EditorApp-DfFT2Dn8.css} +1 -0
- package/dist/assets/{EmbedViewer-BFG6-Ufm.js → EmbedViewer-0S0qXKog.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-DB9fQd5P.js → LandingPageProofDriven-O_yMtAri.js} +1 -1
- package/dist/assets/{PricingPage-BMxYT_F0.js → PricingPage-DGkX3Ahr.js} +1 -1
- package/dist/assets/{SettingsPage-VVQNrCAg.js → SettingsPage-DBsqTB_y.js} +82 -22
- package/dist/assets/{app-Dl9ymBWC.js → app-BE2nD6Yz.js} +1056 -258
- package/dist/assets/cli/{render-CFtwKCCY.js → render-iP9qh475.js} +1533 -207
- package/dist/assets/{evalWorker-CRvbzTXm.js → evalWorker-Ds5U4xtN.js} +2178 -30
- package/dist/assets/inspectWorker-Dll4eVyD.js +12620 -0
- package/dist/assets/{manifold-DpBXFS2K.js → manifold-Bk26ViCr.js} +1 -1
- package/dist/assets/{manifold-DzZ4VRPs.js → manifold-DjYsd7A_.js} +2 -2
- package/dist/assets/{manifold-B9QSr-qP.js → manifold-sJ-axdXM.js} +1 -1
- package/dist/assets/{renderSceneState-BuAXF2jh.js → renderSceneState-Bngp5MrQ.js} +1 -1
- package/dist/assets/{reportWorker-BNWEnRg1.js → reportWorker-CU8RZ4O0.js} +2161 -30
- package/dist/assets/{distance-BEC2RjJi.js → sectionPlaneMath-BdTjyVfs.js} +2539 -1187
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +1 -1
- package/dist/docs-raw/AI/usage.md +7 -2
- package/dist/docs-raw/CLI.md +82 -53
- package/dist/docs-raw/beta-operations.md +5 -0
- package/dist/docs-raw/coding.md +1 -1
- package/dist/docs-raw/generated/concepts.md +59 -2
- package/dist/docs-raw/generated/core.md +206 -1
- package/dist/docs-raw/generated/lib.md +17 -1
- package/dist/docs-raw/generated/viewport.md +1 -1
- package/dist/docs-raw/guides/inspection-bundles.md +36 -13
- package/dist/docs-raw/platform/auth.md +2 -0
- package/dist/docs-raw/platform/google-oauth-setup.md +4 -0
- package/dist/docs-raw/skills/forgecad-make-a-model.md +87 -8
- package/dist/docs-raw/skills/forgecad-prepare-prompt.md +14 -6
- package/dist/docs-raw/skills/forgecad-render-inspect.md +1 -1
- package/dist/docs-raw/skills/index.md +2 -2
- package/dist/index.html +1 -1
- package/dist/sitemap.xml +6 -6
- package/dist-cli/forgecad.js +7975 -4528
- package/dist-cli/forgecad.js.map +1 -1
- package/dist-skill/CONTEXT.md +260 -16
- package/dist-skill/docs/CLI.md +82 -53
- package/dist-skill/docs/generated/core.md +206 -1
- package/dist-skill/docs/generated/lib.md +17 -1
- package/dist-skill/docs/generated/viewport.md +1 -1
- package/dist-skill/docs/guides/inspection-bundles.md +36 -13
- package/dist-skill/docs-dev/CLI.md +82 -53
- package/dist-skill/docs-dev/coding.md +1 -1
- package/dist-skill/docs-dev/generated/core.md +206 -1
- package/dist-skill/docs-dev/generated/lib.md +17 -1
- package/dist-skill/docs-dev/generated/viewport.md +1 -1
- package/dist-skill/docs-dev/guides/inspection-bundles.md +36 -13
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +87 -8
- package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +14 -6
- package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +5 -3
- package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +7 -5
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +1 -1
- package/examples/api/bolted-service-cover.forge.js +17 -0
- package/examples/api/cable-gland-anchor.forge.js +14 -0
- package/examples/api/captured-cartridge-guide.forge.js +14 -0
- package/examples/api/captured-linear-slide.forge.js +13 -0
- package/examples/api/clevis-pin-joint.forge.js +13 -0
- package/examples/api/datum-enclosure.forge.js +16 -0
- package/examples/api/hose-barb-port.forge.js +14 -0
- package/examples/api/intentional-overlap-overmold.forge.js +16 -0
- package/examples/api/knuckled-hinge-assembly.forge.js +15 -0
- package/examples/api/living-hinge-cover.forge.js +14 -0
- package/examples/api/pcb-terminal-block.forge.js +22 -0
- package/examples/api/pinned-lever-pivot-stack.forge.js +14 -0
- package/examples/api/retained-shaft-knob-stack.forge.js +15 -0
- package/examples/api/routed-tube-clip.forge.js +15 -0
- package/examples/api/seated-bearing-stack.forge.js +30 -0
- package/examples/api/snap-latch-cover.forge.js +14 -0
- package/examples/api/static-assembly-connectors.forge.js +14 -16
- package/examples/api/thumb-screw-clamp.forge.js +15 -0
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-DfFT2Dn8.css","assets/landing-proof-driven-B7_RpP79.css","assets/PricingPage-BMedqFef.css"])))=>i.map(i=>d[i]);
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
var _a2;
|
|
6
|
-
import { c as create,
|
|
7
|
-
import { _ as __vitePreload, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, S as Scene, a as PCFSoftShadowMap, V as VSMShadowMap, b as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, c as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, d as Layers, e as Color, f as RGBAFormat, U as UnsignedByteType, g as Vector3, h as Vector2, i as Clock, T as THREE, D as DoubleSide, j as REVISION, M as Mesh, I as IcosahedronGeometry, k as ShaderMaterial, l as Spherical, Q as Quaternion, m as MOUSE, n as TOUCH, o as Ray, p as Plane, q as DataTextureLoader, H as HalfFloatType, F as FloatType, r as DataUtils, t as LinearFilter, u as RedFormat, v as InstancedBufferGeometry, w as Float32BufferAttribute, x as InstancedInterleavedBuffer, y as InterleavedBufferAttribute, E as WireframeGeometry, G as Box3, J as Sphere, K as UniformsUtils, X as UniformsLib, Y as Vector4, Z as Line3, $ as Matrix4, a0 as MathUtils, a1 as Uniform, a2 as WebGLRenderTarget, a3 as DepthTexture, a4 as BackSide, a5 as ClampToEdgeWrapping, a6 as PlaneGeometry, a7 as UVMapping, a8 as DataTexture, a9 as Texture, aa as MeshBasicMaterial, ab as IntType, ac as ShortType, ad as ByteType, ae as UnsignedIntType, af as Loader, ag as LoadingManager, ah as LinearMipMapLinearFilter, ai as FileLoader, aj as NoBlending, ak as CubeReflectionMapping, al as EquirectangularReflectionMapping, am as CubeTextureLoader, an as WebGLCubeRenderTarget, ao as ConstraintSketch, ap as setSketchPlacement3D, aq as Sketch, ar as PROFILE_BACKEND_MARKER, as as FrozenShape, at as setShapeCompilePlan, au as hasAnyPorts, av as setShapePortsInternal, aw as markShapePortsUsed, ax as setParamOverrides, ay as DEFAULT_ACTIVE_BACKEND, az as isConstraintSketch, aA as updateConstraintValue, aB as getShapeCompilePlan, aC as resolveForgeRenderStyle, aD as publishSolverWasmRunDebug, aE as resolveForgeQualityPreset, aF as resolveImportPath, aG as BufferGeometry, aH as LineBasicMaterial, aI as Line$1, aJ as LineDashedMaterial, aK as DepthStencilFormat, aL as UnsignedInt248Type, aM as MeshNormalMaterial, aN as NearestFilter, aO as BasicDepthPacking, aP as EventDispatcher$1, aQ as NoColorSpace, aR as FrontSide, aS as Material, aT as AlwaysDepth, aU as BufferAttribute, aV as CanvasTexture, aW as Object3D, aX as FogExp2, aY as Fog, aZ as AmbientLight, a_ as HemisphereLight, a$ as SpotLight, b0 as PointLight, b1 as DirectionalLight, b2 as analyzeCollisionIntersections, b3 as shapeToGeometry, b4 as buildShapeFromCompilePlan, b5 as sketchToSvg, b6 as sketchToDxf, b7 as runScript, b8 as MeshPhysicalMaterial, b9 as LineSegments, ba as
|
|
6
|
+
import { c as create, j as jsxRuntimeExports, r as reactExports, a as createWithEqualityFn, R as React, T as Tb, s as schedulerExports, b as clientExports, d as reactDomExports, u as useParams, e as useSearchParams, f as useNavigate, L as Link, B as BrowserRouter, g as Routes, h as Route, N as Navigate } from "./vendor-react-Da3A2QmU.js";
|
|
7
|
+
import { _ as __vitePreload, z as zipSync, s as strToU8, W as WebGLRenderer, R as Raycaster, O as OrthographicCamera$1, P as PerspectiveCamera$1, S as Scene, a as PCFSoftShadowMap, V as VSMShadowMap, b as PCFShadowMap, B as BasicShadowMap, C as ColorManagement, L as LinearSRGBColorSpace, c as SRGBColorSpace, N as NoToneMapping, A as ACESFilmicToneMapping, d as Layers, e as Color, f as RGBAFormat, U as UnsignedByteType, g as Vector3, h as Vector2, i as Clock, T as THREE, D as DoubleSide, j as REVISION, M as Mesh, I as IcosahedronGeometry, k as ShaderMaterial, l as Spherical, Q as Quaternion, m as MOUSE, n as TOUCH, o as Ray, p as Plane, q as DataTextureLoader, H as HalfFloatType, F as FloatType, r as DataUtils, t as LinearFilter, u as RedFormat, v as InstancedBufferGeometry, w as Float32BufferAttribute, x as InstancedInterleavedBuffer, y as InterleavedBufferAttribute, E as WireframeGeometry, G as Box3, J as Sphere, K as UniformsUtils, X as UniformsLib, Y as Vector4, Z as Line3, $ as Matrix4, a0 as MathUtils, a1 as Uniform, a2 as WebGLRenderTarget, a3 as DepthTexture, a4 as BackSide, a5 as ClampToEdgeWrapping, a6 as PlaneGeometry, a7 as UVMapping, a8 as DataTexture, a9 as Texture, aa as MeshBasicMaterial, ab as IntType, ac as ShortType, ad as ByteType, ae as UnsignedIntType, af as Loader, ag as LoadingManager, ah as LinearMipMapLinearFilter, ai as FileLoader, aj as NoBlending, ak as CubeReflectionMapping, al as EquirectangularReflectionMapping, am as CubeTextureLoader, an as WebGLCubeRenderTarget, ao as ConstraintSketch, ap as setSketchPlacement3D, aq as Sketch, ar as PROFILE_BACKEND_MARKER, as as FrozenShape, at as setShapeCompilePlan, au as hasAnyPorts, av as setShapePortsInternal, aw as markShapePortsUsed, ax as setParamOverrides, ay as DEFAULT_ACTIVE_BACKEND, az as isConstraintSketch, aA as updateConstraintValue, aB as getShapeCompilePlan, aC as resolveForgeRenderStyle, aD as publishSolverWasmRunDebug, aE as resolveForgeQualityPreset, aF as resolveImportPath, aG as BufferGeometry, aH as LineBasicMaterial, aI as Line$1, aJ as LineDashedMaterial, aK as DepthStencilFormat, aL as UnsignedInt248Type, aM as MeshNormalMaterial, aN as NearestFilter, aO as BasicDepthPacking, aP as EventDispatcher$1, aQ as NoColorSpace, aR as FrontSide, aS as Material, aT as AlwaysDepth, aU as BufferAttribute, aV as CanvasTexture, aW as Object3D, aX as FogExp2, aY as Fog, aZ as AmbientLight, a_ as HemisphereLight, a$ as SpotLight, b0 as PointLight, b1 as DirectionalLight, b2 as analyzeCollisionIntersections, b3 as shapeToGeometry, b4 as buildShapeFromCompilePlan, b5 as sketchToSvg, b6 as sketchToDxf, b7 as runScript, b8 as MeshPhysicalMaterial, b9 as LineSegments, ba as getRenderStylePreset, bb as AdditiveBlending, bc as CatmullRomCurve3, bd as TubeGeometry, be as MeshStandardMaterial, bf as compileSdfNode3, bg as buildSdfRaymarchFragmentShader, bh as SDF_RAYMARCH_PROXY_VERTEX_SHADER, bi as Shape, bj as ShapeGeometry, bk as ShaderLib, bl as CylinderGeometry, bm as parseViewportCameraState, bn as createResolvedExplodeConfig, bo as explodeBoundsCenter, bp as explodeMergeBounds, bq as resolveExplodeDirective, br as computeExplodeMotion, bs as getSketchWorldMatrix, bt as explodeAdd, bu as hasExplodeOverride, bv as resolveExplodeLocalFanDirection, bw as explodeMul, bx as explodeLeafFanStage, by as normalizeCutPlane, bz as toClippingPlane, bA as findJointAnimationClip, bB as resolveJointAnimation, bC as resolveJointViewValues, bD as getShapePorts, bE as getShapeUsedPorts, bF as DEFAULT_VIEW_CONFIG, bG as getKernelFaceNameForTriangle, bH as initKernel, bI as initSolverWasm } from "./sectionPlaneMath-BdTjyVfs.js";
|
|
8
8
|
function getCsrfToken() {
|
|
9
9
|
const match = document.cookie.match(/(?:^|;\s*)fc-csrf-token=([^;]+)/);
|
|
10
10
|
return match == null ? void 0 : match[1];
|
|
@@ -71,6 +71,9 @@ const authApi = {
|
|
|
71
71
|
logout() {
|
|
72
72
|
return authFetch("/api/auth/logout", { method: "POST" });
|
|
73
73
|
},
|
|
74
|
+
deleteAccount() {
|
|
75
|
+
return authFetch("/api/users/me", { method: "DELETE" });
|
|
76
|
+
},
|
|
74
77
|
providers() {
|
|
75
78
|
return authFetch("/api/auth/providers");
|
|
76
79
|
},
|
|
@@ -516,6 +519,17 @@ function applyAuthenticatedUser(set, user) {
|
|
|
516
519
|
set({ user, loading: false, error: null, backendAvailable: true });
|
|
517
520
|
startRefreshTimer();
|
|
518
521
|
}
|
|
522
|
+
function clearAuthenticatedState(set) {
|
|
523
|
+
stopRefreshTimer();
|
|
524
|
+
clearUserCache();
|
|
525
|
+
setCurrentUserId(void 0);
|
|
526
|
+
set({ user: void 0, loading: false, error: null });
|
|
527
|
+
useProjectStore.setState({ projects: [], activeProjectId: null, error: null });
|
|
528
|
+
try {
|
|
529
|
+
localStorage.removeItem("fc-active-project-id");
|
|
530
|
+
} catch {
|
|
531
|
+
}
|
|
532
|
+
}
|
|
519
533
|
const useAuthStore = create((set) => ({
|
|
520
534
|
user: null,
|
|
521
535
|
loading: true,
|
|
@@ -569,21 +583,58 @@ const useAuthStore = create((set) => ({
|
|
|
569
583
|
}
|
|
570
584
|
},
|
|
571
585
|
async logout() {
|
|
572
|
-
stopRefreshTimer();
|
|
573
586
|
try {
|
|
574
587
|
await authApi.logout();
|
|
575
588
|
} finally {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
589
|
+
clearAuthenticatedState(set);
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
async deleteAccount() {
|
|
593
|
+
set({ loading: true, error: null });
|
|
594
|
+
try {
|
|
595
|
+
await authApi.deleteAccount();
|
|
596
|
+
clearAuthenticatedState(set);
|
|
597
|
+
} catch (err) {
|
|
598
|
+
set({ loading: false, error: err.message || "Account deletion failed" });
|
|
599
|
+
throw err;
|
|
584
600
|
}
|
|
585
601
|
}
|
|
586
602
|
}));
|
|
603
|
+
const BRAND_MARK_SRC = "/brand/logo-mark-128.png";
|
|
604
|
+
const BRAND_MARK_SRC_SET = [
|
|
605
|
+
"/brand/logo-mark-64.png 64w",
|
|
606
|
+
"/brand/logo-mark-128.png 128w",
|
|
607
|
+
"/brand/logo-mark-256.png 256w",
|
|
608
|
+
"/brand/logo-mark.png 512w"
|
|
609
|
+
].join(", ");
|
|
610
|
+
function BrandMark({
|
|
611
|
+
size = 24,
|
|
612
|
+
alt = "ForgeCAD logo",
|
|
613
|
+
decorative = false,
|
|
614
|
+
style
|
|
615
|
+
}) {
|
|
616
|
+
const logicalSize = Math.max(1, Math.ceil(size));
|
|
617
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
618
|
+
"img",
|
|
619
|
+
{
|
|
620
|
+
src: BRAND_MARK_SRC,
|
|
621
|
+
srcSet: BRAND_MARK_SRC_SET,
|
|
622
|
+
sizes: `${logicalSize}px`,
|
|
623
|
+
alt: decorative ? "" : alt,
|
|
624
|
+
"aria-hidden": decorative ? "true" : void 0,
|
|
625
|
+
width: size,
|
|
626
|
+
height: size,
|
|
627
|
+
style: {
|
|
628
|
+
width: size,
|
|
629
|
+
height: size,
|
|
630
|
+
display: "block",
|
|
631
|
+
flex: "0 0 auto",
|
|
632
|
+
objectFit: "contain",
|
|
633
|
+
...style
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
}
|
|
587
638
|
let nextId = 0;
|
|
588
639
|
let toasts = [];
|
|
589
640
|
const listeners$1 = /* @__PURE__ */ new Set();
|
|
@@ -779,41 +830,6 @@ const styles = {
|
|
|
779
830
|
opacity: 0.65
|
|
780
831
|
}
|
|
781
832
|
};
|
|
782
|
-
const BRAND_MARK_SRC = "/brand/logo-mark-128.png";
|
|
783
|
-
const BRAND_MARK_SRC_SET = [
|
|
784
|
-
"/brand/logo-mark-64.png 64w",
|
|
785
|
-
"/brand/logo-mark-128.png 128w",
|
|
786
|
-
"/brand/logo-mark-256.png 256w",
|
|
787
|
-
"/brand/logo-mark.png 512w"
|
|
788
|
-
].join(", ");
|
|
789
|
-
function BrandMark({
|
|
790
|
-
size = 24,
|
|
791
|
-
alt = "ForgeCAD logo",
|
|
792
|
-
decorative = false,
|
|
793
|
-
style
|
|
794
|
-
}) {
|
|
795
|
-
const logicalSize = Math.max(1, Math.ceil(size));
|
|
796
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
797
|
-
"img",
|
|
798
|
-
{
|
|
799
|
-
src: BRAND_MARK_SRC,
|
|
800
|
-
srcSet: BRAND_MARK_SRC_SET,
|
|
801
|
-
sizes: `${logicalSize}px`,
|
|
802
|
-
alt: decorative ? "" : alt,
|
|
803
|
-
"aria-hidden": decorative ? "true" : void 0,
|
|
804
|
-
width: size,
|
|
805
|
-
height: size,
|
|
806
|
-
style: {
|
|
807
|
-
width: size,
|
|
808
|
-
height: size,
|
|
809
|
-
display: "block",
|
|
810
|
-
flex: "0 0 auto",
|
|
811
|
-
objectFit: "contain",
|
|
812
|
-
...style
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
);
|
|
816
|
-
}
|
|
817
833
|
function getQueryParam(name) {
|
|
818
834
|
return new URLSearchParams(window.location.search).get(name);
|
|
819
835
|
}
|
|
@@ -14920,7 +14936,7 @@ function planLabel(plan) {
|
|
|
14920
14936
|
case "boolean":
|
|
14921
14937
|
return plan.op === "union" ? "Union" : plan.op === "difference" ? "Subtract" : "Intersect";
|
|
14922
14938
|
case "transform":
|
|
14923
|
-
return
|
|
14939
|
+
return formatTransformLabel(plan.steps);
|
|
14924
14940
|
case "queryOwner":
|
|
14925
14941
|
return planLabel(plan.base);
|
|
14926
14942
|
case "fillet":
|
|
@@ -14969,12 +14985,53 @@ function planLabel(plan) {
|
|
|
14969
14985
|
return `STEP Import (${plan.filePath})`;
|
|
14970
14986
|
}
|
|
14971
14987
|
}
|
|
14988
|
+
function formatTransformLabel(steps) {
|
|
14989
|
+
if (steps.length === 0) return "Transform";
|
|
14990
|
+
const kinds = [...new Set(steps.map((step) => step.kind))];
|
|
14991
|
+
return `Transform (${kinds.join(", ")})`;
|
|
14992
|
+
}
|
|
14972
14993
|
function resolvePlan(plan) {
|
|
14973
14994
|
return plan.kind === "queryOwner" ? resolvePlan(plan.base) : plan;
|
|
14974
14995
|
}
|
|
14975
14996
|
function wrapWithTransforms(plan, transformStacks) {
|
|
14976
14997
|
return transformStacks.reduceRight((inner, steps) => ({ kind: "transform", base: inner, steps }), plan);
|
|
14977
14998
|
}
|
|
14999
|
+
const SHAPE_COMPILE_PLAN_CACHE_KEY_VERSION = "shape-plan-v1";
|
|
15000
|
+
function stableJsonEncode(value, arrayMember) {
|
|
15001
|
+
if (value === void 0 || typeof value === "function" || typeof value === "symbol") {
|
|
15002
|
+
return arrayMember ? "null" : void 0;
|
|
15003
|
+
}
|
|
15004
|
+
if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
|
|
15005
|
+
return JSON.stringify(value);
|
|
15006
|
+
}
|
|
15007
|
+
if (Array.isArray(value)) {
|
|
15008
|
+
return `[${value.map((item) => stableJsonEncode(item, true) ?? "null").join(",")}]`;
|
|
15009
|
+
}
|
|
15010
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
15011
|
+
const encodedEntries = [];
|
|
15012
|
+
for (const [key, item] of entries) {
|
|
15013
|
+
const encoded = stableJsonEncode(item, false);
|
|
15014
|
+
if (encoded !== void 0) encodedEntries.push(`${JSON.stringify(key)}:${encoded}`);
|
|
15015
|
+
}
|
|
15016
|
+
return `{${encodedEntries.join(",")}}`;
|
|
15017
|
+
}
|
|
15018
|
+
function stableJsonStringify(value) {
|
|
15019
|
+
return stableJsonEncode(value, false) ?? "null";
|
|
15020
|
+
}
|
|
15021
|
+
function shapeCompilePlanCacheKey(plan) {
|
|
15022
|
+
return `${SHAPE_COMPILE_PLAN_CACHE_KEY_VERSION}:${stableJsonStringify(plan)}`;
|
|
15023
|
+
}
|
|
15024
|
+
function constructionStepGeometryCacheKey(step) {
|
|
15025
|
+
return step.cumulativePlanCacheKey;
|
|
15026
|
+
}
|
|
15027
|
+
function makeConstructionStep(step) {
|
|
15028
|
+
const planCacheKey = shapeCompilePlanCacheKey(step.plan);
|
|
15029
|
+
return {
|
|
15030
|
+
...step,
|
|
15031
|
+
planCacheKey,
|
|
15032
|
+
cumulativePlanCacheKey: step.cumulativePlan === step.plan ? planCacheKey : shapeCompilePlanCacheKey(step.cumulativePlan)
|
|
15033
|
+
};
|
|
15034
|
+
}
|
|
14978
15035
|
function linearizeConstructionSteps(rootPlan, objectId) {
|
|
14979
15036
|
const steps = [];
|
|
14980
15037
|
const ancestorTransforms = [];
|
|
@@ -15004,16 +15061,18 @@ function linearizeConstructionSteps(rootPlan, objectId) {
|
|
|
15004
15061
|
shapes: childCumulatives
|
|
15005
15062
|
};
|
|
15006
15063
|
const worldPlan = wrapWithTransforms(cumulativePlan, ancestorTransforms);
|
|
15007
|
-
steps.push(
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15064
|
+
steps.push(
|
|
15065
|
+
makeConstructionStep({
|
|
15066
|
+
index: steps.length,
|
|
15067
|
+
label: planLabel(resolved),
|
|
15068
|
+
role: "operation",
|
|
15069
|
+
displayAsTool,
|
|
15070
|
+
stackPopCount: childCumulatives.length,
|
|
15071
|
+
plan: worldPlan,
|
|
15072
|
+
cumulativePlan: worldPlan,
|
|
15073
|
+
objectId
|
|
15074
|
+
})
|
|
15075
|
+
);
|
|
15017
15076
|
return cumulativePlan;
|
|
15018
15077
|
}
|
|
15019
15078
|
// ── Modifications: visit base, then add modification step ──
|
|
@@ -15031,16 +15090,18 @@ function linearizeConstructionSteps(rootPlan, objectId) {
|
|
|
15031
15090
|
const baseCumulative = visit(resolved.base, options);
|
|
15032
15091
|
const modPlan = { ...resolved, base: baseCumulative };
|
|
15033
15092
|
const worldPlan = wrapWithTransforms(modPlan, ancestorTransforms);
|
|
15034
|
-
steps.push(
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15093
|
+
steps.push(
|
|
15094
|
+
makeConstructionStep({
|
|
15095
|
+
index: steps.length,
|
|
15096
|
+
label: planLabel(resolved),
|
|
15097
|
+
role: "modification",
|
|
15098
|
+
displayAsTool,
|
|
15099
|
+
stackPopCount: 1,
|
|
15100
|
+
plan: worldPlan,
|
|
15101
|
+
cumulativePlan: worldPlan,
|
|
15102
|
+
objectId
|
|
15103
|
+
})
|
|
15104
|
+
);
|
|
15044
15105
|
return modPlan;
|
|
15045
15106
|
}
|
|
15046
15107
|
case "surfaceExtend":
|
|
@@ -15048,16 +15109,18 @@ function linearizeConstructionSteps(rootPlan, objectId) {
|
|
|
15048
15109
|
const baseCumulative = visit(resolved.base, options);
|
|
15049
15110
|
const modPlan = { ...resolved, base: baseCumulative };
|
|
15050
15111
|
const worldPlan = wrapWithTransforms(modPlan, ancestorTransforms);
|
|
15051
|
-
steps.push(
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15112
|
+
steps.push(
|
|
15113
|
+
makeConstructionStep({
|
|
15114
|
+
index: steps.length,
|
|
15115
|
+
label: planLabel(resolved),
|
|
15116
|
+
role: "modification",
|
|
15117
|
+
displayAsTool,
|
|
15118
|
+
stackPopCount: 1,
|
|
15119
|
+
plan: worldPlan,
|
|
15120
|
+
cumulativePlan: worldPlan,
|
|
15121
|
+
objectId
|
|
15122
|
+
})
|
|
15123
|
+
);
|
|
15061
15124
|
return modPlan;
|
|
15062
15125
|
}
|
|
15063
15126
|
case "surfaceSew": {
|
|
@@ -15071,31 +15134,35 @@ function linearizeConstructionSteps(rootPlan, objectId) {
|
|
|
15071
15134
|
tolerance: resolved.tolerance
|
|
15072
15135
|
};
|
|
15073
15136
|
const worldPlan = wrapWithTransforms(cumulativePlan, ancestorTransforms);
|
|
15074
|
-
steps.push(
|
|
15075
|
-
|
|
15076
|
-
|
|
15077
|
-
|
|
15078
|
-
|
|
15079
|
-
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15137
|
+
steps.push(
|
|
15138
|
+
makeConstructionStep({
|
|
15139
|
+
index: steps.length,
|
|
15140
|
+
label: planLabel(resolved),
|
|
15141
|
+
role: "operation",
|
|
15142
|
+
displayAsTool,
|
|
15143
|
+
stackPopCount: childCumulatives.length,
|
|
15144
|
+
plan: worldPlan,
|
|
15145
|
+
cumulativePlan: worldPlan,
|
|
15146
|
+
objectId
|
|
15147
|
+
})
|
|
15148
|
+
);
|
|
15084
15149
|
return cumulativePlan;
|
|
15085
15150
|
}
|
|
15086
15151
|
// ── Leaf primitives: add directly as a step ──
|
|
15087
15152
|
default: {
|
|
15088
15153
|
const worldPlan = wrapWithTransforms(resolved, ancestorTransforms);
|
|
15089
|
-
steps.push(
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15154
|
+
steps.push(
|
|
15155
|
+
makeConstructionStep({
|
|
15156
|
+
index: steps.length,
|
|
15157
|
+
label: planLabel(resolved),
|
|
15158
|
+
role: "primitive",
|
|
15159
|
+
displayAsTool,
|
|
15160
|
+
stackPopCount: 0,
|
|
15161
|
+
plan: worldPlan,
|
|
15162
|
+
cumulativePlan: worldPlan,
|
|
15163
|
+
objectId
|
|
15164
|
+
})
|
|
15165
|
+
);
|
|
15099
15166
|
return resolved;
|
|
15100
15167
|
}
|
|
15101
15168
|
}
|
|
@@ -15788,7 +15855,7 @@ const CRASH_COOLDOWN_MS = 2e3;
|
|
|
15788
15855
|
class EvalWorkerClient {
|
|
15789
15856
|
constructor(workerFactory = () => new Worker(new URL(
|
|
15790
15857
|
/* @vite-ignore */
|
|
15791
|
-
"/assets/evalWorker-
|
|
15858
|
+
"/assets/evalWorker-Ds5U4xtN.js",
|
|
15792
15859
|
import.meta.url
|
|
15793
15860
|
), { type: "module" })) {
|
|
15794
15861
|
__publicField(this, "worker", null);
|
|
@@ -17253,6 +17320,14 @@ function buildRunState(previewFile, runResult, state2) {
|
|
|
17253
17320
|
};
|
|
17254
17321
|
}
|
|
17255
17322
|
const VIEW_PREFERENCES_KEY = "fc-view-preferences-v1";
|
|
17323
|
+
const INSPECT_POINT_SAMPLE_COUNT_MIN = 100;
|
|
17324
|
+
const INSPECT_POINT_SAMPLE_COUNT_MAX = 1e4;
|
|
17325
|
+
const DEFAULT_INSPECT_POINT_SAMPLE_COUNT = 2e3;
|
|
17326
|
+
const resolveInspectPointSampleCount = (value) => {
|
|
17327
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
17328
|
+
if (!Number.isFinite(numeric)) return DEFAULT_INSPECT_POINT_SAMPLE_COUNT;
|
|
17329
|
+
return Math.max(INSPECT_POINT_SAMPLE_COUNT_MIN, Math.min(INSPECT_POINT_SAMPLE_COUNT_MAX, Math.round(numeric)));
|
|
17330
|
+
};
|
|
17256
17331
|
const readViewPreferences = () => {
|
|
17257
17332
|
if (typeof window === "undefined") return {};
|
|
17258
17333
|
try {
|
|
@@ -17370,9 +17445,13 @@ const VIEW_INSPECT_CHANNELS = /* @__PURE__ */ new Set([
|
|
|
17370
17445
|
"thickness",
|
|
17371
17446
|
"roughness"
|
|
17372
17447
|
]);
|
|
17448
|
+
const INSPECT_DISPLAY_MODES = /* @__PURE__ */ new Set(["heatmap", "points", "both"]);
|
|
17373
17449
|
function resolveViewInspectChannel(value) {
|
|
17374
17450
|
return typeof value === "string" && VIEW_INSPECT_CHANNELS.has(value) ? value : "none";
|
|
17375
17451
|
}
|
|
17452
|
+
function resolveInspectDisplayMode(value) {
|
|
17453
|
+
return typeof value === "string" && INSPECT_DISPLAY_MODES.has(value) ? value : "heatmap";
|
|
17454
|
+
}
|
|
17376
17455
|
const initialViewPreferences = readViewPreferences();
|
|
17377
17456
|
const initialPreviewFile = resolvePreviewFile(initialActive, INITIAL_FILES);
|
|
17378
17457
|
const initialObjectSettingsByFile = (() => {
|
|
@@ -18137,6 +18216,18 @@ Switch to LOCAL mode or wait for the server to recover.`,
|
|
|
18137
18216
|
writeViewPreferences({ inspectChannel: next });
|
|
18138
18217
|
set({ inspectChannel: next });
|
|
18139
18218
|
},
|
|
18219
|
+
inspectDisplayMode: resolveInspectDisplayMode(initialViewPreferences.inspectDisplayMode),
|
|
18220
|
+
setInspectDisplayMode: (mode) => {
|
|
18221
|
+
const next = resolveInspectDisplayMode(mode);
|
|
18222
|
+
writeViewPreferences({ inspectDisplayMode: next });
|
|
18223
|
+
set({ inspectDisplayMode: next });
|
|
18224
|
+
},
|
|
18225
|
+
inspectPointSampleCount: resolveInspectPointSampleCount(initialViewPreferences.inspectPointSampleCount),
|
|
18226
|
+
setInspectPointSampleCount: (count) => {
|
|
18227
|
+
const next = resolveInspectPointSampleCount(count);
|
|
18228
|
+
writeViewPreferences({ inspectPointSampleCount: next });
|
|
18229
|
+
set({ inspectPointSampleCount: next });
|
|
18230
|
+
},
|
|
18140
18231
|
projectionMode: initialViewPreferences.projectionMode ?? "perspective",
|
|
18141
18232
|
setProjectionMode: (mode) => {
|
|
18142
18233
|
writeViewPreferences({ projectionMode: mode });
|
|
@@ -26747,10 +26838,6 @@ const MASK_PALETTE = [
|
|
|
26747
26838
|
[0, 0, 128],
|
|
26748
26839
|
[128, 128, 128]
|
|
26749
26840
|
];
|
|
26750
|
-
const DISTANCE_NEAR_COLOR = [66, 220, 120];
|
|
26751
|
-
const DISTANCE_MID_COLOR = [255, 214, 0];
|
|
26752
|
-
const DISTANCE_FAR_COLOR = [255, 68, 16];
|
|
26753
|
-
const DISTANCE_UNKNOWN_COLOR = [128, 128, 128];
|
|
26754
26841
|
function rgbToHex(color2) {
|
|
26755
26842
|
return `#${color2.map((value) => value.toString(16).padStart(2, "0")).join("")}`;
|
|
26756
26843
|
}
|
|
@@ -26763,19 +26850,8 @@ function maskColorForIndex(index) {
|
|
|
26763
26850
|
function collisionColorForIndex(index) {
|
|
26764
26851
|
return rgbToHex(COLLISION_PALETTE[(index - 1) % COLLISION_PALETTE.length]);
|
|
26765
26852
|
}
|
|
26766
|
-
|
|
26767
|
-
|
|
26768
|
-
}
|
|
26769
|
-
function lerpRgb(a2, b2, t2) {
|
|
26770
|
-
return [Math.round(lerp$1(a2[0], b2[0], t2)), Math.round(lerp$1(a2[1], b2[1], t2)), Math.round(lerp$1(a2[2], b2[2], t2))];
|
|
26771
|
-
}
|
|
26772
|
-
function distanceColorForRootDistance(distance, maxDistance) {
|
|
26773
|
-
if (!Number.isFinite(distance)) return rgbToHex(DISTANCE_UNKNOWN_COLOR);
|
|
26774
|
-
if (!Number.isFinite(maxDistance) || maxDistance <= 1e-9) return rgbToHex(DISTANCE_NEAR_COLOR);
|
|
26775
|
-
const t2 = Math.max(0, Math.min(1, distance / maxDistance));
|
|
26776
|
-
if (t2 <= 0.5) return rgbToHex(lerpRgb(DISTANCE_NEAR_COLOR, DISTANCE_MID_COLOR, t2 * 2));
|
|
26777
|
-
return rgbToHex(lerpRgb(DISTANCE_MID_COLOR, DISTANCE_FAR_COLOR, (t2 - 0.5) * 2));
|
|
26778
|
-
}
|
|
26853
|
+
const MAX_VIEWPORT_COLLISION_CANDIDATES = 200;
|
|
26854
|
+
const MAX_VIEWPORT_COLLISION_MS = 1e3;
|
|
26779
26855
|
function matrixToCollisionMat4(matrix) {
|
|
26780
26856
|
if (!matrix) return void 0;
|
|
26781
26857
|
const e2 = matrix.elements;
|
|
@@ -26811,7 +26887,11 @@ function CollisionInspectionOverlay({
|
|
|
26811
26887
|
objectMatrices
|
|
26812
26888
|
}) {
|
|
26813
26889
|
const collisionGeometries = reactExports.useMemo(() => {
|
|
26814
|
-
const report = analyzeCollisionIntersections(buildCollisionEntries(objects, objectSettings, objectMatrices)
|
|
26890
|
+
const report = analyzeCollisionIntersections(buildCollisionEntries(objects, objectSettings, objectMatrices), {
|
|
26891
|
+
maxCandidatePairs: MAX_VIEWPORT_COLLISION_CANDIDATES,
|
|
26892
|
+
maxElapsedMs: MAX_VIEWPORT_COLLISION_MS,
|
|
26893
|
+
includeBBoxCandidates: false
|
|
26894
|
+
});
|
|
26815
26895
|
return report.collisions.flatMap((collision) => {
|
|
26816
26896
|
try {
|
|
26817
26897
|
const geometry = shapeToGeometry(collision.shape);
|
|
@@ -26864,7 +26944,8 @@ function ConstructionGhostOverlay({ matrix }) {
|
|
|
26864
26944
|
const MAX_CACHE_SIZE = 40;
|
|
26865
26945
|
const geometryCache = /* @__PURE__ */ new Map();
|
|
26866
26946
|
function getCachedGeometry(step) {
|
|
26867
|
-
const
|
|
26947
|
+
const cacheKey = constructionStepGeometryCacheKey(step);
|
|
26948
|
+
const cached = geometryCache.get(cacheKey);
|
|
26868
26949
|
if (cached) return cached;
|
|
26869
26950
|
try {
|
|
26870
26951
|
const shape = buildShapeFromCompilePlan(step.cumulativePlan);
|
|
@@ -26880,7 +26961,7 @@ function getCachedGeometry(step) {
|
|
|
26880
26961
|
geometryCache.delete(firstKey);
|
|
26881
26962
|
}
|
|
26882
26963
|
}
|
|
26883
|
-
geometryCache.set(
|
|
26964
|
+
geometryCache.set(cacheKey, entry);
|
|
26884
26965
|
return entry;
|
|
26885
26966
|
} catch {
|
|
26886
26967
|
return null;
|
|
@@ -29066,7 +29147,7 @@ function generateReportInWorker(options) {
|
|
|
29066
29147
|
return new Promise((resolve2, reject) => {
|
|
29067
29148
|
const worker = new Worker(new URL(
|
|
29068
29149
|
/* @vite-ignore */
|
|
29069
|
-
"/assets/reportWorker-
|
|
29150
|
+
"/assets/reportWorker-CU8RZ4O0.js",
|
|
29070
29151
|
import.meta.url
|
|
29071
29152
|
), { type: "module" });
|
|
29072
29153
|
const cleanup = () => {
|
|
@@ -32270,16 +32351,44 @@ const PHASE_CONFIG = {
|
|
|
32270
32351
|
evaluating: { color: "#4a9eff", label: "Evaluating model" },
|
|
32271
32352
|
serializing: { color: "#7c4dff", label: "Preparing display" },
|
|
32272
32353
|
exporting: { color: "#4caf50", label: "Exporting geometry" },
|
|
32354
|
+
inspecting: { color: "#14b8a6", label: "Generating inspect view" },
|
|
32273
32355
|
idle: { color: "#888", label: "" }
|
|
32274
32356
|
};
|
|
32275
32357
|
const PHASE_ORDER = ["kernel-init", "evaluating", "serializing"];
|
|
32276
|
-
function
|
|
32358
|
+
function formatEvaluationBackendLabel(activeBackend, computeTarget) {
|
|
32359
|
+
const backend = activeBackend === "occt" ? "OCCT" : activeBackend === "manifold" ? "Manifold" : activeBackend === "truck" ? "Truck" : "kernel";
|
|
32360
|
+
return computeTarget === "server" ? `Server ${backend}` : `Local ${backend}`;
|
|
32361
|
+
}
|
|
32362
|
+
function constructionStepRoleSymbol(role) {
|
|
32363
|
+
if (role === "primitive") return "+";
|
|
32364
|
+
if (role === "operation") return "->";
|
|
32365
|
+
return "~";
|
|
32366
|
+
}
|
|
32367
|
+
function constructionStepPreview(constructionSteps, previewStepIndex) {
|
|
32368
|
+
const stepCount = constructionSteps.length;
|
|
32369
|
+
const displayStepIndex = stepCount > 0 ? (previewStepIndex % stepCount + stepCount) % stepCount : 0;
|
|
32370
|
+
return {
|
|
32371
|
+
displayStepIndex,
|
|
32372
|
+
previewStep: stepCount > 0 ? constructionSteps[displayStepIndex] : null,
|
|
32373
|
+
progress: stepCount > 1 ? (displayStepIndex + 1) / stepCount : 1
|
|
32374
|
+
};
|
|
32375
|
+
}
|
|
32376
|
+
function EvaluationIndicator({
|
|
32377
|
+
phase,
|
|
32378
|
+
label,
|
|
32379
|
+
constructionSteps = [],
|
|
32380
|
+
activeBackend,
|
|
32381
|
+
computeTarget
|
|
32382
|
+
}) {
|
|
32277
32383
|
const [frame2, setFrame] = reactExports.useState(0);
|
|
32278
32384
|
const [elapsed, setElapsed] = reactExports.useState(0);
|
|
32385
|
+
const [previewStepIndex, setPreviewStepIndex] = reactExports.useState(0);
|
|
32279
32386
|
const startRef = reactExports.useRef(Date.now());
|
|
32387
|
+
const stepCount = constructionSteps.length;
|
|
32280
32388
|
reactExports.useEffect(() => {
|
|
32281
32389
|
startRef.current = Date.now();
|
|
32282
32390
|
setElapsed(0);
|
|
32391
|
+
setPreviewStepIndex(0);
|
|
32283
32392
|
}, [phase]);
|
|
32284
32393
|
reactExports.useEffect(() => {
|
|
32285
32394
|
const spinnerInterval = setInterval(() => setFrame((f2) => (f2 + 1) % BRAILLE_FRAMES.length), 80);
|
|
@@ -32289,9 +32398,17 @@ function EvaluationIndicator({ phase }) {
|
|
|
32289
32398
|
clearInterval(timerInterval);
|
|
32290
32399
|
};
|
|
32291
32400
|
}, []);
|
|
32401
|
+
reactExports.useEffect(() => {
|
|
32402
|
+
setPreviewStepIndex(0);
|
|
32403
|
+
if (stepCount <= 1) return;
|
|
32404
|
+
const interval = setInterval(() => setPreviewStepIndex((i) => (i + 1) % stepCount), 700);
|
|
32405
|
+
return () => clearInterval(interval);
|
|
32406
|
+
}, [stepCount]);
|
|
32292
32407
|
const config = PHASE_CONFIG[phase] ?? PHASE_CONFIG["evaluating"];
|
|
32293
32408
|
const elapsedSec = (elapsed / 1e3).toFixed(1);
|
|
32294
|
-
const
|
|
32409
|
+
const phaseOrder = PHASE_ORDER.includes(phase) ? PHASE_ORDER : [phase];
|
|
32410
|
+
const phaseIdx = phaseOrder.indexOf(phase);
|
|
32411
|
+
const { displayStepIndex, previewStep, progress } = constructionStepPreview(constructionSteps, previewStepIndex);
|
|
32295
32412
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32296
32413
|
"div",
|
|
32297
32414
|
{
|
|
@@ -32299,53 +32416,368 @@ function EvaluationIndicator({ phase }) {
|
|
|
32299
32416
|
position: "absolute",
|
|
32300
32417
|
bottom: 16,
|
|
32301
32418
|
right: 16,
|
|
32419
|
+
width: previewStep ? "min(360px, calc(100vw - 32px))" : void 0,
|
|
32302
32420
|
background: "var(--fc-bgPanel)",
|
|
32303
32421
|
border: "1px solid var(--fc-border)",
|
|
32304
32422
|
borderRadius: 8,
|
|
32305
|
-
padding: "8px 14px",
|
|
32423
|
+
padding: previewStep ? "10px 12px" : "8px 14px",
|
|
32306
32424
|
pointerEvents: "none",
|
|
32307
|
-
display: "
|
|
32308
|
-
|
|
32309
|
-
gap: 10,
|
|
32425
|
+
display: "grid",
|
|
32426
|
+
gap: previewStep ? 8 : 0,
|
|
32310
32427
|
fontSize: 12,
|
|
32311
32428
|
animation: "fc-fadein 0.2s ease-out",
|
|
32312
32429
|
boxShadow: "0 4px 16px rgba(0,0,0,0.25)"
|
|
32313
32430
|
},
|
|
32314
32431
|
children: [
|
|
32315
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
32316
|
-
|
|
32317
|
-
|
|
32318
|
-
var _a3;
|
|
32319
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32432
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, minWidth: 0 }, children: [
|
|
32433
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: config.color, fontSize: 16, fontWeight: 700, width: 16, textAlign: "center", flex: "0 0 auto" }, children: BRAILLE_FRAMES[frame2] }),
|
|
32434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32320
32435
|
"span",
|
|
32321
32436
|
{
|
|
32322
32437
|
style: {
|
|
32323
|
-
|
|
32324
|
-
|
|
32325
|
-
|
|
32326
|
-
|
|
32327
|
-
|
|
32328
|
-
|
|
32438
|
+
color: "var(--fc-text)",
|
|
32439
|
+
fontWeight: 500,
|
|
32440
|
+
minWidth: 0,
|
|
32441
|
+
overflow: "hidden",
|
|
32442
|
+
textOverflow: "ellipsis",
|
|
32443
|
+
whiteSpace: "nowrap"
|
|
32444
|
+
},
|
|
32445
|
+
children: label ?? config.label
|
|
32446
|
+
}
|
|
32447
|
+
),
|
|
32448
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { display: "flex", gap: 4, alignItems: "center", marginLeft: "auto", flex: "0 0 auto" }, children: phaseOrder.map((p2, i) => {
|
|
32449
|
+
var _a3;
|
|
32450
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32451
|
+
"span",
|
|
32452
|
+
{
|
|
32453
|
+
style: {
|
|
32454
|
+
width: 6,
|
|
32455
|
+
height: 6,
|
|
32456
|
+
borderRadius: "50%",
|
|
32457
|
+
background: i <= phaseIdx ? ((_a3 = PHASE_CONFIG[p2]) == null ? void 0 : _a3.color) ?? "var(--fc-border)" : "var(--fc-border)",
|
|
32458
|
+
transition: "background 0.3s ease",
|
|
32459
|
+
animation: i === phaseIdx ? "fc-pulse 1.2s ease-in-out infinite" : void 0
|
|
32460
|
+
}
|
|
32461
|
+
},
|
|
32462
|
+
p2
|
|
32463
|
+
);
|
|
32464
|
+
}) }),
|
|
32465
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { color: "var(--fc-textDim)", fontVariantNumeric: "tabular-nums", fontSize: 11, flex: "0 0 auto" }, children: [
|
|
32466
|
+
elapsedSec,
|
|
32467
|
+
"s"
|
|
32468
|
+
] })
|
|
32469
|
+
] }),
|
|
32470
|
+
previewStep && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "grid", gap: 6, minWidth: 0 }, children: [
|
|
32471
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [
|
|
32472
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32473
|
+
"span",
|
|
32474
|
+
{
|
|
32475
|
+
style: {
|
|
32476
|
+
color: "var(--fc-textDim)",
|
|
32477
|
+
fontSize: 10,
|
|
32478
|
+
textTransform: "uppercase",
|
|
32479
|
+
fontWeight: 700,
|
|
32480
|
+
letterSpacing: 0,
|
|
32481
|
+
flex: "0 0 auto"
|
|
32482
|
+
},
|
|
32483
|
+
children: "Cached build path"
|
|
32329
32484
|
}
|
|
32330
|
-
|
|
32331
|
-
|
|
32332
|
-
|
|
32333
|
-
|
|
32334
|
-
|
|
32335
|
-
|
|
32336
|
-
|
|
32485
|
+
),
|
|
32486
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32487
|
+
"span",
|
|
32488
|
+
{
|
|
32489
|
+
style: {
|
|
32490
|
+
color: "var(--fc-textMuted)",
|
|
32491
|
+
fontSize: 11,
|
|
32492
|
+
minWidth: 0,
|
|
32493
|
+
overflow: "hidden",
|
|
32494
|
+
textOverflow: "ellipsis",
|
|
32495
|
+
whiteSpace: "nowrap"
|
|
32496
|
+
},
|
|
32497
|
+
children: formatEvaluationBackendLabel(activeBackend, computeTarget)
|
|
32498
|
+
}
|
|
32499
|
+
)
|
|
32500
|
+
] }),
|
|
32501
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [
|
|
32502
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32503
|
+
"span",
|
|
32504
|
+
{
|
|
32505
|
+
style: {
|
|
32506
|
+
color: config.color,
|
|
32507
|
+
fontVariantNumeric: "tabular-nums",
|
|
32508
|
+
fontSize: 11,
|
|
32509
|
+
fontWeight: 700,
|
|
32510
|
+
flex: "0 0 auto",
|
|
32511
|
+
width: 46
|
|
32512
|
+
},
|
|
32513
|
+
children: [
|
|
32514
|
+
displayStepIndex + 1,
|
|
32515
|
+
"/",
|
|
32516
|
+
stepCount
|
|
32517
|
+
]
|
|
32518
|
+
}
|
|
32519
|
+
),
|
|
32520
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32521
|
+
"span",
|
|
32522
|
+
{
|
|
32523
|
+
style: {
|
|
32524
|
+
color: "var(--fc-text)",
|
|
32525
|
+
minWidth: 0,
|
|
32526
|
+
overflow: "hidden",
|
|
32527
|
+
textOverflow: "ellipsis",
|
|
32528
|
+
whiteSpace: "nowrap"
|
|
32529
|
+
},
|
|
32530
|
+
children: [
|
|
32531
|
+
constructionStepRoleSymbol(previewStep.role),
|
|
32532
|
+
" ",
|
|
32533
|
+
previewStep.label
|
|
32534
|
+
]
|
|
32535
|
+
}
|
|
32536
|
+
),
|
|
32537
|
+
previewStep.displayAsTool && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: config.color, fontSize: 11, flex: "0 0 auto" }, children: "tool" })
|
|
32538
|
+
] }),
|
|
32539
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: 3, borderRadius: 999, background: "var(--fc-borderLight)", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32540
|
+
"div",
|
|
32541
|
+
{
|
|
32542
|
+
style: {
|
|
32543
|
+
width: `${Math.round(progress * 100)}%`,
|
|
32544
|
+
height: "100%",
|
|
32545
|
+
borderRadius: 999,
|
|
32546
|
+
background: config.color,
|
|
32547
|
+
transition: "width 0.2s ease-out"
|
|
32548
|
+
}
|
|
32549
|
+
}
|
|
32550
|
+
) })
|
|
32337
32551
|
] })
|
|
32338
32552
|
]
|
|
32339
32553
|
}
|
|
32340
32554
|
);
|
|
32341
32555
|
}
|
|
32556
|
+
const MIN_FIELD_GRID_SIZE = 18;
|
|
32557
|
+
const MAX_FIELD_GRID_SIZE = 32;
|
|
32558
|
+
const MAX_BLEND_SAMPLES = 12;
|
|
32559
|
+
const MAX_SEARCH_RADIUS = 5;
|
|
32560
|
+
const SAMPLE_RING_OFFSETS = [];
|
|
32561
|
+
for (let radius = 0; radius <= MAX_SEARCH_RADIUS; radius += 1) {
|
|
32562
|
+
const ring = [];
|
|
32563
|
+
for (let x = -radius; x <= radius; x += 1) {
|
|
32564
|
+
for (let y = -radius; y <= radius; y += 1) {
|
|
32565
|
+
for (let z = -radius; z <= radius; z += 1) {
|
|
32566
|
+
if (Math.max(Math.abs(x), Math.abs(y), Math.abs(z)) === radius) ring.push([x, y, z]);
|
|
32567
|
+
}
|
|
32568
|
+
}
|
|
32569
|
+
}
|
|
32570
|
+
SAMPLE_RING_OFFSETS.push(ring);
|
|
32571
|
+
}
|
|
32572
|
+
const INSPECT_HEATMAP_VERTEX_SHADER = `
|
|
32573
|
+
varying vec3 vLocalPosition;
|
|
32574
|
+
varying vec3 vViewDirection;
|
|
32575
|
+
varying vec3 vViewNormal;
|
|
32576
|
+
#include <clipping_planes_pars_vertex>
|
|
32577
|
+
|
|
32578
|
+
void main() {
|
|
32579
|
+
vLocalPosition = position;
|
|
32580
|
+
vViewNormal = normalize(normalMatrix * normal);
|
|
32581
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
32582
|
+
vViewDirection = normalize(-mvPosition.xyz);
|
|
32583
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
32584
|
+
#include <clipping_planes_vertex>
|
|
32585
|
+
}
|
|
32586
|
+
`;
|
|
32587
|
+
const INSPECT_HEATMAP_FRAGMENT_SHADER = `
|
|
32588
|
+
uniform sampler2D uField;
|
|
32589
|
+
uniform float uGridSize;
|
|
32590
|
+
uniform vec3 uBoundsMin;
|
|
32591
|
+
uniform vec3 uBoundsSize;
|
|
32592
|
+
varying vec3 vLocalPosition;
|
|
32593
|
+
varying vec3 vViewDirection;
|
|
32594
|
+
varying vec3 vViewNormal;
|
|
32595
|
+
#include <clipping_planes_pars_fragment>
|
|
32596
|
+
|
|
32597
|
+
vec2 fieldUv(vec3 index) {
|
|
32598
|
+
vec2 atlasSize = vec2(uGridSize * uGridSize, uGridSize);
|
|
32599
|
+
float atlasX = index.x + index.z * uGridSize;
|
|
32600
|
+
return (vec2(atlasX, index.y) + 0.5) / atlasSize;
|
|
32601
|
+
}
|
|
32602
|
+
|
|
32603
|
+
vec3 fetchField(vec3 index) {
|
|
32604
|
+
vec3 bounded = clamp(index, vec3(0.0), vec3(uGridSize - 1.0));
|
|
32605
|
+
return texture2D(uField, fieldUv(bounded)).rgb;
|
|
32606
|
+
}
|
|
32607
|
+
|
|
32608
|
+
vec3 sampleField(vec3 position) {
|
|
32609
|
+
vec3 normalized = clamp((position - uBoundsMin) / max(uBoundsSize, vec3(0.000001)), vec3(0.0), vec3(1.0));
|
|
32610
|
+
vec3 coord = normalized * (uGridSize - 1.0);
|
|
32611
|
+
vec3 base = floor(coord);
|
|
32612
|
+
vec3 f = fract(coord);
|
|
32613
|
+
|
|
32614
|
+
vec3 c000 = fetchField(base + vec3(0.0, 0.0, 0.0));
|
|
32615
|
+
vec3 c100 = fetchField(base + vec3(1.0, 0.0, 0.0));
|
|
32616
|
+
vec3 c010 = fetchField(base + vec3(0.0, 1.0, 0.0));
|
|
32617
|
+
vec3 c110 = fetchField(base + vec3(1.0, 1.0, 0.0));
|
|
32618
|
+
vec3 c001 = fetchField(base + vec3(0.0, 0.0, 1.0));
|
|
32619
|
+
vec3 c101 = fetchField(base + vec3(1.0, 0.0, 1.0));
|
|
32620
|
+
vec3 c011 = fetchField(base + vec3(0.0, 1.0, 1.0));
|
|
32621
|
+
vec3 c111 = fetchField(base + vec3(1.0, 1.0, 1.0));
|
|
32622
|
+
|
|
32623
|
+
vec3 c00 = mix(c000, c100, f.x);
|
|
32624
|
+
vec3 c10 = mix(c010, c110, f.x);
|
|
32625
|
+
vec3 c01 = mix(c001, c101, f.x);
|
|
32626
|
+
vec3 c11 = mix(c011, c111, f.x);
|
|
32627
|
+
return mix(mix(c00, c10, f.y), mix(c01, c11, f.y), f.z);
|
|
32628
|
+
}
|
|
32629
|
+
|
|
32630
|
+
void main() {
|
|
32631
|
+
#include <clipping_planes_fragment>
|
|
32632
|
+
vec3 heat = sampleField(vLocalPosition);
|
|
32633
|
+
float rim = pow(1.0 - clamp(dot(normalize(vViewNormal), normalize(vViewDirection)), 0.0, 1.0), 2.0);
|
|
32634
|
+
vec3 color = heat * (0.88 + rim * 0.2) + vec3(0.025, 0.04, 0.055) * rim;
|
|
32635
|
+
gl_FragColor = vec4(color, 1.0);
|
|
32636
|
+
}
|
|
32637
|
+
`;
|
|
32638
|
+
function gridKey(x, y, z) {
|
|
32639
|
+
return `${x},${y},${z}`;
|
|
32640
|
+
}
|
|
32641
|
+
function buildGeometryBounds(geometry) {
|
|
32642
|
+
const position = geometry.getAttribute("position");
|
|
32643
|
+
if (!position || position.count === 0) return null;
|
|
32644
|
+
const bounds = new Box3().setFromBufferAttribute(position);
|
|
32645
|
+
if (bounds.isEmpty()) return null;
|
|
32646
|
+
const size = bounds.getSize(new Vector3());
|
|
32647
|
+
const pad = Math.max(size.x, size.y, size.z, 1) * 1e-5;
|
|
32648
|
+
bounds.expandByScalar(pad);
|
|
32649
|
+
return bounds;
|
|
32650
|
+
}
|
|
32651
|
+
function buildSampleGrid(pointCloud) {
|
|
32652
|
+
const sampleCount = Math.floor(pointCloud.positions.length / 3);
|
|
32653
|
+
if (sampleCount <= 0) return null;
|
|
32654
|
+
const bounds = new Box3();
|
|
32655
|
+
const point = new Vector3();
|
|
32656
|
+
for (let sample = 0; sample < sampleCount; sample += 1) {
|
|
32657
|
+
const offset = sample * 3;
|
|
32658
|
+
bounds.expandByPoint(point.set(pointCloud.positions[offset], pointCloud.positions[offset + 1], pointCloud.positions[offset + 2]));
|
|
32659
|
+
}
|
|
32660
|
+
const size = bounds.getSize(new Vector3());
|
|
32661
|
+
const maxDim = Math.max(size.x, size.y, size.z);
|
|
32662
|
+
const cellSize = maxDim > 0 ? Math.max(maxDim / Math.cbrt(sampleCount), 1e-6) : 1;
|
|
32663
|
+
const cells = /* @__PURE__ */ new Map();
|
|
32664
|
+
for (let sample = 0; sample < sampleCount; sample += 1) {
|
|
32665
|
+
const offset = sample * 3;
|
|
32666
|
+
const x = Math.floor((pointCloud.positions[offset] - bounds.min.x) / cellSize);
|
|
32667
|
+
const y = Math.floor((pointCloud.positions[offset + 1] - bounds.min.y) / cellSize);
|
|
32668
|
+
const z = Math.floor((pointCloud.positions[offset + 2] - bounds.min.z) / cellSize);
|
|
32669
|
+
const key = gridKey(x, y, z);
|
|
32670
|
+
const entries = cells.get(key);
|
|
32671
|
+
if (entries) {
|
|
32672
|
+
entries.push(sample);
|
|
32673
|
+
} else {
|
|
32674
|
+
cells.set(key, [sample]);
|
|
32675
|
+
}
|
|
32676
|
+
}
|
|
32677
|
+
return { origin: bounds.min, cellSize, cells };
|
|
32678
|
+
}
|
|
32679
|
+
function fieldGridSizeForSampleCount(sampleCount) {
|
|
32680
|
+
if (sampleCount <= 0) return MIN_FIELD_GRID_SIZE;
|
|
32681
|
+
const scaled = Math.ceil(Math.cbrt(sampleCount) * 2.6);
|
|
32682
|
+
return Math.max(MIN_FIELD_GRID_SIZE, Math.min(MAX_FIELD_GRID_SIZE, scaled));
|
|
32683
|
+
}
|
|
32684
|
+
function distanceSquaredToSample(pointCloud, sample, point) {
|
|
32685
|
+
const offset = sample * 3;
|
|
32686
|
+
return (pointCloud.positions[offset] - point.x) ** 2 + (pointCloud.positions[offset + 1] - point.y) ** 2 + (pointCloud.positions[offset + 2] - point.z) ** 2;
|
|
32687
|
+
}
|
|
32688
|
+
function nearestSamples(point, pointCloud, sampleGrid) {
|
|
32689
|
+
const baseX = Math.floor((point.x - sampleGrid.origin.x) / sampleGrid.cellSize);
|
|
32690
|
+
const baseY = Math.floor((point.y - sampleGrid.origin.y) / sampleGrid.cellSize);
|
|
32691
|
+
const baseZ = Math.floor((point.z - sampleGrid.origin.z) / sampleGrid.cellSize);
|
|
32692
|
+
const found = [];
|
|
32693
|
+
for (const ring of SAMPLE_RING_OFFSETS) {
|
|
32694
|
+
for (const [dx, dy, dz] of ring) {
|
|
32695
|
+
const entries = sampleGrid.cells.get(gridKey(baseX + dx, baseY + dy, baseZ + dz));
|
|
32696
|
+
if (!entries) continue;
|
|
32697
|
+
for (const sample of entries) {
|
|
32698
|
+
found.push({ sample, distSq: distanceSquaredToSample(pointCloud, sample, point) });
|
|
32699
|
+
}
|
|
32700
|
+
}
|
|
32701
|
+
if (found.length >= MAX_BLEND_SAMPLES) break;
|
|
32702
|
+
}
|
|
32703
|
+
if (found.length === 0) {
|
|
32704
|
+
const sampleCount = Math.floor(pointCloud.positions.length / 3);
|
|
32705
|
+
for (let sample = 0; sample < sampleCount; sample += 1) {
|
|
32706
|
+
found.push({ sample, distSq: distanceSquaredToSample(pointCloud, sample, point) });
|
|
32707
|
+
}
|
|
32708
|
+
}
|
|
32709
|
+
found.sort((a2, b2) => a2.distSq - b2.distSq);
|
|
32710
|
+
return found.slice(0, MAX_BLEND_SAMPLES);
|
|
32711
|
+
}
|
|
32712
|
+
function blendedColorAt(point, pointCloud, sampleGrid) {
|
|
32713
|
+
const samples = nearestSamples(point, pointCloud, sampleGrid);
|
|
32714
|
+
if (samples.length === 0) return [90, 90, 90];
|
|
32715
|
+
const sigma = Math.max(sampleGrid.cellSize * 1.65, 1e-6);
|
|
32716
|
+
const sigmaSq = sigma * sigma;
|
|
32717
|
+
let weightSum = 0;
|
|
32718
|
+
let r2 = 0;
|
|
32719
|
+
let g2 = 0;
|
|
32720
|
+
let b2 = 0;
|
|
32721
|
+
for (const { sample, distSq } of samples) {
|
|
32722
|
+
const colorOffset = sample * 3;
|
|
32723
|
+
const weight = Math.exp(-distSq / (2 * sigmaSq)) + 1e-4 / Math.max(distSq, 1e-8);
|
|
32724
|
+
weightSum += weight;
|
|
32725
|
+
r2 += (pointCloud.colors[colorOffset] ?? 0.35) * 255 * weight;
|
|
32726
|
+
g2 += (pointCloud.colors[colorOffset + 1] ?? 0.35) * 255 * weight;
|
|
32727
|
+
b2 += (pointCloud.colors[colorOffset + 2] ?? 0.35) * 255 * weight;
|
|
32728
|
+
}
|
|
32729
|
+
if (weightSum <= 0) return [90, 90, 90];
|
|
32730
|
+
return [r2 / weightSum, g2 / weightSum, b2 / weightSum];
|
|
32731
|
+
}
|
|
32732
|
+
function buildInspectHeatmapField(geometry, pointCloud) {
|
|
32733
|
+
const bounds = buildGeometryBounds(geometry);
|
|
32734
|
+
const sampleGrid = buildSampleGrid(pointCloud);
|
|
32735
|
+
if (!bounds || !sampleGrid) return null;
|
|
32736
|
+
const gridSize = fieldGridSizeForSampleCount(Math.floor(pointCloud.positions.length / 3));
|
|
32737
|
+
const boundsSize = bounds.getSize(new Vector3());
|
|
32738
|
+
const data = new Uint8Array(gridSize * gridSize * gridSize * 4);
|
|
32739
|
+
const point = new Vector3();
|
|
32740
|
+
let dataOffset = 0;
|
|
32741
|
+
for (let y = 0; y < gridSize; y += 1) {
|
|
32742
|
+
for (let z = 0; z < gridSize; z += 1) {
|
|
32743
|
+
for (let x = 0; x < gridSize; x += 1) {
|
|
32744
|
+
point.set(
|
|
32745
|
+
bounds.min.x + boundsSize.x * x / (gridSize - 1),
|
|
32746
|
+
bounds.min.y + boundsSize.y * y / (gridSize - 1),
|
|
32747
|
+
bounds.min.z + boundsSize.z * z / (gridSize - 1)
|
|
32748
|
+
);
|
|
32749
|
+
const [r2, g2, b2] = blendedColorAt(point, pointCloud, sampleGrid);
|
|
32750
|
+
data[dataOffset] = Math.max(0, Math.min(255, Math.round(r2)));
|
|
32751
|
+
data[dataOffset + 1] = Math.max(0, Math.min(255, Math.round(g2)));
|
|
32752
|
+
data[dataOffset + 2] = Math.max(0, Math.min(255, Math.round(b2)));
|
|
32753
|
+
data[dataOffset + 3] = 255;
|
|
32754
|
+
dataOffset += 4;
|
|
32755
|
+
}
|
|
32756
|
+
}
|
|
32757
|
+
}
|
|
32758
|
+
const texture = new DataTexture(data, gridSize * gridSize, gridSize, RGBAFormat, UnsignedByteType);
|
|
32759
|
+
texture.minFilter = NearestFilter;
|
|
32760
|
+
texture.magFilter = NearestFilter;
|
|
32761
|
+
texture.generateMipmaps = false;
|
|
32762
|
+
texture.unpackAlignment = 1;
|
|
32763
|
+
texture.needsUpdate = true;
|
|
32764
|
+
return {
|
|
32765
|
+
texture,
|
|
32766
|
+
boundsMin: bounds.min,
|
|
32767
|
+
boundsSize,
|
|
32768
|
+
gridSize
|
|
32769
|
+
};
|
|
32770
|
+
}
|
|
32342
32771
|
function ForgeObject({
|
|
32343
32772
|
obj,
|
|
32344
32773
|
settings,
|
|
32345
32774
|
renderStyle,
|
|
32346
32775
|
renderMode,
|
|
32347
32776
|
inspectChannel = "none",
|
|
32777
|
+
inspectDisplayMode = "heatmap",
|
|
32348
32778
|
inspectColor,
|
|
32779
|
+
inspectMeshColors,
|
|
32780
|
+
inspectPointCloud,
|
|
32349
32781
|
isInteracting,
|
|
32350
32782
|
matrix,
|
|
32351
32783
|
isHovered,
|
|
@@ -32382,16 +32814,26 @@ function ForgeObject({
|
|
|
32382
32814
|
};
|
|
32383
32815
|
}
|
|
32384
32816
|
}, [obj.shape]);
|
|
32385
|
-
const
|
|
32386
|
-
if (!
|
|
32387
|
-
|
|
32388
|
-
|
|
32389
|
-
|
|
32390
|
-
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
32817
|
+
const inspectPointGeo = reactExports.useMemo(() => {
|
|
32818
|
+
if (!inspectPointCloud) return null;
|
|
32819
|
+
const geometry = new BufferGeometry();
|
|
32820
|
+
geometry.setAttribute("position", new BufferAttribute(inspectPointCloud.positions, 3));
|
|
32821
|
+
geometry.setAttribute("color", new BufferAttribute(inspectPointCloud.colors, 3));
|
|
32822
|
+
return geometry;
|
|
32823
|
+
}, [inspectPointCloud]);
|
|
32824
|
+
const inspectMeshColorGeo = reactExports.useMemo(() => {
|
|
32825
|
+
if (!solidGeo || !inspectMeshColors) return null;
|
|
32826
|
+
const position = solidGeo.getAttribute("position");
|
|
32827
|
+
if (!position || inspectMeshColors.length !== position.count * 3) return null;
|
|
32828
|
+
const geometry = solidGeo.clone();
|
|
32829
|
+
geometry.setAttribute("color", new BufferAttribute(inspectMeshColors, 3));
|
|
32830
|
+
return geometry;
|
|
32831
|
+
}, [inspectMeshColors, solidGeo]);
|
|
32832
|
+
const isScalarInspect = inspectChannel === "thickness" || inspectChannel === "roughness";
|
|
32833
|
+
const inspectHeatmapField = reactExports.useMemo(() => {
|
|
32834
|
+
if (!isScalarInspect || !solidGeo || !inspectPointCloud) return null;
|
|
32835
|
+
return buildInspectHeatmapField(solidGeo, inspectPointCloud);
|
|
32836
|
+
}, [inspectPointCloud, isScalarInspect, solidGeo]);
|
|
32395
32837
|
reactExports.useEffect(() => {
|
|
32396
32838
|
return () => {
|
|
32397
32839
|
solidGeo == null ? void 0 : solidGeo.dispose();
|
|
@@ -32400,12 +32842,28 @@ function ForgeObject({
|
|
|
32400
32842
|
}, [edgesGeo, solidGeo]);
|
|
32401
32843
|
reactExports.useEffect(() => {
|
|
32402
32844
|
return () => {
|
|
32403
|
-
|
|
32845
|
+
inspectPointGeo == null ? void 0 : inspectPointGeo.dispose();
|
|
32846
|
+
};
|
|
32847
|
+
}, [inspectPointGeo]);
|
|
32848
|
+
reactExports.useEffect(() => {
|
|
32849
|
+
return () => {
|
|
32850
|
+
inspectMeshColorGeo == null ? void 0 : inspectMeshColorGeo.dispose();
|
|
32404
32851
|
};
|
|
32405
|
-
}, [
|
|
32852
|
+
}, [inspectMeshColorGeo]);
|
|
32853
|
+
reactExports.useEffect(() => {
|
|
32854
|
+
return () => {
|
|
32855
|
+
inspectHeatmapField == null ? void 0 : inspectHeatmapField.texture.dispose();
|
|
32856
|
+
};
|
|
32857
|
+
}, [inspectHeatmapField]);
|
|
32406
32858
|
if (!solidGeo || !settings.visible) return null;
|
|
32407
32859
|
const effectiveRenderMode = isInteracting && renderMode === "overlay" ? "solid" : renderMode;
|
|
32408
32860
|
const isInspecting = inspectChannel !== "none";
|
|
32861
|
+
const showInspectHeatmap = Boolean(
|
|
32862
|
+
isScalarInspect && inspectHeatmapField && (inspectDisplayMode === "heatmap" || inspectDisplayMode === "both")
|
|
32863
|
+
);
|
|
32864
|
+
const showInspectPoints = Boolean(
|
|
32865
|
+
isScalarInspect && inspectPointGeo && (inspectDisplayMode === "points" || inspectDisplayMode === "both")
|
|
32866
|
+
);
|
|
32409
32867
|
const renderStylePreset = getRenderStylePreset(renderStyle);
|
|
32410
32868
|
const materialDefaults = renderStylePreset.material;
|
|
32411
32869
|
const authoredMaterialOpacity = (_a3 = obj.materialProps) == null ? void 0 : _a3.opacity;
|
|
@@ -32421,6 +32879,8 @@ function ForgeObject({
|
|
|
32421
32879
|
const showEdges = !isInspecting && effectiveRenderMode === "overlay";
|
|
32422
32880
|
const showWire = !isInspecting && effectiveRenderMode === "wireframe";
|
|
32423
32881
|
const effectiveClippingPlanes = clippingPlanes ?? [];
|
|
32882
|
+
const inspectSolidGeo = inspectMeshColorGeo ?? solidGeo;
|
|
32883
|
+
const hasInspectMeshColors = inspectMeshColorGeo !== null;
|
|
32424
32884
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32425
32885
|
"group",
|
|
32426
32886
|
{
|
|
@@ -32433,16 +32893,56 @@ function ForgeObject({
|
|
|
32433
32893
|
onDoubleClick,
|
|
32434
32894
|
onContextMenu,
|
|
32435
32895
|
children: [
|
|
32436
|
-
showSolid && (inspectChannel === "mask" || inspectChannel === "connectivity" || inspectChannel === "distance") && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry:
|
|
32896
|
+
showSolid && (inspectChannel === "mask" || inspectChannel === "connectivity" || inspectChannel === "distance") && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: inspectSolidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32897
|
+
"meshBasicMaterial",
|
|
32898
|
+
{
|
|
32899
|
+
color: hasInspectMeshColors ? "#ffffff" : inspectColor ?? settings.color,
|
|
32900
|
+
vertexColors: hasInspectMeshColors,
|
|
32901
|
+
side: DoubleSide,
|
|
32902
|
+
toneMapped: false,
|
|
32903
|
+
clippingPlanes: effectiveClippingPlanes
|
|
32904
|
+
}
|
|
32905
|
+
) }),
|
|
32906
|
+
showSolid && isScalarInspect && !showInspectHeatmap && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32437
32907
|
"meshBasicMaterial",
|
|
32438
32908
|
{
|
|
32439
|
-
color:
|
|
32909
|
+
color: "#26313a",
|
|
32910
|
+
transparent: true,
|
|
32911
|
+
opacity: 0.24,
|
|
32440
32912
|
side: DoubleSide,
|
|
32913
|
+
depthWrite: true,
|
|
32914
|
+
toneMapped: false,
|
|
32915
|
+
clippingPlanes: effectiveClippingPlanes
|
|
32916
|
+
}
|
|
32917
|
+
) }),
|
|
32918
|
+
showSolid && showInspectHeatmap && inspectHeatmapField && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, renderOrder: 4, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32919
|
+
"shaderMaterial",
|
|
32920
|
+
{
|
|
32921
|
+
vertexShader: INSPECT_HEATMAP_VERTEX_SHADER,
|
|
32922
|
+
fragmentShader: INSPECT_HEATMAP_FRAGMENT_SHADER,
|
|
32923
|
+
uniforms: {
|
|
32924
|
+
uField: { value: inspectHeatmapField.texture },
|
|
32925
|
+
uGridSize: { value: inspectHeatmapField.gridSize },
|
|
32926
|
+
uBoundsMin: { value: inspectHeatmapField.boundsMin },
|
|
32927
|
+
uBoundsSize: { value: inspectHeatmapField.boundsSize }
|
|
32928
|
+
},
|
|
32929
|
+
side: DoubleSide,
|
|
32930
|
+
toneMapped: false,
|
|
32931
|
+
clippingPlanes: effectiveClippingPlanes
|
|
32932
|
+
}
|
|
32933
|
+
) }),
|
|
32934
|
+
showSolid && showInspectPoints && inspectPointGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("points", { geometry: inspectPointGeo, raycast: () => null, renderOrder: 5, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32935
|
+
"pointsMaterial",
|
|
32936
|
+
{
|
|
32937
|
+
size: 3,
|
|
32938
|
+
sizeAttenuation: false,
|
|
32939
|
+
vertexColors: true,
|
|
32940
|
+
depthTest: true,
|
|
32941
|
+
depthWrite: false,
|
|
32441
32942
|
toneMapped: false,
|
|
32442
32943
|
clippingPlanes: effectiveClippingPlanes
|
|
32443
32944
|
}
|
|
32444
32945
|
) }),
|
|
32445
|
-
showSolid && (inspectChannel === "thickness" || inspectChannel === "roughness") && inspectionGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: inspectionGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("meshBasicMaterial", { vertexColors: true, side: DoubleSide, toneMapped: false, clippingPlanes: effectiveClippingPlanes }) }),
|
|
32446
32946
|
showSolid && inspectChannel === "collisions" && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32447
32947
|
"meshPhysicalMaterial",
|
|
32448
32948
|
{
|
|
@@ -38049,6 +38549,8 @@ function useViewportState() {
|
|
|
38049
38549
|
const renderMode = useForgeStore((s) => s.renderMode);
|
|
38050
38550
|
const renderStyle = useForgeStore((s) => s.renderStyle);
|
|
38051
38551
|
const inspectChannel = useForgeStore((s) => s.inspectChannel);
|
|
38552
|
+
const inspectDisplayMode = useForgeStore((s) => s.inspectDisplayMode);
|
|
38553
|
+
const inspectPointSampleCount = useForgeStore((s) => s.inspectPointSampleCount);
|
|
38052
38554
|
const projectionMode = useForgeStore((s) => s.projectionMode);
|
|
38053
38555
|
const gridEnabled = useForgeStore((s) => s.gridEnabled);
|
|
38054
38556
|
const gridSize = useForgeStore((s) => s.gridSize);
|
|
@@ -38376,6 +38878,8 @@ function useViewportState() {
|
|
|
38376
38878
|
renderMode,
|
|
38377
38879
|
renderStyle,
|
|
38378
38880
|
inspectChannel,
|
|
38881
|
+
inspectDisplayMode,
|
|
38882
|
+
inspectPointSampleCount,
|
|
38379
38883
|
projectionMode,
|
|
38380
38884
|
gridEnabled,
|
|
38381
38885
|
gridSize,
|
|
@@ -39705,58 +40209,6 @@ function ModelJourneyBar({
|
|
|
39705
40209
|
}
|
|
39706
40210
|
);
|
|
39707
40211
|
}
|
|
39708
|
-
function transformedShapeBounds(obj, matrix) {
|
|
39709
|
-
if (!obj.shape) return null;
|
|
39710
|
-
try {
|
|
39711
|
-
const bb = obj.shape.boundingBox();
|
|
39712
|
-
const bounds = new Box3();
|
|
39713
|
-
if (!expandBoundsByTransformedAabb(bounds, bb.min, bb.max, matrix)) return null;
|
|
39714
|
-
return isFiniteBox3(bounds) ? bounds : null;
|
|
39715
|
-
} catch {
|
|
39716
|
-
return null;
|
|
39717
|
-
}
|
|
39718
|
-
}
|
|
39719
|
-
function bodyCountForShape(obj) {
|
|
39720
|
-
var _a3, _b2;
|
|
39721
|
-
try {
|
|
39722
|
-
const bodyCount = (_b2 = (_a3 = obj.shape) == null ? void 0 : _a3.numBodies) == null ? void 0 : _b2.call(_a3);
|
|
39723
|
-
return typeof bodyCount === "number" && Number.isFinite(bodyCount) ? Math.max(0, Math.round(bodyCount)) : 1;
|
|
39724
|
-
} catch {
|
|
39725
|
-
return 1;
|
|
39726
|
-
}
|
|
39727
|
-
}
|
|
39728
|
-
function buildPhysicalConnectivityEntries(objects, objectSettings, objectMatrices) {
|
|
39729
|
-
const entries = [];
|
|
39730
|
-
objects.forEach((obj) => {
|
|
39731
|
-
var _a3;
|
|
39732
|
-
if (!obj.shape) return;
|
|
39733
|
-
if (((_a3 = objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) return;
|
|
39734
|
-
const bounds = transformedShapeBounds(obj, objectMatrices[obj.id] ?? new Matrix4());
|
|
39735
|
-
if (!bounds) return;
|
|
39736
|
-
entries.push({
|
|
39737
|
-
id: obj.id,
|
|
39738
|
-
name: obj.name,
|
|
39739
|
-
shape: obj.shape,
|
|
39740
|
-
min: [bounds.min.x, bounds.min.y, bounds.min.z],
|
|
39741
|
-
max: [bounds.max.x, bounds.max.y, bounds.max.z],
|
|
39742
|
-
groupName: obj.groupName,
|
|
39743
|
-
treePath: obj.treePath,
|
|
39744
|
-
mock: obj.mock,
|
|
39745
|
-
bodyCount: bodyCountForShape(obj)
|
|
39746
|
-
});
|
|
39747
|
-
});
|
|
39748
|
-
return entries;
|
|
39749
|
-
}
|
|
39750
|
-
function connectivityColorByObjectId(entries) {
|
|
39751
|
-
const report = analyzePhysicalConnectivity(entries);
|
|
39752
|
-
return Object.fromEntries(report.objects.map((object) => [object.id, maskColorForIndex(object.componentIndex - 1)]));
|
|
39753
|
-
}
|
|
39754
|
-
function distanceColorByObjectId(entries) {
|
|
39755
|
-
const report = analyzeDistanceInspection(entries);
|
|
39756
|
-
return Object.fromEntries(
|
|
39757
|
-
report.objects.map((object) => [object.id, distanceColorForRootDistance(object.rootDistance, report.maxRootDistance)])
|
|
39758
|
-
);
|
|
39759
|
-
}
|
|
39760
40212
|
const anchorTransform = {
|
|
39761
40213
|
center: "translate(-50%, -50%)",
|
|
39762
40214
|
top: "translate(-50%, 0)",
|
|
@@ -39804,6 +40256,276 @@ function RenderLabelsOverlay({ labels }) {
|
|
|
39804
40256
|
if (labels.length === 0) return null;
|
|
39805
40257
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("group", { renderOrder: 12, children: labels.map((label) => /* @__PURE__ */ jsxRuntimeExports.jsx(RenderLabelItem, { label }, label.id)) });
|
|
39806
40258
|
}
|
|
40259
|
+
class InspectWorkerClient {
|
|
40260
|
+
constructor(workerFactory = () => new Worker(new URL(
|
|
40261
|
+
/* @vite-ignore */
|
|
40262
|
+
"/assets/inspectWorker-Dll4eVyD.js",
|
|
40263
|
+
import.meta.url
|
|
40264
|
+
), { type: "module" })) {
|
|
40265
|
+
__publicField(this, "worker", null);
|
|
40266
|
+
__publicField(this, "reqId", 0);
|
|
40267
|
+
__publicField(this, "pending", null);
|
|
40268
|
+
this.workerFactory = workerFactory;
|
|
40269
|
+
}
|
|
40270
|
+
getWorker() {
|
|
40271
|
+
if (this.worker) return this.worker;
|
|
40272
|
+
this.worker = this.workerFactory();
|
|
40273
|
+
this.worker.onmessage = (event) => {
|
|
40274
|
+
const data = event.data;
|
|
40275
|
+
const pending = this.pending;
|
|
40276
|
+
if (!pending) return;
|
|
40277
|
+
this.pending = null;
|
|
40278
|
+
if (data.type === "inspect-error") {
|
|
40279
|
+
pending.reject(new Error(data.payload.message));
|
|
40280
|
+
} else {
|
|
40281
|
+
pending.resolve(data.payload.result);
|
|
40282
|
+
}
|
|
40283
|
+
};
|
|
40284
|
+
this.worker.onerror = (event) => {
|
|
40285
|
+
var _a3, _b2;
|
|
40286
|
+
const error = new Error(event.message || "Inspect worker failed unexpectedly.");
|
|
40287
|
+
(_a3 = this.pending) == null ? void 0 : _a3.reject(error);
|
|
40288
|
+
this.pending = null;
|
|
40289
|
+
(_b2 = this.worker) == null ? void 0 : _b2.terminate();
|
|
40290
|
+
this.worker = null;
|
|
40291
|
+
};
|
|
40292
|
+
return this.worker;
|
|
40293
|
+
}
|
|
40294
|
+
replaceActiveWorker() {
|
|
40295
|
+
var _a3, _b2;
|
|
40296
|
+
(_a3 = this.pending) == null ? void 0 : _a3.reject(new Error("cancelled"));
|
|
40297
|
+
this.pending = null;
|
|
40298
|
+
(_b2 = this.worker) == null ? void 0 : _b2.terminate();
|
|
40299
|
+
this.worker = null;
|
|
40300
|
+
}
|
|
40301
|
+
analyze(payload) {
|
|
40302
|
+
if (this.pending) this.replaceActiveWorker();
|
|
40303
|
+
const reqId = ++this.reqId;
|
|
40304
|
+
const request = {
|
|
40305
|
+
type: "analyze",
|
|
40306
|
+
payload: {
|
|
40307
|
+
reqId,
|
|
40308
|
+
...payload
|
|
40309
|
+
}
|
|
40310
|
+
};
|
|
40311
|
+
const transfers = payload.objects.flatMap((object) => object.positions ? [object.positions.buffer] : []);
|
|
40312
|
+
return new Promise((resolve2, reject) => {
|
|
40313
|
+
this.pending = { resolve: resolve2, reject };
|
|
40314
|
+
this.getWorker().postMessage(request, transfers);
|
|
40315
|
+
});
|
|
40316
|
+
}
|
|
40317
|
+
dispose() {
|
|
40318
|
+
this.replaceActiveWorker();
|
|
40319
|
+
}
|
|
40320
|
+
}
|
|
40321
|
+
const inspectWorkerClient = new InspectWorkerClient();
|
|
40322
|
+
const WORKER_CHANNELS = /* @__PURE__ */ new Set(["thickness", "roughness", "connectivity", "distance"]);
|
|
40323
|
+
const SCALAR_WORKER_CHANNELS = /* @__PURE__ */ new Set(["thickness", "roughness"]);
|
|
40324
|
+
const MESH_COMPONENT_WORKER_CHANNELS = /* @__PURE__ */ new Set(["connectivity", "distance"]);
|
|
40325
|
+
const VIEWPORT_SCALAR_SCENE_BUDGET_OBJECTS = 15;
|
|
40326
|
+
class InspectBuildCancelledError extends Error {
|
|
40327
|
+
constructor() {
|
|
40328
|
+
super("cancelled");
|
|
40329
|
+
}
|
|
40330
|
+
}
|
|
40331
|
+
function isScalarWorkerChannel(channel) {
|
|
40332
|
+
return SCALAR_WORKER_CHANNELS.has(channel);
|
|
40333
|
+
}
|
|
40334
|
+
function needsMeshComponents(channel) {
|
|
40335
|
+
return MESH_COMPONENT_WORKER_CHANNELS.has(channel);
|
|
40336
|
+
}
|
|
40337
|
+
function viewportScalarSamplesPerObject(objectCount, inspectPointSampleCount) {
|
|
40338
|
+
const perObjectCap = resolveInspectPointSampleCount(inspectPointSampleCount);
|
|
40339
|
+
if (objectCount <= 0) return perObjectCap;
|
|
40340
|
+
const sceneBudget = perObjectCap * VIEWPORT_SCALAR_SCENE_BUDGET_OBJECTS;
|
|
40341
|
+
const budgeted = Math.floor(sceneBudget / objectCount);
|
|
40342
|
+
return Math.max(INSPECT_POINT_SAMPLE_COUNT_MIN, Math.min(perObjectCap, budgeted));
|
|
40343
|
+
}
|
|
40344
|
+
function yieldToBrowser() {
|
|
40345
|
+
if (typeof window === "undefined") return Promise.resolve();
|
|
40346
|
+
return new Promise((resolve2) => {
|
|
40347
|
+
const maybeIdleWindow = window;
|
|
40348
|
+
if (typeof maybeIdleWindow.requestIdleCallback === "function") {
|
|
40349
|
+
maybeIdleWindow.requestIdleCallback(() => resolve2(), { timeout: 50 });
|
|
40350
|
+
return;
|
|
40351
|
+
}
|
|
40352
|
+
window.setTimeout(resolve2, 0);
|
|
40353
|
+
});
|
|
40354
|
+
}
|
|
40355
|
+
function transformedBounds(obj, matrix) {
|
|
40356
|
+
if (!obj.shape) return null;
|
|
40357
|
+
try {
|
|
40358
|
+
const bbox = obj.shape.boundingBox();
|
|
40359
|
+
const bounds = new Box3();
|
|
40360
|
+
if (!expandBoundsByTransformedAabb(bounds, bbox.min, bbox.max, matrix)) return null;
|
|
40361
|
+
if (!isFiniteBox3(bounds)) return null;
|
|
40362
|
+
return {
|
|
40363
|
+
min: [bounds.min.x, bounds.min.y, bounds.min.z],
|
|
40364
|
+
max: [bounds.max.x, bounds.max.y, bounds.max.z]
|
|
40365
|
+
};
|
|
40366
|
+
} catch {
|
|
40367
|
+
return null;
|
|
40368
|
+
}
|
|
40369
|
+
}
|
|
40370
|
+
function clonePositions(obj, matrix) {
|
|
40371
|
+
var _a3;
|
|
40372
|
+
if (!obj.shape) return void 0;
|
|
40373
|
+
const geometry = obj.shape instanceof FrozenShape ? null : shapeToGeometry(obj.shape);
|
|
40374
|
+
try {
|
|
40375
|
+
const source = obj.shape instanceof FrozenShape ? obj.shape.getPrecomputedGeometry().positions : (_a3 = geometry == null ? void 0 : geometry.solid.getAttribute("position")) == null ? void 0 : _a3.array;
|
|
40376
|
+
if (!source) return void 0;
|
|
40377
|
+
const positions = new Float32Array(source);
|
|
40378
|
+
if (matrix) {
|
|
40379
|
+
const point = new Vector3();
|
|
40380
|
+
for (let index = 0; index < positions.length; index += 3) {
|
|
40381
|
+
point.set(positions[index], positions[index + 1], positions[index + 2]).applyMatrix4(matrix);
|
|
40382
|
+
positions[index] = point.x;
|
|
40383
|
+
positions[index + 1] = point.y;
|
|
40384
|
+
positions[index + 2] = point.z;
|
|
40385
|
+
}
|
|
40386
|
+
}
|
|
40387
|
+
return positions;
|
|
40388
|
+
} finally {
|
|
40389
|
+
geometry == null ? void 0 : geometry.solid.dispose();
|
|
40390
|
+
geometry == null ? void 0 : geometry.edges.dispose();
|
|
40391
|
+
}
|
|
40392
|
+
}
|
|
40393
|
+
async function buildWorkerObjects(args) {
|
|
40394
|
+
var _a3;
|
|
40395
|
+
const needsMesh = isScalarWorkerChannel(args.inspectChannel) || needsMeshComponents(args.inspectChannel);
|
|
40396
|
+
const out = [];
|
|
40397
|
+
for (const obj of args.objects) {
|
|
40398
|
+
if (args.isCancelled()) throw new InspectBuildCancelledError();
|
|
40399
|
+
if (!obj.shape) continue;
|
|
40400
|
+
if (((_a3 = args.objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) continue;
|
|
40401
|
+
await yieldToBrowser();
|
|
40402
|
+
if (args.isCancelled()) throw new InspectBuildCancelledError();
|
|
40403
|
+
const matrix = args.objectMatrices[obj.id] ?? new Matrix4();
|
|
40404
|
+
const bbox = transformedBounds(obj, matrix);
|
|
40405
|
+
if (!bbox) continue;
|
|
40406
|
+
if (args.isCancelled()) throw new InspectBuildCancelledError();
|
|
40407
|
+
out.push({
|
|
40408
|
+
id: obj.id,
|
|
40409
|
+
name: obj.name,
|
|
40410
|
+
groupName: obj.groupName,
|
|
40411
|
+
treePath: obj.treePath,
|
|
40412
|
+
mock: obj.mock,
|
|
40413
|
+
bbox,
|
|
40414
|
+
...needsMesh ? { positions: clonePositions(obj, needsMeshComponents(args.inspectChannel) ? matrix : void 0) } : {}
|
|
40415
|
+
});
|
|
40416
|
+
await yieldToBrowser();
|
|
40417
|
+
}
|
|
40418
|
+
return out;
|
|
40419
|
+
}
|
|
40420
|
+
function analyzePayloadFor(channel, objects, inspectPointSampleCount) {
|
|
40421
|
+
const maxSamplesPerObject = viewportScalarSamplesPerObject(objects.length, inspectPointSampleCount);
|
|
40422
|
+
if (channel === "thickness") {
|
|
40423
|
+
return {
|
|
40424
|
+
channel,
|
|
40425
|
+
objects,
|
|
40426
|
+
thickness: {
|
|
40427
|
+
maxSamplesPerObject
|
|
40428
|
+
}
|
|
40429
|
+
};
|
|
40430
|
+
}
|
|
40431
|
+
if (channel === "roughness") {
|
|
40432
|
+
return {
|
|
40433
|
+
channel,
|
|
40434
|
+
objects,
|
|
40435
|
+
roughness: {
|
|
40436
|
+
maxSamplesPerObject
|
|
40437
|
+
}
|
|
40438
|
+
};
|
|
40439
|
+
}
|
|
40440
|
+
return { channel, objects };
|
|
40441
|
+
}
|
|
40442
|
+
function resultToState(channel, result) {
|
|
40443
|
+
return {
|
|
40444
|
+
status: "ready",
|
|
40445
|
+
channel,
|
|
40446
|
+
objectColors: result.objectColors,
|
|
40447
|
+
meshColors: Object.fromEntries(result.meshColorObjects.map((object) => [object.objectId, object.colors])),
|
|
40448
|
+
pointClouds: Object.fromEntries(
|
|
40449
|
+
result.pointObjects.map((object) => [
|
|
40450
|
+
object.objectId,
|
|
40451
|
+
{
|
|
40452
|
+
sampleCount: object.sampleCount,
|
|
40453
|
+
positions: object.positions,
|
|
40454
|
+
colors: object.colors
|
|
40455
|
+
}
|
|
40456
|
+
])
|
|
40457
|
+
),
|
|
40458
|
+
warnings: result.warnings,
|
|
40459
|
+
error: null
|
|
40460
|
+
};
|
|
40461
|
+
}
|
|
40462
|
+
function useInspectWorkerAnalysis(args) {
|
|
40463
|
+
const [state2, setState] = reactExports.useState({
|
|
40464
|
+
status: "idle",
|
|
40465
|
+
channel: "none",
|
|
40466
|
+
objectColors: {},
|
|
40467
|
+
meshColors: {},
|
|
40468
|
+
pointClouds: {},
|
|
40469
|
+
warnings: [],
|
|
40470
|
+
error: null
|
|
40471
|
+
});
|
|
40472
|
+
reactExports.useEffect(() => {
|
|
40473
|
+
if (!WORKER_CHANNELS.has(args.inspectChannel)) {
|
|
40474
|
+
inspectWorkerClient.dispose();
|
|
40475
|
+
setState({
|
|
40476
|
+
status: "idle",
|
|
40477
|
+
channel: args.inspectChannel,
|
|
40478
|
+
objectColors: {},
|
|
40479
|
+
meshColors: {},
|
|
40480
|
+
pointClouds: {},
|
|
40481
|
+
warnings: [],
|
|
40482
|
+
error: null
|
|
40483
|
+
});
|
|
40484
|
+
return;
|
|
40485
|
+
}
|
|
40486
|
+
let cancelled = false;
|
|
40487
|
+
const channel = args.inspectChannel;
|
|
40488
|
+
setState({
|
|
40489
|
+
status: "loading",
|
|
40490
|
+
channel: args.inspectChannel,
|
|
40491
|
+
objectColors: {},
|
|
40492
|
+
meshColors: {},
|
|
40493
|
+
pointClouds: {},
|
|
40494
|
+
warnings: [],
|
|
40495
|
+
error: null
|
|
40496
|
+
});
|
|
40497
|
+
void (async () => {
|
|
40498
|
+
try {
|
|
40499
|
+
const objects = await buildWorkerObjects({
|
|
40500
|
+
...args,
|
|
40501
|
+
isCancelled: () => cancelled
|
|
40502
|
+
});
|
|
40503
|
+
if (cancelled) return;
|
|
40504
|
+
const result = await inspectWorkerClient.analyze(analyzePayloadFor(channel, objects, args.inspectPointSampleCount));
|
|
40505
|
+
if (cancelled) return;
|
|
40506
|
+
setState(resultToState(args.inspectChannel, result));
|
|
40507
|
+
} catch (error) {
|
|
40508
|
+
if (cancelled || error instanceof InspectBuildCancelledError || error instanceof Error && error.message === "cancelled") {
|
|
40509
|
+
return;
|
|
40510
|
+
}
|
|
40511
|
+
setState({
|
|
40512
|
+
status: "error",
|
|
40513
|
+
channel: args.inspectChannel,
|
|
40514
|
+
objectColors: {},
|
|
40515
|
+
meshColors: {},
|
|
40516
|
+
pointClouds: {},
|
|
40517
|
+
warnings: [],
|
|
40518
|
+
error: error instanceof Error ? error.message : String(error)
|
|
40519
|
+
});
|
|
40520
|
+
}
|
|
40521
|
+
})();
|
|
40522
|
+
return () => {
|
|
40523
|
+
cancelled = true;
|
|
40524
|
+
inspectWorkerClient.dispose();
|
|
40525
|
+
};
|
|
40526
|
+
}, [args.inspectChannel, args.inspectPointSampleCount, args.sceneVersion, args.objects, args.objectSettings, args.objectMatrices]);
|
|
40527
|
+
return state2;
|
|
40528
|
+
}
|
|
39807
40529
|
function panelNumber(value) {
|
|
39808
40530
|
if (!Number.isFinite(value)) return String(value);
|
|
39809
40531
|
if (Number.isInteger(value)) return String(value);
|
|
@@ -39829,6 +40551,20 @@ function edgeCurveLabel(edge) {
|
|
|
39829
40551
|
return "segment";
|
|
39830
40552
|
}
|
|
39831
40553
|
}
|
|
40554
|
+
function inspectChannelLabel(channel) {
|
|
40555
|
+
switch (channel) {
|
|
40556
|
+
case "connectivity":
|
|
40557
|
+
return "Connect";
|
|
40558
|
+
case "distance":
|
|
40559
|
+
return "Distance";
|
|
40560
|
+
case "thickness":
|
|
40561
|
+
return "Thickness";
|
|
40562
|
+
case "roughness":
|
|
40563
|
+
return "Roughness";
|
|
40564
|
+
default:
|
|
40565
|
+
return "Inspect";
|
|
40566
|
+
}
|
|
40567
|
+
}
|
|
39832
40568
|
function edgeBelongsToFace(edge, faceName) {
|
|
39833
40569
|
var _a3;
|
|
39834
40570
|
return edge.faceName === faceName || ((_a3 = edge.curve) == null ? void 0 : _a3.faceName) === faceName || edge.name.startsWith(`${faceName}:`);
|
|
@@ -39916,6 +40652,8 @@ function RenderStyleExposure({ exposure }) {
|
|
|
39916
40652
|
function Viewport() {
|
|
39917
40653
|
var _a3, _b2, _c;
|
|
39918
40654
|
const activeFile = useForgeStore((s) => s.activeFile);
|
|
40655
|
+
const activeBackend = useForgeStore((s) => s.activeBackend);
|
|
40656
|
+
const computeTarget = useForgeStore((s) => s.computeTarget);
|
|
39919
40657
|
const isSvgActive = !!activeFile && activeFile.toLowerCase().endsWith(".svg");
|
|
39920
40658
|
const state2 = useViewportState();
|
|
39921
40659
|
const {
|
|
@@ -39925,6 +40663,8 @@ function Viewport() {
|
|
|
39925
40663
|
renderMode,
|
|
39926
40664
|
renderStyle,
|
|
39927
40665
|
inspectChannel,
|
|
40666
|
+
inspectDisplayMode,
|
|
40667
|
+
inspectPointSampleCount,
|
|
39928
40668
|
projectionMode,
|
|
39929
40669
|
gridEnabled,
|
|
39930
40670
|
gridSize,
|
|
@@ -40025,11 +40765,27 @@ function Viewport() {
|
|
|
40025
40765
|
}
|
|
40026
40766
|
return next;
|
|
40027
40767
|
}, [constructionGhost, focusedObjectIdSet, objectSettings, objects]);
|
|
40028
|
-
const
|
|
40029
|
-
|
|
40030
|
-
|
|
40031
|
-
|
|
40032
|
-
|
|
40768
|
+
const inspectAnalysis = useInspectWorkerAnalysis({
|
|
40769
|
+
inspectChannel,
|
|
40770
|
+
inspectPointSampleCount,
|
|
40771
|
+
sceneVersion,
|
|
40772
|
+
objects,
|
|
40773
|
+
objectSettings,
|
|
40774
|
+
objectMatrices
|
|
40775
|
+
});
|
|
40776
|
+
const inspectLoading = inspectChannelActive && inspectAnalysis.status === "loading";
|
|
40777
|
+
const viewportBusyPhase = isEvaluating || evaluationPhase === "exporting" ? evaluationPhase : inspectLoading ? "inspecting" : null;
|
|
40778
|
+
const viewportBusyLabel = inspectLoading ? `Generating ${inspectChannelLabel(inspectChannel)} inspect view` : void 0;
|
|
40779
|
+
const rebuildHistorySteps = reactExports.useMemo(() => {
|
|
40780
|
+
if (!isEvaluating || historyMode) return [];
|
|
40781
|
+
const historyObjects = [];
|
|
40782
|
+
for (const obj of objects) {
|
|
40783
|
+
if (!obj.shape) continue;
|
|
40784
|
+
const plan = getShapeCompilePlan(obj.shape);
|
|
40785
|
+
if (plan) historyObjects.push({ id: obj.id, plan });
|
|
40786
|
+
}
|
|
40787
|
+
return historyObjects.length > 0 ? linearizeMultiObjectSteps(historyObjects) : [];
|
|
40788
|
+
}, [historyMode, isEvaluating, objects]);
|
|
40033
40789
|
const handlers = useViewportHandlers({
|
|
40034
40790
|
containerRef,
|
|
40035
40791
|
contextMenuRef,
|
|
@@ -40195,7 +40951,10 @@ function Viewport() {
|
|
|
40195
40951
|
renderStyle,
|
|
40196
40952
|
renderMode,
|
|
40197
40953
|
inspectChannel,
|
|
40198
|
-
|
|
40954
|
+
inspectDisplayMode,
|
|
40955
|
+
inspectColor: inspectAnalysis.objectColors[obj.id] ?? maskColorForIndex(objIndex),
|
|
40956
|
+
inspectMeshColors: inspectAnalysis.meshColors[obj.id],
|
|
40957
|
+
inspectPointCloud: inspectAnalysis.pointClouds[obj.id],
|
|
40199
40958
|
isInteracting: isViewportInteracting,
|
|
40200
40959
|
matrix,
|
|
40201
40960
|
isHovered,
|
|
@@ -40452,7 +41211,7 @@ function Viewport() {
|
|
|
40452
41211
|
}
|
|
40453
41212
|
),
|
|
40454
41213
|
/* @__PURE__ */ jsxRuntimeExports.jsx(PerformanceInfoPanel, { enabled: showPerformanceInfo, stats: performanceInfo }),
|
|
40455
|
-
!
|
|
41214
|
+
!viewportBusyPhase && /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomIndicatorPanel, { mmPerPx: zoomMmPerPx }),
|
|
40456
41215
|
isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
40457
41216
|
SketchRulersOverlay,
|
|
40458
41217
|
{
|
|
@@ -40483,7 +41242,44 @@ function Viewport() {
|
|
|
40483
41242
|
}
|
|
40484
41243
|
),
|
|
40485
41244
|
measureMode && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasureInfoPanel, {}),
|
|
40486
|
-
|
|
41245
|
+
viewportBusyPhase && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
41246
|
+
EvaluationIndicator,
|
|
41247
|
+
{
|
|
41248
|
+
phase: viewportBusyPhase,
|
|
41249
|
+
label: viewportBusyLabel,
|
|
41250
|
+
constructionSteps: rebuildHistorySteps,
|
|
41251
|
+
activeBackend,
|
|
41252
|
+
computeTarget
|
|
41253
|
+
}
|
|
41254
|
+
),
|
|
41255
|
+
inspectChannelActive && inspectAnalysis.status === "error" && inspectAnalysis.error && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
41256
|
+
"div",
|
|
41257
|
+
{
|
|
41258
|
+
style: {
|
|
41259
|
+
position: "absolute",
|
|
41260
|
+
top: 12,
|
|
41261
|
+
left: "50%",
|
|
41262
|
+
transform: "translateX(-50%)",
|
|
41263
|
+
background: "rgba(127, 29, 29, 0.92)",
|
|
41264
|
+
color: "#fee2e2",
|
|
41265
|
+
border: "1px solid rgba(254, 202, 202, 0.4)",
|
|
41266
|
+
borderRadius: 6,
|
|
41267
|
+
padding: "7px 12px",
|
|
41268
|
+
fontSize: 12,
|
|
41269
|
+
fontWeight: 600,
|
|
41270
|
+
pointerEvents: "none",
|
|
41271
|
+
zIndex: 12,
|
|
41272
|
+
maxWidth: "min(520px, calc(100% - 32px))",
|
|
41273
|
+
whiteSpace: "nowrap",
|
|
41274
|
+
overflow: "hidden",
|
|
41275
|
+
textOverflow: "ellipsis"
|
|
41276
|
+
},
|
|
41277
|
+
children: [
|
|
41278
|
+
"Inspect failed: ",
|
|
41279
|
+
inspectAnalysis.error
|
|
41280
|
+
]
|
|
41281
|
+
}
|
|
41282
|
+
),
|
|
40487
41283
|
/* @__PURE__ */ jsxRuntimeExports.jsx(HoverTooltipLayer, { ref: hoverTooltipRef, enabled: objectPickSyncEnabled && !measureMode }),
|
|
40488
41284
|
objectContextMenu && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
40489
41285
|
"div",
|
|
@@ -40941,7 +41737,7 @@ function Viewport() {
|
|
|
40941
41737
|
}
|
|
40942
41738
|
);
|
|
40943
41739
|
}
|
|
40944
|
-
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
41740
|
+
const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-BujZvuwX.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
40945
41741
|
const PENDING_SHARE_COPY_KEY = "fc-pending-share-copy";
|
|
40946
41742
|
function storePendingShareCopy(shareId) {
|
|
40947
41743
|
sessionStorage.setItem(PENDING_SHARE_COPY_KEY, shareId);
|
|
@@ -41128,15 +41924,15 @@ const PublishedModelPage$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Objec
|
|
|
41128
41924
|
consumePendingShareCopy,
|
|
41129
41925
|
storePendingShareCopy
|
|
41130
41926
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
41131
|
-
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-
|
|
41132
|
-
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-
|
|
41133
|
-
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-
|
|
41134
|
-
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-
|
|
41927
|
+
reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-O_yMtAri.js"), true ? __vite__mapDeps([1]) : void 0).then((m2) => ({ default: m2.LandingPageProofDriven })));
|
|
41928
|
+
const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-DLhIIZyJ.js"), true ? [] : void 0).then((m2) => ({ default: m2.DocsPage })));
|
|
41929
|
+
reactExports.lazy(() => __vitePreload(() => import("./BlogPage-CI_P0_Pf.js"), true ? [] : void 0).then((m2) => ({ default: m2.BlogPage })));
|
|
41930
|
+
reactExports.lazy(() => __vitePreload(() => import("./AdminPage-DX0mpSZT.js"), true ? [] : void 0).then((m2) => ({ default: m2.AdminPage })));
|
|
41135
41931
|
reactExports.lazy(() => __vitePreload(() => Promise.resolve().then(() => PublishedModelPage$1), true ? void 0 : void 0).then((m2) => ({ default: m2.PublishedModelPage })));
|
|
41136
|
-
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-
|
|
41137
|
-
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-
|
|
41138
|
-
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-
|
|
41139
|
-
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-
|
|
41932
|
+
reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-DBsqTB_y.js"), true ? [] : void 0).then((m2) => ({ default: m2.SettingsPage })));
|
|
41933
|
+
reactExports.lazy(() => __vitePreload(() => import("./PricingPage-DGkX3Ahr.js"), true ? __vite__mapDeps([2,1]) : void 0).then((m2) => ({ default: m2.PricingPage })));
|
|
41934
|
+
const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-BujZvuwX.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
|
|
41935
|
+
const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-0S0qXKog.js"), true ? [] : void 0).then((m2) => ({ default: m2.EmbedViewer })));
|
|
41140
41936
|
const embedMode = isEmbedMode() && !window.location.pathname.startsWith("/m/");
|
|
41141
41937
|
const EDITABLE_CRASH_FILE = /\.(?:forge\.js|[cm]?[jt]sx?|json|md|txt|svg)$/i;
|
|
41142
41938
|
function firstMeaningfulLine(text) {
|
|
@@ -41353,7 +42149,7 @@ function App() {
|
|
|
41353
42149
|
applyTheme(localStorage.getItem("fc-theme") || "dark");
|
|
41354
42150
|
clientExports.createRoot(document.getElementById("root")).render(/* @__PURE__ */ jsxRuntimeExports.jsx(App, {}));
|
|
41355
42151
|
export {
|
|
41356
|
-
|
|
42152
|
+
ViewController as $,
|
|
41357
42153
|
AuthApiError as A,
|
|
41358
42154
|
BrandMark as B,
|
|
41359
42155
|
exportExactFromStore as C,
|
|
@@ -41375,36 +42171,38 @@ export {
|
|
|
41375
42171
|
resolveJointRange as S,
|
|
41376
42172
|
useJointsConfig as T,
|
|
41377
42173
|
useJointAnimationValues as U,
|
|
41378
|
-
|
|
41379
|
-
|
|
41380
|
-
|
|
41381
|
-
|
|
41382
|
-
|
|
41383
|
-
|
|
42174
|
+
INSPECT_POINT_SAMPLE_COUNT_MAX as V,
|
|
42175
|
+
INSPECT_POINT_SAMPLE_COUNT_MIN as W,
|
|
42176
|
+
expandBoundsByTransformedAabb as X,
|
|
42177
|
+
Canvas as Y,
|
|
42178
|
+
PerspectiveCamera as Z,
|
|
42179
|
+
ControlsInteractionBridge as _,
|
|
41384
42180
|
applyTheme as a,
|
|
41385
|
-
|
|
41386
|
-
|
|
41387
|
-
|
|
41388
|
-
|
|
41389
|
-
|
|
41390
|
-
|
|
41391
|
-
|
|
41392
|
-
|
|
41393
|
-
|
|
41394
|
-
|
|
41395
|
-
|
|
41396
|
-
|
|
41397
|
-
|
|
41398
|
-
|
|
41399
|
-
|
|
41400
|
-
|
|
41401
|
-
|
|
41402
|
-
|
|
41403
|
-
|
|
41404
|
-
|
|
41405
|
-
|
|
41406
|
-
|
|
41407
|
-
|
|
42181
|
+
SceneConfigurator as a0,
|
|
42182
|
+
LocalStudioEnvironment as a1,
|
|
42183
|
+
RenderLabelsOverlay as a2,
|
|
42184
|
+
Grid as a3,
|
|
42185
|
+
OrbitControls2 as a4,
|
|
42186
|
+
TOUCH_GESTURES_3D as a5,
|
|
42187
|
+
MOUSE_BUTTONS_3D as a6,
|
|
42188
|
+
ModelJourneyBar as a7,
|
|
42189
|
+
FOCUS_MODE_DIM_OPACITY as a8,
|
|
42190
|
+
useJointAnimationLoop as a9,
|
|
42191
|
+
computeJointNodeMatrices as aa,
|
|
42192
|
+
computeObjectJointMatrices as ab,
|
|
42193
|
+
readLastActiveFileForUser as ac,
|
|
42194
|
+
ToastContainer as ad,
|
|
42195
|
+
isMobile as ae,
|
|
42196
|
+
useFeatureFlag as af,
|
|
42197
|
+
decodeSharedHash as ag,
|
|
42198
|
+
decodeSharedBundle as ah,
|
|
42199
|
+
getExternalUrl as ai,
|
|
42200
|
+
getGistId as aj,
|
|
42201
|
+
Viewport as ak,
|
|
42202
|
+
shouldBlockBrowserShortcut as al,
|
|
42203
|
+
useDrawStore as am,
|
|
42204
|
+
storePendingShareCopy as an,
|
|
42205
|
+
share as ao,
|
|
41408
42206
|
authFetch as b,
|
|
41409
42207
|
authApi as c,
|
|
41410
42208
|
showToast as d,
|