forgecad 0.9.2 → 0.9.3

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 (79) hide show
  1. package/LICENSE +7 -5
  2. package/README.md +1 -1
  3. package/README.public.md +24 -2
  4. package/dist/assets/{AdminPage-Bs4PiK00.js → AdminPage-4jihcEk_.js} +1 -1
  5. package/dist/assets/{BlogPage-DVmgN0ma.js → BlogPage-BvzruKtw.js} +1 -1
  6. package/dist/assets/{DocsPage-BP6wlsBN.js → DocsPage-DHbd-WS-.js} +13 -13
  7. package/dist/assets/{EditorApp-Arw2NnGJ.js → EditorApp-C5P2rBfh.js} +433 -84
  8. package/dist/assets/{EditorApp-VY9lXx0N.css → EditorApp-DS0AIUrZ.css} +25 -0
  9. package/dist/assets/{EmbedViewer-qgQiOahL.js → EmbedViewer-B70wQwlE.js} +2 -2
  10. package/dist/assets/{LandingPageProofDriven-DvhtmWOz.js → LandingPageProofDriven-DIsYTnep.js} +1 -1
  11. package/dist/assets/{PricingPage-Ck3CP2ti.css → PricingPage-BMedqFef.css} +48 -0
  12. package/dist/assets/{PricingPage-657oLvWh.js → PricingPage-YPOr12pP.js} +34 -6
  13. package/dist/assets/{SettingsPage-wNy3_2yn.js → SettingsPage-rntoyJ3b.js} +10 -13
  14. package/dist/assets/{app-BdBoMQeO.js → app-CWucmnLZ.js} +801 -1208
  15. package/dist/assets/cli/{render-Ci3jjyT1.js → render-DZHmUySW.js} +214 -23
  16. package/dist/assets/copy-CQKQppF-.js +8 -0
  17. package/dist/assets/{evalWorker-CMCAbK8r.js → evalWorker-C3dKxi9Y.js} +1117 -95
  18. package/dist/assets/{manifold-BMn-8Vf8.js → manifold-CQ3FhfWB.js} +1 -1
  19. package/dist/assets/{manifold-jlYQ6E5R.js → manifold-CU0G1yYL.js} +1 -1
  20. package/dist/assets/{manifold-DbyILno4.js → manifold-CYWZMfjB.js} +2 -2
  21. package/dist/assets/{renderSceneState-DAnqvxSt.js → renderSceneState-BBUrnsUN.js} +1 -1
  22. package/dist/assets/{reportWorker-BcRVMHK-.js → reportWorker-BhZ7DjxQ.js} +1091 -95
  23. package/dist/assets/{sectionPlaneMath-DXJ_TdIW.js → sectionPlaneMath-BxfokaJE.js} +1091 -95
  24. package/dist/cli/render.html +1 -1
  25. package/dist/docs/index.html +2 -2
  26. package/dist/docs-raw/AI/usage.md +182 -89
  27. package/dist/docs-raw/API/core/concepts.md +26 -0
  28. package/dist/docs-raw/CLI.md +58 -37
  29. package/dist/docs-raw/INDEX.md +81 -64
  30. package/dist/docs-raw/cli-monetization.md +9 -8
  31. package/dist/docs-raw/generated/concepts.md +111 -4
  32. package/dist/docs-raw/generated/core.md +2 -0
  33. package/dist/docs-raw/generated/curves.md +480 -1
  34. package/dist/docs-raw/generated/output.md +1 -0
  35. package/dist/docs-raw/generated/sketch.md +2 -0
  36. package/dist/docs-raw/generated/viewport.md +81 -3
  37. package/dist/docs-raw/product/user-outreach-email-templates.md +159 -0
  38. package/dist/docs-raw/skills/forgecad-image-replicator.md +1 -1
  39. package/dist/docs-raw/skills/forgecad-make-a-model.md +33 -4
  40. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +1 -1
  41. package/dist/docs-raw/skills/forgecad-project.md +1 -1
  42. package/dist/docs-raw/skills/forgecad-render-inspect.md +1 -1
  43. package/dist/docs-raw/skills/forgecad.md +2 -1
  44. package/dist/docs-raw/welcome.md +85 -137
  45. package/dist/index.html +1 -1
  46. package/dist/llms.txt +4 -3
  47. package/dist/sitemap.xml +6 -6
  48. package/dist-cli/forgecad.js +1413 -219
  49. package/dist-cli/forgecad.js.map +1 -1
  50. package/dist-skill/CONTEXT.md +594 -5
  51. package/dist-skill/SKILL-dev.md +2 -1
  52. package/dist-skill/SKILL.md +2 -1
  53. package/dist-skill/docs/API/core/concepts.md +26 -0
  54. package/dist-skill/docs/CLI.md +58 -37
  55. package/dist-skill/docs/generated/core.md +2 -0
  56. package/dist-skill/docs/generated/curves.md +480 -1
  57. package/dist-skill/docs/generated/output.md +1 -0
  58. package/dist-skill/docs/generated/sketch.md +2 -0
  59. package/dist-skill/docs/generated/viewport.md +81 -3
  60. package/dist-skill/docs-dev/API/core/concepts.md +26 -0
  61. package/dist-skill/docs-dev/CLI.md +58 -37
  62. package/dist-skill/docs-dev/generated/core.md +2 -0
  63. package/dist-skill/docs-dev/generated/curves.md +480 -1
  64. package/dist-skill/docs-dev/generated/output.md +1 -0
  65. package/dist-skill/docs-dev/generated/sketch.md +2 -0
  66. package/dist-skill/docs-dev/generated/viewport.md +81 -3
  67. package/dist-skill/library/README.md +0 -1
  68. package/dist-skill/library/forgecad-image-replicator/SKILL.md +1 -1
  69. package/dist-skill/library/forgecad-make-a-model/SKILL.md +33 -4
  70. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +1 -1
  71. package/dist-skill/library/forgecad-project/SKILL.md +1 -1
  72. package/dist-skill/library/forgecad-render-inspect/SKILL.md +1 -1
  73. package/examples/api/conformal-product-ribbon.forge.js +77 -0
  74. package/examples/api/render-labels.forge.js +33 -0
  75. package/examples/api/text2d-basics.forge.js +6 -3
  76. package/package.json +1 -1
  77. package/dist-skill/library/forgecad-deep-dive/SKILL.md +0 -120
  78. package/dist-skill/library/forgecad-deep-dive/agents/openai.yaml +0 -4
  79. package/dist-skill/library/forgecad-deep-dive/references/output-shape.md +0 -64
