opengeometry 2.0.9 → 2.0.11

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <a href="https://opengeometry.io">
2
+ <a href="https://opengeometry.io?utm_source=github">
3
3
  <img src="https://raw.githubusercontent.com/OpenGeometry-io/.github/main/profile/opengeometryTextLogo.png" alt="OpenGeometry" />
4
4
  </a>
5
5
  </p>
@@ -7,24 +7,24 @@
7
7
  <h1 align="center">OpenGeometry</h1>
8
8
 
9
9
  <p align="center">
10
- <strong>Browser-native CAD kernel built with Rust, WebAssembly, and Three.js.</strong>
10
+ <strong>Browser-native CAD kernel for Web Apps and AI CAD built with Rust, WebAssembly, and Three.js.</strong>
11
11
  </p>
12
12
 
13
13
  <p align="center">
14
14
  <a href="https://www.npmjs.com/package/opengeometry"><img src="https://img.shields.io/npm/v/opengeometry?style=flat-square&color=4460FF&label=npm" alt="npm version" /></a>
15
15
  <a href="https://github.com/OpenGeometry-io/OpenGeometry/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/opengeometry-io/opengeometry?style=flat-square" alt="License" /></a>
16
- <a href="https://discord.com/invite/cZY2Vm6E"><img src="https://img.shields.io/badge/Discord-Join%20us-5865F2?style=flat-square&logo=discord&logoColor=white" alt="Discord" /></a>
16
+ <a href="https://discord.gg/9wJpbfgGGA"><img src="https://img.shields.io/badge/Discord-Join%20us-5865F2?style=flat-square&logo=discord&logoColor=white" alt="Discord" /></a>
17
17
  <a href="https://x.com/openGeometry"><img src="https://img.shields.io/badge/Twitter-Follow-1DA1F2?style=flat-square&logo=x&logoColor=white" alt="Twitter" /></a>
18
18
  <a href="https://linkedin.com/company/openGeometry"><img src="https://img.shields.io/badge/LinkedIn-Connect-0A66C2?style=flat-square&logo=linkedin&logoColor=white" alt="LinkedIn" /></a>
19
19
  </p>
20
20
 
21
21
  <p align="center">
22
- <a href="https://opengeometry.io">Website</a> · <a href="https://docs.opengeometry.io">Documentation</a> · <a href="https://demo.opengeometry.io">Live Demos</a> · <a href="https://opengeometry.io/blog">Blog</a> · <a href="https://www.npmjs.com/package/opengeometry">npm</a>
22
+ <a href="https://opengeometry.io?utm_source=github">Website</a> · <a href="https://docs.opengeometry.io/OpenGeometry?utm_source=github">Documentation</a> · <a href="https://demos.opengeometry.io?utm_source=github">Live Demos</a> · <a href="https://blog.opengeometry.io?utm_source=github">Blog</a> · <a href="https://www.npmjs.com/package/opengeometry">npm</a>
23
23
  </p>
24
24
 
25
25
  ---
26
26
 
27
- > **Actively maintained and growing.** We're building OpenGeometry in the open. APIs, examples, and package structure are evolving, we are actively improving and expanding the project. Star the repo to follow along. If you have questions or want to get involved, join the [Discord](https://discord.com/invite/cZY2Vm6E) or check out the [issues](https://github.com/OpenGeometry-io/OpenGeometry/issues)
27
+ > **Actively maintained and growing.** We're building OpenGeometry in the open. APIs, examples, and package structure are evolving, we are actively improving and expanding the project. Star the repo to follow along. If you have questions or want to get involved, join the [Discord](https://discord.com/invite/9wJpbfgGGA) or check out the [issues](https://github.com/OpenGeometry-io/OpenGeometry/issues)
28
28
 
29
29
  ---
30
30
 
@@ -55,15 +55,15 @@ Good examples include:
55
55
 
56
56
  - AI copilots that translate user intent into concrete modeling operations
57
57
  - prompt-to-geometry or agent-driven editing flows inside browser CAD tools
58
- - AI-assisted design interfaces that still need reliable extrusion, boolean, projection, and export workflows
58
+ - AI first design interfaces that still need reliable extrusion, boolean, projection, and export workflows
59
59
 
60
60
  ## Good fit / Not the right fit
61
61
 
62
62
  **Good fit**
63
63
 
