forgecad 0.9.7 → 0.9.8

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-CXaVLMiV.js} +1 -1
  3. package/dist/assets/{BlogPage-CI_P0_Pf.js → BlogPage-Crpr3JjH.js} +1 -1
  4. package/dist/assets/{DocsPage-DLhIIZyJ.js → DocsPage-CNBKuitP.js} +2 -2
  5. package/dist/assets/{EditorApp-DfFT2Dn8.css → EditorApp-D11wL4Qn.css} +51 -0
  6. package/dist/assets/{EditorApp-BujZvuwX.js → EditorApp-DVMnXOmO.js} +151 -9
  7. package/dist/assets/{EmbedViewer-0S0qXKog.js → EmbedViewer-KXFLSnpo.js} +2 -2
  8. package/dist/assets/{LandingPageProofDriven-O_yMtAri.js → LandingPageProofDriven-2q2sn7aW.js} +1 -1
  9. package/dist/assets/{PricingPage-DGkX3Ahr.js → PricingPage-CVvgdv0i.js} +1 -1
  10. package/dist/assets/{SettingsPage-DBsqTB_y.js → SettingsPage-BVj1FtEv.js} +1 -1
  11. package/dist/assets/__vite-browser-external-Dhvy_jtL.js +4 -0
  12. package/dist/assets/{app-BE2nD6Yz.js → app-Dn4EwHhN.js} +707 -458
  13. package/dist/assets/cli/{render-iP9qh475.js → render-BI3gLMXz.js} +1011 -145
  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-sJ-axdXM.js → manifold-BVi4_OeB.js} +1 -1
  18. package/dist/assets/{manifold-DjYsd7A_.js → manifold-C6-sZYQN.js} +2 -2
  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-BIvOkPK3.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-iBAeF8RM.js} +483 -71
  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
@@ -1,10 +1,10 @@
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]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/EditorApp-D11wL4Qn.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
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";
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 geometryWithVisibleVertexColors, bb as getRenderStylePreset, bc as AdditiveBlending, bd as ZEBRA_STRIPE_SOFTNESS, be as ZEBRA_STRIPE_SCALE, bf as ZEBRA_LIGHT_COLOR, bg as ZEBRA_DARK_COLOR, bh as ZEBRA_ACCENT_COLOR, bi as ZEBRA_STRIPE_FRAGMENT_SHADER, bj as ZEBRA_STRIPE_VERTEX_SHADER, bk as SURFACE_FIELD_FRAGMENT_SHADER, bl as SURFACE_FIELD_VERTEX_SHADER, bm as CatmullRomCurve3, bn as TubeGeometry, bo as MeshStandardMaterial, bp as compileSdfNode3, bq as buildSdfRaymarchFragmentShader, br as SDF_RAYMARCH_PROXY_VERTEX_SHADER, bs as Shape, bt as ShapeGeometry, bu as ShaderLib, bv as CylinderGeometry, bw as parseViewportCameraState, bx as createResolvedExplodeConfig, by as explodeBoundsCenter, bz as explodeMergeBounds, bA as resolveExplodeDirective, bB as computeExplodeMotion, bC as getSketchWorldMatrix, bD as explodeAdd, bE as hasExplodeOverride, bF as resolveExplodeLocalFanDirection, bG as explodeMul, bH as explodeLeafFanStage, bI as normalizeCutPlane, bJ as toClippingPlane, bK as findJointAnimationClip, bL as resolveJointAnimation, bM as resolveJointViewValues, bN as getShapePorts, bO as getShapeUsedPorts, bP as DEFAULT_VIEW_CONFIG, bQ as getKernelFaceNameForTriangle, bR as resolveScalarSceneSampleBudget, bS as initKernel, bT as initSolverWasm } from "./scalar-sampling-budget-iBAeF8RM.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];
@@ -15021,9 +15021,6 @@ function stableJsonStringify(value) {
15021
15021
  function shapeCompilePlanCacheKey(plan) {
15022
15022
  return `${SHAPE_COMPILE_PLAN_CACHE_KEY_VERSION}:${stableJsonStringify(plan)}`;
15023
15023
  }
15024
- function constructionStepGeometryCacheKey(step) {
15025
- return step.cumulativePlanCacheKey;
15026
- }
15027
15024
  function makeConstructionStep(step) {
15028
15025
  const planCacheKey = shapeCompilePlanCacheKey(step.plan);
15029
15026
  return {
@@ -15855,7 +15852,7 @@ const CRASH_COOLDOWN_MS = 2e3;
15855
15852
  class EvalWorkerClient {
15856
15853
  constructor(workerFactory = () => new Worker(new URL(
15857
15854
  /* @vite-ignore */
15858
- "/assets/evalWorker-Ds5U4xtN.js",
15855
+ "/assets/evalWorker-CtO7GsJR.js",
15859
15856
  import.meta.url
15860
15857
  ), { type: "module" })) {
15861
15858
  __publicField(this, "worker", null);
@@ -17323,11 +17320,48 @@ const VIEW_PREFERENCES_KEY = "fc-view-preferences-v1";
17323
17320
  const INSPECT_POINT_SAMPLE_COUNT_MIN = 100;
17324
17321
  const INSPECT_POINT_SAMPLE_COUNT_MAX = 1e4;
17325
17322
  const DEFAULT_INSPECT_POINT_SAMPLE_COUNT = 2e3;
17323
+ const DEFAULT_MANUAL_SCENE_SETTINGS = {
17324
+ enabled: false,
17325
+ backgroundColor: "#f6f7f8",
17326
+ groundVisible: true,
17327
+ groundColor: "#eef0f2",
17328
+ ambientIntensity: 0.3,
17329
+ keyIntensity: 1.45,
17330
+ fillIntensity: 0.55,
17331
+ rimIntensity: 0.2,
17332
+ environmentIntensity: 0.9
17333
+ };
17326
17334
  const resolveInspectPointSampleCount = (value) => {
17327
17335
  const numeric = typeof value === "number" ? value : Number(value);
17328
17336
  if (!Number.isFinite(numeric)) return DEFAULT_INSPECT_POINT_SAMPLE_COUNT;
17329
17337
  return Math.max(INSPECT_POINT_SAMPLE_COUNT_MIN, Math.min(INSPECT_POINT_SAMPLE_COUNT_MAX, Math.round(numeric)));
17330
17338
  };
17339
+ const HEX_COLOR_RE = /^#[0-9a-f]{6}$/i;
17340
+ const resolveHexColor = (value, fallback) => {
17341
+ return typeof value === "string" && HEX_COLOR_RE.test(value) ? value : fallback;
17342
+ };
17343
+ const resolveClampedNumber = (value, fallback, min, max2) => {
17344
+ const numeric = typeof value === "number" ? value : Number(value);
17345
+ if (!Number.isFinite(numeric)) return fallback;
17346
+ return Math.max(min, Math.min(max2, numeric));
17347
+ };
17348
+ const resolveManualSceneSettings = (value) => {
17349
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
17350
+ return DEFAULT_MANUAL_SCENE_SETTINGS;
17351
+ }
17352
+ const raw = value;
17353
+ return {
17354
+ enabled: typeof raw.enabled === "boolean" ? raw.enabled : DEFAULT_MANUAL_SCENE_SETTINGS.enabled,
17355
+ backgroundColor: resolveHexColor(raw.backgroundColor, DEFAULT_MANUAL_SCENE_SETTINGS.backgroundColor),
17356
+ groundVisible: typeof raw.groundVisible === "boolean" ? raw.groundVisible : DEFAULT_MANUAL_SCENE_SETTINGS.groundVisible,
17357
+ groundColor: resolveHexColor(raw.groundColor, DEFAULT_MANUAL_SCENE_SETTINGS.groundColor),
17358
+ ambientIntensity: resolveClampedNumber(raw.ambientIntensity, DEFAULT_MANUAL_SCENE_SETTINGS.ambientIntensity, 0, 3),
17359
+ keyIntensity: resolveClampedNumber(raw.keyIntensity, DEFAULT_MANUAL_SCENE_SETTINGS.keyIntensity, 0, 5),
17360
+ fillIntensity: resolveClampedNumber(raw.fillIntensity, DEFAULT_MANUAL_SCENE_SETTINGS.fillIntensity, 0, 3),
17361
+ rimIntensity: resolveClampedNumber(raw.rimIntensity, DEFAULT_MANUAL_SCENE_SETTINGS.rimIntensity, 0, 3),
17362
+ environmentIntensity: resolveClampedNumber(raw.environmentIntensity, DEFAULT_MANUAL_SCENE_SETTINGS.environmentIntensity, 0, 3)
17363
+ };
17364
+ };
17331
17365
  const readViewPreferences = () => {
17332
17366
  if (typeof window === "undefined") return {};
17333
17367
  try {
@@ -17439,7 +17473,10 @@ const INITIAL_SAVED = {};
17439
17473
  const VIEW_INSPECT_CHANNELS = /* @__PURE__ */ new Set([
17440
17474
  "none",
17441
17475
  "mask",
17476
+ "normals",
17477
+ "zebra",
17442
17478
  "connectivity",
17479
+ "floating",
17443
17480
  "distance",
17444
17481
  "collisions",
17445
17482
  "thickness",
@@ -18210,6 +18247,16 @@ Switch to LOCAL mode or wait for the server to recover.`,
18210
18247
  writeViewPreferences({ renderMode: mode });
18211
18248
  set({ renderMode: mode });
18212
18249
  },
18250
+ manualScene: resolveManualSceneSettings(initialViewPreferences.manualScene),
18251
+ setManualScene: (patch) => set((state2) => {
18252
+ const next = resolveManualSceneSettings({ ...state2.manualScene, ...patch });
18253
+ writeViewPreferences({ manualScene: next });
18254
+ return { manualScene: next };
18255
+ }),
18256
+ resetManualScene: () => {
18257
+ writeViewPreferences({ manualScene: DEFAULT_MANUAL_SCENE_SETTINGS });
18258
+ set({ manualScene: DEFAULT_MANUAL_SCENE_SETTINGS });
18259
+ },
18213
18260
  inspectChannel: resolveViewInspectChannel(initialViewPreferences.inspectChannel),
18214
18261
  setInspectChannel: (channel) => {
18215
18262
  const next = resolveViewInspectChannel(channel);
@@ -18234,11 +18281,16 @@ Switch to LOCAL mode or wait for the server to recover.`,
18234
18281
  set({ projectionMode: mode });
18235
18282
  },
18236
18283
  gridEnabled: initialViewPreferences.gridEnabled ?? true,
18284
+ axesVisible: initialViewPreferences.axesVisible ?? true,
18237
18285
  gridSize: initialViewPreferences.gridSize ?? 10,
18238
18286
  setGridEnabled: (enabled) => {
18239
18287
  writeViewPreferences({ gridEnabled: enabled });
18240
18288
  set({ gridEnabled: enabled });
18241
18289
  },
18290
+ setAxesVisible: (visible) => {
18291
+ writeViewPreferences({ axesVisible: visible });
18292
+ set({ axesVisible: visible });
18293
+ },
18242
18294
  setGridSize: (size) => {
18243
18295
  writeViewPreferences({ gridSize: size });
18244
18296
  set({ gridSize: size });
@@ -26737,12 +26789,12 @@ function SceneEffects({ config }) {
26737
26789
  /* @__PURE__ */ jsxRuntimeExports.jsx(dt$1, { children: effects })
26738
26790
  ] });
26739
26791
  }
26740
- function ScenePostProcessing({ config }) {
26792
+ function ScenePostProcessing({ config, interactivePreview }) {
26741
26793
  const pp = config.postProcessing;
26742
26794
  if (!pp) return null;
26743
26795
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
26744
26796
  pp.toneMappingExposure !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneExposure, { exposure: pp.toneMappingExposure }),
26745
- /* @__PURE__ */ jsxRuntimeExports.jsx(SceneEffects, { config })
26797
+ !interactivePreview && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneEffects, { config })
26746
26798
  ] });
26747
26799
  }
26748
26800
  function SceneEnvironment({ config }) {
@@ -26757,9 +26809,9 @@ function SceneEnvironment({ config }) {
26757
26809
  }
26758
26810
  );
26759
26811
  }
