brepjs 20.12.2 → 20.12.5

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 (100) hide show
  1. package/dist/2d.cjs +6 -6
  2. package/dist/2d.js +6 -6
  3. package/dist/{adjacencyFns-C0YD3Zrp.js → adjacencyFns-B2Po1gPs.js} +3 -3
  4. package/dist/{adjacencyFns-Cibtcqdl.cjs → adjacencyFns-Cho9v3Q3.cjs} +3 -3
  5. package/dist/{blueprint-p1SmFAfl.cjs → blueprint-ERmwk6zG.cjs} +5 -5
  6. package/dist/{blueprint-CLgJoNt5.js → blueprint-Zmt5-07y.js} +5 -5
  7. package/dist/{blueprintFns-DU8_o9zy.cjs → blueprintFns-B_sxtIo7.cjs} +2 -2
  8. package/dist/{blueprintFns-D4wl5Fft.js → blueprintFns-Dtm-XukP.js} +2 -2
  9. package/dist/{blueprintSketcher-BTJqAd7E.cjs → blueprintSketcher-CZyokLGJ.cjs} +3 -3
  10. package/dist/{blueprintSketcher-CmR6Mi91.js → blueprintSketcher-CwTAtrkY.js} +3 -3
  11. package/dist/{boolean2D-CEPQF4LP.cjs → boolean2D-CRuNKgXs.cjs} +4 -4
  12. package/dist/{boolean2D-C3bLz5i0.js → boolean2D-yUpS8onH.js} +4 -4
  13. package/dist/brepjs.cjs +128 -100
  14. package/dist/brepjs.js +128 -100
  15. package/dist/{cameraFns-CUX8VNKT.cjs → cameraFns-DB1IyMmS.cjs} +3 -3
  16. package/dist/{cameraFns-xUCRxpsa.js → cameraFns-DRok4UxZ.js} +3 -3
  17. package/dist/core.cjs +2 -2
  18. package/dist/core.js +2 -2
  19. package/dist/{cornerFinder-CBjvTijF.js → cornerFinder-D5qnDbtZ.js} +1 -1
  20. package/dist/{cornerFinder-BToeCt6c.cjs → cornerFinder-DfYBHHZG.cjs} +1 -1
  21. package/dist/{curveFns-AMqd_WaO.js → curveFns-BGPSFUWB.js} +1 -1
  22. package/dist/{curveFns-CMiP40Ko.cjs → curveFns-BKT4Sg8q.cjs} +1 -1
  23. package/dist/{drawFns-BOyA7iOt.cjs → drawFns-D8e5RiRe.cjs} +23 -15
  24. package/dist/{drawFns-DzqPMBHE.js → drawFns-aGufr-pr.js} +23 -15
  25. package/dist/{faceFns-C6fYNgZl.cjs → faceFns-Cx7cwUMx.cjs} +2 -2
  26. package/dist/{faceFns-DEDlLMcn.js → faceFns-lE2OvBfq.js} +2 -2
  27. package/dist/{healingFns-CJIIjQKh.js → healingFns-B94zSk1-.js} +5 -5
  28. package/dist/{healingFns-383ByJpH.cjs → healingFns-CcgyrL6h.cjs} +5 -5
  29. package/dist/{helpers-DxoCOnD_.cjs → helpers-C4f2MV-r.cjs} +14 -10
  30. package/dist/{helpers-i26hsY3T.js → helpers-CNgipe6l.js} +14 -10
  31. package/dist/{importFns-Fr6WPpl2.cjs → importFns-fIdcaMqt.cjs} +2 -2
  32. package/dist/{importFns-Bz4sXl93.js → importFns-gB1X3ti2.js} +2 -2
  33. package/dist/index.d.ts +2 -2
  34. package/dist/io.cjs +2 -2
  35. package/dist/io.js +2 -2
  36. package/dist/kernel/geometry2d.d.ts +7 -0
  37. package/dist/kernel/occtWasm/constructionOps.d.ts +1 -1
  38. package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
  39. package/dist/kernel/occtWasm/occtWasmAdapter.d.ts +1 -1
  40. package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
  41. package/dist/kernel/occtWasm/occtWasmTypes.d.ts +5 -0
  42. package/dist/{loftFns-BsFinbgs.cjs → loftFns-AHaYxJyS.cjs} +17 -2
  43. package/dist/{loftFns-pMh0ET-J.js → loftFns-mbyBvJ8Y.js} +17 -2
  44. package/dist/{measureFns-BuxKO1GV.js → measureFns-C94G0fH8.js} +102 -35
  45. package/dist/{measureFns-Ed7LXAhG.cjs → measureFns-CuabRDRL.cjs} +102 -35
  46. package/dist/measurement/measureFns.d.ts +3 -2
  47. package/dist/measurement.cjs +2 -2
  48. package/dist/measurement.js +2 -2
  49. package/dist/{meshFns-BNrdUhgG.cjs → meshFns-GXF5gPZL.cjs} +3 -3
  50. package/dist/{meshFns-LytwBtBQ.js → meshFns-jarDZKw1.js} +3 -3
  51. package/dist/{occtWasmAdapter-D1EXktNq.cjs → occtWasmAdapter-DeoeK2iJ.cjs} +39 -7
  52. package/dist/{occtWasmAdapter-RBm-JLoN.js → occtWasmAdapter-DlNmVNUn.js} +39 -7
  53. package/dist/operations/patternFns.d.ts +6 -1
  54. package/dist/operations.cjs +2 -2
  55. package/dist/operations.js +2 -2
  56. package/dist/{originTrackingFns-BqlxFeWq.js → originTrackingFns-BxeUD2NM.js} +2 -2
  57. package/dist/{originTrackingFns-BRJ2PZ8J.cjs → originTrackingFns-C-yuMV3m.cjs} +2 -2
  58. package/dist/{primitiveFns-wOdKnYBs.cjs → primitiveFns-BVAkYHVf.cjs} +7 -14
  59. package/dist/{primitiveFns-DrEUKZvX.js → primitiveFns-CualoFAk.js} +7 -14
  60. package/dist/{principalBoxFns-D8rqqCl2.cjs → principalBoxFns-DHh5_HCw.cjs} +3 -3
  61. package/dist/{principalBoxFns-C0UzVmfC.js → principalBoxFns-DtI7tVuS.js} +3 -3
  62. package/dist/projection.cjs +1 -1
  63. package/dist/projection.js +1 -1
  64. package/dist/query/finderCore.d.ts +7 -7
  65. package/dist/query.cjs +2 -2
  66. package/dist/query.js +2 -2
  67. package/dist/{refResolveFns-BqcjC50D.js → refResolveFns--SRyN2qa.js} +6 -6
  68. package/dist/{refResolveFns-C23E6pcj.cjs → refResolveFns-CaAw-ya3.cjs} +6 -6
  69. package/dist/{shapeFns-D7DcPxfx.js → shapeFns-CdrDroOM.js} +2 -2
  70. package/dist/{shapeFns-CHFmX5HQ.cjs → shapeFns-CwjjUOr0.cjs} +2 -2
  71. package/dist/shapeRef.cjs +1 -1
  72. package/dist/shapeRef.js +1 -1
  73. package/dist/{shapeTypes-HDVHzNk1.cjs → shapeTypes-D938X2mg.cjs} +1 -1
  74. package/dist/{shapeTypes-Db3yAgTO.js → shapeTypes-PNVEv6ga.js} +1 -1
  75. package/dist/sketching/sketchFns.d.ts +8 -3
  76. package/dist/sketching/sketches.d.ts +8 -0
  77. package/dist/sketching.cjs +3 -3
  78. package/dist/sketching.js +3 -3
  79. package/dist/{solidBuilders-DYumkmVa.cjs → solidBuilders-CAkBQKWb.cjs} +5 -5
  80. package/dist/{solidBuilders-CAiqZrAE.js → solidBuilders-Hft8Cr6a.js} +5 -5
  81. package/dist/{surfaceBuilders-o3H-x6Ca.cjs → surfaceBuilders-BKCiVf7T.cjs} +3 -3
  82. package/dist/{surfaceBuilders-CW6cUdk9.js → surfaceBuilders-CrO_BBKM.js} +3 -3
  83. package/dist/text.cjs +2 -2
  84. package/dist/text.js +2 -2
  85. package/dist/{textBlueprints-BE9fvro-.js → textBlueprints-B8q2a-nN.js} +52 -16
  86. package/dist/{textBlueprints-BSU9_W8u.cjs → textBlueprints-C9HeYc5a.cjs} +52 -16
  87. package/dist/{textMetrics-BHunx03s.cjs → textMetrics-1fhCSAGF.cjs} +1 -1
  88. package/dist/{textMetrics-DBqFVzjh.js → textMetrics-DJfTSy6w.js} +1 -1
  89. package/dist/{threadFns-DckgA8OY.cjs → threadFns-CVIEbOW3.cjs} +37 -29
  90. package/dist/{threadFns-DViBlfHh.js → threadFns-f2KwibLR.js} +36 -28
  91. package/dist/topology/apiTypes.d.ts +13 -7
  92. package/dist/topology/topologyQueryFns.d.ts +9 -1
  93. package/dist/topology.cjs +9 -9
  94. package/dist/topology.d.ts +1 -1
  95. package/dist/topology.js +9 -9
  96. package/dist/{topologyQueryFns-gyva7bvF.cjs → topologyQueryFns-4WYqtSFF.cjs} +1 -14
  97. package/dist/{topologyQueryFns-DKNVBMuN.js → topologyQueryFns-BZUY10TD.js} +1 -14
  98. package/dist/{validityTypes-BmqE7KfX.js → validityTypes-DAXIqwZM.js} +1 -1
  99. package/dist/{validityTypes-CwMwVFdY.cjs → validityTypes-tWSx_zAH.cjs} +1 -1
  100. package/package.json +2 -1