64
- - browser CAD, AEC/BIM, and geometry-heavy web applications
64
+ - browser CAD, AEC/BIM, Mechanical, and geometry-heavy web applications
65
65
  - Three.js-based modeling tools that need a real kernel behind them
66
- - AI-assisted CAD frontends that need deterministic geometry execution in the browser
66
+ - AI first CAD frontends that need deterministic geometry execution in the browser
67
67
 
68
68
  **Not the default fit**
69
69
 
@@ -77,10 +77,10 @@ If you are using ChatGPT, Claude, Gemini, Copilot, or other coding agents on thi
77
77
 
78
78
  - [AGENTS.md](./AGENTS.md) - single source of truth for all coding agents (architecture, commands, gotchas, behavioral rules)
79
79
  - [README.md](./README.md) - product overview, positioning, and quick start
80
- - [Quickstart](https://docs.opengeometry.io/quickstart)
81
- - [Three.js integration](https://docs.opengeometry.io/integration/threejs)
82
- - [Boolean operations](https://docs.opengeometry.io/api/operations/boolean-operations)
83
- - [Extrude](https://docs.opengeometry.io/api/operations/extrude)
80
+ - [Quickstart](https://docs.opengeometry.io/OpenGeometry/quickstart)
81
+ - [Installation](https://docs.opengeometry.io/OpenGeometry/installation)
82
+ - [Boolean operations](https://docs.opengeometry.io/OpenGeometry/concepts/booleans)
83
+ - [Extrude](https://docs.opengeometry.io/OpenGeometry/api/operations/extrude)
84
84
 
85
85
  ### What you can do today
86
86
 
@@ -96,7 +96,7 @@ If you are using ChatGPT, Claude, Gemini, Copilot, or other coding agents on thi
96
96
 
97
97
  See OpenGeometry in action — interactive, browser-based demos showcasing the kernel's capabilities:
98
98
 
99
- **[demo.opengeometry.io](https://demo.opengeometry.io)**
99
+ **[demos.opengeometry.io](https://demos.opengeometry.io)**
100
100
 
101
101
  Demos include primitives rendering, shape generation, sweep operations, boolean operations, file exports, and more. All running client-side via WebAssembly.
102
102
 
@@ -139,7 +139,7 @@ cuboid.setPlacement({
139
139
 
140
140
  Scenegraph behavior is snapshot-based: `add*ToScene` captures geometry at insert time. If you change placement/config later, push updates explicitly via `replaceBrepEntityInScene` or `refreshBrepEntityInScene`.
141
141
 
142
- For a complete walkthrough, see the [Quick Start guide](https://docs.opengeometry.io/quickstart) or clone the [quickstart-js](https://github.com/OpenGeometry-io/quickstart-js) repo.
142
+ For a complete walkthrough, see the [Quick Start guide](https://docs.opengeometry.io/OpenGeometry/quickstart) or clone the [quickstart-js](https://github.com/OpenGeometry-io/quickstart-js) repo.
143
143
 
144
144
  ## Documentation
145
145
 
@@ -148,10 +148,10 @@ Full API reference, guides, and concepts are available at:
148
148
  **[docs.opengeometry.io](https://docs.opengeometry.io)**
149
149
 
150
150
  Key pages:
151
- - [Installation](https://docs.opengeometry.io/installation)
152
- - [Quick Start](https://docs.opengeometry.io/quickstart)
153
- - [Architecture & Concepts](https://docs.opengeometry.io/concepts/architecture)
154
- - [API Reference](https://docs.opengeometry.io/api)
151
+ - [Installation](https://docs.opengeometry.io/OpenGeometry/installation)
152
+ - [Quick Start](https://docs.opengeometry.io/OpenGeometry/quickstart)
153
+ - [Architecture & Concepts](https://docs.opengeometry.io/OpenGeometry/concepts/architecture)
154
+ - [API Reference](https://docs.opengeometry.io/OpenGeometry/api/)
155
155
 
156
156
  ## Repository Structure
157
157
 
@@ -165,7 +165,7 @@ docs/ Documentation source (Mintlify)
165
165
 
166
166
  ## Building from Source
167
167
 
168
- **Prerequisites:** Node.js, npm, Rust toolchain, `wasm-pack`
168
+ **Prerequisites:** Node.js, npm, Rust 1.89.0+ with `wasm32-unknown-unknown`, `wasm-pack`
169
169
 
170
170
  ```bash
171
171
  # Install dependencies
@@ -191,28 +191,25 @@ npm test
191
191
  - Contributors interested in the **Rust → WASM geometry pipeline**
192
192
  - Anyone exploring **open-source CAD kernel internals**
193
193
 
194
- If you just want a quick look, start with the [hosted demos](https://demo.opengeometry.io) or the [quickstart repo](https://github.com/OpenGeometry-io/quickstart-js).
194
+ If you just want a quick look, start with the [hosted demos](https://demos.opengeometry.io) or the [quickstart repo](https://github.com/OpenGeometry-io/quickstart-js).
195
195
 
196
196
  ## Community
197
197
 
198
198
  We'd love to have you involved — whether you're using OpenGeometry, building on it, or just curious.
199
199
 
200
- - **[Discord](https://discord.com/invite/cZY2Vm6E)** — Chat with the team and community
200
+ - **[Discord](https://discord.com/invite/9wJpbfgGGA)** — Chat with the team and community
201
201
  - **[Twitter / X](https://x.com/openGeometry)** — Updates and announcements
202
202
  - **[LinkedIn](https://linkedin.com/company/openGeometry)** — Company updates
203
203
  - **[GitHub Issues](https://github.com/OpenGeometry-io/OpenGeometry/issues)** — Bug reports and feature requests
204
- - **[Blog](https://opengeometry.io/blog)** — Deep dives and release notes
204
+ - **[Blog](https://blog.opengeometry.io?utm_source=github)** — Deep dives and release notes
205
205
 
206
206
  ## Contributing
207
207
 
208
- OpenGeometry is open source under the [MPL-2.0 license](./LICENSE.md). Contributions are welcome — check the [issues](https://github.com/OpenGeometry-io/OpenGeometry/issues) for good starting points or open a discussion on [Discord](https://discord.com/invite/cZY2Vm6E).
208
+ OpenGeometry is open source under the [MPL-2.0 license](./LICENSE.md). Contributions are welcome — check the [issues](https://github.com/OpenGeometry-io/OpenGeometry/issues) for good starting points or open a discussion on [Discord](https://discord.com/invite/9wJpbfgGGA).
209
209
 
210
210
  ## AI Agent Docs Policy
211
211
 
212
- - All AI coding agent instructions live in a single file: [AGENTS.md](./AGENTS.md).
213
- `CLAUDE.md` and `.github/copilot-instructions.md` are thin redirects to it.
214
- - Stable architecture and domain notes are tracked in [`knowledge/`](./knowledge/).
215
- - User-facing docs live in [`docs/`](./docs/) (Mintlify source).
212
+ - If you're an AI agent, start with [AGENTS.md](./AGENTS.md) for architecture, commands, and behavioral rules.
216
213
  - Agents should not create planning, handoff, or runbook files during a task. The
217
214
  conversation, the diff, and the commit message are the handoff.
218
215
 
package/index.d.ts CHANGED
@@ -97,6 +97,6 @@ export * from "./src/freeform/index.js";
97
97
  */
98
98
  export * from "./src/editor/index.js";
99
99
  /**
100
- * Kernel-backed modeling operations.
100
+ * Kernel-backed modeling operations (incl. analytic polyline offset → regions).
101
101
  */
102
102
  export * from "./src/operations/index.js";
package/index.js CHANGED
@@ -209,16 +209,42 @@ function getStringFromWasm0(ptr, len) {
209
209
  ptr = ptr >>> 0;
210
210
  return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
211
211
  }
212
- function _assertClass(instance, klass) {
213
- if (!(instance instanceof klass)) {
214
- throw new Error(`expected instance of ${klass.name}`);
215
- }
216
- }
217
212
  function takeFromExternrefTable0(idx) {
218
213
  const value = wasm.__wbindgen_export_2.get(idx);
219
214
  wasm.__externref_table_dealloc(idx);
220
215
  return value;
221
216
  }
217
+ /**
218
+ * @param {string} local_brep_serialized
219
+ * @param {number} height
220
+ * @returns {string}
221
+ */
222
+ function extrudeBrepFace$1(local_brep_serialized, height) {
223
+ let deferred3_0;
224
+ let deferred3_1;
225
+ try {
226
+ const ptr0 = passStringToWasm0(local_brep_serialized, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
227
+ const len0 = WASM_VECTOR_LEN;
228
+ const ret = wasm.extrudeBrepFace(ptr0, len0, height);
229
+ var ptr2 = ret[0];
230
+ var len2 = ret[1];
231
+ if (ret[3]) {
232
+ ptr2 = 0;
233
+ len2 = 0;
234
+ throw takeFromExternrefTable0(ret[2]);
235
+ }
236
+ deferred3_0 = ptr2;
237
+ deferred3_1 = len2;
238
+ return getStringFromWasm0(ptr2, len2);
239
+ } finally {
240
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
241
+ }
242
+ }
243
+ function _assertClass(instance, klass) {
244
+ if (!(instance instanceof klass)) {
245
+ throw new Error(`expected instance of ${klass.name}`);
246
+ }
247
+ }
222
248
  let cachedFloat64ArrayMemory0 = null;
223
249
  function getFloat64ArrayMemory0() {
224
250
  if (cachedFloat64ArrayMemory0 === null || cachedFloat64ArrayMemory0.byteLength === 0) {
@@ -239,9 +265,63 @@ function passArrayJsValueToWasm0(array, malloc) {
239
265
  WASM_VECTOR_LEN = array.length;
240
266
  return ptr;
241
267
  }
268
+ function getArrayJsValueFromWasm0(ptr, len) {
269
+ ptr = ptr >>> 0;
270
+ const mem = getDataViewMemory0();
271
+ const result = [];
272
+ for (let i = ptr; i < ptr + 4 * len; i += 4) {
273
+ result.push(wasm.__wbindgen_export_2.get(mem.getUint32(i, true)));
274
+ }
275
+ wasm.__externref_drop_slice(ptr, len);
276
+ return result;
277
+ }
242
278
  function isLikeNone(x) {
243
279
  return x === undefined || x === null;
244
280
  }
281
+ function passArrayF64ToWasm0(arg, malloc) {
282
+ const ptr = malloc(arg.length * 8, 8) >>> 0;
283
+ getFloat64ArrayMemory0().set(arg, ptr / 8);
284
+ WASM_VECTOR_LEN = arg.length;
285
+ return ptr;
286
+ }
287
+ /**
288
+ * Wasm entry point: offset a centreline by `width` into stroked regions via the
289
+ * deterministic analytic offset. `centreline_flat` is `[x0,y0,z0, …]`. Returns
290
+ * CW-outer / CCW-hole regions, canonicalised; empty (does NOT throw) when degenerate.
291
+ * @param {Float64Array} centreline_flat
292
+ * @param {number} width
293
+ * @param {boolean} closed
294
+ * @param {number} miter_limit
295
+ * @returns {OGOffsetRegionsResult}
296
+ */
297
+ function offsetPolylineRegions$1(centreline_flat, width, closed, miter_limit) {
298
+ const ptr0 = passArrayF64ToWasm0(centreline_flat, wasm.__wbindgen_malloc);
299
+ const len0 = WASM_VECTOR_LEN;
300
+ const ret = wasm.offsetPolylineRegions(ptr0, len0, width, closed, miter_limit);
301
+ if (ret[2]) {
302
+ throw takeFromExternrefTable0(ret[1]);
303
+ }
304
+ return OGOffsetRegionsResult.__wrap(ret[0]);
305
+ }
306
+
307
+ /**
308
+ * Wasm entry point: merge a GROUP of separate polylines (a crossing T / X / L
309
+ * overlap) into one clean stroked region by nonzero-winding union of their mitered
310
+ * bands. `polylines_json` is `[{centreline:[x,y,z,…], width, closed}, …]`. Returns
311
+ * CW-outer / CCW-hole regions (one or more); empty when nothing is buildable.
312
+ * @param {string} polylines_json
313
+ * @returns {OGOffsetRegionsResult}
314
+ */
315
+ function offsetPolylineGroupRegions$1(polylines_json) {
316
+ const ptr0 = passStringToWasm0(polylines_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
317
+ const len0 = WASM_VECTOR_LEN;
318
+ const ret = wasm.offsetPolylineGroupRegions(ptr0, len0);
319
+ if (ret[2]) {
320
+ throw takeFromExternrefTable0(ret[1]);
321
+ }
322
+ return OGOffsetRegionsResult.__wrap(ret[0]);
323
+ }
324
+
245
325
  /**
246
326
  * Wasm entry point for union.
247
327
  * @param {string} lhs_brep_serialized
@@ -327,40 +407,22 @@ function booleanSubtractionMany(lhs_brep_serialized, cutters_brep_serialized, op
327
407
  }
328
408
 
329
409
  /**
330
- * @param {string} local_brep_serialized
331
- * @param {number} height
332
- * @returns {string}
410
+ * Wasm entry point for array-backed batched union. Accepts a JSON array of
411
+ * serialized BReps and folds them with `batch_union` in one boundary crossing.
412
+ * @param {string} operands_brep_serialized
413
+ * @param {string | null} [options_json]
414
+ * @returns {OGBooleanResult}
333
415
  */
334
- function extrudeBrepFace$1(local_brep_serialized, height) {
335
- let deferred3_0;
336
- let deferred3_1;
337
- try {
338
- const ptr0 = passStringToWasm0(local_brep_serialized, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
339
- const len0 = WASM_VECTOR_LEN;
340
- const ret = wasm.extrudeBrepFace(ptr0, len0, height);
341
- var ptr2 = ret[0];
342
- var len2 = ret[1];
343
- if (ret[3]) {
344
- ptr2 = 0;
345
- len2 = 0;
346
- throw takeFromExternrefTable0(ret[2]);
347
- }
348
- deferred3_0 = ptr2;
349
- deferred3_1 = len2;
350
- return getStringFromWasm0(ptr2, len2);
351
- } finally {
352
- wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
353
- }
354
- }
355
- function getArrayJsValueFromWasm0(ptr, len) {
356
- ptr = ptr >>> 0;
357
- const mem = getDataViewMemory0();
358
- const result = [];
359
- for (let i = ptr; i < ptr + 4 * len; i += 4) {
360
- result.push(wasm.__wbindgen_export_2.get(mem.getUint32(i, true)));
416
+ function batchUnion(operands_brep_serialized, options_json) {
417
+ const ptr0 = passStringToWasm0(operands_brep_serialized, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
418
+ const len0 = WASM_VECTOR_LEN;
419
+ var ptr1 = isLikeNone(options_json) ? 0 : passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
420
+ var len1 = WASM_VECTOR_LEN;
421
+ const ret = wasm.batchUnion(ptr0, len0, ptr1, len1);
422
+ if (ret[2]) {
423
+ throw takeFromExternrefTable0(ret[1]);
361
424
  }
362
- wasm.__externref_drop_slice(ptr, len);
363
- return result;
425
+ return OGBooleanResult.__wrap(ret[0]);
364
426
  }
365
427
  const Matrix3Finalization = typeof FinalizationRegistry === 'undefined' ? {
366
428
  register: () => {},
@@ -2818,7 +2880,7 @@ class OGLine {
2818
2880
  * @returns {Vector3}
2819
2881
  */
2820
2882
  get_anchor() {
2821
- const ret = wasm.ogcurve_get_anchor(this.__wbg_ptr);
2883
+ const ret = wasm.ogline_get_anchor(this.__wbg_ptr);
2822
2884
  return Vector3.__wrap(ret);
2823
2885
  }
2824
2886
  /**
@@ -2872,6 +2934,50 @@ class OGLine {
2872
2934
  }
2873
2935
  }
2874
2936
  }
2937
+ const OGOffsetRegionsResultFinalization = typeof FinalizationRegistry === 'undefined' ? {
2938
+ register: () => {},
2939
+ unregister: () => {}
2940
+ } : new FinalizationRegistry(ptr => wasm.__wbg_ogoffsetregionsresult_free(ptr >>> 0, 1));
2941
+ /**
2942
+ * Result payload for a polyline offset: a list of regions (each an outer ring +
2943
+ * inner-void holes). Normally one region; a self-crossing closed centreline (e.g.
2944
+ * a figure-8) yields one per simple sub-loop. The deterministic analytic offset —
2945
+ * no extrude/solid. Used to build the plan polygons + extruded base solids in JS.
2946
+ */
2947
+ class OGOffsetRegionsResult {
2948
+ static __wrap(ptr) {
2949
+ ptr = ptr >>> 0;
2950
+ const obj = Object.create(OGOffsetRegionsResult.prototype);
2951
+ obj.__wbg_ptr = ptr;
2952
+ OGOffsetRegionsResultFinalization.register(obj, obj.__wbg_ptr, obj);
2953
+ return obj;
2954
+ }
2955
+ __destroy_into_raw() {
2956
+ const ptr = this.__wbg_ptr;
2957
+ this.__wbg_ptr = 0;
2958
+ OGOffsetRegionsResultFinalization.unregister(this);
2959
+ return ptr;
2960
+ }
2961
+ free() {
2962
+ const ptr = this.__destroy_into_raw();
2963
+ wasm.__wbg_ogoffsetregionsresult_free(ptr, 0);
2964
+ }
2965
+ /**
2966
+ * @returns {string}
2967
+ */
2968
+ get regionsSerialized() {
2969
+ let deferred1_0;
2970
+ let deferred1_1;
2971
+ try {
2972
+ const ret = wasm.ogoffsetregionsresult_regionsSerialized(this.__wbg_ptr);
2973
+ deferred1_0 = ret[0];
2974
+ deferred1_1 = ret[1];
2975
+ return getStringFromWasm0(ret[0], ret[1]);
2976
+ } finally {
2977
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2978
+ }
2979
+ }
2980
+ }
2875
2981
  const OGPolygonFinalization = typeof FinalizationRegistry === 'undefined' ? {
2876
2982
  register: () => {},
2877
2983
  unregister: () => {}
@@ -3444,7 +3550,7 @@ class OGPolyline {
3444
3550
  * @returns {Vector3}
3445
3551
  */
3446
3552
  get_anchor() {
3447
- const ret = wasm.ogcurve_get_anchor(this.__wbg_ptr);
3553
+ const ret = wasm.ogpolyline_get_anchor(this.__wbg_ptr);
3448
3554
  return Vector3.__wrap(ret);
3449
3555
  }
3450
3556
  /**
@@ -5435,7 +5541,7 @@ class OGWedge {
5435
5541
  * @returns {Vector3}
5436
5542
  */
5437
5543
  get_anchor() {
5438
- const ret = wasm.ogwedge_get_anchor(this.__wbg_ptr);
5544
+ const ret = wasm.ogarc_get_anchor(this.__wbg_ptr);
5439
5545
  return Vector3.__wrap(ret);
5440
5546
  }
5441
5547
  }
@@ -5862,6 +5968,7 @@ var OGKernel = /*#__PURE__*/Object.freeze({
5862
5968
  OGFreeformGeometry: OGFreeformGeometry,
5863
5969
  OGIfcExportResult: OGIfcExportResult,
5864
5970
  OGLine: OGLine,
5971
+ OGOffsetRegionsResult: OGOffsetRegionsResult,
5865
5972
  OGPolygon: OGPolygon,
5866
5973
  OGPolyline: OGPolyline,
5867
5974
  OGRectangle: OGRectangle,
@@ -5872,13 +5979,16 @@ var OGKernel = /*#__PURE__*/Object.freeze({
5872
5979
  OGSweep: OGSweep,
5873
5980
  OGWedge: OGWedge,
5874
5981
  Vector3: Vector3,
5982
+ batchUnion: batchUnion,
5875
5983
  booleanIntersection: booleanIntersection$1,
5876
5984
  booleanSubtraction: booleanSubtraction$1,
5877
5985
  booleanSubtractionMany: booleanSubtractionMany,
5878
5986
  booleanUnion: booleanUnion$1,
5879
5987
  default: __wbg_init,
5880
5988
  extrudeBrepFace: extrudeBrepFace$1,
5881
- initSync: initSync
5989
+ initSync: initSync,
5990
+ offsetPolylineGroupRegions: offsetPolylineGroupRegions$1,
5991
+ offsetPolylineRegions: offsetPolylineRegions$1
5882
5992
  });
5883
5993
 
5884
5994
  function spotLabelElement() {
@@ -11145,6 +11255,44 @@ function createEditorModesExample(scene) {
11145
11255
  };
11146
11256
  }
11147
11257
 
11258
+ /**
11259
+ * Offset a centreline by ±half-width into one or more filled REGIONS, via the
11260
+ * deterministic analytic offset — miters / flat bevels at `miterLimit`, concave
11261
+ * trims, and nonzero-winding resolution of reflex / closed loops. NO boolean union
11262
+ * (so it is deterministic, unlike the 3D-mesh CSG path). A simple centreline returns
11263
+ * one region; a self-crossing closed centreline (e.g. a figure-8) returns one per
11264
+ * simple sub-loop. Returns an EMPTY array for a genuinely unbuildable input (does
11265
+ * not throw, so it never looks like a kernel crash). Rings are CW-outer / CCW-holes.
11266
+ *
11267
+ * @param centrelineFlat centreline points as `[x,y,z, …]`.
11268
+ * @param width full stroke width (offset ±width/2 on each side).
11269
+ * @param miterLimit SVG stroke-miterlimit; corners sharper than this bevel. Default 4.
11270
+ */
11271
+ function offsetPolylineRegions(centrelineFlat, width, closed, miterLimit = 4) {
11272
+ const buildExport = offsetPolylineRegions$1;
11273
+ if (typeof buildExport !== "function") {
11274
+ throw new Error("offsetPolylineRegions is not available in the loaded wasm package. Rebuild opengeometry wasm bindings.");
11275
+ }
11276
+ const flat = centrelineFlat instanceof Float64Array ? centrelineFlat : new Float64Array(centrelineFlat);
11277
+ const result = buildExport(flat, width, closed, miterLimit);
11278
+ return JSON.parse(result.regionsSerialized);
11279
+ }
11280
+ /**
11281
+ * Merge a GROUP of separate polylines (a crossing T / X / L overlap) into one clean
11282
+ * region by nonzero-winding union of their mitered bands — the overlapping strokes
11283
+ * merge into a single region with mitered/bevelled corners, no internal edges.
11284
+ * Returns CW-outer / CCW-hole regions (one or more); empty if nothing is buildable.
11285
+ * No CSG. Used to render/extrude an overlapping crossing as one joined mass.
11286
+ */
11287
+ function offsetPolylineGroupRegions(polylines) {
11288
+ const buildExport = offsetPolylineGroupRegions$1;
11289
+ if (typeof buildExport !== "function") {
11290
+ throw new Error("offsetPolylineGroupRegions is not available in the loaded wasm package. Rebuild opengeometry wasm bindings.");
11291
+ }
11292
+ const result = buildExport(JSON.stringify(polylines));
11293
+ return JSON.parse(result.regionsSerialized);
11294
+ }
11295
+
11148
11296
  /**
11149
11297
  * Shared runtime entrypoint used to initialize the OpenGeometry wasm module.
11150
11298
  */
@@ -11209,5 +11357,5 @@ class OpenGeometry {
11209
11357
  OpenGeometry.version = OPEN_GEOMETRY_THREE_VERSION;
11210
11358
  OpenGeometry.instance = null;
11211
11359
 
11212
- export { Arc, BooleanError, BooleanResult, CoincidentFacesError, Cuboid, Curve, CutterExceedsHostError, Cylinder, FreeformEditor, FreeformGeometry, Line, NonManifoldOutputError, OGSceneManager, OpenGeometry, Opening, OverlappingCuttersError, Polygon, Polyline, Rectangle, Solid, Sphere, SpotLabel, Sweep, Vector3, Wedge, booleanIntersection, booleanSubtraction, booleanUnion, clonePlacement, createBooleanExample, createEditorModesExample, createFreeformEditor, createFreeformGeometry, createOffsetExample, createParametricEditCapabilities, createPrimitivesExample, createShapesExample, createSweepExample, createWallFromOffsetsExample, describeWallSubtractError, executeBooleanSubtractionMany, extrudeBrepFace, parseBooleanError, toObjectTransformation$1 as toObjectTransformation };
11360
+ export { Arc, BooleanError, BooleanResult, CoincidentFacesError, Cuboid, Curve, CutterExceedsHostError, Cylinder, FreeformEditor, FreeformGeometry, Line, NonManifoldOutputError, OGSceneManager, OpenGeometry, Opening, OverlappingCuttersError, Polygon, Polyline, Rectangle, Solid, Sphere, SpotLabel, Sweep, Vector3, Wedge, booleanIntersection, booleanSubtraction, booleanUnion, clonePlacement, createBooleanExample, createEditorModesExample, createFreeformEditor, createFreeformGeometry, createOffsetExample, createParametricEditCapabilities, createPrimitivesExample, createShapesExample, createSweepExample, createWallFromOffsetsExample, describeWallSubtractError, executeBooleanSubtractionMany, extrudeBrepFace, offsetPolylineGroupRegions, offsetPolylineRegions, parseBooleanError, toObjectTransformation$1 as toObjectTransformation };
11213
11361
  //# sourceMappingURL=index.js.map