@@ -1,8 +1,8 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { D as DoubleSide, bF as initSolverWasm, bE as initKernel, S as Scene, bG as BoxGeometry, bc as MeshStandardMaterial, a4 as BackSide, a$ as PointLight, M as Mesh, aa as MeshBasicMaterial, bH as localAabbPlaneRelation, h as Vector2, bI as ShapeUtils, g as Vector3, e as Color, aB as resolveForgeRenderStyle, b8 as getRenderStylePreset, ax as setParamOverrides, b5 as runScript, a0 as MathUtils, G as Box3, bJ as Group, b2 as shapeToGeometry, b6 as MeshPhysicalMaterial, b9 as AdditiveBlending, aG as LineBasicMaterial, b7 as LineSegments, aF as BufferGeometry, P as PerspectiveCamera, k as ShaderMaterial, bK as intersectWithPlane, W as WebGLRenderer, A as ACESFilmicToneMapping, c as SRGBColorSpace, bL as parseCameraCliSpec, bM as PMREMGenerator, aU as CanvasTexture, aV as Object3D, aW as FogExp2, aX as Fog, aY as AmbientLight, b0 as DirectionalLight, aZ as HemisphereLight, by as findJointAnimationClip, p as Plane, Y as Vector4, $ as Matrix4, bf as SDF_RAYMARCH_PROXY_VERTEX_SHADER, be as buildSdfRaymarchFragmentShader, O as OrthographicCamera, bz as resolveJointAnimation, bA as resolveJointViewValues, R as Raycaster, aT as BufferAttribute, bN as worldAuthorPlaneToLocal, a_ as SpotLight } from "../sectionPlaneMath-DXJ_TdIW.js";
5
- import { m as mergeViewportRenderSceneStates, p as parseRenderSceneCliSpec } from "../renderSceneState-DAnqvxSt.js";
4
+ import { D as DoubleSide, bF as initSolverWasm, bE as initKernel, S as Scene, bG as BoxGeometry, bc as MeshStandardMaterial, a4 as BackSide, a$ as PointLight, M as Mesh, aa as MeshBasicMaterial, bH as localAabbPlaneRelation, h as Vector2, bI as ShapeUtils, g as Vector3, e as Color, aB as resolveForgeRenderStyle, b8 as getRenderStylePreset, ax as setParamOverrides, b5 as runScript, a0 as MathUtils, G as Box3, bJ as Group, b2 as shapeToGeometry, b6 as MeshPhysicalMaterial, b9 as AdditiveBlending, aG as LineBasicMaterial, b7 as LineSegments, aF as BufferGeometry, P as PerspectiveCamera, k as ShaderMaterial, bK as intersectWithPlane, W as WebGLRenderer, A as ACESFilmicToneMapping, c as SRGBColorSpace, bL as parseCameraCliSpec, bM as PMREMGenerator, aU as CanvasTexture, aV as Object3D, aW as FogExp2, aX as Fog, aY as AmbientLight, b0 as DirectionalLight, aZ as HemisphereLight, by as findJointAnimationClip, p as Plane, Y as Vector4, $ as Matrix4, bf as SDF_RAYMARCH_PROXY_VERTEX_SHADER, be as buildSdfRaymarchFragmentShader, O as OrthographicCamera, bz as resolveJointAnimation, bA as resolveJointViewValues, R as Raycaster, aT as BufferAttribute, bN as worldAuthorPlaneToLocal, a_ as SpotLight } from "../sectionPlaneMath-BxfokaJE.js";
5
+ import { m as mergeViewportRenderSceneStates, p as parseRenderSceneCliSpec } from "../renderSceneState-BBUrnsUN.js";
6
6
  const CAD_MATERIAL_PROPS = {
7
7
  color: 6003669,
8
8
  metalness: 0.05,
@@ -1069,6 +1069,34 @@ function analyzeDistanceInspection(entries, rawOptions = {}) {
1069
1069
  warnings: [...connectivity.warnings]
1070
1070
  };
1071
1071
  }