26760
- function SceneGround({ config, modelBoundsMinZ }) {
26812
+ function SceneGround({ config, modelBoundsMinZ, hidden }) {
26761
26813
  const ground = config.ground;
26762
- if (!ground || ground.visible === false) return null;
26814
+ if (hidden || !ground || ground.visible === false) return null;
26763
26815
  const offset = ground.offset ?? 0;
26764
26816
  const height = (modelBoundsMinZ ?? 0) - offset;
26765
26817
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("mesh", { position: [0, 0, height], receiveShadow: ground.receiveShadow ?? false, children: [
@@ -26769,8 +26821,10 @@ function SceneGround({ config, modelBoundsMinZ }) {
26769
26821
  }
26770
26822
  function SceneConfigurator({
26771
26823
  config,
26824
+ interactivePreview = false,
26772
26825
  controlsRef,
26773
26826
  modelBoundsMinZ,
26827
+ hideGround = false,
26774
26828
  onDefaultLightsOverridden,
26775
26829
  onDefaultEnvironmentOverridden
26776
26830
  }) {
@@ -26785,11 +26839,11 @@ function SceneConfigurator({
26785
26839
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
26786
26840
  /* @__PURE__ */ jsxRuntimeExports.jsx(SceneBackground, { config }),
26787
26841
  /* @__PURE__ */ jsxRuntimeExports.jsx(SceneCamera, { config, controlsRef }),
26788
- config.lights && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneLights, { lights: config.lights }),
26842
+ !interactivePreview && config.lights && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneLights, { lights: config.lights }),
26789
26843
  config.fog && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneFog, { fog: config.fog }),
26790
- config.environment && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneEnvironment, { config }),
26791
- config.ground && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneGround, { config, modelBoundsMinZ }),
26792
- /* @__PURE__ */ jsxRuntimeExports.jsx(ScenePostProcessing, { config })
26844
+ !interactivePreview && config.environment && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneEnvironment, { config }),
26845
+ config.ground && /* @__PURE__ */ jsxRuntimeExports.jsx(SceneGround, { config, modelBoundsMinZ, hidden: hideGround }),
26846
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ScenePostProcessing, { config, interactivePreview })
26793
26847
  ] });
26794
26848
  }
26795
26849
  function ClippingManager({ active }) {
@@ -26799,9 +26853,44 @@ function ClippingManager({ active }) {
26799
26853
  }, [gl, active]);
26800
26854
  return null;
26801
26855
  }