@@ -1,14 +1,14 @@
1
- const require_shapeTypes = require("./shapeTypes-HDVHzNk1.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-D938X2mg.cjs");
2
2
  const require_errors = require("./errors-O_blYTWT.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-gyva7bvF.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns-4WYqtSFF.cjs");
4
4
  const require_constants = require("./constants-oee0S_x6.cjs");
5
5
  const require_vecOps = require("./vecOps-CrGEPPQM.cjs");
6
6
  const require_planeOps = require("./planeOps-DZfLToKZ.cjs");
7
- const require_faceFns = require("./faceFns-C6fYNgZl.cjs");
8
- const require_originTrackingFns = require("./originTrackingFns-BRJ2PZ8J.cjs");
7
+ const require_faceFns = require("./faceFns-Cx7cwUMx.cjs");
8
+ const require_originTrackingFns = require("./originTrackingFns-C-yuMV3m.cjs");
9
9
  const require_faceRoleFns = require("./faceRoleFns-Db5bYj4Q.cjs");
10
10
  const require_arrayAccess = require("./arrayAccess-DpJYARwv.cjs");
11
- const require_surfaceBuilders = require("./surfaceBuilders-o3H-x6Ca.cjs");
11
+ const require_surfaceBuilders = require("./surfaceBuilders-BKCiVf7T.cjs");
12
12
  // src/topology/metadata/faceTagFns.ts
13
13
  var shapeTagStore = /* @__PURE__ */ new WeakMap();
14
14
  var tagMetadataStore = /* @__PURE__ */ new WeakMap();
@@ -1,14 +1,14 @@
1
- import { C as isSolid, D as getShapeKind, E as GeometryCleanupError, G as _usingCtx, S as isShell, d as createSolid, f as createVertex, h as disposeResultShape, n as castResultShape, q as getKernel, s as createCompound, x as isShape3D } from "./shapeTypes-Db3yAgTO.js";
1
+ import { C as isSolid, D as getShapeKind, E as GeometryCleanupError, G as _usingCtx, S as isShell, d as createSolid, f as createVertex, h as disposeResultShape, n as castResultShape, q as getKernel, s as createCompound, x as isShape3D } from "./shapeTypes-PNVEv6ga.js";
2
2
  import { E as ok, P as unwrap, b as isErr, d as validationError, g as err, i as kernelError, l as typeCastError, m as andThen, t as BrepErrorCode } from "./errors-BTccWbtE.js";
3
- import { C as subShapeHashes, c as getFaces, f as getVertices, p as getWires, s as getEdges } from "./topologyQueryFns-DKNVBMuN.js";
3
+ import { C as subShapeHashes, c as getFaces, f as getVertices, p as getWires, s as getEdges } from "./topologyQueryFns-BZUY10TD.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-iraOnb2p.js";
5
5
  import { a as vecDot, g as vecSub, h as vecScale, t as vecAdd } from "./vecOps-S-m9H_fe.js";
6
6
  import { o as resolvePlane } from "./planeOps-D3yDuMux.js";