1072
+ function formatAvailableViews(views) {
1073
+ const names = Object.keys(views ?? {}).sort();
1074
+ if (names.length === 0) {
1075
+ return "No named render views are declared with scene({ views }).";
1076
+ }
1077
+ return `Available views: ${names.join(", ")}.`;
1078
+ }
1079
+ function sceneViewCameraToViewportCameraState(camera) {
1080
+ return {
1081
+ projectionMode: camera.type ?? "perspective",
1082
+ position: camera.position,
1083
+ target: camera.target,
1084
+ up: camera.up ?? [0, 0, 1],
1085
+ ...camera.fov !== void 0 ? { fov: camera.fov } : {}
1086
+ };
1087
+ }
1088
+ function resolveNamedSceneViewCamera(sceneConfig, viewName) {
1089
+ const normalizedName = viewName.trim();
1090
+ if (!normalizedName) {
1091
+ throw new Error("Named render view cannot be empty.");
1092
+ }
1093
+ const views = (sceneConfig == null ? void 0 : sceneConfig.views) ?? null;
1094
+ const view = views == null ? void 0 : views[normalizedName];
1095
+ if (!view) {
1096
+ throw new Error(`Named render view "${normalizedName}" was not found. ${formatAvailableViews(views)}`);
1097
+ }
1098
+ return sceneViewCameraToViewportCameraState(view.camera);
1099
+ }
1072
1100
  function edgesStrokeAttrs(preset) {
1073
1101
  switch (preset) {
1074
1102
  case "off":
@@ -1290,6 +1318,24 @@ let rendererPixelRatio = 1;
1290
1318
  let rendererContextKey = "";
1291
1319
  let captureSession = null;
1292
1320
  let studioEnvTexture = null;
1321
+ function createCaptureDebugLogger(enabled) {
1322
+ const start = performance.now();
1323
+ let previous = start;
1324
+ return (phase, detail = {}) => {
1325
+ if (!enabled) return;
1326
+ const now = performance.now();
1327
+ const sinceStart = (now - start).toFixed(1);
1328
+ const delta = (now - previous).toFixed(1);
1329
+ previous = now;
1330
+ let detailText = "";
1331
+ try {
1332
+ detailText = Object.keys(detail).length > 0 ? ` ${JSON.stringify(detail)}` : "";
1333
+ } catch {
1334
+ detailText = " [detail-unserializable]";
1335
+ }
1336
+ console.info(`[forge-capture:debug] +${sinceStart}ms Δ${delta}ms ${phase}${detailText}`);
1337
+ };
1338
+ }
1293
1339
  const COLLISION_SOURCE_OPACITY = 0.22;
1294
1340
  const COLLISION_SOURCE_COLOR = [180, 200, 220];
1295
1341
  const COLLISION_HIGHLIGHT_COLOR = [255, 68, 16];
@@ -2429,11 +2475,19 @@ function parseColor(input, fallback) {
2429
2475
  return new Color(fallback);
2430
2476
  }
2431
2477
  }
2432
- function buildSectionMeshPayload(objectId, shape) {
2478
+ function buildSectionMeshPayload(objectId, shape, debug, objectName) {
2433
2479
  try {
2480
+ const start = performance.now();
2434
2481
  const mesh = shape.getMesh();
2435
2482
  const bb = shape.boundingBox();
2436
2483
  if (!mesh.triVerts.length || !mesh.vertProperties.length) return null;
2484
+ debug == null ? void 0 : debug("sectionMesh:built", {
2485
+ objectId,
2486
+ name: objectName,
2487
+ ms: Number((performance.now() - start).toFixed(1)),
2488
+ triangles: Math.floor(mesh.triVerts.length / 3),
2489
+ vertices: Math.floor(mesh.vertProperties.length / Math.max(1, mesh.numProp))
2490
+ });
2437
2491
  return {
2438
2492
  meshId: `capture:${objectId}`,
2439
2493
  numProp: mesh.numProp,
@@ -2444,7 +2498,12 @@ function buildSectionMeshPayload(objectId, shape) {
2444
2498
  max: [bb.max[0], bb.max[1], bb.max[2]]
2445
2499
  }
2446
2500
  };
2447
- } catch {
2501
+ } catch (err) {
2502
+ debug == null ? void 0 : debug("sectionMesh:error", {
2503
+ objectId,
2504
+ name: objectName,
2505
+ error: err instanceof Error ? err.message : String(err)
2506
+ });
2448
2507
  return null;
2449
2508
  }
2450
2509
  }
@@ -2842,23 +2901,51 @@ function applyObjectTransforms(session, animationProgress) {
2842
2901
  });
2843
2902
  session.collisionReport = null;
2844
2903
  }