26856
+ function matrixToCollisionMat4(matrix) {
26857
+ if (!matrix) return void 0;
26858
+ const e2 = matrix.elements;
26859
+ return [e2[0], e2[1], e2[2], e2[3], e2[4], e2[5], e2[6], e2[7], e2[8], e2[9], e2[10], e2[11], e2[12], e2[13], e2[14], e2[15]];
26860
+ }
26861
+ function buildViewportCollisionEntries(objects, objectSettings, objectMatrices) {
26862
+ const entries = [];
26863
+ objects.forEach((obj) => {
26864
+ var _a3;
26865
+ if (!obj.shape) return;
26866
+ if (((_a3 = objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) return;
26867
+ try {
26868
+ const bb = obj.shape.boundingBox();
26869
+ entries.push({
26870
+ id: obj.id,
26871
+ name: obj.name,
26872
+ shape: obj.shape,
26873
+ min: [bb.min[0], bb.min[1], bb.min[2]],
26874
+ max: [bb.max[0], bb.max[1], bb.max[2]],
26875
+ transform: matrixToCollisionMat4(objectMatrices[obj.id]),
26876
+ groupName: obj.groupName,
26877
+ treePath: obj.treePath,
26878
+ mock: obj.mock
26879
+ });
26880
+ } catch {
26881
+ }
26882
+ });
26883
+ return entries;
26884
+ }
26885
+ function analyzeViewportCollisions(objects, objectSettings, objectMatrices) {
26886
+ return analyzeCollisionIntersections(buildViewportCollisionEntries(objects, objectSettings, objectMatrices), {
26887
+ includeBBoxCandidates: false
26888
+ });
26889
+ }
26802
26890
  const COLLISION_SOURCE_OPACITY = 0.22;
26803
26891
  const COLLISION_SOURCE_COLOR = [180, 200, 220];
26804
26892
  const COLLISION_HIGHLIGHT_COLOR = [255, 68, 16];
26893
+ const FLOATING_CONTEXT_COLOR = [38, 49, 58];
26805
26894
  const COLLISION_PALETTE = [
26806
26895
  COLLISION_HIGHLIGHT_COLOR,
26807
26896
  [0, 204, 255],
@@ -26850,48 +26939,13 @@ function maskColorForIndex(index) {
26850
26939
  function collisionColorForIndex(index) {
26851
26940
  return rgbToHex(COLLISION_PALETTE[(index - 1) % COLLISION_PALETTE.length]);
26852
26941
  }
26853
- const MAX_VIEWPORT_COLLISION_CANDIDATES = 200;
26854
- const MAX_VIEWPORT_COLLISION_MS = 1e3;
26855
- function matrixToCollisionMat4(matrix) {
26856
- if (!matrix) return void 0;
26857
- const e2 = matrix.elements;
26858
- return [e2[0], e2[1], e2[2], e2[3], e2[4], e2[5], e2[6], e2[7], e2[8], e2[9], e2[10], e2[11], e2[12], e2[13], e2[14], e2[15]];
26859
- }
26860
- function buildCollisionEntries(objects, objectSettings, objectMatrices) {
26861
- const entries = [];
26862
- objects.forEach((obj) => {
26863
- var _a3;
26864
- if (!obj.shape) return;
26865
- if (((_a3 = objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) return;
26866
- try {
26867
- const bb = obj.shape.boundingBox();
26868
- entries.push({
26869
- id: obj.id,
26870
- name: obj.name,
26871
- shape: obj.shape,
26872
- min: [bb.min[0], bb.min[1], bb.min[2]],
26873
- max: [bb.max[0], bb.max[1], bb.max[2]],
26874
- transform: matrixToCollisionMat4(objectMatrices[obj.id]),
26875
- groupName: obj.groupName,
26876
- treePath: obj.treePath,
26877
- mock: obj.mock
26878
- });
26879
- } catch {
26880
- }
26881
- });
26882
- return entries;
26883
- }
26884
26942
  function CollisionInspectionOverlay({
26885
26943
  objects,
26886
26944
  objectSettings,
26887
26945
  objectMatrices
26888
26946
  }) {
26889
26947
  const collisionGeometries = reactExports.useMemo(() => {
26890
- const report = analyzeCollisionIntersections(buildCollisionEntries(objects, objectSettings, objectMatrices), {
26891
- maxCandidatePairs: MAX_VIEWPORT_COLLISION_CANDIDATES,
26892
- maxElapsedMs: MAX_VIEWPORT_COLLISION_MS,
26893
- includeBBoxCandidates: false
26894
- });
26948
+ const report = analyzeViewportCollisions(objects, objectSettings, objectMatrices);
26895
26949
  return report.collisions.flatMap((collision) => {
26896
26950
  try {
26897
26951
  const geometry = shapeToGeometry(collision.shape);
@@ -26941,53 +26995,108 @@ function ConstructionGhostOverlay({ matrix }) {
26941
26995
  /* @__PURE__ */ jsxRuntimeExports.jsx("lineSegments", { geometry: edgesGeo, renderOrder: 3, children: /* @__PURE__ */ jsxRuntimeExports.jsx("lineBasicMaterial", { color: "#4a9eff", transparent: true, opacity: 0.55, depthTest: false, depthWrite: false }) })
26942
26996
  ] });
26943
26997
  }
26944
- const MAX_CACHE_SIZE = 40;
26945
- const geometryCache = /* @__PURE__ */ new Map();
26946
- function getCachedGeometry(step) {
26947
- const cacheKey = constructionStepGeometryCacheKey(step);
26948
- const cached = geometryCache.get(cacheKey);
26949
- if (cached) return cached;
26950
- try {
26951
- const shape = buildShapeFromCompilePlan(step.cumulativePlan);
26952
- const { solid, edges, hasSmoothNormals } = shapeToGeometry(shape);
26953
- if (!solid || !edges) return null;
26954
- const entry = { solid, edges, hasSmoothNormals };
26955
- if (geometryCache.size >= MAX_CACHE_SIZE) {
26956
- const firstKey = geometryCache.keys().next().value;
26957
- if (firstKey !== void 0) {
26958
- const old = geometryCache.get(firstKey);
26959
- old == null ? void 0 : old.solid.dispose();
26960
- old == null ? void 0 : old.edges.dispose();
26961
- geometryCache.delete(firstKey);
26962
- }
26963
- }
26964
- geometryCache.set(cacheKey, entry);
26965
- return entry;
26966
- } catch {
26967
- return null;
26998
+ class ConstructionHistoryWorkerClient {
26999
+ constructor(workerFactory = () => new Worker(new URL(
27000
+ /* @vite-ignore */
27001
+ "/assets/constructionHistoryWorker-z9_LGiRd.js",
27002
+ import.meta.url
27003
+ ), { type: "module" })) {
27004
+ __publicField(this, "worker", null);
27005
+ __publicField(this, "reqId", 0);
27006
+ __publicField(this, "pending", null);
27007
+ this.workerFactory = workerFactory;
27008
+ }
27009
+ getWorker() {
27010
+ if (this.worker) return this.worker;
27011
+ this.worker = this.workerFactory();
27012
+ this.worker.onmessage = (event) => {
27013
+ const data = event.data;
27014
+ const pending = this.pending;
27015
+ if (!pending) return;
27016
+ this.pending = null;
27017
+ if (data.type === "history-geometry-error") {
27018
+ pending.reject(new Error(data.payload.message));
27019
+ } else {
27020
+ pending.resolve(data.payload.result);
27021
+ }
27022
+ };
27023
+ this.worker.onerror = (event) => {
27024
+ var _a3, _b2;
27025
+ const error = new Error(event.message || "Construction history worker failed unexpectedly.");
27026
+ (_a3 = this.pending) == null ? void 0 : _a3.reject(error);
27027
+ this.pending = null;
27028
+ (_b2 = this.worker) == null ? void 0 : _b2.terminate();
27029
+ this.worker = null;
27030
+ };
27031
+ return this.worker;
27032
+ }
27033
+ replaceActiveWorker() {
27034
+ var _a3, _b2;
27035
+ (_a3 = this.pending) == null ? void 0 : _a3.reject(new Error("cancelled"));
27036
+ this.pending = null;
27037
+ (_b2 = this.worker) == null ? void 0 : _b2.terminate();
27038
+ this.worker = null;
27039
+ }
27040
+ build(payload) {
27041
+ if (this.pending) this.replaceActiveWorker();
27042
+ const reqId = ++this.reqId;
27043
+ const request = {
27044
+ type: "build",
27045
+ payload: {
27046
+ reqId,
27047
+ ...payload
27048
+ }
27049
+ };
27050
+ return new Promise((resolve2, reject) => {
27051
+ this.pending = { resolve: resolve2, reject };
27052
+ this.getWorker().postMessage(request);
27053
+ });
27054
+ }
27055
+ dispose() {
27056
+ this.replaceActiveWorker();
26968
27057
  }
26969
27058
  }
26970
- function clearHistoryGeometryCache() {
26971
- for (const entry of geometryCache.values()) {
26972
- entry.solid.dispose();
26973
- entry.edges.dispose();
27059
+ const constructionHistoryWorkerClient = new ConstructionHistoryWorkerClient();
27060
+ function historyGeometryRequestKey(activeBackend, items) {
27061
+ return `${activeBackend}:${items.map(({ objectId, step }) => `${objectId}:${step.index}:${step.cumulativePlanCacheKey}`).join("|")}`;
27062
+ }
27063
+ function geometryItemKey(objectId, stepIndex) {
27064
+ return `${objectId}:${stepIndex}`;
27065
+ }
27066
+ function bufferGeometryFromWorkerGeometry(geometry) {
27067
+ const solid = new BufferGeometry();
27068
+ solid.setAttribute("position", new BufferAttribute(geometry.positions, 3));
27069
+ if (geometry.normals.length > 0) solid.setAttribute("normal", new BufferAttribute(geometry.normals, 3));
27070
+ if (geometry.triangleFaceIds.length > 0) {
27071
+ solid.userData.forgeTriangleFaceIds = geometry.triangleFaceIds;
27072
+ solid.userData.forgeFaceIdNames = geometry.faceIdNames;
26974
27073
  }
26975
- geometryCache.clear();
27074
+ const edges = new BufferGeometry();
27075
+ edges.setAttribute("position", new BufferAttribute(geometry.edgePositions, 3));
27076
+ return { solid, edges, hasSmoothNormals: geometry.hasSmoothNormals };
27077
+ }
27078
+ function disposeBufferedHistoryGeometry(geometry) {
27079
+ geometry.solid.dispose();
27080
+ geometry.edges.dispose();
26976
27081
  }
26977
27082
  function ConstructionHistoryOverlay({
27083
+ activeBackend,
26978
27084
  objectMatrices,
26979
- objectSettings
27085
+ objectSettings,
27086
+ onGeometryStatusChange
26980
27087
  }) {
26981
27088
  const historyMode = useForgeStore((s) => s.historyMode);
26982
27089
  const historySteps = useForgeStore((s) => s.historySteps);
26983
27090
  const historyCurrentStep = useForgeStore((s) => s.historyCurrentStep);
26984
27091
  const theme = useForgeStore((s) => themes[s.theme]);
26985
27092
  const [fadeOpacity, setFadeOpacity] = reactExports.useState(1);
27093
+ const [objectGeos, setObjectGeos] = reactExports.useState([]);
26986
27094
  const fadeRef = reactExports.useRef(0);
27095
+ const objectGeosRef = reactExports.useRef([]);
26987
27096
  const prevStepRef = reactExports.useRef(-1);
26988
27097
  reactExports.useEffect(() => {
26989
- return () => clearHistoryGeometryCache();
26990
- }, []);
27098
+ return () => onGeometryStatusChange == null ? void 0 : onGeometryStatusChange({ status: "idle", stepCount: 0, error: null });
27099
+ }, [onGeometryStatusChange]);
26991
27100
  reactExports.useEffect(() => {
26992
27101
  if (prevStepRef.current !== historyCurrentStep) {
26993
27102
  prevStepRef.current = historyCurrentStep;
@@ -27008,16 +27117,86 @@ function ConstructionHistoryOverlay({
27008
27117
  }, [historyCurrentStep]);
27009
27118
  const visibleStacks = reactExports.useMemo(() => buildVisibleHistoryStacks(historySteps, historyCurrentStep), [historySteps, historyCurrentStep]);
27010
27119
  const currentStep = historySteps[historyCurrentStep] ?? null;
27011
- const objectGeos = reactExports.useMemo(() => {
27012
- const result = [];
27120
+ const visibleHistoryItems = reactExports.useMemo(() => {
27121
+ const items = [];
27013
27122
  for (const [objectId, stack] of visibleStacks) {
27014
- for (const step of stack) {
27015
- const geo = getCachedGeometry(step);
27016
- if (geo) result.push({ objectId, geo, step });
27017
- }
27123
+ for (const step of stack) items.push({ objectId, step });
27018
27124
  }
27019
- return result;
27125
+ return items;
27020
27126
  }, [visibleStacks]);
27127
+ const requestKey = reactExports.useMemo(
27128
+ () => historyMode && visibleHistoryItems.length > 0 ? historyGeometryRequestKey(activeBackend, visibleHistoryItems) : "idle",
27129
+ [activeBackend, historyMode, visibleHistoryItems]
27130
+ );
27131
+ const [geometryState, setGeometryState] = reactExports.useState({
27132
+ status: "idle",
27133
+ requestKey: "idle",
27134
+ geometries: [],
27135
+ error: null
27136
+ });
27137
+ reactExports.useEffect(() => {
27138
+ onGeometryStatusChange == null ? void 0 : onGeometryStatusChange({
27139
+ status: historyMode ? geometryState.status : "idle",
27140
+ stepCount: visibleHistoryItems.length,
27141
+ error: historyMode ? geometryState.error : null
27142
+ });
27143
+ }, [geometryState.error, geometryState.status, historyMode, onGeometryStatusChange, visibleHistoryItems.length]);
27144
+ reactExports.useEffect(() => {
27145
+ if (!historyMode || visibleHistoryItems.length === 0) {
27146
+ constructionHistoryWorkerClient.dispose();
27147
+ setGeometryState({ status: "idle", requestKey, geometries: [], error: null });
27148
+ return;
27149
+ }
27150
+ let cancelled = false;
27151
+ setGeometryState({ status: "loading", requestKey, geometries: [], error: null });
27152
+ void constructionHistoryWorkerClient.build({
27153
+ activeBackend,
27154
+ items: visibleHistoryItems.map(({ objectId, step }) => ({
27155
+ objectId,
27156
+ stepIndex: step.index,
27157
+ cumulativePlan: step.cumulativePlan
27158
+ }))
27159
+ }).then((result) => {
27160
+ if (cancelled) return;
27161
+ setGeometryState({ status: "ready", requestKey, geometries: result.geometries, error: null });
27162
+ }).catch((error) => {
27163
+ if (cancelled || error instanceof Error && error.message === "cancelled") return;
27164
+ setGeometryState({
27165
+ status: "error",
27166
+ requestKey,
27167
+ geometries: [],
27168
+ error: error instanceof Error ? error.message : String(error)
27169
+ });
27170
+ });
27171
+ return () => {
27172
+ cancelled = true;
27173
+ constructionHistoryWorkerClient.dispose();
27174
+ };
27175
+ }, [activeBackend, historyMode, requestKey, visibleHistoryItems]);
27176
+ reactExports.useEffect(() => {
27177
+ const nextGeos = [];
27178
+ if (historyMode && geometryState.status === "ready" && geometryState.requestKey === requestKey) {
27179
+ const itemByKey = new Map(visibleHistoryItems.map((item) => [geometryItemKey(item.objectId, item.step.index), item]));
27180
+ for (const geometry of geometryState.geometries) {
27181
+ const item = itemByKey.get(geometryItemKey(geometry.objectId, geometry.stepIndex));
27182
+ if (!item) continue;
27183
+ nextGeos.push({
27184
+ objectId: item.objectId,
27185
+ step: item.step,
27186
+ geo: bufferGeometryFromWorkerGeometry(geometry)
27187
+ });
27188
+ }
27189
+ }
27190
+ for (const { geo } of objectGeosRef.current) disposeBufferedHistoryGeometry(geo);
27191
+ objectGeosRef.current = nextGeos;
27192
+ setObjectGeos(nextGeos);
27193
+ }, [geometryState, historyMode, requestKey, visibleHistoryItems]);
27194
+ reactExports.useEffect(() => {
27195
+ return () => {
27196
+ for (const { geo } of objectGeosRef.current) disposeBufferedHistoryGeometry(geo);
27197
+ objectGeosRef.current = [];
27198
+ };
27199
+ }, []);
27021
27200
  if (!historyMode || objectGeos.length === 0) return null;
27022
27201
  return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: objectGeos.map(({ objectId, geo, step }) => {
27023
27202
  var _a3;
@@ -29147,7 +29326,7 @@ function generateReportInWorker(options) {
29147
29326
  return new Promise((resolve2, reject) => {
29148
29327
  const worker = new Worker(new URL(
29149
29328
  /* @vite-ignore */
29150
- "/assets/reportWorker-CU8RZ4O0.js",
29329
+ "/assets/reportWorker-Bz9tGiHb.js",
29151
29330
  import.meta.url
29152
29331
  ), { type: "module" });
29153
29332
  const cleanup = () => {
@@ -32352,6 +32531,7 @@ const PHASE_CONFIG = {
32352
32531
  serializing: { color: "#7c4dff", label: "Preparing display" },
32353
32532
  exporting: { color: "#4caf50", label: "Exporting geometry" },
32354
32533
  inspecting: { color: "#14b8a6", label: "Generating inspect view" },
32534
+ history: { color: "#c084fc", label: "Building timeline geometry" },
32355
32535
  idle: { color: "#888", label: "" }
32356
32536
  };
32357
32537
  const PHASE_ORDER = ["kernel-init", "evaluating", "serializing"];
@@ -32359,36 +32539,18 @@ function formatEvaluationBackendLabel(activeBackend, computeTarget) {
32359
32539
  const backend = activeBackend === "occt" ? "OCCT" : activeBackend === "manifold" ? "Manifold" : activeBackend === "truck" ? "Truck" : "kernel";
32360
32540
  return computeTarget === "server" ? `Server ${backend}` : `Local ${backend}`;
32361
32541
  }
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
32542
  function EvaluationIndicator({
32377
32543
  phase,
32378
32544
  label,
32379
- constructionSteps = [],
32380
32545
  activeBackend,
32381
32546
  computeTarget
32382
32547
  }) {
32383
32548
  const [frame2, setFrame] = reactExports.useState(0);
32384
32549
  const [elapsed, setElapsed] = reactExports.useState(0);
32385
- const [previewStepIndex, setPreviewStepIndex] = reactExports.useState(0);
32386
32550
  const startRef = reactExports.useRef(Date.now());
32387
- const stepCount = constructionSteps.length;
32388
32551
  reactExports.useEffect(() => {
32389
32552
  startRef.current = Date.now();
32390
32553
  setElapsed(0);
32391
- setPreviewStepIndex(0);
32392
32554
  }, [phase]);
32393
32555
  reactExports.useEffect(() => {
32394
32556
  const spinnerInterval = setInterval(() => setFrame((f2) => (f2 + 1) % BRAILLE_FRAMES.length), 80);
@@ -32398,166 +32560,85 @@ function EvaluationIndicator({
32398
32560
  clearInterval(timerInterval);
32399
32561
  };
32400
32562
  }, []);
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]);
32407
32563
  const config = PHASE_CONFIG[phase] ?? PHASE_CONFIG["evaluating"];
32408
32564
  const elapsedSec = (elapsed / 1e3).toFixed(1);
32409
32565
  const phaseOrder = PHASE_ORDER.includes(phase) ? PHASE_ORDER : [phase];
32410
32566
  const phaseIdx = phaseOrder.indexOf(phase);
32411
- const { displayStepIndex, previewStep, progress } = constructionStepPreview(constructionSteps, previewStepIndex);
32412
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
32567
+ const backendLabel = formatEvaluationBackendLabel(activeBackend, computeTarget);
32568
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
32413
32569
  "div",
32414
32570
  {
32415
32571
  style: {
32416
32572
  position: "absolute",
32417
32573
  bottom: 16,
32418
32574
  right: 16,
32419
- width: previewStep ? "min(360px, calc(100vw - 32px))" : void 0,
32420
32575
  background: "var(--fc-bgPanel)",
32421
32576
  border: "1px solid var(--fc-border)",
32422
32577
  borderRadius: 8,
32423
- padding: previewStep ? "10px 12px" : "8px 14px",
32578
+ padding: "8px 14px",
32424
32579
  pointerEvents: "none",
32425
32580
  display: "grid",
32426
- gap: previewStep ? 8 : 0,
32581
+ gap: 0,
32427
32582
  fontSize: 12,
32428
32583
  animation: "fc-fadein 0.2s ease-out",
32429
32584
  boxShadow: "0 4px 16px rgba(0,0,0,0.25)"
32430
32585
  },
32431
- children: [
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(
32586
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, minWidth: 0 }, children: [
32587
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: config.color, fontSize: 16, fontWeight: 700, width: 16, textAlign: "center", flex: "0 0 auto" }, children: BRAILLE_FRAMES[frame2] }),
32588
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
32589
+ "span",
32590
+ {
32591
+ style: {
32592
+ color: "var(--fc-text)",
32593
+ fontWeight: 500,
32594
+ minWidth: 0,
32595
+ overflow: "hidden",
32596
+ textOverflow: "ellipsis",
32597
+ whiteSpace: "nowrap"
32598
+ },
32599
+ children: label ?? config.label
32600
+ }
32601
+ ),
32602
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
32603
+ "span",
32604
+ {
32605
+ style: {
32606
+ color: "var(--fc-textMuted)",
32607
+ fontSize: 11,
32608
+ minWidth: 0,
32609
+ overflow: "hidden",
32610
+ textOverflow: "ellipsis",
32611
+ whiteSpace: "nowrap"
32612
+ },
32613
+ children: backendLabel
32614
+ }
32615
+ ),
32616
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { display: "flex", gap: 4, alignItems: "center", marginLeft: "auto", flex: "0 0 auto" }, children: phaseOrder.map((p2, i) => {
32617
+ var _a3;
32618
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
32435
32619
  "span",
32436
32620
  {
32437
32621
  style: {
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"
32484
- }
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"
32622
+ width: 6,
32623
+ height: 6,
32624
+ borderRadius: "50%",
32625
+ background: i <= phaseIdx ? ((_a3 = PHASE_CONFIG[p2]) == null ? void 0 : _a3.color) ?? "var(--fc-border)" : "var(--fc-border)",
32626
+ transition: "background 0.3s ease",
32627
+ animation: i === phaseIdx ? "fc-pulse 1.2s ease-in-out infinite" : void 0
32548
32628
  }
32549
- }
32550
- ) })
32629
+ },
32630
+ p2
32631
+ );
32632
+ }) }),
32633
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { color: "var(--fc-textDim)", fontVariantNumeric: "tabular-nums", fontSize: 11, flex: "0 0 auto" }, children: [
32634
+ elapsedSec,
32635
+ "s"
32551
32636
  ] })
32552
- ]
32637
+ ] })
32553
32638
  }
32554
32639
  );
32555
32640
  }
32556
- const MIN_FIELD_GRID_SIZE = 18;
32557
- const MAX_FIELD_GRID_SIZE = 32;
32558
- const MAX_BLEND_SAMPLES = 12;
32559
32641
  const MAX_SEARCH_RADIUS = 5;
32560
- const SAMPLE_RING_OFFSETS = [];
32561
32642
  for (let radius = 0; radius <= MAX_SEARCH_RADIUS; radius += 1) {
32562
32643
  const ring = [];
32563
32644
  for (let x = -radius; x <= radius; x += 1) {
@@ -32567,7 +32648,6 @@ for (let radius = 0; radius <= MAX_SEARCH_RADIUS; radius += 1) {
32567
32648
  }
32568
32649
  }
32569
32650
  }
32570
- SAMPLE_RING_OFFSETS.push(ring);
32571
32651
  }
32572
32652
  const INSPECT_HEATMAP_VERTEX_SHADER = `
32573
32653
  varying vec3 vLocalPosition;
@@ -32635,127 +32715,14 @@ const INSPECT_HEATMAP_FRAGMENT_SHADER = `
32635
32715
  gl_FragColor = vec4(color, 1.0);
32636
32716
  }
32637
32717
  `;
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);
32718
+ function createInspectHeatmapField(field) {
32719
+ const texture = new DataTexture(
32720
+ field.data,
32721
+ field.gridSize * field.gridSize,
32722
+ field.gridSize,
32723
+ RGBAFormat,
32724
+ UnsignedByteType
32725
+ );
32759
32726
  texture.minFilter = NearestFilter;
32760
32727
  texture.magFilter = NearestFilter;
32761
32728
  texture.generateMipmaps = false;
@@ -32763,11 +32730,72 @@ function buildInspectHeatmapField(geometry, pointCloud) {
32763
32730
  texture.needsUpdate = true;
32764
32731
  return {
32765
32732
  texture,
32766
- boundsMin: bounds.min,
32767
- boundsSize,
32768
- gridSize
32733
+ boundsMin: new Vector3(...field.boundsMin),
32734
+ boundsSize: new Vector3(...field.boundsSize),
32735
+ gridSize: field.gridSize
32769
32736
  };
32770
32737
  }
32738
+ function fieldKindUniform(kind) {
32739
+ return kind === "hybrid" ? 1 : 0;
32740
+ }
32741
+ function SurfaceFieldMaterial({
32742
+ field,
32743
+ color: color2,
32744
+ clippingPlanes,
32745
+ fieldScale
32746
+ }) {
32747
+ const uniforms = reactExports.useMemo(
32748
+ () => ({
32749
+ uAccentColor: { value: new Color(field.accentColor) },
32750
+ uBaseColor: { value: new Color(field.baseColor) },
32751
+ uDarkColor: { value: new Color(field.darkColor) },
32752
+ uFieldKind: { value: fieldKindUniform(field.kind) },
32753
+ uFieldScale: { value: fieldScale },
32754
+ uGlow: { value: field.glow },
32755
+ uLineColor: { value: new Color(field.lineColor) },
32756
+ uLineWidth: { value: field.lineWidth },
32757
+ uNodeColor: { value: new Color(field.nodeColor) },
32758
+ uObjectColor: { value: new Color(color2) },
32759
+ uObjectColorMix: { value: field.objectColorMix },
32760
+ uSpacing: { value: field.spacing }
32761
+ }),
32762
+ [color2, field, fieldScale]
32763
+ );
32764
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
32765
+ "shaderMaterial",
32766
+ {
32767
+ vertexShader: SURFACE_FIELD_VERTEX_SHADER,
32768
+ fragmentShader: SURFACE_FIELD_FRAGMENT_SHADER,
32769
+ uniforms,
32770
+ side: DoubleSide,
32771
+ toneMapped: false,
32772
+ clippingPlanes
32773
+ }
32774
+ );
32775
+ }
32776
+ function ZebraInspectionMaterial({ clippingPlanes }) {
32777
+ const uniforms = reactExports.useMemo(
32778
+ () => ({
32779
+ uAccentColor: { value: new Color(ZEBRA_ACCENT_COLOR) },
32780
+ uDarkColor: { value: new Color(ZEBRA_DARK_COLOR) },
32781
+ uLightColor: { value: new Color(ZEBRA_LIGHT_COLOR) },
32782
+ uStripeScale: { value: ZEBRA_STRIPE_SCALE },
32783
+ uStripeSoftness: { value: ZEBRA_STRIPE_SOFTNESS }
32784
+ }),
32785
+ []
32786
+ );
32787
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
32788
+ "shaderMaterial",
32789
+ {
32790
+ vertexShader: ZEBRA_STRIPE_VERTEX_SHADER,
32791
+ fragmentShader: ZEBRA_STRIPE_FRAGMENT_SHADER,
32792
+ uniforms,
32793
+ side: DoubleSide,
32794
+ toneMapped: false,
32795
+ clippingPlanes
32796
+ }
32797
+ );
32798
+ }
32771
32799
  function ForgeObject({
32772
32800
  obj,
32773
32801
  settings,
@@ -32778,8 +32806,10 @@ function ForgeObject({
32778
32806
  inspectColor,
32779
32807
  inspectMeshColors,
32780
32808
  inspectPointCloud,
32809
+ inspectHeatmapFieldData,
32781
32810
  isInteracting,
32782
32811
  matrix,
32812
+ surfaceFieldScale,
32783
32813
  isHovered,
32784
32814
  clippingPlanes,
32785
32815
  debugHighlightColor,
@@ -32825,15 +32855,16 @@ function ForgeObject({
32825
32855
  if (!solidGeo || !inspectMeshColors) return null;
32826
32856
  const position = solidGeo.getAttribute("position");
32827
32857
  if (!position || inspectMeshColors.length !== position.count * 3) return null;
32858
+ if (inspectChannel === "floating") return geometryWithVisibleVertexColors(solidGeo, inspectMeshColors);
32828
32859
  const geometry = solidGeo.clone();
32829
32860
  geometry.setAttribute("color", new BufferAttribute(inspectMeshColors, 3));
32830
32861
  return geometry;
32831
- }, [inspectMeshColors, solidGeo]);
32862
+ }, [inspectChannel, inspectMeshColors, solidGeo]);
32832
32863
  const isScalarInspect = inspectChannel === "thickness" || inspectChannel === "roughness";
32833
32864
  const inspectHeatmapField = reactExports.useMemo(() => {
32834
- if (!isScalarInspect || !solidGeo || !inspectPointCloud) return null;
32835
- return buildInspectHeatmapField(solidGeo, inspectPointCloud);
32836
- }, [inspectPointCloud, isScalarInspect, solidGeo]);
32865
+ if (!isScalarInspect || !inspectHeatmapFieldData) return null;
32866
+ return createInspectHeatmapField(inspectHeatmapFieldData);
32867
+ }, [inspectHeatmapFieldData, isScalarInspect]);
32837
32868
  reactExports.useEffect(() => {
32838
32869
  return () => {
32839
32870
  solidGeo == null ? void 0 : solidGeo.dispose();
@@ -32861,11 +32892,13 @@ function ForgeObject({
32861
32892
  const showInspectHeatmap = Boolean(
32862
32893
  isScalarInspect && inspectHeatmapField && (inspectDisplayMode === "heatmap" || inspectDisplayMode === "both")
32863
32894
  );
32895
+ const showScalarContextMesh = Boolean(isScalarInspect && !showInspectHeatmap);
32864
32896
  const showInspectPoints = Boolean(
32865
32897
  isScalarInspect && inspectPointGeo && (inspectDisplayMode === "points" || inspectDisplayMode === "both")
32866
32898
  );
32867
32899
  const renderStylePreset = getRenderStylePreset(renderStyle);
32868
32900
  const materialDefaults = renderStylePreset.material;
32901
+ const surfaceField = renderStylePreset.surfaceField;
32869
32902
  const authoredMaterialOpacity = (_a3 = obj.materialProps) == null ? void 0 : _a3.opacity;
32870
32903
  const authoredMaterialTransmission = (_b2 = obj.materialProps) == null ? void 0 : _b2.transmission;
32871
32904
  const hasAuthoredTransparency = authoredMaterialOpacity !== void 0 && authoredMaterialOpacity < 0.99 || authoredMaterialTransmission !== void 0 && authoredMaterialTransmission > 0;
@@ -32881,6 +32914,8 @@ function ForgeObject({
32881
32914
  const effectiveClippingPlanes = clippingPlanes ?? [];
32882
32915
  const inspectSolidGeo = inspectMeshColorGeo ?? solidGeo;
32883
32916
  const hasInspectMeshColors = inspectMeshColorGeo !== null;
32917
+ const showFloatingContext = showSolid && inspectChannel === "floating";
32918
+ const showFloatingObject = inspectChannel !== "floating" || hasInspectMeshColors || inspectColor !== "#000000";
32884
32919
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
32885
32920
  "group",
32886
32921
  {
@@ -32893,17 +32928,42 @@ function ForgeObject({
32893
32928
  onDoubleClick,
32894
32929
  onContextMenu,
32895
32930
  children: [
32896
- showSolid && (inspectChannel === "mask" || inspectChannel === "connectivity" || inspectChannel === "distance") && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: inspectSolidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32931
+ showFloatingContext && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, renderOrder: 1, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32932
+ "meshBasicMaterial",
32933
+ {
32934
+ color: rgbToHex(FLOATING_CONTEXT_COLOR),
32935
+ transparent: true,
32936
+ opacity: 0.18,
32937
+ side: DoubleSide,
32938
+ depthWrite: false,
32939
+ toneMapped: false,
32940
+ clippingPlanes: effectiveClippingPlanes
32941
+ }
32942
+ ) }),
32943
+ showSolid && (inspectChannel === "mask" || inspectChannel === "connectivity" || inspectChannel === "floating" || inspectChannel === "distance") && showFloatingObject && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: inspectSolidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32897
32944
  "meshBasicMaterial",
32898
32945
  {
32899
32946
  color: hasInspectMeshColors ? "#ffffff" : inspectColor ?? settings.color,
32900
32947
  vertexColors: hasInspectMeshColors,
32901
32948
  side: DoubleSide,
32902
32949
  toneMapped: false,
32950
+ clippingPlanes: effectiveClippingPlanes,
32951
+ polygonOffset: inspectChannel === "floating",
32952
+ polygonOffsetFactor: -1,
32953
+ polygonOffsetUnits: -1
32954
+ }
32955
+ ) }),
32956
+ showSolid && inspectChannel === "normals" && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32957
+ "meshNormalMaterial",
32958
+ {
32959
+ flatShading: !hasSmoothNormals,
32960
+ side: DoubleSide,
32961
+ toneMapped: false,
32903
32962
  clippingPlanes: effectiveClippingPlanes
32904
32963
  }
32905
32964
  ) }),
32906
- showSolid && isScalarInspect && !showInspectHeatmap && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32965
+ showSolid && inspectChannel === "zebra" && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZebraInspectionMaterial, { clippingPlanes: effectiveClippingPlanes }) }),
32966
+ showSolid && showScalarContextMesh && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, renderOrder: 3, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32907
32967
  "meshBasicMaterial",
32908
32968
  {
32909
32969
  color: "#26313a",
@@ -32931,7 +32991,7 @@ function ForgeObject({
32931
32991
  clippingPlanes: effectiveClippingPlanes
32932
32992
  }
32933
32993
  ) }),
32934
- showSolid && showInspectPoints && inspectPointGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("points", { geometry: inspectPointGeo, raycast: () => null, renderOrder: 5, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32994
+ showInspectPoints && inspectPointGeo && /* @__PURE__ */ jsxRuntimeExports.jsx("points", { geometry: inspectPointGeo, raycast: () => null, renderOrder: 5, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
32935
32995
  "pointsMaterial",
32936
32996
  {
32937
32997
  size: 3,
@@ -32956,7 +33016,15 @@ function ForgeObject({
32956
33016
  clippingPlanes: effectiveClippingPlanes
32957
33017
  }
32958
33018
  ) }),
32959
- showSolid && inspectChannel === "none" && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
33019
+ showSolid && inspectChannel === "none" && /* @__PURE__ */ jsxRuntimeExports.jsx("mesh", { geometry: solidGeo, userData: { forgeMesh: true }, children: surfaceField.enabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(
33020
+ SurfaceFieldMaterial,
33021
+ {
33022
+ field: surfaceField,
33023
+ color: settings.color,
33024
+ clippingPlanes: effectiveClippingPlanes,
33025
+ fieldScale: surfaceFieldScale
33026
+ }
33027
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
32960
33028
  "meshPhysicalMaterial",
32961
33029
  {
32962
33030
  color: settings.color,
@@ -38548,11 +38616,13 @@ function useViewportState() {
38548
38616
  const files = useForgeStore((s) => s.files);
38549
38617
  const renderMode = useForgeStore((s) => s.renderMode);
38550
38618
  const renderStyle = useForgeStore((s) => s.renderStyle);
38619
+ const manualScene = useForgeStore((s) => s.manualScene);
38551
38620
  const inspectChannel = useForgeStore((s) => s.inspectChannel);
38552
38621
  const inspectDisplayMode = useForgeStore((s) => s.inspectDisplayMode);
38553
38622
  const inspectPointSampleCount = useForgeStore((s) => s.inspectPointSampleCount);
38554
38623
  const projectionMode = useForgeStore((s) => s.projectionMode);
38555
38624
  const gridEnabled = useForgeStore((s) => s.gridEnabled);
38625
+ const axesVisible = useForgeStore((s) => s.axesVisible);
38556
38626
  const gridSize = useForgeStore((s) => s.gridSize);
38557
38627
  const showPerformanceInfo = useForgeStore((s) => s.showPerformanceInfo);
38558
38628
  const objectSettings = useForgeStore((s) => s.objectSettings);
@@ -38713,6 +38783,26 @@ function useViewportState() {
38713
38783
  });
38714
38784
  return hasBounds ? bounds.min.z : null;
38715
38785
  }, [objects, objectMatrices]);
38786
+ const surfaceFieldScale = reactExports.useMemo(() => {
38787
+ const bounds = new Box3();
38788
+ let hasBounds = false;
38789
+ objects.forEach((obj) => {
38790
+ var _a3;
38791
+ if (((_a3 = objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) return;
38792
+ const matrix = objectMatrices[obj.id] ?? new Matrix4();
38793
+ if (obj.shape) {
38794
+ try {
38795
+ const bb = obj.shape.boundingBox();
38796
+ if (expandBoundsByTransformedAabb(bounds, bb.min, bb.max, matrix)) hasBounds = true;
38797
+ } catch {
38798
+ }
38799
+ }
38800
+ });
38801
+ if (!hasBounds) return 1;
38802
+ const size = bounds.getSize(new Vector3());
38803
+ const maxDim = Math.max(size.x, size.y, size.z);
38804
+ return Number.isFinite(maxDim) && maxDim > 0 ? maxDim / 5 : 1;
38805
+ }, [objectMatrices, objects, objectSettings]);
38716
38806
  useJointAnimationLoop(activeJointAnimation);
38717
38807
  const anySectionActive = activeCutPlaneDefs.length > 0;
38718
38808
  const sectionGuideBoundsKey = (sectionPlaneGuidesEnabled || sectionExplorerEnabled) && anySectionActive ? objectMatrices : null;
@@ -38877,11 +38967,13 @@ function useViewportState() {
38877
38967
  files,
38878
38968
  renderMode,
38879
38969
  renderStyle,
38970
+ manualScene,
38880
38971
  inspectChannel,
38881
38972
  inspectDisplayMode,
38882
38973
  inspectPointSampleCount,
38883
38974
  projectionMode,
38884
38975
  gridEnabled,
38976
+ axesVisible,
38885
38977
  gridSize,
38886
38978
  showPerformanceInfo,
38887
38979
  objectSettings,
@@ -38954,6 +39046,7 @@ function useViewportState() {
38954
39046
  jointsConfig,
38955
39047
  sceneConfig,
38956
39048
  modelBoundsMinZ,
39049
+ surfaceFieldScale,
38957
39050
  focusedObjectIdSet,
38958
39051
  visibleSceneObjectCount,
38959
39052
  visibleModelTriangles,
@@ -40259,7 +40352,7 @@ function RenderLabelsOverlay({ labels }) {
40259
40352
  class InspectWorkerClient {
40260
40353
  constructor(workerFactory = () => new Worker(new URL(
40261
40354
  /* @vite-ignore */
40262
- "/assets/inspectWorker-Dll4eVyD.js",
40355
+ "/assets/inspectWorker-BZ2CkQZr.js",
40263
40356
  import.meta.url
40264
40357
  ), { type: "module" })) {
40265
40358
  __publicField(this, "worker", null);
@@ -40319,10 +40412,11 @@ class InspectWorkerClient {
40319
40412
  }
40320
40413
  }
40321
40414
  const inspectWorkerClient = new InspectWorkerClient();
40322
- const WORKER_CHANNELS = /* @__PURE__ */ new Set(["thickness", "roughness", "connectivity", "distance"]);
40415
+ const WORKER_CHANNELS = /* @__PURE__ */ new Set(["thickness", "roughness", "connectivity", "floating", "distance"]);
40323
40416
  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;
40417
+ const MESH_COMPONENT_WORKER_CHANNELS = /* @__PURE__ */ new Set(["connectivity", "floating", "distance"]);
40418
+ const IDENTITY_MATRIX_ELEMENTS = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
40419
+ const INSPECT_BUILD_YIELD_INTERVAL_MS = 8;
40326
40420
  class InspectBuildCancelledError extends Error {
40327
40421
  constructor() {
40328
40422
  super("cancelled");
@@ -40334,23 +40428,34 @@ function isScalarWorkerChannel(channel) {
40334
40428
  function needsMeshComponents(channel) {
40335
40429
  return MESH_COMPONENT_WORKER_CHANNELS.has(channel);
40336
40430
  }
40431
+ function shouldIncludeInspectPositions(channel, obj) {
40432
+ var _a3;
40433
+ if (isScalarWorkerChannel(channel)) return true;
40434
+ if (!needsMeshComponents(channel)) return false;
40435
+ if (channel === "floating") return true;
40436
+ const sources = (_a3 = obj.geometryInfo) == null ? void 0 : _a3.sources;
40437
+ return !((sources == null ? void 0 : sources.length) === 1 && sources[0] === "primitive");
40438
+ }
40337
40439
  function viewportScalarSamplesPerObject(objectCount, inspectPointSampleCount) {
40338
40440
  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));
40441
+ return resolveScalarSceneSampleBudget({
40442
+ objectCount,
40443
+ maxSamplesPerObject: perObjectCap,
40444
+ minSamplesPerObject: INSPECT_POINT_SAMPLE_COUNT_MIN
40445
+ }).effectiveMaxSamplesPerObject;
40343
40446
  }
40344
40447
  function yieldToBrowser() {
40345
40448
  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
- });
40449
+ return new Promise((resolve2) => window.setTimeout(resolve2, 0));
40450
+ }
40451
+ function createBuildYield(isCancelled) {
40452
+ let lastYield = performance.now();
40453
+ return async () => {
40454
+ if (performance.now() - lastYield < INSPECT_BUILD_YIELD_INTERVAL_MS) return;
40455
+ await yieldToBrowser();
40456
+ if (isCancelled()) throw new InspectBuildCancelledError();
40457
+ lastYield = performance.now();
40458
+ };
40354
40459
  }
40355
40460
  function transformedBounds(obj, matrix) {
40356
40461
  if (!obj.shape) return null;
@@ -40367,6 +40472,31 @@ function transformedBounds(obj, matrix) {
40367
40472
  return null;
40368
40473
  }
40369
40474
  }
40475
+ function matrixIsIdentity(matrix) {
40476
+ if (!matrix) return true;
40477
+ const elements = matrix.elements;
40478
+ return IDENTITY_MATRIX_ELEMENTS.every((value, index) => elements[index] === value);
40479
+ }
40480
+ function clonePositionsWithOptionalTransform(source, matrix) {
40481
+ const positions = new Float32Array(source);
40482
+ if (matrixIsIdentity(matrix)) return positions;
40483
+ const e2 = matrix.elements;
40484
+ for (let index = 0; index < positions.length; index += 3) {
40485
+ const x = positions[index];
40486
+ const y = positions[index + 1];
40487
+ const z = positions[index + 2];
40488
+ const w = e2[3] * x + e2[7] * y + e2[11] * z + e2[15];
40489
+ positions[index] = e2[0] * x + e2[4] * y + e2[8] * z + e2[12];
40490
+ positions[index + 1] = e2[1] * x + e2[5] * y + e2[9] * z + e2[13];
40491
+ positions[index + 2] = e2[2] * x + e2[6] * y + e2[10] * z + e2[14];
40492
+ if (w !== 1 && w !== 0) {
40493
+ positions[index] /= w;
40494
+ positions[index + 1] /= w;
40495
+ positions[index + 2] /= w;
40496
+ }
40497
+ }
40498
+ return positions;
40499
+ }
40370
40500
  function clonePositions(obj, matrix) {
40371
40501
  var _a3;
40372
40502
  if (!obj.shape) return void 0;
@@ -40374,17 +40504,7 @@ function clonePositions(obj, matrix) {
40374
40504
  try {
40375
40505
  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
40506
  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;
40507
+ return clonePositionsWithOptionalTransform(source, matrix);
40388
40508
  } finally {
40389
40509
  geometry == null ? void 0 : geometry.solid.dispose();
40390
40510
  geometry == null ? void 0 : geometry.edges.dispose();
@@ -40392,18 +40512,17 @@ function clonePositions(obj, matrix) {
40392
40512
  }
40393
40513
  async function buildWorkerObjects(args) {
40394
40514
  var _a3;
40395
- const needsMesh = isScalarWorkerChannel(args.inspectChannel) || needsMeshComponents(args.inspectChannel);
40396
40515
  const out = [];
40516
+ const maybeYield = createBuildYield(args.isCancelled);
40397
40517
  for (const obj of args.objects) {
40398
40518
  if (args.isCancelled()) throw new InspectBuildCancelledError();
40399
40519
  if (!obj.shape) continue;
40400
40520
  if (((_a3 = args.objectSettings[obj.id]) == null ? void 0 : _a3.visible) === false) continue;
40401
- await yieldToBrowser();
40402
- if (args.isCancelled()) throw new InspectBuildCancelledError();
40403
40521
  const matrix = args.objectMatrices[obj.id] ?? new Matrix4();
40404
40522
  const bbox = transformedBounds(obj, matrix);
40405
40523
  if (!bbox) continue;
40406
40524
  if (args.isCancelled()) throw new InspectBuildCancelledError();
40525
+ const positions = shouldIncludeInspectPositions(args.inspectChannel, obj) ? clonePositions(obj, needsMeshComponents(args.inspectChannel) ? matrix : void 0) : void 0;
40407
40526
  out.push({
40408
40527
  id: obj.id,
40409
40528
  name: obj.name,
@@ -40411,13 +40530,13 @@ async function buildWorkerObjects(args) {
40411
40530
  treePath: obj.treePath,
40412
40531
  mock: obj.mock,
40413
40532
  bbox,
40414
- ...needsMesh ? { positions: clonePositions(obj, needsMeshComponents(args.inspectChannel) ? matrix : void 0) } : {}
40533
+ ...positions ? { positions } : {}
40415
40534
  });
40416
- await yieldToBrowser();
40535
+ await maybeYield();
40417
40536
  }
40418
40537
  return out;
40419
40538
  }
40420
- function analyzePayloadFor(channel, objects, inspectPointSampleCount) {
40539
+ function analyzePayloadFor(channel, objects, inspectPointSampleCount, groundZ) {
40421
40540
  const maxSamplesPerObject = viewportScalarSamplesPerObject(objects.length, inspectPointSampleCount);
40422
40541
  if (channel === "thickness") {
40423
40542
  return {
@@ -40437,7 +40556,7 @@ function analyzePayloadFor(channel, objects, inspectPointSampleCount) {
40437
40556
  }
40438
40557
  };
40439
40558
  }
40440
- return { channel, objects };
40559
+ return { channel, objects, groundZ };
40441
40560
  }
40442
40561
  function resultToState(channel, result) {
40443
40562
  return {
@@ -40445,6 +40564,17 @@ function resultToState(channel, result) {
40445
40564
  channel,
40446
40565
  objectColors: result.objectColors,
40447
40566
  meshColors: Object.fromEntries(result.meshColorObjects.map((object) => [object.objectId, object.colors])),
40567
+ heatmapFields: Object.fromEntries(
40568
+ result.heatmapFieldObjects.map((object) => [
40569
+ object.objectId,
40570
+ {
40571
+ data: object.data,
40572
+ boundsMin: object.boundsMin,
40573
+ boundsSize: object.boundsSize,
40574
+ gridSize: object.gridSize
40575
+ }
40576
+ ])
40577
+ ),
40448
40578
  pointClouds: Object.fromEntries(
40449
40579
  result.pointObjects.map((object) => [
40450
40580
  object.objectId,
@@ -40466,6 +40596,7 @@ function useInspectWorkerAnalysis(args) {
40466
40596
  objectColors: {},
40467
40597
  meshColors: {},
40468
40598
  pointClouds: {},
40599
+ heatmapFields: {},
40469
40600
  warnings: [],
40470
40601
  error: null
40471
40602
  });
@@ -40478,6 +40609,7 @@ function useInspectWorkerAnalysis(args) {
40478
40609
  objectColors: {},
40479
40610
  meshColors: {},
40480
40611
  pointClouds: {},
40612
+ heatmapFields: {},
40481
40613
  warnings: [],
40482
40614
  error: null
40483
40615
  });
@@ -40491,6 +40623,7 @@ function useInspectWorkerAnalysis(args) {
40491
40623
  objectColors: {},
40492
40624
  meshColors: {},
40493
40625
  pointClouds: {},
40626
+ heatmapFields: {},
40494
40627
  warnings: [],
40495
40628
  error: null
40496
40629
  });
@@ -40501,7 +40634,8 @@ function useInspectWorkerAnalysis(args) {
40501
40634
  isCancelled: () => cancelled
40502
40635
  });
40503
40636
  if (cancelled) return;
40504
- const result = await inspectWorkerClient.analyze(analyzePayloadFor(channel, objects, args.inspectPointSampleCount));
40637
+ const groundZ = typeof args.groundZ === "number" && Number.isFinite(args.groundZ) ? args.groundZ : 0;
40638
+ const result = await inspectWorkerClient.analyze(analyzePayloadFor(channel, objects, args.inspectPointSampleCount, groundZ));
40505
40639
  if (cancelled) return;
40506
40640
  setState(resultToState(args.inspectChannel, result));
40507
40641
  } catch (error) {
@@ -40514,6 +40648,7 @@ function useInspectWorkerAnalysis(args) {
40514
40648
  objectColors: {},
40515
40649
  meshColors: {},
40516
40650
  pointClouds: {},
40651
+ heatmapFields: {},
40517
40652
  warnings: [],
40518
40653
  error: error instanceof Error ? error.message : String(error)
40519
40654
  });
@@ -40523,9 +40658,72 @@ function useInspectWorkerAnalysis(args) {
40523
40658
  cancelled = true;
40524
40659
  inspectWorkerClient.dispose();
40525
40660
  };
40526
- }, [args.inspectChannel, args.inspectPointSampleCount, args.sceneVersion, args.objects, args.objectSettings, args.objectMatrices]);
40661
+ }, [
40662
+ args.inspectChannel,
40663
+ args.inspectPointSampleCount,
40664
+ args.sceneVersion,
40665
+ args.objects,
40666
+ args.objectSettings,
40667
+ args.objectMatrices,
40668
+ args.groundZ
40669
+ ]);
40527
40670
  return state2;
40528
40671
  }
40672
+ function buildManualSceneConfig(base, manualScene, renderStylePreset) {
40673
+ var _a3, _b2, _c;
40674
+ const lights = [
40675
+ { type: "ambient", color: "#ffffff", intensity: manualScene.ambientIntensity },
40676
+ {
40677
+ type: "directional",
40678
+ position: renderStylePreset.lights.keyPosition,
40679
+ color: renderStylePreset.lights.keyColor,
40680
+ intensity: manualScene.keyIntensity,
40681
+ castShadow: true
40682
+ },
40683
+ {
40684
+ type: "directional",
40685
+ position: renderStylePreset.lights.fillPosition,
40686
+ color: renderStylePreset.lights.fillColor,
40687
+ intensity: manualScene.fillIntensity
40688
+ }
40689
+ ];
40690
+ if (manualScene.rimIntensity > 0) {
40691
+ lights.push({
40692
+ type: "directional",
40693
+ position: renderStylePreset.lights.rimPosition,
40694
+ color: renderStylePreset.lights.rimColor,
40695
+ intensity: manualScene.rimIntensity
40696
+ });
40697
+ }
40698
+ lights.push({
40699
+ type: "hemisphere",
40700
+ skyColor: renderStylePreset.lights.hemisphereSky,
40701
+ groundColor: manualScene.groundColor,
40702
+ intensity: renderStylePreset.lights.hemisphereIntensity
40703
+ });
40704
+ return {
40705
+ background: manualScene.backgroundColor,
40706
+ camera: (base == null ? void 0 : base.camera) ?? null,
40707
+ views: (base == null ? void 0 : base.views) ?? null,
40708
+ journeys: (base == null ? void 0 : base.journeys) ?? null,
40709
+ lights,
40710
+ environment: {
40711
+ ...(base == null ? void 0 : base.environment) ?? {},
40712
+ preset: ((_a3 = base == null ? void 0 : base.environment) == null ? void 0 : _a3.preset) ?? "studio",
40713
+ intensity: manualScene.environmentIntensity,
40714
+ background: ((_b2 = base == null ? void 0 : base.environment) == null ? void 0 : _b2.background) ?? false
40715
+ },
40716
+ fog: (base == null ? void 0 : base.fog) ?? null,
40717
+ postProcessing: (base == null ? void 0 : base.postProcessing) ?? null,
40718
+ ground: {
40719
+ ...(base == null ? void 0 : base.ground) ?? {},
40720
+ visible: manualScene.groundVisible,
40721
+ color: manualScene.groundColor,
40722
+ receiveShadow: ((_c = base == null ? void 0 : base.ground) == null ? void 0 : _c.receiveShadow) ?? true
40723
+ },
40724
+ capture: (base == null ? void 0 : base.capture) ?? null
40725
+ };
40726
+ }
40529
40727
  function panelNumber(value) {
40530
40728
  if (!Number.isFinite(value)) return String(value);
40531
40729
  if (Number.isInteger(value)) return String(value);
@@ -40555,8 +40753,14 @@ function inspectChannelLabel(channel) {
40555
40753
  switch (channel) {
40556
40754
  case "connectivity":
40557
40755
  return "Connect";
40756
+ case "floating":
40757
+ return "Floating";
40558
40758
  case "distance":
40559
40759
  return "Distance";
40760
+ case "normals":
40761
+ return "Normals";
40762
+ case "zebra":
40763
+ return "Zebra";
40560
40764
  case "thickness":
40561
40765
  return "Thickness";
40562
40766
  case "roughness":
@@ -40650,7 +40854,7 @@ function RenderStyleExposure({ exposure }) {
40650
40854
  return null;
40651
40855
  }
40652
40856
  function Viewport() {
40653
- var _a3, _b2, _c;
40857
+ var _a3, _b2, _c, _d;
40654
40858
  const activeFile = useForgeStore((s) => s.activeFile);
40655
40859
  const activeBackend = useForgeStore((s) => s.activeBackend);
40656
40860
  const computeTarget = useForgeStore((s) => s.computeTarget);
@@ -40662,11 +40866,13 @@ function Viewport() {
40662
40866
  evaluationPhase,
40663
40867
  renderMode,
40664
40868
  renderStyle,
40869
+ manualScene,
40665
40870
  inspectChannel,
40666
40871
  inspectDisplayMode,
40667
40872
  inspectPointSampleCount,
40668
40873
  projectionMode,
40669
40874
  gridEnabled,
40875
+ axesVisible,
40670
40876
  gridSize,
40671
40877
  showPerformanceInfo,
40672
40878
  objectSettings,
@@ -40714,6 +40920,7 @@ function Viewport() {
40714
40920
  isSketchOnly,
40715
40921
  sceneConfig,
40716
40922
  modelBoundsMinZ,
40923
+ surfaceFieldScale,
40717
40924
  focusedObjectIdSet,
40718
40925
  visibleSceneObjectCount,
40719
40926
  visibleModelTriangles,
@@ -40734,6 +40941,11 @@ function Viewport() {
40734
40941
  const historyObjectIds = useForgeStore((s) => s.historyObjectIds);
40735
40942
  useHistoryPlaybackLoop();
40736
40943
  const [viewPersistenceResolved, setViewPersistenceResolved] = reactExports.useState(false);
40944
+ const [historyGeometryStatus, setHistoryGeometryStatus] = reactExports.useState({
40945
+ status: "idle",
40946
+ stepCount: 0,
40947
+ error: null
40948
+ });
40737
40949
  const [isViewportInteracting, setIsViewportInteracting] = reactExports.useState(false);
40738
40950
  const [zoomMmPerPx, setZoomMmPerPx] = reactExports.useState(null);
40739
40951
  const hoverTooltipRef = reactExports.useRef(null);
@@ -40748,6 +40960,12 @@ function Viewport() {
40748
40960
  const contextMenuRef = reactExports.useRef(null);
40749
40961
  const t2 = themes[themeName];
40750
40962
  const renderStylePreset = reactExports.useMemo(() => getRenderStylePreset(renderStyle), [renderStyle]);
40963
+ const effectiveSceneConfig = reactExports.useMemo(
40964
+ () => manualScene.enabled ? buildManualSceneConfig(sceneConfig, manualScene, renderStylePreset) : sceneConfig,
40965
+ [manualScene, renderStylePreset, sceneConfig]
40966
+ );
40967
+ const inspectGroundOffset = typeof ((_a3 = effectiveSceneConfig == null ? void 0 : effectiveSceneConfig.ground) == null ? void 0 : _a3.offset) === "number" && Number.isFinite(effectiveSceneConfig.ground.offset) ? effectiveSceneConfig.ground.offset : 0;
40968
+ const inspectGroundZ = (modelBoundsMinZ ?? 0) - inspectGroundOffset;
40751
40969
  const inspectChannelActive = inspectChannel !== "none";
40752
40970
  const hasVisibleSdfObjects = objects.some((obj) => {
40753
40971
  var _a4;
@@ -40771,21 +40989,13 @@ function Viewport() {
40771
40989
  sceneVersion,
40772
40990
  objects,
40773
40991
  objectSettings,
40774
- objectMatrices
40992
+ objectMatrices,
40993
+ groundZ: inspectGroundZ
40775
40994
  });
40776
40995
  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]);
40996
+ const historyGeometryLoading = historyMode && historyGeometryStatus.status === "loading";
40997
+ const viewportBusyPhase = isEvaluating || evaluationPhase === "exporting" ? evaluationPhase : historyGeometryLoading ? "history" : inspectLoading ? "inspecting" : null;
40998
+ const viewportBusyLabel = historyGeometryLoading ? "Building timeline geometry" : inspectLoading ? `Generating ${inspectChannelLabel(inspectChannel)} inspect view` : void 0;
40789
40999
  const handlers = useViewportHandlers({
40790
41000
  containerRef,
40791
41001
  contextMenuRef,
@@ -40849,7 +41059,7 @@ function Viewport() {
40849
41059
  Canvas,
40850
41060
  {
40851
41061
  style: {
40852
- background: inspectChannelActive ? "#000000" : renderStyle === "classic" ? t2.viewportBg : renderStylePreset.background,
41062
+ background: renderStyle === "classic" ? t2.viewportBg : renderStylePreset.background,
40853
41063
  cursor: measureMode ? "crosshair" : "default"
40854
41064
  },
40855
41065
  dpr: canvasDpr,
@@ -40866,19 +41076,21 @@ function Viewport() {
40866
41076
  children: [
40867
41077
  /* @__PURE__ */ jsxRuntimeExports.jsxs(reactExports.Suspense, { fallback: null, children: [
40868
41078
  projectionMode === "orthographic" ? /* @__PURE__ */ jsxRuntimeExports.jsx(OrthographicCamera, { makeDefault: true, position: [120, 80, 120], zoom: 2, near: -5e4, far: 5e4, up: [0, 0, 1] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(PerspectiveCamera, { makeDefault: true, position: [120, 80, 120], fov: 45, near: 0.1, far: 1e5, up: [0, 0, 1] }),
40869
- ((_a3 = sceneConfig == null ? void 0 : sceneConfig.postProcessing) == null ? void 0 : _a3.toneMappingExposure) === void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(RenderStyleExposure, { exposure: renderStylePreset.toneMappingExposure }),
40870
- sceneConfig && /* @__PURE__ */ jsxRuntimeExports.jsx(
41079
+ ((_b2 = effectiveSceneConfig == null ? void 0 : effectiveSceneConfig.postProcessing) == null ? void 0 : _b2.toneMappingExposure) === void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(RenderStyleExposure, { exposure: renderStylePreset.toneMappingExposure }),
41080
+ effectiveSceneConfig && /* @__PURE__ */ jsxRuntimeExports.jsx(
40871
41081
  SceneConfigurator,
40872
41082
  {
40873
- config: sceneConfig,
41083
+ config: effectiveSceneConfig,
41084
+ interactivePreview: isViewportInteracting,
40874
41085
  controlsRef,
40875
41086
  modelBoundsMinZ,
41087
+ hideGround: inspectChannelActive,
40876
41088
  onDefaultLightsOverridden: handleDefaultLightsOverridden,
40877
41089
  onDefaultEnvironmentOverridden: handleDefaultEnvironmentOverridden
40878
41090
  }
40879
41091
  ),
40880
- !defaultEnvironmentOverridden && /* @__PURE__ */ jsxRuntimeExports.jsx(LocalEnvironment, { preset: "studio", intensity: renderStylePreset.environmentIntensity }),
40881
- !defaultLightsOverridden && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
41092
+ !isViewportInteracting && !defaultEnvironmentOverridden && /* @__PURE__ */ jsxRuntimeExports.jsx(LocalEnvironment, { preset: "studio", intensity: renderStylePreset.environmentIntensity }),
41093
+ (isViewportInteracting || !defaultLightsOverridden) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
40882
41094
  /* @__PURE__ */ jsxRuntimeExports.jsx("ambientLight", { intensity: renderStylePreset.lights.ambientIntensity }),
40883
41095
  /* @__PURE__ */ jsxRuntimeExports.jsx(
40884
41096
  "directionalLight",
@@ -40917,8 +41129,8 @@ function Viewport() {
40917
41129
  )
40918
41130
  ] }),
40919
41131
  /* @__PURE__ */ jsxRuntimeExports.jsx(ClippingManager, { active: hasAnyObjectCutPlanes }),
40920
- !inspectChannelActive && sectionExplorerEnabled && /* @__PURE__ */ jsxRuntimeExports.jsx(SectionExplorerGizmo, { size: sectionGuideSize }),
40921
- !inspectChannelActive && sectionPlaneGuidesEnabled && activeCutPlaneDefs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
41132
+ sectionExplorerEnabled && /* @__PURE__ */ jsxRuntimeExports.jsx(SectionExplorerGizmo, { size: sectionGuideSize }),
41133
+ sectionPlaneGuidesEnabled && activeCutPlaneDefs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
40922
41134
  SectionPlaneGuides,
40923
41135
  {
40924
41136
  cutPlanes: scriptCutPlaneDefs,
@@ -40952,11 +41164,13 @@ function Viewport() {
40952
41164
  renderMode,
40953
41165
  inspectChannel,
40954
41166
  inspectDisplayMode,
40955
- inspectColor: inspectAnalysis.objectColors[obj.id] ?? maskColorForIndex(objIndex),
41167
+ inspectColor: inspectChannel === "floating" ? inspectAnalysis.objectColors[obj.id] ?? "#000000" : inspectAnalysis.objectColors[obj.id] ?? maskColorForIndex(objIndex),
40956
41168
  inspectMeshColors: inspectAnalysis.meshColors[obj.id],
40957
41169
  inspectPointCloud: inspectAnalysis.pointClouds[obj.id],
41170
+ inspectHeatmapFieldData: inspectAnalysis.heatmapFields[obj.id],
40958
41171
  isInteracting: isViewportInteracting,
40959
41172
  matrix,
41173
+ surfaceFieldScale,
40960
41174
  isHovered,
40961
41175
  clippingPlanes: objectClippingPlanes,
40962
41176
  debugHighlightColor: shapeHl == null ? void 0 : shapeHl.color,
@@ -41020,7 +41234,7 @@ function Viewport() {
41020
41234
  return null;
41021
41235
  }),
41022
41236
  inspectChannel === "collisions" && /* @__PURE__ */ jsxRuntimeExports.jsx(CollisionInspectionOverlay, { objects, objectSettings, objectMatrices }),
41023
- !inspectChannelActive && /* @__PURE__ */ jsxRuntimeExports.jsx(
41237
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
41024
41238
  SectionCaps,
41025
41239
  {
41026
41240
  sceneVersion,
@@ -41032,17 +41246,25 @@ function Viewport() {
41032
41246
  isInteracting: isViewportInteracting
41033
41247
  }
41034
41248
  ),
41035
- !inspectChannelActive && constructionGhost && /* @__PURE__ */ jsxRuntimeExports.jsx(ConstructionGhostOverlay, { matrix: constructionGhostMatrix }),
41036
- !inspectChannelActive && historyMode && /* @__PURE__ */ jsxRuntimeExports.jsx(ConstructionHistoryOverlay, { objectMatrices, objectSettings }),
41037
- !inspectChannelActive && hoveredJointOverlay && /* @__PURE__ */ jsxRuntimeExports.jsx(HoveredJointOverlay, { state: hoveredJointOverlay, config: jointOverlayConfig }),
41038
- !inspectChannelActive && dimensionsVisible && dimensions.map((d) => /* @__PURE__ */ jsxRuntimeExports.jsx(DimensionAnnotation, { def: d, lengthUnit }, d.id)),
41039
- !inspectChannelActive && /* @__PURE__ */ jsxRuntimeExports.jsx(RenderLabelsOverlay, { labels: renderLabels }),
41040
- !inspectChannelActive && attachmentsVisible !== "none" && attachmentPoints.map((ap) => {
41249
+ constructionGhost && /* @__PURE__ */ jsxRuntimeExports.jsx(ConstructionGhostOverlay, { matrix: constructionGhostMatrix }),
41250
+ historyMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
41251
+ ConstructionHistoryOverlay,
41252
+ {
41253
+ activeBackend,
41254
+ objectMatrices,
41255
+ objectSettings,
41256
+ onGeometryStatusChange: setHistoryGeometryStatus
41257
+ }
41258
+ ),
41259
+ hoveredJointOverlay && /* @__PURE__ */ jsxRuntimeExports.jsx(HoveredJointOverlay, { state: hoveredJointOverlay, config: jointOverlayConfig }),
41260
+ dimensionsVisible && dimensions.map((d) => /* @__PURE__ */ jsxRuntimeExports.jsx(DimensionAnnotation, { def: d, lengthUnit }, d.id)),
41261
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RenderLabelsOverlay, { labels: renderLabels }),
41262
+ attachmentsVisible !== "none" && attachmentPoints.map((ap) => {
41041
41263
  const matrix = objectMatrices[ap.objectId];
41042
41264
  return matrix ? /* @__PURE__ */ jsxRuntimeExports.jsx("group", { matrixAutoUpdate: false, matrix, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectorAttachmentAnnotation, { def: ap }) }, `${ap.objectId}:${ap.name}`) : /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectorAttachmentAnnotation, { def: ap }, `${ap.objectId}:${ap.name}`);
41043
41265
  }),
41044
41266
  /* @__PURE__ */ jsxRuntimeExports.jsx(MeasureTool, {}),
41045
- !inspectChannelActive && debugHighlights3D.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(DebugHighlightsOverlay, { highlights: debugHighlights3D }),
41267
+ debugHighlights3D.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(DebugHighlightsOverlay, { highlights: debugHighlights3D }),
41046
41268
  drawFlagEnabled && /* @__PURE__ */ jsxRuntimeExports.jsx(DrawCanvas, {}),
41047
41269
  /* @__PURE__ */ jsxRuntimeExports.jsx(
41048
41270
  PerformanceInfoSampler,
@@ -41055,7 +41277,7 @@ function Viewport() {
41055
41277
  }
41056
41278
  ),
41057
41279
  /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomSampler, { onZoomChange: setZoomMmPerPx }),
41058
- !inspectChannelActive && gridEnabled && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41280
+ gridEnabled && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41059
41281
  Grid,
41060
41282
  {
41061
41283
  args: [500, 500],
@@ -41070,7 +41292,7 @@ function Viewport() {
41070
41292
  infiniteGrid: true
41071
41293
  }
41072
41294
  ),
41073
- !inspectChannelActive && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41295
+ !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41074
41296
  SdfRaymarchLayer,
41075
41297
  {
41076
41298
  objects,
@@ -41085,11 +41307,11 @@ function Viewport() {
41085
41307
  onContextMenu: (obj, event) => handleObjectContextMenu(obj, event)
41086
41308
  }
41087
41309
  ),
41088
- !inspectChannelActive && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(LabeledAxes, {}),
41089
- !inspectChannelActive && isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(SketchAxes, {}),
41310
+ axesVisible && !isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(LabeledAxes, {}),
41311
+ axesVisible && isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(SketchAxes, {}),
41090
41312
  isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(CursorTracker, { onMove: (x, y) => setCursorPos({ x, y }) }),
41091
41313
  isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(SketchRulersUpdater, { hCanvasRef: hRulerRef, vCanvasRef: vRulerRef }),
41092
- !inspectChannelActive && gridEnabled && isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41314
+ gridEnabled && isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(
41093
41315
  Grid,
41094
41316
  {
41095
41317
  args: [500, 500],
@@ -41202,7 +41424,7 @@ function Viewport() {
41202
41424
  /* @__PURE__ */ jsxRuntimeExports.jsx(
41203
41425
  ModelJourneyBar,
41204
41426
  {
41205
- journeys: sceneConfig == null ? void 0 : sceneConfig.journeys,
41427
+ journeys: effectiveSceneConfig == null ? void 0 : effectiveSceneConfig.journeys,
41206
41428
  isViewportInteracting,
41207
41429
  requestViewCommand,
41208
41430
  selectObject,
@@ -41217,8 +41439,8 @@ function Viewport() {
41217
41439
  {
41218
41440
  hCanvasRef: hRulerRef,
41219
41441
  vCanvasRef: vRulerRef,
41220
- viewportWidth: ((_b2 = containerRef.current) == null ? void 0 : _b2.clientWidth) ?? 800,
41221
- viewportHeight: ((_c = containerRef.current) == null ? void 0 : _c.clientHeight) ?? 600
41442
+ viewportWidth: ((_c = containerRef.current) == null ? void 0 : _c.clientWidth) ?? 800,
41443
+ viewportHeight: ((_d = containerRef.current) == null ? void 0 : _d.clientHeight) ?? 600
41222
41444
  }
41223
41445
  ),
41224
41446
  isSketchOnly && /* @__PURE__ */ jsxRuntimeExports.jsx(CursorCoordinatesPanel, { x: cursorPos.x, y: cursorPos.y }),
@@ -41247,7 +41469,6 @@ function Viewport() {
41247
41469
  {
41248
41470
  phase: viewportBusyPhase,
41249
41471
  label: viewportBusyLabel,
41250
- constructionSteps: rebuildHistorySteps,
41251
41472
  activeBackend,
41252
41473
  computeTarget
41253
41474
  }
@@ -41280,6 +41501,34 @@ function Viewport() {
41280
41501
  ]
41281
41502
  }
41282
41503
  ),
41504
+ historyMode && historyGeometryStatus.status === "error" && historyGeometryStatus.error && /* @__PURE__ */ jsxRuntimeExports.jsxs(
41505
+ "div",
41506
+ {
41507
+ style: {
41508
+ position: "absolute",
41509
+ top: 12,
41510
+ left: "50%",
41511
+ transform: "translateX(-50%)",
41512
+ background: "rgba(127, 29, 29, 0.92)",
41513
+ color: "#fee2e2",
41514
+ border: "1px solid rgba(254, 202, 202, 0.4)",
41515
+ borderRadius: 6,
41516
+ padding: "7px 12px",
41517
+ fontSize: 12,
41518
+ fontWeight: 600,
41519
+ pointerEvents: "none",
41520
+ zIndex: 12,
41521
+ maxWidth: "min(520px, calc(100% - 32px))",
41522
+ whiteSpace: "nowrap",
41523
+ overflow: "hidden",
41524
+ textOverflow: "ellipsis"
41525
+ },
41526
+ children: [
41527
+ "Timeline failed: ",
41528
+ historyGeometryStatus.error
41529
+ ]
41530
+ }
41531
+ ),
41283
41532
  /* @__PURE__ */ jsxRuntimeExports.jsx(HoverTooltipLayer, { ref: hoverTooltipRef, enabled: objectPickSyncEnabled && !measureMode }),
41284
41533
  objectContextMenu && /* @__PURE__ */ jsxRuntimeExports.jsxs(
41285
41534
  "div",
@@ -41737,7 +41986,7 @@ function Viewport() {
41737
41986
  }
41738
41987
  );
41739
41988
  }
41740
- const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-BujZvuwX.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
41989
+ const EditorApp$1 = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-DVMnXOmO.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
41741
41990
  const PENDING_SHARE_COPY_KEY = "fc-pending-share-copy";
41742
41991
  function storePendingShareCopy(shareId) {
41743
41992
  sessionStorage.setItem(PENDING_SHARE_COPY_KEY, shareId);
@@ -41924,15 +42173,15 @@ const PublishedModelPage$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Objec
41924
42173
  consumePendingShareCopy,
41925
42174
  storePendingShareCopy
41926
42175
  }, Symbol.toStringTag, { value: "Module" }));
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 })));
42176
+ reactExports.lazy(() => __vitePreload(() => import("./LandingPageProofDriven-2q2sn7aW.js"), true ? __vite__mapDeps([1]) : void 0).then((m2) => ({ default: m2.LandingPageProofDriven })));
42177
+ const DocsPage = reactExports.lazy(() => __vitePreload(() => import("./DocsPage-CNBKuitP.js"), true ? [] : void 0).then((m2) => ({ default: m2.DocsPage })));
42178
+ reactExports.lazy(() => __vitePreload(() => import("./BlogPage-Crpr3JjH.js"), true ? [] : void 0).then((m2) => ({ default: m2.BlogPage })));
42179
+ reactExports.lazy(() => __vitePreload(() => import("./AdminPage-CXaVLMiV.js"), true ? [] : void 0).then((m2) => ({ default: m2.AdminPage })));
41931
42180
  reactExports.lazy(() => __vitePreload(() => Promise.resolve().then(() => PublishedModelPage$1), true ? void 0 : void 0).then((m2) => ({ default: m2.PublishedModelPage })));
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 })));
42181
+ reactExports.lazy(() => __vitePreload(() => import("./SettingsPage-BVj1FtEv.js"), true ? [] : void 0).then((m2) => ({ default: m2.SettingsPage })));
42182
+ reactExports.lazy(() => __vitePreload(() => import("./PricingPage-CVvgdv0i.js"), true ? __vite__mapDeps([2,1]) : void 0).then((m2) => ({ default: m2.PricingPage })));
42183
+ const EditorApp = reactExports.lazy(() => __vitePreload(() => import("./EditorApp-DVMnXOmO.js"), true ? __vite__mapDeps([0]) : void 0).then((m2) => ({ default: m2.EditorApp })));
42184
+ const EmbedViewer = reactExports.lazy(() => __vitePreload(() => import("./EmbedViewer-KXFLSnpo.js"), true ? [] : void 0).then((m2) => ({ default: m2.EmbedViewer })));
41936
42185
  const embedMode = isEmbedMode() && !window.location.pathname.startsWith("/m/");
41937
42186
  const EDITABLE_CRASH_FILE = /\.(?:forge\.js|[cm]?[jt]sx?|json|md|txt|svg)$/i;
41938
42187
  function firstMeaningfulLine(text) {