7
- import { _ as cast, y as downcast } from "./faceFns-DEDlLMcn.js";
8
- import { n as propagateOriginsByHash, r as propagateOriginsFromEvolution, t as getFaceOrigins } from "./originTrackingFns-BqlxFeWq.js";
7
+ import { _ as cast, y as downcast } from "./faceFns-lE2OvBfq.js";
8
+ import { n as propagateOriginsByHash, r as propagateOriginsFromEvolution, t as getFaceOrigins } from "./originTrackingFns-BxeUD2NM.js";
9
9
  import { n as hasFaceRoles, r as propagateFaceRolesFromEvolution } from "./faceRoleFns-BPxzQF-n.js";
10
10
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-BpgouNir.js";
11
- import { r as makeFace } from "./surfaceBuilders-CW6cUdk9.js";
11
+ import { r as makeFace } from "./surfaceBuilders-CrO_BBKM.js";
12
12
  // src/topology/metadata/faceTagFns.ts
13
13
  var shapeTagStore = /* @__PURE__ */ new WeakMap();
14
14
  var tagMetadataStore = /* @__PURE__ */ new WeakMap();
@@ -1,7 +1,7 @@
1
- const require_shapeTypes = require("./shapeTypes-HDVHzNk1.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-D938X2mg.cjs");
2
2
  const require_errors = require("./errors-O_blYTWT.cjs");
3
- const require_validityTypes = require("./validityTypes-CwMwVFdY.cjs");
4
- const require_faceFns = require("./faceFns-C6fYNgZl.cjs");
3
+ const require_validityTypes = require("./validityTypes-tWSx_zAH.cjs");
4
+ const require_faceFns = require("./faceFns-Cx7cwUMx.cjs");
5
5
  // src/utils/range.ts
6
6
  /** Generate an array of integers `[0, 1, …, len - 1]`. */
