brepjs 18.131.0 → 18.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/brepjs.cjs CHANGED
@@ -1809,8 +1809,8 @@ function hashEdgeRef(h0, ref) {
1809
1809
  * serializable node data (the cache key stays purely structural); it
1810
1810
  * resolves against the materialized target at evaluation, so an upstream
1811
1811
  * parameter edit re-targets the same edge by its face roles. */
1812
- function fillet$1(target, ref, radius) {
1813
- const copied = {
1812
+ function copyEdgeRef(ref) {
1813
+ return {
1814
1814
  origin: ref.origin,
1815
1815
  faceRoles: [ref.faceRoles[0], ref.faceRoles[1]],
1816
1816
  hint: {
@@ -1819,6 +1819,9 @@ function fillet$1(target, ref, radius) {
1819
1819
  midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
1820
1820
  }
1821
1821
  };
1822
+ }
1823
+ function fillet$1(target, ref, radius) {
1824
+ const copied = copyEdgeRef(ref);
1822
1825
  const re = asScalarExpr(radius);
1823
1826
  let h = mix(startHash("Fillet"), target);
1824
1827
  h = hashEdgeRef(h, copied);
@@ -1832,6 +1835,23 @@ function fillet$1(target, ref, radius) {
1832
1835
  freeParams: depsOf(target, re)
1833
1836
  };
1834
1837
  }
1838
+ /** Chamfer the edge named by a lineage ref on the evaluated target. Same
1839
+ * contract as `fillet`: the ref is deep-copied, serializable node data. */
1840
+ function chamfer$1(target, ref, distance) {
1841
+ const copied = copyEdgeRef(ref);
1842
+ const de = asScalarExpr(distance);
1843
+ let h = mix(startHash("Chamfer"), target);
1844
+ h = hashEdgeRef(h, copied);
1845
+ h = mix(h, de);
1846
+ return {
1847
+ kind: "Chamfer",
1848
+ target,
1849
+ ref: copied,
1850
+ distance: de,
1851
+ structuralHash: h,
1852
+ freeParams: depsOf(target, de)
1853
+ };
1854
+ }
1835
1855
  /** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
1836
1856
  * the evaluated result of `target`. Metadata rides beside the geometry: the
1837
1857
  * evaluator re-tags the shared target materialization with an independent
@@ -1984,7 +2004,8 @@ function outputKindOf(node) {
1984
2004
  case "Revolve":
1985
2005
  case "Loft":
1986
2006
  case "Sweep":
1987
- case "Fillet": return "Solid";
2007
+ case "Fillet":
2008
+ case "Chamfer": return "Solid";
1988
2009
  case "Profile": return "Face";
1989
2010
  case "Path": return "Wire";
1990
2011
  case "Compound": return "Compound";
@@ -2634,7 +2655,7 @@ function evalExtrude(node, ctx) {
2634
2655
  function evalRevolve(node, ctx) {
2635
2656
  const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
2636
2657
  if (!a.ok) return a;
2637
- if (a.value <= 0) return require_errors.err(require_errors.validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
2658
+ if (!Number.isFinite(a.value) || a.value <= 0) return require_errors.err(require_errors.validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
2638
2659
  const deg = Math.min(a.value, 360);
2639
2660
  const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : require_errors.ok([
2640
2661
  0,
@@ -2995,7 +3016,7 @@ function evalColor(node, ctx) {
2995
3016
  function evalFillet(node, ctx) {
2996
3017
  const radius = evalScalar(node.radius, ctx.env, "Fillet.radius");
2997
3018
  if (!radius.ok) return radius;
2998
- if (radius.value <= 0) return require_errors.err(require_errors.validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
3019
+ if (!Number.isFinite(radius.value) || radius.value <= 0) return require_errors.err(require_errors.validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
2999
3020
  const t = ctx.evalNode(node.target);
3000
3021
  if (!t.ok) return t;
3001
3022
  if (!require_shapeTypes.isSolid(t.value)) return require_errors.err(require_errors.validationError("CSG_FILLET_TARGET", "Fillet.target did not produce a Solid"));
@@ -3007,6 +3028,22 @@ function evalFillet(node, ctx) {
3007
3028
  return require_healingFns.fillet(solid.value, [resolved.entity], radius.value);
3008
3029
  }
3009
3030
  //#endregion
3031
+ //#region src/csg/evaluators/chamfer.ts
3032
+ function evalChamfer(node, ctx) {
3033
+ const distance = evalScalar(node.distance, ctx.env, "Chamfer.distance");
3034
+ if (!distance.ok) return distance;
3035
+ if (!Number.isFinite(distance.value) || distance.value <= 0) return require_errors.err(require_errors.validationError("CSG_CHAMFER_DISTANCE", `Chamfer.distance must be positive, got ${distance.value}`));
3036
+ const t = ctx.evalNode(node.target);
3037
+ if (!t.ok) return t;
3038
+ if (!require_shapeTypes.isSolid(t.value)) return require_errors.err(require_errors.validationError("CSG_CHAMFER_TARGET", "Chamfer.target did not produce a Solid"));
3039
+ const solid = require_validityTypes.validSolid(t.value);
3040
+ if (!solid.ok) return require_errors.err(require_errors.validationError("CSG_CHAMFER_TARGET", solid.error));
3041
+ const resolved = require_refResolveFns.resolveRefIn(node.ref, t.value);
3042
+ if (!resolved.ok) return require_errors.err(require_errors.validationError("CSG_CHAMFER_REF", `Chamfer.ref did not resolve: ${resolved.reason}`));
3043
+ if (!require_shapeTypes.isEdge(resolved.entity)) return require_errors.err(require_errors.validationError("CSG_CHAMFER_REF", "Chamfer.ref resolved to a non-edge"));
3044
+ return require_healingFns.chamfer(solid.value, [resolved.entity], distance.value);
3045
+ }
3046
+ //#endregion
3010
3047
  //#region src/csg/evaluate.ts
3011
3048
  function dispatch(node, ctx) {
3012
3049
  switch (node.kind) {
@@ -3031,6 +3068,19 @@ function dispatch(node, ctx) {
3031
3068
  case "Mirror": return evalMirror(node, ctx);
3032
3069
  case "Compound": return evalCompound(node, ctx);
3033
3070
  case "Instance": return evalInstance(node, ctx);
3071
+ case "Extrude":
3072
+ case "Revolve":
3073
+ case "Loft":
3074
+ case "Path":
3075
+ case "Sweep":
3076
+ case "Profile":
3077
+ case "Color":
3078
+ case "Fillet":
3079
+ case "Chamfer": return dispatchFeature(node, ctx);
3080
+ }
3081
+ }
3082
+ function dispatchFeature(node, ctx) {
3083
+ switch (node.kind) {
3034
3084
  case "Extrude": return evalExtrude(node, ctx);
3035
3085
  case "Revolve": return evalRevolve(node, ctx);
3036
3086
  case "Loft": return evalLoft(node, ctx);
@@ -3039,6 +3089,7 @@ function dispatch(node, ctx) {
3039
3089
  case "Profile": return evalProfile(node, ctx);
3040
3090
  case "Color": return evalColor(node, ctx);
3041
3091
  case "Fillet": return evalFillet(node, ctx);
3092
+ case "Chamfer": return evalChamfer(node, ctx);
3042
3093
  }
3043
3094
  }
3044
3095
  function hashExprValue(h, v) {
@@ -3448,7 +3499,7 @@ function withEvaluator(options, fn) {
3448
3499
  var MIN_CSG_VERSION = 1;
3449
3500
  function toJSON(node) {
3450
3501
  return {
3451
- csgVersion: 5,
3502
+ csgVersion: 6,
3452
3503
  root: nodeToJson(node)
3453
3504
  };
3454
3505
  }
@@ -3604,6 +3655,17 @@ function segmentToJson(s) {
3604
3655
  };
3605
3656
  }
3606
3657
  }
3658
+ function edgeRefToJson(ref) {
3659
+ return {
3660
+ origin: ref.origin,
3661
+ faceRoles: [...ref.faceRoles],
3662
+ hint: {
3663
+ entityType: "edge",
3664
+ length: ref.hint.length,
3665
+ midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
3666
+ }
3667
+ };
3668
+ }
3607
3669
  function contourToJson(c) {
3608
3670
  return {
3609
3671
  start: exprToJson(c.start),
@@ -3681,17 +3743,15 @@ function nodeToJson(n) {
3681
3743
  if (n.kind === "Fillet") return {
3682
3744
  kind: "Fillet",
3683
3745
  target: nodeToJson(n.target),
3684
- ref: {
3685
- origin: n.ref.origin,
3686
- faceRoles: [...n.ref.faceRoles],
3687
- hint: {
3688
- entityType: "edge",
3689
- length: n.ref.hint.length,
3690
- midpoint: n.ref.hint.midpoint ? [...n.ref.hint.midpoint] : void 0
3691
- }
3692
- },
3746
+ ref: edgeRefToJson(n.ref),
3693
3747
  radius: exprToJson(n.radius)
3694
3748
  };
3749
+ if (n.kind === "Chamfer") return {
3750
+ kind: "Chamfer",
3751
+ target: nodeToJson(n.target),
3752
+ ref: edgeRefToJson(n.ref),
3753
+ distance: exprToJson(n.distance)
3754
+ };
3695
3755
  if (n.kind === "Compound") return {
3696
3756
  kind: "Compound",
3697
3757
  children: n.children.map(nodeToJson)
@@ -3735,7 +3795,7 @@ function readVec2(v, where) {
3735
3795
  function fromJSON(envelope) {
3736
3796
  if (!isObj(envelope)) return bad("input is not an object");
3737
3797
  const v = envelope["csgVersion"];
3738
- if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 5) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..5)`);
3798
+ if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 6) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..6)`);
3739
3799
  const root = envelope["root"];
3740
3800
  return readNode(root);
3741
3801
  }
@@ -3851,6 +3911,7 @@ function readNode(j) {
3851
3911
  case "Profile": return readProfile(j);
3852
3912
  case "Color": return readColor(j);
3853
3913
  case "Fillet": return readFillet(j);
3914
+ case "Chamfer": return readChamfer(j);
3854
3915
  default: return bad(`unknown node kind: ${String(kind)}`);
3855
3916
  }
3856
3917
  }
@@ -4100,28 +4161,23 @@ function readContour(j, where) {
4100
4161
  }
4101
4162
  return require_errors.ok(contour(start.value, segments));
4102
4163
  }
4103
- function readFillet(j) {
4104
- const target = readNode(j["target"]);
4105
- if (!target.ok) return target;
4106
- const radius = readExpr(j["radius"]);
4107
- if (!radius.ok) return radius;
4108
- const ref = j["ref"];
4109
- if (!isObj(ref)) return bad("Fillet.ref: not an object");
4110
- const origin = ref["origin"];
4111
- if (!isString(origin)) return bad("Fillet.ref.origin: not a string");
4112
- const roles = ref["faceRoles"];
4113
- if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad("Fillet.ref.faceRoles: expected two role strings");
4114
- const hintRaw = ref["hint"];
4115
- if (!isObj(hintRaw)) return bad("Fillet.ref.hint: not an object");
4164
+ function readEdgeRef(j, where) {
4165
+ if (!isObj(j)) return bad(`${where}: not an object`);
4166
+ const origin = j["origin"];
4167
+ if (!isString(origin)) return bad(`${where}.origin: not a string`);
4168
+ const roles = j["faceRoles"];
4169
+ if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad(`${where}.faceRoles: expected two role strings`);
4170
+ const hintRaw = j["hint"];
4171
+ if (!isObj(hintRaw)) return bad(`${where}.hint: not an object`);
4116
4172
  const length = hintRaw["length"];
4117
- if (length !== void 0 && !isNumber$1(length)) return bad("Fillet.ref.hint.length");
4173
+ if (length !== void 0 && !isNumber$1(length)) return bad(`${where}.hint.length`);
4118
4174
  let midpoint;
4119
4175
  if (hintRaw["midpoint"] !== void 0) {
4120
- const m = readVec3(hintRaw["midpoint"], "Fillet.ref.hint.midpoint");
4176
+ const m = readVec3(hintRaw["midpoint"], `${where}.hint.midpoint`);
4121
4177
  if (!m.ok) return m;
4122
4178
  midpoint = m.value;
4123
4179
  }
4124
- return require_errors.ok(fillet$1(target.value, {
4180
+ return require_errors.ok({
4125
4181
  origin,
4126
4182
  faceRoles: [roles[0], roles[1]],
4127
4183
  hint: {
@@ -4129,7 +4185,25 @@ function readFillet(j) {
4129
4185
  length,
4130
4186
  midpoint
4131
4187
  }
4132
- }, radius.value));
4188
+ });
4189
+ }
4190
+ function readFillet(j) {
4191
+ const target = readNode(j["target"]);
4192
+ if (!target.ok) return target;
4193
+ const radius = readExpr(j["radius"]);
4194
+ if (!radius.ok) return radius;
4195
+ const ref = readEdgeRef(j["ref"], "Fillet.ref");
4196
+ if (!ref.ok) return ref;
4197
+ return require_errors.ok(fillet$1(target.value, ref.value, radius.value));
4198
+ }
4199
+ function readChamfer(j) {
4200
+ const target = readNode(j["target"]);
4201
+ if (!target.ok) return target;
4202
+ const distance = readExpr(j["distance"]);
4203
+ if (!distance.ok) return distance;
4204
+ const ref = readEdgeRef(j["ref"], "Chamfer.ref");
4205
+ if (!ref.ok) return ref;
4206
+ return require_errors.ok(chamfer$1(target.value, ref.value, distance.value));
4133
4207
  }
4134
4208
  function readColor(j) {
4135
4209
  const target = readNode(j["target"]);
@@ -4290,7 +4364,8 @@ function optimizeNode(n) {
4290
4364
  case "Profile":
4291
4365
  case "Path":
4292
4366
  case "Color":
4293
- case "Fillet": return optimizeFeature(n);
4367
+ case "Fillet":
4368
+ case "Chamfer": return optimizeFeature(n);
4294
4369
  }
4295
4370
  }
4296
4371
  function optimizeFeature(n) {
@@ -4306,6 +4381,7 @@ function optimizeFeature(n) {
4306
4381
  case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
4307
4382
  case "Color": return color(optimizeNode(n.target), [...n.color]);
4308
4383
  case "Fillet": return fillet$1(optimizeNode(n.target), n.ref, foldExpr(n.radius));
4384
+ case "Chamfer": return chamfer$1(optimizeNode(n.target), n.ref, foldExpr(n.distance));
4309
4385
  }
4310
4386
  }
4311
4387
  function optimizeTransform(n) {
@@ -4416,7 +4492,8 @@ function rebuildChildren(n, pred, repl) {
4416
4492
  case "Loft":
4417
4493
  case "Sweep":
4418
4494
  case "Color":
4419
- case "Fillet": return rebuildFeature(n, pred, repl);
4495
+ case "Fillet":
4496
+ case "Chamfer": return rebuildFeature(n, pred, repl);
4420
4497
  }
4421
4498
  }
4422
4499
  function rebuildFeature(n, pred, repl) {
@@ -4430,6 +4507,7 @@ function rebuildFeature(n, pred, repl) {
4430
4507
  case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
4431
4508
  case "Color": return color(walk(n.target, pred, repl), [...n.color]);
4432
4509
  case "Fillet": return fillet$1(walk(n.target, pred, repl), n.ref, n.radius);
4510
+ case "Chamfer": return chamfer$1(walk(n.target, pred, repl), n.ref, n.distance);
4433
4511
  }
4434
4512
  }
4435
4513
  function forEachNode(root, fn) {
@@ -4460,7 +4538,8 @@ function childrenOf(n) {
4460
4538
  case "Scale":
4461
4539
  case "Mirror":
4462
4540
  case "Color":
4463
- case "Fillet": return [n.target];
4541
+ case "Fillet":
4542
+ case "Chamfer": return [n.target];
4464
4543
  case "Compound": return n.children;
4465
4544
  case "Instance": return [n.source];
4466
4545
  case "Extrude":
@@ -8471,7 +8550,7 @@ var patterns_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8471
8550
  //#endregion
8472
8551
  //#region src/ns/csg.ts
8473
8552
  var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8474
- CSG_VERSION: () => 5,
8553
+ CSG_VERSION: () => 6,
8475
8554
  Evaluator: () => Evaluator,
8476
8555
  add: () => add$1,
8477
8556
  arbitraryClosedProfile: () => arbitraryClosedProfile,
@@ -8486,6 +8565,7 @@ var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8486
8565
  box: () => box$2,
8487
8566
  buildVec: () => buildVec,
8488
8567
  cShapeProfile: () => cShapeProfile,
8568
+ chamfer: () => chamfer$1,
8489
8569
  circle: () => circle$1,
8490
8570
  circleHollowProfile: () => circleHollowProfile,
8491
8571
  circularProfile: () => circularProfile,
package/dist/brepjs.js CHANGED
@@ -17,7 +17,7 @@ import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as get
17
17
  import { a as meshEdges$1, c as meshMultiLOD, d as createMeshCache, i as mesh$1, l as buildMeshCacheKey, n as exportSTEP, o as meshLODs, r as exportSTL, s as meshLODsProgressive, t as exportIGES, u as clearMeshCache } from "./meshFns-CpfeEN1b.js";
18
18
  import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
19
19
  import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, p as makeEllipseArc, r as makeFace, s as assembleWire, u as makeBezierCurve } from "./surfaceBuilders-B7WlmoVr.js";
20
- import { A as toBufferGeometryData, C as chamfer$1, D as shell$1, E as offset$1, M as toLODGeometryData, N as toLODGeometryLevels, O as thicken$1, P as toLineGeometryData, S as chamferDistAngle, T as fillet$2, _ as checkBoolean, a as healFace, b as getNurbsCurveData, c as isValid$1, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, i as heal$1, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, w as draft$1, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-BrrTpxjI.js";
20
+ import { A as toBufferGeometryData, C as chamfer$2, D as shell$1, E as offset$1, M as toLODGeometryData, N as toLODGeometryLevels, O as thicken$1, P as toLineGeometryData, S as chamferDistAngle, T as fillet$2, _ as checkBoolean, a as healFace, b as getNurbsCurveData, c as isValid$1, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, i as heal$1, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, w as draft$1, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-BrrTpxjI.js";
21
21
  import { A as setJointValue, B as walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, G as quatFromAxisAngle, H as circularPattern, I as createAssemblyNode, J as quatRotate, K as quatFromTo, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, Y as createAssembly, _ as exportURDF, a as deserializeHistory, b as inverseKinematics, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, j as setJointValues, k as revoluteJoint, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, q as quatMultiply, r as createHistory, s as getShape, t as thread, u as registerShape, v as importURDF, w as forwardKinematics, x as jointTrajectory, y as jointsFromDH, z as updateNode } from "./threadFns-B6-3UeCZ.js";
22
22
  import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-yZiAeqft.js";
23
23
  import { a as createTypedFinder, i as wireFinder, n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-BiqV-wPK.js";
@@ -1819,8 +1819,8 @@ function hashEdgeRef(h0, ref) {
1819
1819
  * serializable node data (the cache key stays purely structural); it
1820
1820
  * resolves against the materialized target at evaluation, so an upstream
1821
1821
  * parameter edit re-targets the same edge by its face roles. */
1822
- function fillet$1(target, ref, radius) {
1823
- const copied = {
1822
+ function copyEdgeRef(ref) {
1823
+ return {
1824
1824
  origin: ref.origin,
1825
1825
  faceRoles: [ref.faceRoles[0], ref.faceRoles[1]],
1826
1826
  hint: {
@@ -1829,6 +1829,9 @@ function fillet$1(target, ref, radius) {
1829
1829
  midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
1830
1830
  }
1831
1831
  };
1832
+ }
1833
+ function fillet$1(target, ref, radius) {
1834
+ const copied = copyEdgeRef(ref);
1832
1835
  const re = asScalarExpr(radius);
1833
1836
  let h = mix(startHash("Fillet"), target);
1834
1837
  h = hashEdgeRef(h, copied);
@@ -1842,6 +1845,23 @@ function fillet$1(target, ref, radius) {
1842
1845
  freeParams: depsOf(target, re)
1843
1846
  };
1844
1847
  }
1848
+ /** Chamfer the edge named by a lineage ref on the evaluated target. Same
1849
+ * contract as `fillet`: the ref is deep-copied, serializable node data. */
1850
+ function chamfer$1(target, ref, distance) {
1851
+ const copied = copyEdgeRef(ref);
1852
+ const de = asScalarExpr(distance);
1853
+ let h = mix(startHash("Chamfer"), target);
1854
+ h = hashEdgeRef(h, copied);
1855
+ h = mix(h, de);
1856
+ return {
1857
+ kind: "Chamfer",
1858
+ target,
1859
+ ref: copied,
1860
+ distance: de,
1861
+ structuralHash: h,
1862
+ freeParams: depsOf(target, de)
1863
+ };
1864
+ }
1845
1865
  /** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
1846
1866
  * the evaluated result of `target`. Metadata rides beside the geometry: the
1847
1867
  * evaluator re-tags the shared target materialization with an independent
@@ -1994,7 +2014,8 @@ function outputKindOf(node) {
1994
2014
  case "Revolve":
1995
2015
  case "Loft":
1996
2016
  case "Sweep":
1997
- case "Fillet": return "Solid";
2017
+ case "Fillet":
2018
+ case "Chamfer": return "Solid";
1998
2019
  case "Profile": return "Face";
1999
2020
  case "Path": return "Wire";
2000
2021
  case "Compound": return "Compound";
@@ -2644,7 +2665,7 @@ function evalExtrude(node, ctx) {
2644
2665
  function evalRevolve(node, ctx) {
2645
2666
  const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
2646
2667
  if (!a.ok) return a;
2647
- if (a.value <= 0) return err(validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
2668
+ if (!Number.isFinite(a.value) || a.value <= 0) return err(validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
2648
2669
  const deg = Math.min(a.value, 360);
2649
2670
  const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : ok([
2650
2671
  0,
@@ -3005,7 +3026,7 @@ function evalColor(node, ctx) {
3005
3026
  function evalFillet(node, ctx) {
3006
3027
  const radius = evalScalar(node.radius, ctx.env, "Fillet.radius");
3007
3028
  if (!radius.ok) return radius;
3008
- if (radius.value <= 0) return err(validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
3029
+ if (!Number.isFinite(radius.value) || radius.value <= 0) return err(validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
3009
3030
  const t = ctx.evalNode(node.target);
3010
3031
  if (!t.ok) return t;
3011
3032
  if (!isSolid(t.value)) return err(validationError("CSG_FILLET_TARGET", "Fillet.target did not produce a Solid"));
@@ -3017,6 +3038,22 @@ function evalFillet(node, ctx) {
3017
3038
  return fillet$2(solid.value, [resolved.entity], radius.value);
3018
3039
  }
3019
3040
  //#endregion
3041
+ //#region src/csg/evaluators/chamfer.ts
3042
+ function evalChamfer(node, ctx) {
3043
+ const distance = evalScalar(node.distance, ctx.env, "Chamfer.distance");
3044
+ if (!distance.ok) return distance;
3045
+ if (!Number.isFinite(distance.value) || distance.value <= 0) return err(validationError("CSG_CHAMFER_DISTANCE", `Chamfer.distance must be positive, got ${distance.value}`));
3046
+ const t = ctx.evalNode(node.target);
3047
+ if (!t.ok) return t;
3048
+ if (!isSolid(t.value)) return err(validationError("CSG_CHAMFER_TARGET", "Chamfer.target did not produce a Solid"));
3049
+ const solid = validSolid(t.value);
3050
+ if (!solid.ok) return err(validationError("CSG_CHAMFER_TARGET", solid.error));
3051
+ const resolved = resolveRefIn(node.ref, t.value);
3052
+ if (!resolved.ok) return err(validationError("CSG_CHAMFER_REF", `Chamfer.ref did not resolve: ${resolved.reason}`));
3053
+ if (!isEdge(resolved.entity)) return err(validationError("CSG_CHAMFER_REF", "Chamfer.ref resolved to a non-edge"));
3054
+ return chamfer$2(solid.value, [resolved.entity], distance.value);
3055
+ }
3056
+ //#endregion
3020
3057
  //#region src/csg/evaluate.ts
3021
3058
  function dispatch(node, ctx) {
3022
3059
  switch (node.kind) {
@@ -3041,6 +3078,19 @@ function dispatch(node, ctx) {
3041
3078
  case "Mirror": return evalMirror(node, ctx);
3042
3079
  case "Compound": return evalCompound(node, ctx);
3043
3080
  case "Instance": return evalInstance(node, ctx);
3081
+ case "Extrude":
3082
+ case "Revolve":
3083
+ case "Loft":
3084
+ case "Path":
3085
+ case "Sweep":
3086
+ case "Profile":
3087
+ case "Color":
3088
+ case "Fillet":
3089
+ case "Chamfer": return dispatchFeature(node, ctx);
3090
+ }
3091
+ }
3092
+ function dispatchFeature(node, ctx) {
3093
+ switch (node.kind) {
3044
3094
  case "Extrude": return evalExtrude(node, ctx);
3045
3095
  case "Revolve": return evalRevolve(node, ctx);
3046
3096
  case "Loft": return evalLoft(node, ctx);
@@ -3049,6 +3099,7 @@ function dispatch(node, ctx) {
3049
3099
  case "Profile": return evalProfile(node, ctx);
3050
3100
  case "Color": return evalColor(node, ctx);
3051
3101
  case "Fillet": return evalFillet(node, ctx);
3102
+ case "Chamfer": return evalChamfer(node, ctx);
3052
3103
  }
3053
3104
  }
3054
3105
  function hashExprValue(h, v) {
@@ -3458,7 +3509,7 @@ function withEvaluator(options, fn) {
3458
3509
  var MIN_CSG_VERSION = 1;
3459
3510
  function toJSON(node) {
3460
3511
  return {
3461
- csgVersion: 5,
3512
+ csgVersion: 6,
3462
3513
  root: nodeToJson(node)
3463
3514
  };
3464
3515
  }
@@ -3614,6 +3665,17 @@ function segmentToJson(s) {
3614
3665
  };
3615
3666
  }
3616
3667
  }
3668
+ function edgeRefToJson(ref) {
3669
+ return {
3670
+ origin: ref.origin,
3671
+ faceRoles: [...ref.faceRoles],
3672
+ hint: {
3673
+ entityType: "edge",
3674
+ length: ref.hint.length,
3675
+ midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
3676
+ }
3677
+ };
3678
+ }
3617
3679
  function contourToJson(c) {
3618
3680
  return {
3619
3681
  start: exprToJson(c.start),
@@ -3691,17 +3753,15 @@ function nodeToJson(n) {
3691
3753
  if (n.kind === "Fillet") return {
3692
3754
  kind: "Fillet",
3693
3755
  target: nodeToJson(n.target),
3694
- ref: {
3695
- origin: n.ref.origin,
3696
- faceRoles: [...n.ref.faceRoles],
3697
- hint: {
3698
- entityType: "edge",
3699
- length: n.ref.hint.length,
3700
- midpoint: n.ref.hint.midpoint ? [...n.ref.hint.midpoint] : void 0
3701
- }
3702
- },
3756
+ ref: edgeRefToJson(n.ref),
3703
3757
  radius: exprToJson(n.radius)
3704
3758
  };
3759
+ if (n.kind === "Chamfer") return {
3760
+ kind: "Chamfer",
3761
+ target: nodeToJson(n.target),
3762
+ ref: edgeRefToJson(n.ref),
3763
+ distance: exprToJson(n.distance)
3764
+ };
3705
3765
  if (n.kind === "Compound") return {
3706
3766
  kind: "Compound",
3707
3767
  children: n.children.map(nodeToJson)
@@ -3745,7 +3805,7 @@ function readVec2(v, where) {
3745
3805
  function fromJSON(envelope) {
3746
3806
  if (!isObj(envelope)) return bad("input is not an object");
3747
3807
  const v = envelope["csgVersion"];
3748
- if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 5) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..5)`);
3808
+ if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 6) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..6)`);
3749
3809
  const root = envelope["root"];
3750
3810
  return readNode(root);
3751
3811
  }
@@ -3861,6 +3921,7 @@ function readNode(j) {
3861
3921
  case "Profile": return readProfile(j);
3862
3922
  case "Color": return readColor(j);
3863
3923
  case "Fillet": return readFillet(j);
3924
+ case "Chamfer": return readChamfer(j);
3864
3925
  default: return bad(`unknown node kind: ${String(kind)}`);
3865
3926
  }
3866
3927
  }
@@ -4110,28 +4171,23 @@ function readContour(j, where) {
4110
4171
  }
4111
4172
  return ok(contour(start.value, segments));
4112
4173
  }
4113
- function readFillet(j) {
4114
- const target = readNode(j["target"]);
4115
- if (!target.ok) return target;
4116
- const radius = readExpr(j["radius"]);
4117
- if (!radius.ok) return radius;
4118
- const ref = j["ref"];
4119
- if (!isObj(ref)) return bad("Fillet.ref: not an object");
4120
- const origin = ref["origin"];
4121
- if (!isString(origin)) return bad("Fillet.ref.origin: not a string");
4122
- const roles = ref["faceRoles"];
4123
- if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad("Fillet.ref.faceRoles: expected two role strings");
4124
- const hintRaw = ref["hint"];
4125
- if (!isObj(hintRaw)) return bad("Fillet.ref.hint: not an object");
4174
+ function readEdgeRef(j, where) {
4175
+ if (!isObj(j)) return bad(`${where}: not an object`);
4176
+ const origin = j["origin"];
4177
+ if (!isString(origin)) return bad(`${where}.origin: not a string`);
4178
+ const roles = j["faceRoles"];
4179
+ if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad(`${where}.faceRoles: expected two role strings`);
4180
+ const hintRaw = j["hint"];
4181
+ if (!isObj(hintRaw)) return bad(`${where}.hint: not an object`);
4126
4182
  const length = hintRaw["length"];
4127
- if (length !== void 0 && !isNumber$1(length)) return bad("Fillet.ref.hint.length");
4183
+ if (length !== void 0 && !isNumber$1(length)) return bad(`${where}.hint.length`);
4128
4184
  let midpoint;
4129
4185
  if (hintRaw["midpoint"] !== void 0) {
4130
- const m = readVec3(hintRaw["midpoint"], "Fillet.ref.hint.midpoint");
4186
+ const m = readVec3(hintRaw["midpoint"], `${where}.hint.midpoint`);
4131
4187
  if (!m.ok) return m;
4132
4188
  midpoint = m.value;
4133
4189
  }
4134
- return ok(fillet$1(target.value, {
4190
+ return ok({
4135
4191
  origin,
4136
4192
  faceRoles: [roles[0], roles[1]],
4137
4193
  hint: {
@@ -4139,7 +4195,25 @@ function readFillet(j) {
4139
4195
  length,
4140
4196
  midpoint
4141
4197
  }
4142
- }, radius.value));
4198
+ });
4199
+ }
4200
+ function readFillet(j) {
4201
+ const target = readNode(j["target"]);
4202
+ if (!target.ok) return target;
4203
+ const radius = readExpr(j["radius"]);
4204
+ if (!radius.ok) return radius;
4205
+ const ref = readEdgeRef(j["ref"], "Fillet.ref");
4206
+ if (!ref.ok) return ref;
4207
+ return ok(fillet$1(target.value, ref.value, radius.value));
4208
+ }
4209
+ function readChamfer(j) {
4210
+ const target = readNode(j["target"]);
4211
+ if (!target.ok) return target;
4212
+ const distance = readExpr(j["distance"]);
4213
+ if (!distance.ok) return distance;
4214
+ const ref = readEdgeRef(j["ref"], "Chamfer.ref");
4215
+ if (!ref.ok) return ref;
4216
+ return ok(chamfer$1(target.value, ref.value, distance.value));
4143
4217
  }
4144
4218
  function readColor(j) {
4145
4219
  const target = readNode(j["target"]);
@@ -4300,7 +4374,8 @@ function optimizeNode(n) {
4300
4374
  case "Profile":
4301
4375
  case "Path":
4302
4376
  case "Color":
4303
- case "Fillet": return optimizeFeature(n);
4377
+ case "Fillet":
4378
+ case "Chamfer": return optimizeFeature(n);
4304
4379
  }
4305
4380
  }
4306
4381
  function optimizeFeature(n) {
@@ -4316,6 +4391,7 @@ function optimizeFeature(n) {
4316
4391
  case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
4317
4392
  case "Color": return color(optimizeNode(n.target), [...n.color]);
4318
4393
  case "Fillet": return fillet$1(optimizeNode(n.target), n.ref, foldExpr(n.radius));
4394
+ case "Chamfer": return chamfer$1(optimizeNode(n.target), n.ref, foldExpr(n.distance));
4319
4395
  }
4320
4396
  }
4321
4397
  function optimizeTransform(n) {
@@ -4426,7 +4502,8 @@ function rebuildChildren(n, pred, repl) {
4426
4502
  case "Loft":
4427
4503
  case "Sweep":
4428
4504
  case "Color":
4429
- case "Fillet": return rebuildFeature(n, pred, repl);
4505
+ case "Fillet":
4506
+ case "Chamfer": return rebuildFeature(n, pred, repl);
4430
4507
  }
4431
4508
  }
4432
4509
  function rebuildFeature(n, pred, repl) {
@@ -4440,6 +4517,7 @@ function rebuildFeature(n, pred, repl) {
4440
4517
  case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
4441
4518
  case "Color": return color(walk(n.target, pred, repl), [...n.color]);
4442
4519
  case "Fillet": return fillet$1(walk(n.target, pred, repl), n.ref, n.radius);
4520
+ case "Chamfer": return chamfer$1(walk(n.target, pred, repl), n.ref, n.distance);
4443
4521
  }
4444
4522
  }
4445
4523
  function forEachNode(root, fn) {
@@ -4470,7 +4548,8 @@ function childrenOf(n) {
4470
4548
  case "Scale":
4471
4549
  case "Mirror":
4472
4550
  case "Color":
4473
- case "Fillet": return [n.target];
4551
+ case "Fillet":
4552
+ case "Chamfer": return [n.target];
4474
4553
  case "Compound": return n.children;
4475
4554
  case "Instance": return [n.source];
4476
4555
  case "Extrude":
@@ -7075,7 +7154,7 @@ function chamfer(shape, edgesOrDistance, maybeDistance) {
7075
7154
  const selectedEdges = edges ?? getEdges(s);
7076
7155
  return chamferDistAngle(s, [...selectedEdges], normalized.distance, normalized.angle);
7077
7156
  }
7078
- return chamfer$1(s, edges, normalized.distance);
7157
+ return chamfer$2(s, edges, normalized.distance);
7079
7158
  }
7080
7159
  /** Create a hollow shell by removing faces and offsetting remaining walls. */
7081
7160
  function shell(shape, faces, thickness, options) {
@@ -8480,7 +8559,7 @@ var patterns_exports = /* @__PURE__ */ __exportAll({
8480
8559
  //#endregion
8481
8560
  //#region src/ns/csg.ts
8482
8561
  var csg_exports = /* @__PURE__ */ __exportAll({
8483
- CSG_VERSION: () => 5,
8562
+ CSG_VERSION: () => 6,
8484
8563
  Evaluator: () => Evaluator,
8485
8564
  add: () => add$1,
8486
8565
  arbitraryClosedProfile: () => arbitraryClosedProfile,
@@ -8495,6 +8574,7 @@ var csg_exports = /* @__PURE__ */ __exportAll({
8495
8574
  box: () => box$2,
8496
8575
  buildVec: () => buildVec,
8497
8576
  cShapeProfile: () => cShapeProfile,
8577
+ chamfer: () => chamfer$1,
8498
8578
  circle: () => circle$1,
8499
8579
  circleHollowProfile: () => circleHollowProfile,
8500
8580
  circularProfile: () => circularProfile,
@@ -3,7 +3,7 @@ import { Contour, Segment2D } from './segments.js';
3
3
  import { Matrix4x4 } from '../core/types.js';
4
4
  import { ColorInput } from '../topology/metadata/colorFns.js';
5
5
  import { EdgeRef } from '../topology/shapeRef/shapeRefTypes.js';
6
- import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
6
+ import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, ChamferNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
7
7
  export declare function box(x: ScalarInput, y: ScalarInput, z: ScalarInput): BoxNode;
8
8
  export declare function sphere(radius: ScalarInput): SphereNode;
9
9
  export declare function cylinder(radius: ScalarInput, height: ScalarInput): CylinderNode;
@@ -37,11 +37,10 @@ export interface MirrorOptions {
37
37
  }
38
38
  export declare function mirror(target: IRNode, options?: MirrorOptions): MirrorNode;
39
39
  export declare function extrude(profile: FaceNode, vector: Vec3Input): ExtrudeNode;
40
- /** Fillet the edge named by a lineage ref on the evaluated target. The ref is
41
- * serializable node data (the cache key stays purely structural); it
42
- * resolves against the materialized target at evaluation, so an upstream
43
- * parameter edit re-targets the same edge by its face roles. */
44
40
  export declare function fillet(target: IRNode, ref: EdgeRef, radius: ScalarInput): FilletNode;
41
+ /** Chamfer the edge named by a lineage ref on the evaluated target. Same
42
+ * contract as `fillet`: the ref is deep-copied, serializable node data. */
43
+ export declare function chamfer(target: IRNode, ref: EdgeRef, distance: ScalarInput): ChamferNode;
45
44
  /** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
46
45
  * the evaluated result of `target`. Metadata rides beside the geometry: the
47
46
  * evaluator re-tags the shared target materialization with an independent
@@ -0,0 +1,5 @@
1
+ import { Result } from '../../core/result.js';
2
+ import { AnyShape, Dimension } from '../../core/shapeTypes.js';
3
+ import { ChamferNode } from '../types.js';
4
+ import { EvalContext } from './context.js';
5
+ export declare function evalChamfer(node: ChamferNode, ctx: EvalContext): Result<AnyShape<Dimension>>;
@@ -5,9 +5,9 @@
5
5
  * parameterize via named expression bindings; evaluate against the active
6
6
  * kernel with subtree-level cache reuse for incremental parametric edits.
7
7
  */
8
- export { box, sphere, cylinder, cone, torus, polygon, circle, line, vertex, emptySolid, emptyFace, emptyWire, fuse, cut, intersect, fuseAll, cutAll, translate, rotate, scale, mirror, extrude, revolve, loft, sweep, profile, path, color, fillet, compound, instance, type RevolveOptions, type LoftOptions, type SweepNodeOptions, type RotateOptions, type ScaleOptions, type MirrorOptions, } from './builders.js';
8
+ export { box, sphere, cylinder, cone, torus, polygon, circle, line, vertex, emptySolid, emptyFace, emptyWire, fuse, cut, intersect, fuseAll, cutAll, translate, rotate, scale, mirror, extrude, revolve, loft, sweep, profile, path, color, fillet, chamfer, compound, instance, type RevolveOptions, type LoftOptions, type SweepNodeOptions, type RotateOptions, type ScaleOptions, type MirrorOptions, } from './builders.js';
9
9
  export { numLit, vec3Lit, vec2Lit, param, binOp, unaryOp, component, buildVec, add, mul, asScalarExpr, asVec3Expr, asVec2Expr, type Expr, type ExprValue, type Env, type ScalarInput, type Vec3Input, type Vec2Input, type BinaryOp, type UnaryOp, } from './expressions.js';
10
- export type { IRNode, NodeKind, OutputKind, PrimitiveNode, BooleanNode, TransformIRNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
10
+ export type { IRNode, NodeKind, OutputKind, PrimitiveNode, BooleanNode, TransformIRNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, ChamferNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
11
11
  export { outputKindOf } from './types.js';
12
12
  export { lineTo, arcTo, bezierTo, ellipseArcTo, contour, type Contour, type Segment2D, type SegmentOptions, type EllipseArcOptions, } from './segments.js';
13
13
  export { rectangularProfile, circularProfile, iBeamProfile, asymmetricIProfile, lShapeProfile, tShapeProfile, uShapeProfile, zShapeProfile, cShapeProfile, ellipseProfile, trapeziumProfile, rectangleHollowProfile, circleHollowProfile, arbitraryClosedProfile, arbitraryProfileWithVoids, type IBeamParams, type AsymmetricIParams, type LShapeParams, type TShapeParams, type UShapeParams, type ZShapeParams, type CShapeParams, type TrapeziumParams, type RectangleHollowParams, type CircleHollowParams, } from './profiles.js';
@@ -1,6 +1,6 @@
1
1
  import { Result } from '../core/result.js';
2
2
  import { IRNode } from './types.js';
3
- export declare const CSG_VERSION = 5;
3
+ export declare const CSG_VERSION = 6;
4
4
  export interface CsgEnvelope {
5
5
  readonly csgVersion: number;
6
6
  readonly root: unknown;
@@ -134,6 +134,13 @@ export interface FilletNode extends IRNodeBase {
134
134
  readonly ref: EdgeRef;
135
135
  readonly radius: Expr;
136
136
  }
137
+ export interface ChamferNode extends IRNodeBase {
138
+ readonly kind: 'Chamfer';
139
+ readonly target: IRNode;
140
+ /** Serializable lineage ref naming the edge by its two adjacent face roles. */
141
+ readonly ref: EdgeRef;
142
+ readonly distance: Expr;
143
+ }
137
144
  export interface ColorNode extends IRNodeBase {
138
145
  readonly kind: 'Color';
139
146
  readonly target: IRNode;
@@ -186,7 +193,7 @@ export interface InstanceNode extends IRNodeBase {
186
193
  export type PrimitiveNode = BoxNode | SphereNode | CylinderNode | ConeNode | TorusNode | PolygonNode | CircleNode | LineNode | VertexLitNode | EmptyNode;
187
194
  export type BooleanNode = FuseNode | CutNode | IntersectNode | FuseAllNode | CutAllNode;
188
195
  export type TransformIRNode = TranslateNode | RotateNode | ScaleNode | MirrorNode;
189
- export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | SweepNode | ProfileNode | PathNode | ColorNode | FilletNode | CompoundNode | InstanceNode;
196
+ export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | SweepNode | ProfileNode | PathNode | ColorNode | FilletNode | ChamferNode | CompoundNode | InstanceNode;
190
197
  export type NodeKind = IRNode['kind'];
191
198
  export type AnyNode = IRNode;
192
199
  /** Nodes that produce a 3D solid. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs",
3
- "version": "18.131.0",
3
+ "version": "18.133.0",
4
4
  "description": "Web CAD library with pluggable geometry kernel",
5
5
  "keywords": [
6
6
  "cad",