2845
- function updateSectionSweepCaps(session, progress, mode) {
2846
- var _a;
2904
+ function updateSectionSweepCaps(session, progress, mode, debug) {
2905
+ var _a, _b;
2847
2906
  const sweep = session.sweep;
2848
2907
  if (!sweep) return;
2849
2908
  const t = easedSweepProgress(progress, sweep.ease);
2850
2909
  const offset = sweep.from + (sweep.to - sweep.from) * t;
2910
+ debug == null ? void 0 : debug("frame:caps:start", {
2911
+ progress: Number(progress.toFixed(4)),
2912
+ offset: Number(offset.toFixed(4)),
2913
+ mode
2914
+ });
2851
2915
  sweep.clippingPlane.constant = offset;
2852
2916
  clearSectionCapGroups(session);
2853
- if (mode === "wireframe") return;
2917
+ if (mode === "wireframe") {
2918
+ debug == null ? void 0 : debug("frame:caps:skip-wireframe");
2919
+ return;
2920
+ }
2854
2921
  session.scene.updateMatrixWorld(true);
2855
- for (const renderable of session.renderables) {
2922
+ let computed = 0;
2923
+ let emitted = 0;
2924
+ for (let index = 0; index < session.renderables.length; index += 1) {
2925
+ const renderable = session.renderables[index];
2856
2926
  if (!renderable.sectionMesh) continue;
2857
2927
  const localPlane = worldAuthorPlaneToLocal({ normal: sweep.normal, offset }, renderable.root.matrixWorld);
2858
2928
  if (!localPlane) continue;
2929
+ const capStart = performance.now();
2930
+ debug == null ? void 0 : debug("frame:cap:start", {
2931
+ index: index + 1,
2932
+ id: renderable.id,
2933
+ name: renderable.name
2934
+ });
2859
2935
  const payload = computeMeshSectionCap(renderable.sectionMesh, localPlane);
2860
- (_a = payload.warnings) == null ? void 0 : _a.forEach((warning) => sweep.warnings.add(warning));
2936
+ computed += 1;
2937
+ debug == null ? void 0 : debug("frame:cap:end", {
2938
+ index: index + 1,
2939
+ id: renderable.id,
2940
+ name: renderable.name,
2941
+ ms: Number((performance.now() - capStart).toFixed(1)),
2942
+ positions: payload.positions.length / 3,
2943
+ triangles: payload.indices.length / 3,
2944
+ warnings: ((_a = payload.warnings) == null ? void 0 : _a.join(",")) ?? ""
2945
+ });
2946
+ (_b = payload.warnings) == null ? void 0 : _b.forEach((warning) => sweep.warnings.add(warning));
2861
2947
  if (payload.positions.length === 0 || payload.indices.length === 0) continue;
2948
+ emitted += 1;
2862
2949
  const clippingPlanes = (renderable.solidMaterial.clippingPlanes ?? []).filter((plane) => plane !== sweep.clippingPlane);
2863
2950
  const geometry = createSectionCapGeometry(payload);
2864
2951
  const material = createSectionCapMaterial({
@@ -2889,11 +2976,21 @@ function updateSectionSweepCaps(session, progress, mode) {
2889
2976
  renderable.sectionCapGroup.add(outline);
2890
2977
  }
2891
2978
  }
2979
+ debug == null ? void 0 : debug("frame:caps:end", { computed, emitted });
2892
2980
  }
2893
2981
  function renderCaptureFrame(session, opts) {
2894
2982
  const mode = (opts == null ? void 0 : opts.mode) ?? "solid";
2895
2983
  const cameraMotion = (opts == null ? void 0 : opts.cameraMotion) ?? "orbit";
2896
2984
  const shouldProfile = (opts == null ? void 0 : opts.profile) === true;
2985
+ const debug = createCaptureDebugLogger(opts == null ? void 0 : opts.debug);
2986
+ debug("frame:start", {
2987
+ mode,
2988
+ cameraMotion,
2989
+ turn: opts == null ? void 0 : opts.turn,
2990
+ animationProgress: opts == null ? void 0 : opts.animationProgress,
2991
+ sweepProgress: opts == null ? void 0 : opts.sweepProgress,
2992
+ imageFormat: (opts == null ? void 0 : opts.imageFormat) ?? "png"
2993
+ });
2897
2994
  const start = shouldProfile ? performance.now() : 0;
2898
2995
  let mark = start;
2899
2996
  const timings = {
@@ -2921,7 +3018,7 @@ function renderCaptureFrame(session, opts) {
2921
3018
  applyOrbitPose(session, (opts == null ? void 0 : opts.turn) ?? 0, opts == null ? void 0 : opts.pitchDeg);
2922
3019
  }
2923
3020
  captureMark("cameraMs");
2924
- updateSectionSweepCaps(session, (opts == null ? void 0 : opts.sweepProgress) ?? 0, mode);
3021
+ updateSectionSweepCaps(session, (opts == null ? void 0 : opts.sweepProgress) ?? 0, mode, debug);
2925
3022
  captureMark("capsMs");
2926
3023
  const r = getRenderer(session.size, session.pixelRatio);
2927
3024
  session.scene.updateMatrixWorld(true);
@@ -2930,6 +3027,7 @@ function renderCaptureFrame(session, opts) {
2930
3027
  captureMark("renderMs");
2931
3028
  const png = captureRenderedImage(session.size, (opts == null ? void 0 : opts.imageFormat) === "jpeg" ? "jpeg" : "png", (opts == null ? void 0 : opts.jpegQuality) ?? 0.96);
2932
3029
  captureMark("pngMs");
3030
+ debug("frame:end");
2933
3031
  if (shouldProfile) {
2934
3032
  timings.totalMs = performance.now() - start;
2935
3033
  return { png, timings };
@@ -2982,9 +3080,17 @@ function isFocusVisible(obj, focus, hide) {
2982
3080
  return true;
2983
3081
  }
2984
3082
  function createSession(code, opts) {
2985
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3083
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
2986
3084
  const size = (opts == null ? void 0 : opts.size) ?? 1024;
2987
3085
  const pixelRatio = (opts == null ? void 0 : opts.pixelRatio) ?? 1;
3086
+ const debug = createCaptureDebugLogger(opts == null ? void 0 : opts.debug);
3087
+ debug("session:start", {
3088
+ capture: (opts == null ? void 0 : opts.capture) ?? "orbit",
3089
+ size,
3090
+ pixelRatio,
3091
+ quality: (opts == null ? void 0 : opts.quality) ?? "high",
3092
+ fileName: (opts == null ? void 0 : opts.fileName) ?? "main.forge.js"
3093
+ });
2988
3094
  const r = getRenderer(size, pixelRatio);
2989
3095
  const renderStyle = resolveForgeRenderStyle(opts == null ? void 0 : opts.renderStyle);
2990
3096
  const renderStylePreset = getRenderStylePreset(renderStyle);
@@ -2995,8 +3101,20 @@ function createSession(code, opts) {
2995
3101
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
2996
3102
  }
2997
3103
  setParamOverrides((opts == null ? void 0 : opts.paramOverrides) ?? {});
2998
- const result = runScript(code, (opts == null ? void 0 : opts.fileName) || "main.forge.js", (opts == null ? void 0 : opts.allFiles) || {}, { quality: (opts == null ? void 0 : opts.quality) ?? "high" });
3104
+ debug("session:runScript:start");
3105
+ const runStart = performance.now();
3106
+ const result = runScript(code, (opts == null ? void 0 : opts.fileName) || "main.forge.js", (opts == null ? void 0 : opts.allFiles) || {}, {
3107
+ quality: (opts == null ? void 0 : opts.quality) ?? "high",
3108
+ debug: (opts == null ? void 0 : opts.debug) ? (phase, detail) => debug(`runScript:${phase}`, detail) : void 0
3109
+ });
3110
+ debug("session:runScript:end", {
3111
+ ms: Number((performance.now() - runStart).toFixed(1)),
3112
+ objects: ((_a = result.objects) == null ? void 0 : _a.length) ?? 0,
3113
+ cutPlanes: ((_b = result.cutPlanes) == null ? void 0 : _b.length) ?? 0,
3114
+ hasError: Boolean(result.error)
3115
+ });
2999
3116
  if (result.error) {
3117
+ debug("session:error", { error: String(result.error) });
3000
3118
  return { ok: false, error: String(result.error) };
3001
3119
  }
3002
3120
  const focus = (opts == null ? void 0 : opts.focus) ?? null;
@@ -3017,6 +3135,13 @@ function createSession(code, opts) {
3017
3135
  return { ok: false, error: "No renderable shape or SDF returned" };
3018
3136
  }
3019
3137
  const visibleObjs = objs.filter((entry) => entry.visible);
3138
+ debug("session:objects", {
3139
+ totalObjects: result.objects.length,
3140
+ renderableObjects: objs.length,
3141
+ visibleObjects: visibleObjs.length,
3142
+ shapeObjects: visibleObjs.filter((entry) => entry.shape != null).length,
3143
+ sdfObjects: visibleObjs.filter((entry) => entry.sdf != null).length
3144
+ });
3020
3145
  const boundsObjs = visibleObjs.length > 0 ? visibleObjs : objs;
3021
3146
  const objectVisibility = new Map(objs.map((entry) => [entry.source.id, entry.visible]));
3022
3147
  const objectRenderability = new Set(objs.map((entry) => entry.source.id));
@@ -3065,6 +3190,21 @@ function createSession(code, opts) {
3065
3190
  }) : [];
3066
3191
  const scene = new Scene();
3067
3192
  const sceneConfig = result.sceneConfig ?? null;
3193
+ try {
3194
+ if (opts == null ? void 0 : opts.viewName) {
3195
+ if (requestedSceneState == null ? void 0 : requestedSceneState.camera) {
3196
+ return {
3197
+ ok: false,
3198
+ error: "Cannot use --view with an explicit render camera. Remove --camera or the camera field from --scene."
3199
+ };
3200
+ }
3201
+ requestedSceneState = mergeViewportRenderSceneStates(requestedSceneState, {
3202
+ camera: resolveNamedSceneViewCamera(sceneConfig, opts.viewName)
3203
+ });
3204
+ }
3205
+ } catch (err) {
3206
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
3207
+ }
3068
3208
  scene.background = parseColor((opts == null ? void 0 : opts.background) ?? renderStylePreset.background, DEFAULT_BACKGROUND);
3069
3209
  scene.environment = (opts == null ? void 0 : opts.capture) === "section-sweep" ? null : getStudioEnvironment(r);
3070
3210
  r.toneMappingExposure = renderStylePreset.toneMappingExposure;
@@ -3074,6 +3214,10 @@ function createSession(code, opts) {
3074
3214
  addRenderStyleLights(scene, renderStyle);
3075
3215
  }
3076
3216
  const sceneSummary = summarizeSceneGeometry(boundsObjs);
3217
+ debug("session:summary", {
3218
+ bbox: sceneSummary.bbox,
3219
+ volume: Number(sceneSummary.volume.toFixed(1))
3220
+ });
3077
3221
  const { bbox } = sceneSummary;
3078
3222
  const bb = new Box3(new Vector3(...bbox.min), new Vector3(...bbox.max));
3079
3223
  const center = new Vector3();
@@ -3083,19 +3227,29 @@ function createSession(code, opts) {
3083
3227
  const maxDim = Math.max(1, bsize.x, bsize.y, bsize.z);
3084
3228
  const fov = 45;
3085
3229
  const distance = maxDim / (2 * Math.tan(fov * Math.PI / 360)) * 1.6;
3086
- const cameraFov = ((_a = requestedSceneState == null ? void 0 : requestedSceneState.camera) == null ? void 0 : _a.fov) ?? ((_b = sceneConfig == null ? void 0 : sceneConfig.camera) == null ? void 0 : _b.fov) ?? fov;
3087
- const joints = ((_c = result.jointsView) == null ? void 0 : _c.enabled) === false ? [] : ((_d = result.jointsView) == null ? void 0 : _d.joints) ?? [];
3088
- const jointCouplings = ((_e = result.jointsView) == null ? void 0 : _e.enabled) === false ? [] : ((_f = result.jointsView) == null ? void 0 : _f.couplings) ?? [];
3089
- const animationClips = ((_g = result.jointsView) == null ? void 0 : _g.enabled) === false ? [] : ((_h = result.jointsView) == null ? void 0 : _h.animations) ?? [];
3090
- const defaultAnimation = ((_i = result.jointsView) == null ? void 0 : _i.defaultAnimation) ?? null;
3230
+ const cameraFov = ((_c = requestedSceneState == null ? void 0 : requestedSceneState.camera) == null ? void 0 : _c.fov) ?? ((_d = sceneConfig == null ? void 0 : sceneConfig.camera) == null ? void 0 : _d.fov) ?? fov;
3231
+ const joints = ((_e = result.jointsView) == null ? void 0 : _e.enabled) === false ? [] : ((_f = result.jointsView) == null ? void 0 : _f.joints) ?? [];
3232
+ const jointCouplings = ((_g = result.jointsView) == null ? void 0 : _g.enabled) === false ? [] : ((_h = result.jointsView) == null ? void 0 : _h.couplings) ?? [];
3233
+ const animationClips = ((_i = result.jointsView) == null ? void 0 : _i.enabled) === false ? [] : ((_j = result.jointsView) == null ? void 0 : _j.animations) ?? [];
3234
+ const defaultAnimation = ((_k = result.jointsView) == null ? void 0 : _k.defaultAnimation) ?? null;
3091
3235
  let selectedAnimation;
3092
3236
  let sweep = null;
3093
3237
  try {
3094
3238
  selectedAnimation = resolveSelectedAnimation(animationClips, (opts == null ? void 0 : opts.capture) ?? "orbit", defaultAnimation, opts == null ? void 0 : opts.animationName);
3095
3239
  sweep = (opts == null ? void 0 : opts.capture) === "section-sweep" ? createSectionSweepState((opts == null ? void 0 : opts.sweep) ?? {}, bbox) : null;
3096
3240
  } catch (err) {
3241
+ debug("session:sweep:error", { error: err instanceof Error ? err.message : String(err) });
3097
3242
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
3098
3243
  }
3244
+ if (sweep) {
3245
+ debug("session:sweep", {
3246
+ normal: sweep.normal,
3247
+ from: Number(sweep.from.toFixed(4)),
3248
+ to: Number(sweep.to.toFixed(4)),
3249
+ padding: Number(sweep.padding.toFixed(4)),
3250
+ style: sweep.style
3251
+ });
3252
+ }
3099
3253
  const enabledCutPlanes = new Set((opts == null ? void 0 : opts.enabledCutPlanes) ?? []);
3100
3254
  const availableCutPlanes = result.cutPlanes.filter((cp) => new Vector3(cp.normal[0], cp.normal[1], cp.normal[2]).lengthSq() > 1e-8);
3101
3255
  if (enabledCutPlanes.size > 0) {
@@ -3110,8 +3264,23 @@ function createSession(code, opts) {
3110
3264
  }
3111
3265
  const activeCutPlanes = availableCutPlanes.filter((cp) => enabledCutPlanes.has(cp.name));
3112
3266
  const renderables = [];
3113
- for (const obj of visibleObjs) {
3267
+ debug("session:renderables:start", {
3268
+ visibleObjects: visibleObjs.length,
3269
+ activeCutPlanes: activeCutPlanes.length,
3270
+ sectionSweep: Boolean(sweep)
3271
+ });
3272
+ for (let renderableIndex = 0; renderableIndex < visibleObjs.length; renderableIndex += 1) {
3273
+ const obj = visibleObjs[renderableIndex];
3114
3274
  const mp = obj.materialProps;
3275
+ const objectLabel = obj.source.name || obj.source.id;
3276
+ debug("renderable:start", {
3277
+ index: renderableIndex + 1,
3278
+ total: visibleObjs.length,
3279
+ id: obj.source.id,
3280
+ name: objectLabel,
3281
+ hasShape: Boolean(obj.shape),
3282
+ hasSdf: Boolean(obj.sdf)
3283
+ });
3115
3284
  const applicableCutPlanes = activeCutPlanes.filter((cutPlane) => !isObjectExcludedFromCutPlane(obj.source, cutPlane)).map(toClippingPlane);
3116
3285
  if (sweep && !isObjectExcludedFromCutPlane(obj.source, { normal: sweep.normal, offset: sweep.from })) {
3117
3286
  applicableCutPlanes.push(sweep.clippingPlane);
@@ -3127,7 +3296,16 @@ function createSession(code, opts) {
3127
3296
  let sdfRaymarch;
3128
3297
  let sectionMesh = null;
3129
3298
  if (obj.shape) {
3299
+ const geometryStart = performance.now();
3130
3300
  const geo = shapeToGeometry(obj.shape);
3301
+ debug("renderable:geometry", {
3302
+ index: renderableIndex + 1,
3303
+ id: obj.source.id,
3304
+ name: objectLabel,
3305
+ ms: Number((performance.now() - geometryStart).toFixed(1)),
3306
+ triangles: Math.floor((((_l = geo.solid.getAttribute("position")) == null ? void 0 : _l.count) ?? 0) / 3),
3307
+ edgeSegments: Math.floor((((_m = geo.edges.getAttribute("position")) == null ? void 0 : _m.count) ?? 0) / 2)
3308
+ });
3131
3309
  const materialDefaults = renderStylePreset.material;
3132
3310
  const authoredMaterialOpacity = mp == null ? void 0 : mp.opacity;
3133
3311
  const authoredMaterialTransmission = mp == null ? void 0 : mp.transmission;
@@ -3185,9 +3363,16 @@ function createSession(code, opts) {
3185
3363
  clippingPlanes: applicableCutPlanes
3186
3364
  });
3187
3365
  wire = new LineSegments(geo.edges, wireMaterial);
3188
- sectionMesh = sweep ? buildSectionMeshPayload(obj.source.id, obj.shape) : null;
3366
+ sectionMesh = sweep ? buildSectionMeshPayload(obj.source.id, obj.shape, debug, objectLabel) : null;
3189
3367
  } else if (obj.sdf) {
3368
+ const sdfStart = performance.now();
3190
3369
  const sdfRenderable = createSdfRaymarchRuntime(obj, applicableCutPlanes);
3370
+ debug("renderable:sdf", {
3371
+ index: renderableIndex + 1,
3372
+ id: obj.source.id,
3373
+ name: objectLabel,
3374
+ ms: Number((performance.now() - sdfStart).toFixed(1))
3375
+ });
3191
3376
  solid = sdfRenderable.mesh;
3192
3377
  solidMaterial = sdfRenderable.material;
3193
3378
  sdfRaymarch = sdfRenderable.runtime;
@@ -3241,7 +3426,7 @@ function createSession(code, opts) {
3241
3426
  }
3242
3427
  const cameraSpec = sceneConfigCameraState && (opts == null ? void 0 : opts.capture) === "section-sweep" ? fitCameraStateToBounds(sceneConfigCameraState, bbox, cameraFov) : (requestedSceneState == null ? void 0 : requestedSceneState.camera) ?? sceneConfigCameraState;
3243
3428
  const cameraRig = buildCameraRig(center, distance, maxDim, cameraSpec, cameraFov);
3244
- const explicitCameraFov = (cameraSpec == null ? void 0 : cameraSpec.fov) ?? ((_j = sceneConfig == null ? void 0 : sceneConfig.camera) == null ? void 0 : _j.fov);
3429
+ const explicitCameraFov = (cameraSpec == null ? void 0 : cameraSpec.fov) ?? ((_n = sceneConfig == null ? void 0 : sceneConfig.camera) == null ? void 0 : _n.fov);
3245
3430
  if (explicitCameraFov && cameraRig.camera instanceof PerspectiveCamera) {
3246
3431
  cameraRig.camera.fov = explicitCameraFov;
3247
3432
  cameraRig.camera.updateProjectionMatrix();
@@ -3282,9 +3467,11 @@ function createSession(code, opts) {
3282
3467
  captureDefaults: (sceneConfig == null ? void 0 : sceneConfig.capture) ?? null,
3283
3468
  renderStyle
3284
3469
  };
3470
+ debug("session:renderables:end", { renderables: renderables.length });
3285
3471
  setSessionMode(session, "solid");
3286
3472
  applyObjectTransforms(session, 0);
3287
3473
  applyCameraPose(session.camera, session.fixedCameraState);
3474
+ debug("session:ready");
3288
3475
  return { ok: true, session };
3289
3476
  }
3290
3477
  async function setup() {
@@ -3302,10 +3489,13 @@ async function emitInspectProgress(opts, event) {
3302
3489
  }
3303
3490
  }
3304
3491
  window.__forgeRender = async (code, opts) => {
3305
- var _a;
3492
+ var _a, _b;
3306
3493
  const requestedCameraTokens = (opts == null ? void 0 : opts.cameras) ?? (opts == null ? void 0 : opts.angles);
3307
3494
  const hasDirectionalCameraTokens = Array.isArray(requestedCameraTokens) && requestedCameraTokens.length > 0;
3308
- const hasExplicitFixedCamera = Boolean((opts == null ? void 0 : opts.camera) || (opts == null ? void 0 : opts.cameraSpec) || ((_a = opts == null ? void 0 : opts.sceneState) == null ? void 0 : _a.camera) || (opts == null ? void 0 : opts.sceneSpec));
3495
+ if ((opts == null ? void 0 : opts.viewName) && hasDirectionalCameraTokens) {
3496
+ return { ok: false, error: "Cannot use --view with --camera or --angles. Choose either a model-declared view or an explicit camera." };
3497
+ }
3498
+ const hasExplicitFixedCamera = Boolean((opts == null ? void 0 : opts.camera) || (opts == null ? void 0 : opts.cameraSpec) || ((_a = opts == null ? void 0 : opts.sceneState) == null ? void 0 : _a.camera) || (opts == null ? void 0 : opts.sceneSpec) || (opts == null ? void 0 : opts.viewName));
3309
3499
  const cameraTokens = hasDirectionalCameraTokens ? requestedCameraTokens : hasExplicitFixedCamera ? ["__fixed"] : ["iso"];
3310
3500
  const requestedChannelList = (opts == null ? void 0 : opts.channels) ?? ["rgb"];
3311
3501
  const requestedChannels = new Set(requestedChannelList);
@@ -3319,6 +3509,7 @@ window.__forgeRender = async (code, opts) => {
3319
3509
  background: opts == null ? void 0 : opts.background,
3320
3510
  camera: opts == null ? void 0 : opts.camera,
3321
3511
  cameraSpec: opts == null ? void 0 : opts.cameraSpec,
3512
+ viewName: opts == null ? void 0 : opts.viewName,
3322
3513
  sceneState: opts == null ? void 0 : opts.sceneState,
3323
3514
  sceneSpec: opts == null ? void 0 : opts.sceneSpec,
3324
3515
  focus: opts == null ? void 0 : opts.focus,
@@ -3380,7 +3571,7 @@ window.__forgeRender = async (code, opts) => {
3380
3571
  try {
3381
3572
  let label;
3382
3573
  if (token === "__fixed") {
3383
- label = "camera";
3574
+ label = ((_b = opts == null ? void 0 : opts.viewName) == null ? void 0 : _b.trim()) || "camera";
3384
3575
  applyCameraPose(session.camera, session.fixedCameraState);
3385
3576
  } else {
3386
3577
  const parsed = parseCameraToken(token);
@@ -0,0 +1,8 @@
1
+ const COMMERCIAL_USE_CASES = "client, employer, sale, funded product, or closed commercial IP";
2
+ const PRODUCTION_EXPORT_COPY = `Free to export. For ${COMMERCIAL_USE_CASES} work, Pro covers commercial use and support.`;
3
+ const PRO_STORAGE_UPGRADE_COPY = "Upgrade for 500 MB and commercial coverage.";
4
+ export {
5
+ COMMERCIAL_USE_CASES as C,
6
+ PRO_STORAGE_UPGRADE_COPY as P,
7
+ PRODUCTION_EXPORT_COPY as a
8
+ };