7
7
  function range(len) {
@@ -1,7 +1,7 @@
1
- import { G as _usingCtx, N as DisposalScope, c as createEdge, l as createFace, p as createWire, q as getKernel, y as isFace } from "./shapeTypes-Db3yAgTO.js";
1
+ import { G as _usingCtx, N as DisposalScope, c as createEdge, l as createFace, p as createWire, q as getKernel, y as isFace } from "./shapeTypes-PNVEv6ga.js";
2
2
  import { E as ok, d as validationError, g as err, i as kernelError, m as andThen } from "./errors-BTccWbtE.js";
3
- import { a as isPlanarFace } from "./validityTypes-BmqE7KfX.js";
4
- import { _ as cast, u as outerWire } from "./faceFns-DEDlLMcn.js";
3
+ import { a as isPlanarFace } from "./validityTypes-DAXIqwZM.js";
4
+ import { _ as cast, u as outerWire } from "./faceFns-lE2OvBfq.js";
5
5
  // src/utils/range.ts
6
6
  /** Generate an array of integers `[0, 1, …, len - 1]`. */
7
7
  function range(len) {
package/dist/text.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_textBlueprints = require("./textBlueprints-BSU9_W8u.cjs");
3
- const require_textMetrics = require("./textMetrics-BHunx03s.cjs");
2
+ const require_textBlueprints = require("./textBlueprints-C9HeYc5a.cjs");
3
+ const require_textMetrics = require("./textMetrics-1fhCSAGF.cjs");
4
4
  exports.fontMetrics = require_textMetrics.fontMetrics;
5
5
  exports.getFont = require_textBlueprints.getFont;
6
6
  exports.loadFont = require_textBlueprints.loadFont;
package/dist/text.js CHANGED
@@ -1,3 +1,3 @@
1
- import { i as setFallbackFont, n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-BE9fvro-.js";
2
- import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-DBqFVzjh.js";
1
+ import { i as setFallbackFont, n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-B8q2a-nN.js";
2
+ import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-DJfTSy6w.js";
3
3
  export { fontMetrics, getFont, loadFont, setFallbackFont, sketchText, textBlueprints, textMetrics };
@@ -1,18 +1,18 @@
1
- import { d as createSolid, h as disposeResultShape, l as createFace, m as disposeDowncastSource, n as castResultShape, p as createWire, q as getKernel, x as isShape3D } from "./shapeTypes-Db3yAgTO.js";
1
+ import { d as createSolid, h as disposeResultShape, l as createFace, m as disposeDowncastSource, n as castResultShape, p as createWire, q as getKernel, x as isShape3D } from "./shapeTypes-PNVEv6ga.js";
2
2
  import { n as bug } from "./bug-ClMTAJhe.js";
3
3
  import { E as ok, P as unwrap, d as validationError, g as err, i as kernelError, l as typeCastError, r as ioError, t as BrepErrorCode } from "./errors-BTccWbtE.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-iraOnb2p.js";
5
5
  import { r as toVec3 } from "./types-CKXsIm9-.js";
6
6
  import { c as vecLength, d as vecNormalize, h as vecScale, i as vecDistance, r as vecCross, t as vecAdd } from "./vecOps-S-m9H_fe.js";
7
7
  import { n as createPlane } from "./planeOps-D3yDuMux.js";
8
- import { v as copyShape } from "./faceFns-DEDlLMcn.js";
9
- import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-CAiqZrAE.js";
8
+ import { v as copyShape } from "./faceFns-lE2OvBfq.js";
9
+ import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-Hft8Cr6a.js";
10
10
  import { i as setFaceRoles } from "./faceRoleFns-BPxzQF-n.js";
11
- import { l as curveStartPoint, u as curveTangentAt } from "./curveFns-AMqd_WaO.js";
11
+ import { l as curveStartPoint, u as curveTangentAt } from "./curveFns-BGPSFUWB.js";
12
12
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-BpgouNir.js";
13
- import { i as makeNewFaceWithinFace, r as makeFace, t as addHolesInFace } from "./surfaceBuilders-CW6cUdk9.js";
14
- import { r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-CmR6Mi91.js";
15
- import { c as twistExtrude, r as complexExtrude, s as sweep, t as loft } from "./loftFns-pMh0ET-J.js";
13
+ import { i as makeNewFaceWithinFace, r as makeFace, t as addHolesInFace } from "./surfaceBuilders-CrO_BBKM.js";
14
+ import { r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-CwTAtrkY.js";
15
+ import { c as twistExtrude, r as complexExtrude, s as sweep, t as loft } from "./loftFns-mbyBvJ8Y.js";
16
16
  import opentype from "opentype.js";
17
17
  // src/topology/shapeRef/extrudeRoleFns.ts
18
18
  /** Match tolerance as a fraction of the extrusion's size. */
@@ -406,9 +406,18 @@ function sketchWires(sketch) {
406
406
  /**
407
407
  * Revolve a sketch around an axis to produce a solid of revolution.
408
408
  *
409
+ * Accepts anything `Drawing.sketchOnPlane` returns: a profile with holes or
410
+ * several profiles revolves each one and returns them as a compound.
411
+ *
409
412
  * @remarks Consumes the sketch — calling twice throws on the second call.
410
413
  */
411
- function sketchRevolve(sketch, revolutionAxis, { origin } = {}) {
414
+ function sketchRevolve(sketch, revolutionAxis, config = {}) {
415
+ if (!(sketch instanceof Sketch)) {
416
+ const solid = sketch.revolve(revolutionAxis, config);
417
+ if (sketch instanceof CompoundSketch) sketch.delete();
418
+ return solid;
419
+ }
420
+ const { origin } = config;
412
421
  const face = unwrap(makeFace(sketch.wire));
413
422
  const center = origin ? toVec3(origin) : sketch.defaultOrigin;
414
423
  const dir = revolutionAxis ? toVec3(revolutionAxis) : [
@@ -425,11 +434,19 @@ function sketchRevolve(sketch, revolutionAxis, { origin } = {}) {
425
434
  * Extrude a sketch to a given distance.
426
435
  *
427
436
  * Supports profile (taper) extrusion via `extrusionProfile`, twist extrusion
428
- * via `twistAngle`, and direction/origin overrides.
437
+ * via `twistAngle`, and direction/origin overrides. Accepts anything
438
+ * `Drawing.sketchOnPlane` returns: a profile with holes or several profiles
439
+ * extrudes each one and returns them as a compound.
429
440
  *
430
441
  * @remarks Consumes the sketch — calling twice throws on the second call.
431
442
  */
432
- function sketchExtrude(sketch, extrusionDistance, { extrusionDirection, extrusionProfile, twistAngle, origin } = {}) {
443
+ function sketchExtrude(sketch, extrusionDistance, config = {}) {
444
+ if (!(sketch instanceof Sketch)) {
445
+ const solid = sketch.extrude(extrusionDistance, config);
446
+ if (sketch instanceof CompoundSketch) sketch.delete();
447
+ return solid;
448
+ }
449
+ const { extrusionDirection, extrusionProfile, twistAngle, origin } = config;
433
450
  const direction = extrusionDirection ? toVec3(extrusionDirection) : sketch.defaultDirection;
434
451
  const extrusionVec = vecScale(vecNormalize(direction), extrusionDistance);
435
452
  const originVec = origin ? toVec3(origin) : sketch.defaultOrigin;
@@ -467,9 +484,13 @@ function sketchSweep(sketch, sketchOnPlane, sweepConfig = {}) {
467
484
  ...sweepConfig
468
485
  };
469
486
  if (sketch.baseFace) config.support = sketch.baseFace.wrapped;
470
- const shape = unwrap(sweep(profile.wire, sketch.wire, config));
471
- sketch.delete();
472
- return shape;
487
+ try {
488
+ const shape = unwrap(sweep(profile.wire, sketch.wire, config));
489
+ sketch.delete();
490
+ return shape;
491
+ } finally {
492
+ profile.delete();
493
+ }
473
494
  }
474
495
  /**
475
496
  * Loft between this sketch and one or more other sketches.
@@ -744,6 +765,10 @@ var Sketches = class {
744
765
  if (!(only instanceof Sketch)) bug(`Sketches.${op}`, `${op} is only supported on single-wire profiles.`);
745
766
  return only;
746
767
  }
768
+ /** Release the kernel resources of every contained sketch. */
769
+ delete() {
770
+ for (const s of this.sketches) s.delete();
771
+ }
747
772
  /** Build a face from the sole contained profile (see {@link Sketches.faces}). */
748
773
  face() {
749
774
  if (this.sketches.length !== 1) bug("Sketches.face", "Multiple profiles — use faces() to combine them.");
@@ -785,14 +810,25 @@ var Sketches = class {
785
810
  */
786
811
  extrude(extrusionDistance, extrusionConfig = {}) {
787
812
  const extruded = this.sketches.map((s) => s.extrude(extrusionDistance, extrusionConfig));
788
- return makeCompound(extruded);
813
+ return this.consumeInto(extruded);
789
814
  }
790
815
  /**
791
816
  * Revolves the drawing on an axis (defined by its direction and an origin
792
817
  * (defaults to the sketch origin)
793
818
  */
794
819
  revolve(revolutionAxis, config) {
795
- return makeCompound(this.sketches.map((s) => s.revolve(revolutionAxis, config)));
820
+ return this.consumeInto(this.sketches.map((s) => s.revolve(revolutionAxis, config)));
821
+ }
822
+ /**
823
+ * Combine per-profile results into one compound (which holds its own references) and
824
+ * release what the profiles leave behind: a `Sketch` deletes itself when extruded or
825
+ * revolved, but a `CompoundSketch` leaves its wires to the caller.
826
+ */
827
+ consumeInto(parts) {
828
+ const compound = makeCompound(parts);
829
+ for (const part of parts) part[Symbol.dispose]();
830
+ for (const s of this.sketches) if (!(s instanceof Sketch)) s.delete();
831
+ return compound;
796
832
  }
797
833
  };
798
834
  // src/text/fontRegistry.ts
@@ -900,7 +936,7 @@ function textBlueprints(text, { startX = 0, startY = 0, fontSize = 16, fontFamil
900
936
  let font = getFont(fontFamily);
901
937
  if (!font) font = getFont();
902
938
  if (!font) bug("text", "No fonts loaded. Call loadFont() before using text functions.");
903
- const writtenText = font.getPath(text, -startX, -startY, fontSize);
939
+ const writtenText = font.getPath(text, startX, -startY, fontSize);
904
940
  const blueprints = Array.from(sketchFontCommands(writtenText.commands));
905
941
  return organiseBlueprints(blueprints).mirror([0, 0]);
906
942
  }
@@ -1,19 +1,19 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-BW-eSwOZ.cjs");
2
- const require_shapeTypes = require("./shapeTypes-HDVHzNk1.cjs");
2
+ const require_shapeTypes = require("./shapeTypes-D938X2mg.cjs");
3
3
  const require_bug = require("./bug-CBcpIPuf.cjs");
4
4
  const require_errors = require("./errors-O_blYTWT.cjs");
5
5
  const require_constants = require("./constants-oee0S_x6.cjs");
6
6
  const require_types = require("./types-CjF9Rofr.cjs");
7
7
  const require_vecOps = require("./vecOps-CrGEPPQM.cjs");
8
8
  const require_planeOps = require("./planeOps-DZfLToKZ.cjs");
9
- const require_faceFns = require("./faceFns-C6fYNgZl.cjs");
10
- const require_solidBuilders = require("./solidBuilders-DYumkmVa.cjs");
9
+ const require_faceFns = require("./faceFns-Cx7cwUMx.cjs");
10
+ const require_solidBuilders = require("./solidBuilders-CAkBQKWb.cjs");
11
11
  const require_faceRoleFns = require("./faceRoleFns-Db5bYj4Q.cjs");
12
- const require_curveFns = require("./curveFns-CMiP40Ko.cjs");
12
+ const require_curveFns = require("./curveFns-BKT4Sg8q.cjs");
13
13
  const require_arrayAccess = require("./arrayAccess-DpJYARwv.cjs");
14
- const require_surfaceBuilders = require("./surfaceBuilders-o3H-x6Ca.cjs");
15
- const require_blueprintSketcher = require("./blueprintSketcher-BTJqAd7E.cjs");
16
- const require_loftFns = require("./loftFns-BsFinbgs.cjs");
14
+ const require_surfaceBuilders = require("./surfaceBuilders-BKCiVf7T.cjs");
15
+ const require_blueprintSketcher = require("./blueprintSketcher-CZyokLGJ.cjs");
16
+ const require_loftFns = require("./loftFns-AHaYxJyS.cjs");
17
17
  let opentype_js = require("opentype.js");
18
18
  opentype_js = require_rolldown_runtime.__toESM(opentype_js, 1);
19
19
  // src/topology/shapeRef/extrudeRoleFns.ts
@@ -408,9 +408,18 @@ function sketchWires(sketch) {
408
408
  /**
409
409
  * Revolve a sketch around an axis to produce a solid of revolution.
410
410
  *
411
+ * Accepts anything `Drawing.sketchOnPlane` returns: a profile with holes or
412
+ * several profiles revolves each one and returns them as a compound.
413
+ *
411
414
  * @remarks Consumes the sketch — calling twice throws on the second call.
412
415
  */
413
- function sketchRevolve(sketch, revolutionAxis, { origin } = {}) {
416
+ function sketchRevolve(sketch, revolutionAxis, config = {}) {
417
+ if (!(sketch instanceof Sketch)) {
418
+ const solid = sketch.revolve(revolutionAxis, config);
419
+ if (sketch instanceof CompoundSketch) sketch.delete();
420
+ return solid;
421
+ }
422
+ const { origin } = config;
414
423
  const face = require_errors.unwrap(require_surfaceBuilders.makeFace(sketch.wire));
415
424
  const center = origin ? require_types.toVec3(origin) : sketch.defaultOrigin;
416
425
  const dir = revolutionAxis ? require_types.toVec3(revolutionAxis) : [
@@ -427,11 +436,19 @@ function sketchRevolve(sketch, revolutionAxis, { origin } = {}) {
427
436
  * Extrude a sketch to a given distance.
428
437
  *
429
438
  * Supports profile (taper) extrusion via `extrusionProfile`, twist extrusion
430
- * via `twistAngle`, and direction/origin overrides.
439
+ * via `twistAngle`, and direction/origin overrides. Accepts anything
440
+ * `Drawing.sketchOnPlane` returns: a profile with holes or several profiles
441
+ * extrudes each one and returns them as a compound.
431
442
  *
432
443
  * @remarks Consumes the sketch — calling twice throws on the second call.
433
444
  */
434
- function sketchExtrude(sketch, extrusionDistance, { extrusionDirection, extrusionProfile, twistAngle, origin } = {}) {
445
+ function sketchExtrude(sketch, extrusionDistance, config = {}) {
446
+ if (!(sketch instanceof Sketch)) {
447
+ const solid = sketch.extrude(extrusionDistance, config);
448
+ if (sketch instanceof CompoundSketch) sketch.delete();
449
+ return solid;
450
+ }
451
+ const { extrusionDirection, extrusionProfile, twistAngle, origin } = config;
435
452
  const direction = extrusionDirection ? require_types.toVec3(extrusionDirection) : sketch.defaultDirection;
436
453
  const extrusionVec = require_vecOps.vecScale(require_vecOps.vecNormalize(direction), extrusionDistance);
437
454
  const originVec = origin ? require_types.toVec3(origin) : sketch.defaultOrigin;
@@ -469,9 +486,13 @@ function sketchSweep(sketch, sketchOnPlane, sweepConfig = {}) {
469
486
  ...sweepConfig
470
487
  };
471
488
  if (sketch.baseFace) config.support = sketch.baseFace.wrapped;
472
- const shape = require_errors.unwrap(require_loftFns.sweep(profile.wire, sketch.wire, config));
473
- sketch.delete();
474
- return shape;
489
+ try {
490
+ const shape = require_errors.unwrap(require_loftFns.sweep(profile.wire, sketch.wire, config));
491
+ sketch.delete();
492
+ return shape;
493
+ } finally {
494
+ profile.delete();
495
+ }
475
496
  }
476
497
  /**
477
498
  * Loft between this sketch and one or more other sketches.
@@ -746,6 +767,10 @@ var Sketches = class {
746
767
  if (!(only instanceof Sketch)) require_bug.bug(`Sketches.${op}`, `${op} is only supported on single-wire profiles.`);
747
768
  return only;
748
769
  }
770
+ /** Release the kernel resources of every contained sketch. */
771
+ delete() {
772
+ for (const s of this.sketches) s.delete();
773
+ }
749
774
  /** Build a face from the sole contained profile (see {@link Sketches.faces}). */
750
775
  face() {
751
776
  if (this.sketches.length !== 1) require_bug.bug("Sketches.face", "Multiple profiles — use faces() to combine them.");
@@ -787,14 +812,25 @@ var Sketches = class {
787
812
  */
788
813
  extrude(extrusionDistance, extrusionConfig = {}) {
789
814
  const extruded = this.sketches.map((s) => s.extrude(extrusionDistance, extrusionConfig));
790
- return require_solidBuilders.makeCompound(extruded);
815
+ return this.consumeInto(extruded);
791
816
  }
792
817
  /**
793
818
  * Revolves the drawing on an axis (defined by its direction and an origin
794
819
  * (defaults to the sketch origin)
795
820
  */
796
821
  revolve(revolutionAxis, config) {
797
- return require_solidBuilders.makeCompound(this.sketches.map((s) => s.revolve(revolutionAxis, config)));
822
+ return this.consumeInto(this.sketches.map((s) => s.revolve(revolutionAxis, config)));
823
+ }
824
+ /**
825
+ * Combine per-profile results into one compound (which holds its own references) and
826
+ * release what the profiles leave behind: a `Sketch` deletes itself when extruded or
827
+ * revolved, but a `CompoundSketch` leaves its wires to the caller.
828
+ */
829
+ consumeInto(parts) {
830
+ const compound = require_solidBuilders.makeCompound(parts);
831
+ for (const part of parts) part[Symbol.dispose]();
832
+ for (const s of this.sketches) if (!(s instanceof Sketch)) s.delete();
833
+ return compound;
798
834
  }
799
835
  };
800
836
  // src/text/fontRegistry.ts
@@ -902,7 +938,7 @@ function textBlueprints(text, { startX = 0, startY = 0, fontSize = 16, fontFamil
902
938
  let font = getFont(fontFamily);
903
939
  if (!font) font = getFont();
904
940
  if (!font) require_bug.bug("text", "No fonts loaded. Call loadFont() before using text functions.");
905
- const writtenText = font.getPath(text, -startX, -startY, fontSize);
941
+ const writtenText = font.getPath(text, startX, -startY, fontSize);
906
942
  const blueprints = Array.from(sketchFontCommands(writtenText.commands));
907
943
  return require_blueprintSketcher.organiseBlueprints(blueprints).mirror([0, 0]);
908
944
  }
@@ -1,5 +1,5 @@
1
1
  const require_errors = require("./errors-O_blYTWT.cjs");
2
- const require_textBlueprints = require("./textBlueprints-BSU9_W8u.cjs");
2
+ const require_textBlueprints = require("./textBlueprints-C9HeYc5a.cjs");
3
3
  // src/text/sketchText.ts
4
4
  /**
5
5
  * Render text as 3D sketch outlines on a plane.
@@ -1,5 +1,5 @@
1
1
  import { E as ok, d as validationError, g as err, t as BrepErrorCode } from "./errors-BTccWbtE.js";
2
- import { _ as wrapSketchData, a as Sketches, n as getFont, t as textBlueprints, y as CompoundSketch } from "./textBlueprints-BE9fvro-.js";
2
+ import { _ as wrapSketchData, a as Sketches, n as getFont, t as textBlueprints, y as CompoundSketch } from "./textBlueprints-B8q2a-nN.js";
3
3
  // src/text/sketchText.ts
4
4
  /**
5
5
  * Render text as 3D sketch outlines on a plane.
@@ -1,12 +1,12 @@
1
- const require_shapeTypes = require("./shapeTypes-HDVHzNk1.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-D938X2mg.cjs");
2
2
  const require_errors = require("./errors-O_blYTWT.cjs");
3
3
  const require_vecOps = require("./vecOps-CrGEPPQM.cjs");
4
- const require_faceFns = require("./faceFns-C6fYNgZl.cjs");
5
- const require_solidBuilders = require("./solidBuilders-DYumkmVa.cjs");
6
- const require_primitiveFns = require("./primitiveFns-wOdKnYBs.cjs");
7
- const require_shapeFns = require("./shapeFns-CHFmX5HQ.cjs");
8
- const require_loftFns = require("./loftFns-BsFinbgs.cjs");
9
- const require_refResolveFns = require("./refResolveFns-C23E6pcj.cjs");
4
+ const require_faceFns = require("./faceFns-Cx7cwUMx.cjs");
5
+ const require_solidBuilders = require("./solidBuilders-CAkBQKWb.cjs");
6
+ const require_primitiveFns = require("./primitiveFns-BVAkYHVf.cjs");
7
+ const require_shapeFns = require("./shapeFns-CwjjUOr0.cjs");
8
+ const require_loftFns = require("./loftFns-AHaYxJyS.cjs");
9
+ const require_refResolveFns = require("./refResolveFns-CaAw-ya3.cjs");
10
10
  // src/utils/uuid.ts
11
11
  /** Generate a v4-style UUID string using `crypto.getRandomValues`. */
12
12
  function uuidv() {
@@ -147,7 +147,7 @@ function quatMultiply(a, b) {
147
147
  */
148
148
  function linearPattern(shape, direction, count, spacing, options) {
149
149
  if (count < 1) return require_errors.err(require_errors.validationError("PATTERN_INVALID_COUNT", "Pattern count must be at least 1"));
150
- if (count === 1) return require_errors.ok(shape);
150
+ if (count === 1) return require_shapeFns.clone(shape);
151
151
  if (require_vecOps.vecIsZero(direction)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_DIRECTION", "Pattern direction cannot be zero"));
152
152
  const dir = require_vecOps.vecNormalize(direction);
153
153
  const copies = require_shapeTypes.getKernel().linearPattern(shape.wrapped, [...dir], spacing, count).map((s) => require_shapeTypes.castResultShape(s));
@@ -163,10 +163,15 @@ function linearPattern(shape, direction, count, spacing, options) {
163
163
  /**
164
164
  * Create a circular pattern of a shape around an axis.
165
165
  *
166
+ * A full turn (`fullAngle` of ±360) spaces the copies `fullAngle / count`
167
+ * apart, so the last copy does not land on the first. Any other angle is an
168
+ * open arc: the first copy stays in place, the last lands at `fullAngle`, and
169
+ * they are spaced `fullAngle / (count - 1)` apart.
170
+ *
166
171
  * @param shape - The shape to replicate
167
172
  * @param axis - Rotation axis direction
168
173
  * @param count - Total number of copies (including the original)
169
- * @param fullAngle - Total angle to spread copies over in degrees (default: 360)
174
+ * @param fullAngle - Angle in degrees the copies span (default: 360)
170
175
  * @param center - Center point of rotation (default: [0,0,0])
171
176
  * @param options - Boolean options for the fuse operation
172
177
  * @returns Fused shape of all copies
@@ -177,9 +182,9 @@ function circularPattern(shape, axis, count, fullAngle = 360, center = [
177
182
  0
178
183
  ], options) {
179
184
  if (count < 1) return require_errors.err(require_errors.validationError("PATTERN_INVALID_COUNT", "Pattern count must be at least 1"));
180
- if (count === 1) return require_errors.ok(shape);
185
+ if (count === 1) return require_shapeFns.clone(shape);
181
186
  if (require_vecOps.vecIsZero(axis)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_AXIS", "Pattern axis cannot be zero"));
182
- const angleStep = fullAngle / count;
187
+ const angleStep = fullAngle / (Math.abs(Math.abs(fullAngle) - 360) < 1e-9 ? count : count - 1);
183
188
  const copies = require_shapeTypes.getKernel().circularPattern(shape.wrapped, [...center], [...axis], angleStep, count).map((s) => require_shapeTypes.castResultShape(s));
184
189
  try {
185
190
  return require_solidBuilders.fuseAll(copies, {
@@ -204,24 +209,27 @@ function circularPattern(shape, axis, count, fullAngle = 360, center = [
204
209
  * @returns Compound shape containing all copies, or fused result
205
210
  */
206
211
  function gridPattern(shape, directionX, directionY, countX, countY, spacingX, spacingY, options) {
207
- if (countX < 1 || countY < 1) return require_errors.err(require_errors.validationError("PATTERN_INVALID_COUNT", "Grid pattern counts must be at least 1"));
208
- if (countX === 1 && countY === 1) return require_errors.ok(shape);
209
- if (require_vecOps.vecIsZero(directionX)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_DIRECTION", "Grid directionX cannot be zero"));
210
- if (require_vecOps.vecIsZero(directionY)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_DIRECTION", "Grid directionY cannot be zero"));
211
- const kernel = require_shapeTypes.getKernel();
212
- const dirX = require_vecOps.vecNormalize(directionX);
213
- const dirY = require_vecOps.vecNormalize(directionY);
214
- if (typeof kernel.gridPattern === "function") {
215
- const compound = kernel.gridPattern(shape.wrapped, [...dirX], [...dirY], spacingX, spacingY, countX, countY);
216
- return require_errors.ok(require_shapeTypes.castResultShape(compound));
217
- }
218
- const rowResult = linearPattern(shape, directionX, countX, spacingX, options);
219
- if (!rowResult.ok) return rowResult;
220
- const row = rowResult.value;
221
- const out = linearPattern(row, directionY, countY, spacingY, options);
222
- const passthrough = out.ok && out.value === row;
223
- if (row !== shape && !passthrough) row[Symbol.dispose]();
224
- return out;
212
+ try {
213
+ var _usingCtx$2 = require_shapeTypes._usingCtx();
214
+ if (countX < 1 || countY < 1) return require_errors.err(require_errors.validationError("PATTERN_INVALID_COUNT", "Grid pattern counts must be at least 1"));
215
+ if (countX === 1 && countY === 1) return require_shapeFns.clone(shape);
216
+ if (require_vecOps.vecIsZero(directionX)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_DIRECTION", "Grid directionX cannot be zero"));
217
+ if (require_vecOps.vecIsZero(directionY)) return require_errors.err(require_errors.validationError("PATTERN_ZERO_DIRECTION", "Grid directionY cannot be zero"));
218
+ const kernel = require_shapeTypes.getKernel();
219
+ const dirX = require_vecOps.vecNormalize(directionX);
220
+ const dirY = require_vecOps.vecNormalize(directionY);
221
+ if (typeof kernel.gridPattern === "function") {
222
+ const compound = kernel.gridPattern(shape.wrapped, [...dirX], [...dirY], spacingX, spacingY, countX, countY);
223
+ return require_errors.ok(require_shapeTypes.castResultShape(compound));
224
+ }
225
+ const rowResult = linearPattern(shape, directionX, countX, spacingX, options);
226
+ if (!rowResult.ok) return rowResult;
227
+ return linearPattern(_usingCtx$2.u(rowResult.value), directionY, countY, spacingY, options);
228
+ } catch (_) {
229
+ _usingCtx$2.e = _;
230
+ } finally {
231
+ _usingCtx$2.d();
232
+ }
225
233
  }
226
234
  // src/operations/exporterFns.ts
227
235
  /**
@@ -1,12 +1,12 @@
1
- import { F as createKernelHandle, G as _usingCtx, N as DisposalScope, n as castResultShape, q as getKernel, x as isShape3D } from "./shapeTypes-Db3yAgTO.js";
1
+ import { F as createKernelHandle, G as _usingCtx, N as DisposalScope, n as castResultShape, q as getKernel, x as isShape3D } from "./shapeTypes-PNVEv6ga.js";
2
2
  import { E as ok, d as validationError, g as err, n as computationError, r as ioError, t as BrepErrorCode, x as isOk } from "./errors-BTccWbtE.js";
3
3
  import { d as vecNormalize, s as vecIsZero } from "./vecOps-S-m9H_fe.js";
4
- import { b as fromBREP } from "./faceFns-DEDlLMcn.js";
5
- import { h as fuseAll } from "./solidBuilders-CAiqZrAE.js";
6
- import { E as wire, h as line } from "./primitiveFns-DrEUKZvX.js";
7
- import { s as toBREP } from "./shapeFns-D7DcPxfx.js";
8
- import { t as loft } from "./loftFns-pMh0ET-J.js";
9
- import { c as resolveRefParams } from "./refResolveFns-BqcjC50D.js";
4
+ import { b as fromBREP } from "./faceFns-lE2OvBfq.js";
5
+ import { h as fuseAll } from "./solidBuilders-Hft8Cr6a.js";
6
+ import { E as wire, h as line } from "./primitiveFns-CualoFAk.js";
7
+ import { s as toBREP, t as clone } from "./shapeFns-CdrDroOM.js";
8
+ import { t as loft } from "./loftFns-mbyBvJ8Y.js";
9
+ import { c as resolveRefParams } from "./refResolveFns--SRyN2qa.js";
10
10
  // src/utils/uuid.ts
11
11
  /** Generate a v4-style UUID string using `crypto.getRandomValues`. */
12
12
  function uuidv() {
@@ -147,7 +147,7 @@ function quatMultiply(a, b) {
147
147
  */
148
148
  function linearPattern(shape, direction, count, spacing, options) {
149
149
  if (count < 1) return err(validationError("PATTERN_INVALID_COUNT", "Pattern count must be at least 1"));
150
- if (count === 1) return ok(shape);
150
+ if (count === 1) return clone(shape);
151
151
  if (vecIsZero(direction)) return err(validationError("PATTERN_ZERO_DIRECTION", "Pattern direction cannot be zero"));
152
152
  const dir = vecNormalize(direction);
153
153
  const copies = getKernel().linearPattern(shape.wrapped, [...dir], spacing, count).map((s) => castResultShape(s));
@@ -163,10 +163,15 @@ function linearPattern(shape, direction, count, spacing, options) {
163
163
  /**
164
164
  * Create a circular pattern of a shape around an axis.
165
165
  *
166
+ * A full turn (`fullAngle` of ±360) spaces the copies `fullAngle / count`
167
+ * apart, so the last copy does not land on the first. Any other angle is an
168
+ * open arc: the first copy stays in place, the last lands at `fullAngle`, and
169
+ * they are spaced `fullAngle / (count - 1)` apart.
170
+ *
166
171
  * @param shape - The shape to replicate
167
172
  * @param axis - Rotation axis direction
168
173
  * @param count - Total number of copies (including the original)
169
- * @param fullAngle - Total angle to spread copies over in degrees (default: 360)
174
+ * @param fullAngle - Angle in degrees the copies span (default: 360)
170
175
  * @param center - Center point of rotation (default: [0,0,0])
171
176
  * @param options - Boolean options for the fuse operation
172
177
  * @returns Fused shape of all copies
@@ -177,9 +182,9 @@ function circularPattern(shape, axis, count, fullAngle = 360, center = [
177
182
  0
178
183
  ], options) {
179
184
  if (count < 1) return err(validationError("PATTERN_INVALID_COUNT", "Pattern count must be at least 1"));
180
- if (count === 1) return ok(shape);
185
+ if (count === 1) return clone(shape);
181
186
  if (vecIsZero(axis)) return err(validationError("PATTERN_ZERO_AXIS", "Pattern axis cannot be zero"));
182
- const angleStep = fullAngle / count;
187
+ const angleStep = fullAngle / (Math.abs(Math.abs(fullAngle) - 360) < 1e-9 ? count : count - 1);
183
188
  const copies = getKernel().circularPattern(shape.wrapped, [...center], [...axis], angleStep, count).map((s) => castResultShape(s));
184
189
  try {
185
190
  return fuseAll(copies, {
@@ -204,24 +209,27 @@ function circularPattern(shape, axis, count, fullAngle = 360, center = [
204
209
  * @returns Compound shape containing all copies, or fused result
205
210
  */
206
211
  function gridPattern(shape, directionX, directionY, countX, countY, spacingX, spacingY, options) {
207
- if (countX < 1 || countY < 1) return err(validationError("PATTERN_INVALID_COUNT", "Grid pattern counts must be at least 1"));
208
- if (countX === 1 && countY === 1) return ok(shape);
209
- if (vecIsZero(directionX)) return err(validationError("PATTERN_ZERO_DIRECTION", "Grid directionX cannot be zero"));
210
- if (vecIsZero(directionY)) return err(validationError("PATTERN_ZERO_DIRECTION", "Grid directionY cannot be zero"));
211
- const kernel = getKernel();
212
- const dirX = vecNormalize(directionX);
213
- const dirY = vecNormalize(directionY);
214
- if (typeof kernel.gridPattern === "function") {
215
- const compound = kernel.gridPattern(shape.wrapped, [...dirX], [...dirY], spacingX, spacingY, countX, countY);
216
- return ok(castResultShape(compound));
212
+ try {
213
+ var _usingCtx$2 = _usingCtx();
214
+ if (countX < 1 || countY < 1) return err(validationError("PATTERN_INVALID_COUNT", "Grid pattern counts must be at least 1"));
215
+ if (countX === 1 && countY === 1) return clone(shape);
216
+ if (vecIsZero(directionX)) return err(validationError("PATTERN_ZERO_DIRECTION", "Grid directionX cannot be zero"));
217
+ if (vecIsZero(directionY)) return err(validationError("PATTERN_ZERO_DIRECTION", "Grid directionY cannot be zero"));
218
+ const kernel = getKernel();
219
+ const dirX = vecNormalize(directionX);
220
+ const dirY = vecNormalize(directionY);
221
+ if (typeof kernel.gridPattern === "function") {
222
+ const compound = kernel.gridPattern(shape.wrapped, [...dirX], [...dirY], spacingX, spacingY, countX, countY);
223
+ return ok(castResultShape(compound));
224
+ }
225
+ const rowResult = linearPattern(shape, directionX, countX, spacingX, options);
226
+ if (!rowResult.ok) return rowResult;
227
+ return linearPattern(_usingCtx$2.u(rowResult.value), directionY, countY, spacingY, options);
228
+ } catch (_) {
229
+ _usingCtx$2.e = _;
230
+ } finally {
231
+ _usingCtx$2.d();
217
232
  }
218
- const rowResult = linearPattern(shape, directionX, countX, spacingX, options);
219
- if (!rowResult.ok) return rowResult;
220
- const row = rowResult.value;
221
- const out = linearPattern(row, directionY, countY, spacingY, options);
222
- const passthrough = out.ok && out.value === row;
223
- if (row !== shape && !passthrough) row[Symbol.dispose]();
224
- return out;
225
233
  }
226
234
  // src/operations/exporterFns.ts
227
235
  /**
@@ -2,13 +2,14 @@ import { Vec2, Vec3 } from '../core/types.js';
2
2
  import { AnyShape, Dimension, Edge, Face, Wire, Shape3D } from '../core/shapeTypes.js';
3
3
  import { EdgeFinderFn, FaceFinderFn, ShapeFinder } from '../query/finderFns.js';
4
4
  /**
5
- * Structural type matching a Drawing's wire-producing interface.
6
- * Used in place of importing the actual Drawing class to avoid
7
- * Layer 2 → Layer 3 boundary violations.
5
+ * Structural type matching a Drawing: it sketches onto a plane as something
6
+ * that builds a face (holes included). Used in place of importing the actual
7
+ * Drawing class to avoid Layer 2 → Layer 3 boundary violations.
8
8
  */
9
9
  export interface DrawingLike {
10
- sketchOnPlane(plane: string): {
11
- wire: Wire;
10
+ sketchOnPlane(plane: 'XY'): {
11
+ face(): Face;
12
+ delete?(): void;
12
13
  };
13
14
  }
14
15
  type FinderFor<T extends AnyShape<Dimension>> = T extends Edge ? EdgeFinderFn : T extends Face ? FaceFinderFn : ShapeFinder<T>;
@@ -66,7 +67,12 @@ export interface DrillOptions {
66
67
  }
67
68
  /** Options for the pocket() compound operation. */
68
69
  export interface PocketOptions {
69
- /** 2D profile shape to cut into the face. */
70
+ /**
71
+ * 2D profile to cut into the face, drawn in XY with its origin at the face
72
+ * centre. On faces parallel to XY it keeps the world X and Y axes; on any
73
+ * other face its Y axis runs up the face and its X axis points right as seen
74
+ * from outside.
75
+ */
70
76
  profile: DrawingLike | Wire;
71
77
  /** Which face to pocket. Default: top face. */
72
78
  face?: Face | FinderFn<Face>;
@@ -75,7 +81,7 @@ export interface PocketOptions {
75
81
  }
76
82
  /** Options for the boss() compound operation. */
77
83
  export interface BossOptions {
78
- /** 2D profile shape to extrude onto the face. */
84
+ /** 2D profile to extrude from the face, placed as for {@link PocketOptions.profile}. */
79
85
  profile: DrawingLike | Wire;
80
86
  /** Which face to add onto. Default: top face. */
81
87
  face?: Face | FinderFn<Face>;