@metamesh/modeling 0.9.0 → 0.11.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +66 -422
  3. package/THIRD_PARTY_NOTICES.md +4 -148
  4. package/dist/api/engine.d.ts +105 -8
  5. package/dist/api/geometry.d.ts +95 -83
  6. package/dist/api/index.d.ts +767 -772
  7. package/dist/engine/construction-operations.js +3 -1
  8. package/dist/engine/deferred-context.js +182 -0
  9. package/dist/engine/execution.js +38 -4
  10. package/dist/engine/finalization.js +65 -133
  11. package/dist/engine/geometry-recipes.js +12 -0
  12. package/dist/engine/immutable-generation-data.js +186 -0
  13. package/dist/engine/index.js +57 -35
  14. package/dist/engine/kernel/manifold.wasm +0 -0
  15. package/dist/engine/model-dependencies.js +46 -0
  16. package/dist/engine/model-summary.js +43 -0
  17. package/dist/engine/native/ownership.js +11 -5
  18. package/dist/engine/placement.js +24 -0
  19. package/dist/engine/recipe-realization.js +119 -0
  20. package/dist/engine/session-graph.js +442 -0
  21. package/dist/engine/session-native.js +90 -0
  22. package/dist/engine/session-snapshot.js +153 -0
  23. package/dist/engine/session.js +184 -0
  24. package/dist/engine/shape-anchors.js +5 -0
  25. package/dist/geometry/index.js +2 -2
  26. package/dist/geometry/mesh-centroid.js +7 -6
  27. package/dist/geometry/mesh-planar.js +11 -10
  28. package/dist/geometry/mesh-quality.js +15 -14
  29. package/dist/geometry/mesh-signature.js +8 -7
  30. package/dist/geometry/mesh-solid.js +10 -4
  31. package/dist/geometry/mesh.js +36 -31
  32. package/dist/geometry/profiles/{cross-section.js → contour.js} +3 -3
  33. package/dist/geometry/profiles/{open-profile.js → side-profile.js} +3 -3
  34. package/dist/geometry/svg-import.js +1 -16
  35. package/dist/index.js +2 -0
  36. package/dist/model/execution-binding.js +5 -5
  37. package/dist/model/generation.js +27 -0
  38. package/dist/model/immutable-buffer.js +111 -0
  39. package/dist/model/modeling-context.js +1 -0
  40. package/dist/model/operations.js +521 -160
  41. package/dist/model/shape-handles.js +44 -0
  42. package/package.json +4 -4
@@ -1,153 +1,9 @@
1
1
  # Third-party notices
2
2
 
3
- `dist/geometry-module.js` includes source from the packages listed below. The private
4
- `dist/engine/kernel/` contains exact Manifold 3.5.4 JS/WASM bytes, verified by SHA-256 during the
5
- build. Its complete Apache-2.0 license is distributed at `dist/engine/kernel/LICENSE`.
6
-
7
- ## Manifold 3.5.4 (Apache-2.0)
3
+ Modeling redistributes the Manifold kernel loader and WASM under Apache-2.0.
4
+ The complete upstream license is included at `dist/engine/kernel/LICENSE`; the build verifies
5
+ these files against the pinned upstream package.
8
6
 
9
7
  Source: https://github.com/elalish/manifold
10
8
 
11
- The package incorporates only the kernel loader and WASM, with their license. Upstream CLI,
12
- glTF utilities, examples, and their dependencies are excluded.
13
-
14
- ## polygon-clipping 0.15.7 (MIT)
15
-
16
- Copyright (c) 2018 Mike Fogel <mike@fogel.ca> - covers everything not specially attributed to
17
- others below.
18
-
19
- Copyright (c) 2016 Alexander Milevski <info@w8r.name> - covers all portions originally part of
20
- github:w8r/martinez, from which this project was forked on February 2, 2018.
21
-
22
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
23
- associated documentation files (the "Software"), to deal in the Software without restriction,
24
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
25
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
26
- furnished to do so, subject to the following conditions:
27
-
28
- The above copyright notice and this permission notice shall be included in all copies or
29
- substantial portions of the Software.
30
-
31
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
32
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
34
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
35
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36
-
37
- ## splaytree 3.1.2 (MIT)
38
-
39
- Copyright (c) 2019 Alexander Milevski <info@w8r.name>
40
-
41
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
42
- associated documentation files (the "Software"), to deal in the Software without restriction,
43
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
44
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
45
- furnished to do so, subject to the following conditions:
46
-
47
- The above copyright notice and this permission notice shall be included in all copies or
48
- substantial portions of the Software.
49
-
50
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
51
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
52
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
53
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
54
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55
-
56
- ## TypeScript runtime helpers in polygon-clipping 0.15.7 (Apache-2.0)
57
-
58
- Copyright (c) Microsoft Corporation. All rights reserved.
59
-
60
- Licensed under the Apache License, Version 2.0. A copy of that license is included in `LICENSE`.
61
-
62
- ## svg-pathdata 9.0.0 (MIT)
63
-
64
- Copyright © 2017 Nicolas Froidure
65
-
66
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
67
- associated documentation files (the "Software"), to deal in the Software without restriction,
68
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
69
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
70
- furnished to do so, subject to the following conditions:
71
-
72
- The above copyright notice and this permission notice shall be included in all copies or
73
- substantial portions of the Software.
74
-
75
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
76
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
78
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
79
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
80
-
81
- ## saxes 6.0.0 (ISC)
82
-
83
- Copyright (c) Contributors
84
-
85
- Permission to use, copy, modify, and/or distribute this software for any purpose with or without
86
- fee is hereby granted, provided that the above copyright notice and this permission notice appear
87
- in all copies.
88
-
89
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
90
- SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
91
- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
92
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
93
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
94
- OF THIS SOFTWARE.
95
-
96
- Saxes is forked from sax, which carries the following notice:
97
-
98
- Copyright (c) Isaac Z. Schlueter and Contributors
99
-
100
- Permission to use, copy, modify, and/or distribute this software for any purpose with or without
101
- fee is hereby granted, provided that the above copyright notice and this permission notice appear
102
- in all copies.
103
-
104
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
105
- SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
106
- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
107
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108
- NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
109
- OF THIS SOFTWARE.
110
-
111
- ## xmlchars 2.2.0 (MIT)
112
-
113
- Copyright Louis-Dominique Dubeau and contributors to xmlchars
114
-
115
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
116
- associated documentation files (the "Software"), to deal in the Software without restriction,
117
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
118
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
119
- furnished to do so, subject to the following conditions:
120
-
121
- The above copyright notice and this permission notice shall be included in all copies or
122
- substantial portions of the Software.
123
-
124
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
125
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
126
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
127
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
128
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
129
-
130
- ## robust-predicates (Unlicense)
131
-
132
- The browser distribution bundled by polygon-clipping 0.15.7 contains robust-predicates code but
133
- does not identify a more specific embedded version.
134
-
135
- This is free and unencumbered software released into the public domain.
136
-
137
- Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in
138
- source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by
139
- any means.
140
-
141
- In jurisdictions that recognize copyright laws, the author or authors of this software dedicate
142
- any and all copyright interest in the software to the public domain. We make this dedication for
143
- the benefit of the public at large and to the detriment of our heirs and successors. We intend this
144
- dedication to be an overt act of relinquishment in perpetuity of all present and future rights to
145
- this software under copyright law.
146
-
147
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
148
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
149
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
150
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
151
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
152
-
153
- For more information, please refer to <http://unlicense.org/>.
9
+ Other runtime dependencies are installed separately and retain their own licenses.
@@ -1,16 +1,16 @@
1
1
  import type { TriangleMesh } from "@metamesh/modeling/geometry";
2
- import type { BuildOutput, FinalizedModel, GeometryResolution, ModelingContext, ModelingLimits, FinalizedPart, GeometrySamplingLimits } from "@metamesh/modeling";
2
+ import type { FinalizedModel, FinalizedPart, GenerationDiagnostic, GeometryResolution, ModelingLimits, ModelProgram, Vec3 } from "@metamesh/modeling";
3
3
  /** Default host resource ceilings for parts, vertices, triangles, and transferable bytes. */
4
4
  declare const defaultModelingLimits: Readonly<ModelingLimits>;
5
5
 
6
6
 
7
7
  /** Execution settings supplied by the host, independently of generator metadata. */
8
- export interface BuildOptions {
8
+ export interface GenerationOptions {
9
9
  /** Optional bounded intersection and nested-shell checks; defaults to indexed topology validation. */
10
10
  readonly meshValidation?: "topology" | "solid";
11
11
  /** Per-build limits, no larger than the configured engine ceilings. */
12
12
  readonly limits?: Partial<ModelingLimits>;
13
- /** Physical sampling defaults; model-derived contexts and exact counts override these. */
13
+ /** Physical sampling defaults; operation options and exact counts override these. */
14
14
  readonly resolution?: GeometryResolution;
15
15
  /** Optional bounded planar cleanup; unsupported candidates preserve the original part. */
16
16
  readonly meshTopologyMode?: "original" | "optimized";
@@ -21,11 +21,90 @@ export interface BuildOptions {
21
21
  export interface ModelEngine {
22
22
  /** Immutable resource ceilings selected when this engine was initialized. */
23
23
  readonly limits: ModelingLimits;
24
- /** Runs once, finalizes copied parts, and disposes all native values on every exit. */
25
- build(build: (model: ModelingContext) => BuildOutput, options?: BuildOptions): FinalizedModel;
24
+ /** Creates isolated caches; prepared service capabilities remain fixed for its lifetime. */
25
+ createSession<P, S>(program: ModelProgram<P, S>, ...options: keyof S extends never ? [options?: SessionOptions<S>] : [options: SessionOptions<S> & {
26
+ readonly services: S;
27
+ }]): ModelSession<P>;
26
28
  /** Serializes already finalized mesh parts; never prepares or builds a generator again. */
27
29
  export3mf(parts: readonly ExportMeshPart[], options?: Export3mfOptions): Promise<ArrayBuffer>;
28
30
  }
31
+ /** Fixed generation policy and deterministic host capabilities for one model session. */
32
+ export interface SessionOptions<S = Record<never, never>> extends GenerationOptions {
33
+ /** Host-owned synchronous capabilities, required when declared by the program. The original
34
+ * environment is retained; its behavior and assets must remain deterministic and fixed for
35
+ * this session. Equivalent function wrappers do not constitute an asset revision.
36
+ */
37
+ readonly services?: S;
38
+ /** Enables reuse; defaults to true. Set false for uncached output equivalence checks. */
39
+ readonly cache?: boolean;
40
+ /** Development-only cache-hit probe: reruns pure callbacks and compares bounded data/recipes.
41
+ * Unsupported closures or large results fail explicitly; this cannot prove arbitrary JavaScript.
42
+ */
43
+ readonly verifyCache?: boolean;
44
+ }
45
+ /** Validated local geometry resource; accessors return owned buffer copies. */
46
+ export interface GeometryResource extends TriangleMesh {
47
+ /** Session-scoped immutable resource identity, stable while geometry is reused. */
48
+ readonly id: string;
49
+ /** Immutable resource revision; a new resource receives a new identity. */
50
+ readonly revision: number;
51
+ /** Facts for the exact local manufacturing buffers. */
52
+ readonly measurements: FinalizedPart["measurements"];
53
+ }
54
+ /** A world-space manufacturing part plus its reusable local renderer resource. */
55
+ export interface SnapshotPart extends FinalizedPart {
56
+ /** Validated geometry in local coordinates, independent of placement and appearance. */
57
+ readonly geometry: GeometryResource;
58
+ /** XYZ translation in millimetres after rotation. */
59
+ readonly position: Vec3;
60
+ /** Fixed global X, then Y, then Z rotation in degrees. */
61
+ readonly rotation: Vec3;
62
+ }
63
+ /** Captured immutable revision; disposal never changes another snapshot or an in-flight export. */
64
+ export interface ModelSnapshot extends FinalizedModel {
65
+ /** Ordered world-space parts, each referring to reusable local geometry. */
66
+ readonly parts: readonly SnapshotPart[];
67
+ /** Nonblocking diagnostics emitted for this revision. */
68
+ readonly diagnostics: readonly GenerationDiagnostic[];
69
+ /** Known dependency graph; outer reads remain conservative model-wide dependencies. */
70
+ readonly dependencies: ModelDependencies;
71
+ /** Releases this snapshot's references; idempotent, further access is invalid. */
72
+ dispose(): void;
73
+ }
74
+ /** Known dependencies for inspection; plain JavaScript bindings do not reveal their parameter origin. */
75
+ export interface ModelDependencies {
76
+ /** Parameter keys read outside computed callbacks, affecting structure or ordinary code. */
77
+ readonly modelParameters: readonly string[];
78
+ /** Direct dependencies recorded by successfully evaluated computations. */
79
+ readonly computations: readonly {
80
+ /** Session-local computation identity. */
81
+ readonly id: string;
82
+ /** Direct top-level parameter reads. */
83
+ readonly parameters: readonly string[];
84
+ /** Direct computed-reader dependencies. */
85
+ readonly computations: readonly string[];
86
+ }[];
87
+ /** Part reader roots and known transitive parameter dependencies. */
88
+ readonly parts: readonly {
89
+ /** Stable semantic output part identity. */
90
+ readonly id: string;
91
+ /** Computed readers supplied as geometry or placement roots. */
92
+ readonly computations: readonly string[];
93
+ /** Known transitive parameter dependencies through these roots. */
94
+ readonly parameters: readonly string[];
95
+ }[];
96
+ }
97
+ /** Stateful execution owner; a failed revision cannot change previously returned snapshots. */
98
+ export interface ModelSession<P> {
99
+ /** Generates an atomic manufacturing snapshot or throws; parameters are copied and frozen. */
100
+ run(params: Readonly<P>): ModelSnapshot;
101
+ /** Runs declaration and reached assertions without realizing returned parts. */
102
+ validate(params: Readonly<P>): readonly GenerationDiagnostic[];
103
+ /** Clears optional caches without invalidating captured snapshots. */
104
+ clearCache(): void;
105
+ /** Releases session ownership; idempotent, captured snapshots remain usable. */
106
+ dispose(): void;
107
+ }
29
108
  /**
30
109
  * Manufacturing buffers accepted by the snapshot exporter.
31
110
  */
@@ -59,17 +138,35 @@ export { defaultModelingLimits };
59
138
  /** URL of the package's pinned WASM asset; browser bundlers may replace it with their emitted URL. */
60
139
  export declare const modelingWasmUrl: string;
61
140
 
141
+ /**
142
+ * Runs declaration and immediate assertions without initializing a kernel or finalizing parts.
143
+ * Geometry observations require an initialized session's `validate` method instead.
144
+ */
145
+ export declare function validateModel<P, S>(program: ModelProgram<P, S>, params: Readonly<P>, ...settings: keyof S extends never ? [options?: SessionOptions<S>] : [options: SessionOptions<S> & {
146
+ readonly services: S;
147
+ }]): readonly GenerationDiagnostic[];
62
148
  /**
63
149
  * Initializes one host kernel and returns a lifecycle-safe engine. No generator initializes WASM.
64
150
  *
65
151
  * @example Build a box in a host application
66
152
  * ```ts
67
- * import { box } from "@metamesh/modeling";
153
+ * import { box, generate } from "@metamesh/modeling";
68
154
  * import { createModelEngine } from "@metamesh/modeling/engine";
69
155
  *
70
156
  * const engine = await createModelEngine();
71
- * const snapshot = engine.build(() => box({ size: [30, 20, 8] }));
157
+ * const model = generate<Record<never, never>>(({ part }) => [part("body", box({ size: [30, 20, 8] }))]);
158
+ * const session = engine.createSession(model);
159
+ * try {
160
+ * const snapshot = session.run({});
161
+ * try {
162
+ * await engine.export3mf(snapshot.parts);
163
+ * } finally {
164
+ * snapshot.dispose();
165
+ * }
166
+ * } finally {
167
+ * session.dispose();
168
+ * }
72
169
  * ```
73
170
  */
74
171
  export declare function createModelEngine(options?: ModelEngineOptions): Promise<ModelEngine>;
75
- export type { BuildOutput, FinalizedModel, FinalizedPart, ModelingContext, ModelingLimits, GeometryResolution, GeometrySamplingLimits, };
172
+ export type { ModelingLimits };
@@ -436,6 +436,39 @@ export declare interface ArcCurve3 {
436
436
  */
437
437
  export declare function computeTriangleMeshCentroid(mesh: TriangleMesh): Vec3;
438
438
 
439
+ /** One explicitly closed planar contour, independent of editor metadata and parameter contracts. */
440
+ export declare interface ContourCurve {
441
+ /** Initial anchor; coordinates may be any finite value. */
442
+ readonly start: ContourPoint;
443
+ /** Ordered chain of 2–32 segments; the final end must exactly match start. */
444
+ readonly segments: readonly ContourSegment[];
445
+ }
446
+
447
+ /** Planar X and upward Y in millimetres, or in units converted by sampling scales. */
448
+ export declare interface ContourPoint {
449
+ /** Horizontal coordinate; physical scaling does not center the contour. */
450
+ readonly x: number;
451
+ /** Upward planar coordinate. */
452
+ readonly y: number;
453
+ }
454
+
455
+ /** Straight or cubic Bézier segment in one closed planar contour. */
456
+ export declare type ContourSegment = {
457
+ /** Straight segment discriminator. */
458
+ readonly type: "line";
459
+ /** Next anchor; the final anchor repeats the curve start. */
460
+ readonly end: ContourPoint;
461
+ } | {
462
+ /** Cubic Bézier segment discriminator. */
463
+ readonly type: "cubic";
464
+ /** Outgoing control from the previous anchor. */
465
+ readonly control1: ContourPoint;
466
+ /** Incoming control at the next anchor. */
467
+ readonly control2: ContourPoint;
468
+ /** Next anchor; the final anchor repeats the curve start. */
469
+ readonly end: ContourPoint;
470
+ };
471
+
439
472
  /** One sampled component retaining contour identities and logical point correspondence. */
440
473
  export declare interface CorrespondingComponent {
441
474
  /** Stable canonical lowercase identity; unique within the containing topology or output. */
@@ -520,39 +553,6 @@ export declare interface ArcCurve3 {
520
553
  */
521
554
  export declare const cross3: (a: Vec3, b: Vec3) => Vec3;
522
555
 
523
- /** One explicitly closed planar contour, independent of editor metadata and parameter contracts. */
524
- export declare interface CrossSectionCurve {
525
- /** Initial anchor; coordinates may be any finite value. */
526
- readonly start: CrossSectionPoint;
527
- /** Ordered chain of 2–32 segments; the final end must exactly match start. */
528
- readonly segments: readonly CrossSectionSegment[];
529
- }
530
-
531
- /** Planar X and upward Y in millimetres, or in units converted by sampling scales. */
532
- export declare interface CrossSectionPoint {
533
- /** Horizontal coordinate; physical scaling does not center the contour. */
534
- readonly x: number;
535
- /** Upward planar coordinate. */
536
- readonly y: number;
537
- }
538
-
539
- /** Straight or cubic Bézier segment in one closed planar contour. */
540
- export declare type CrossSectionSegment = {
541
- /** Straight segment discriminator. */
542
- readonly type: "line";
543
- /** Next anchor; the final anchor repeats the curve start. */
544
- readonly end: CrossSectionPoint;
545
- } | {
546
- /** Cubic Bézier segment discriminator. */
547
- readonly type: "cubic";
548
- /** Outgoing control from the previous anchor. */
549
- readonly control1: CrossSectionPoint;
550
- /** Incoming control at the next anchor. */
551
- readonly control2: CrossSectionPoint;
552
- /** Next anchor; the final anchor repeats the curve start. */
553
- readonly end: CrossSectionPoint;
554
- };
555
-
556
556
  /** Planar cubic Bézier with explicit endpoint and control coordinates. */
557
557
  export declare interface CubicBezierCurve2 {
558
558
  /** Selects a cubic Bézier through two endpoints and two controls. */
@@ -1226,7 +1226,19 @@ export declare interface ArcCurve3 {
1226
1226
  readonly end: Vec3;
1227
1227
  }
1228
1228
 
1229
- /** Deterministic ordered edge subdivision or bounded geometric vertex association. */
1229
+ /**
1230
+ * Associates ordered loft contours without inferring component identities or repairing topology.
1231
+ *
1232
+ * - `direct` preserves seams and subdivides edges to a common count without dropping vertices.
1233
+ * - `reindex` applies direct subdivision, then selects the next contour's cyclic phase with the
1234
+ * least total world-space connection length.
1235
+ * - `fast-distance` preserves supplied seams and minimizes connection length over ordered closed
1236
+ * vertex associations, repeating vertices for triangular fans.
1237
+ * - `distance` runs the same ordered optimization over every cyclic phase of the next contour.
1238
+ *
1239
+ * Components and holes are paired by their existing order. Use identified profiles when semantic
1240
+ * correspondence must remain authoritative.
1241
+ */
1230
1242
  export declare type LoftCorrespondence = "direct" | "reindex" | "fast-distance" | "distance";
1231
1243
 
1232
1244
  /**
@@ -1475,39 +1487,6 @@ export declare interface ArcCurve3 {
1475
1487
  */
1476
1488
  export declare function normalizeRegion2(region: Region2, tolerance?: GeometryToleranceOptions): Region2;
1477
1489
 
1478
- /** An open radius/height outline; consumers own closure, mounting geometry, and wall policy. */
1479
- export declare interface OpenProfileCurve {
1480
- /** Initial radius/height anchor. */
1481
- readonly start: OpenProfilePoint;
1482
- /** Ordered chain of 1–31 straight or cubic segments. */
1483
- readonly segments: readonly OpenProfileSegment[];
1484
- }
1485
-
1486
- /** Radius and upward height in millimetres, or in units converted by sampling scales. */
1487
- export declare interface OpenProfilePoint {
1488
- /** Nonnegative distance from the revolution axis. */
1489
- readonly radius: number;
1490
- /** Upward axial coordinate; anchors progress strictly upward. */
1491
- readonly height: number;
1492
- }
1493
-
1494
- /** One straight or cubic segment of an open, upward-progressing radius/height outline. */
1495
- export declare type OpenProfileSegment = {
1496
- /** Straight segment discriminator. */
1497
- readonly type: "line";
1498
- /** Next strictly higher anchor. */
1499
- readonly end: OpenProfilePoint;
1500
- } | {
1501
- /** Cubic Bézier segment discriminator. */
1502
- readonly type: "cubic";
1503
- /** Outgoing control, with height between the start and second control. */
1504
- readonly control1: OpenProfilePoint;
1505
- /** Incoming control, with height between the first control and end. */
1506
- readonly control2: OpenProfilePoint;
1507
- /** Next strictly higher anchor. */
1508
- readonly end: OpenProfilePoint;
1509
- };
1510
-
1511
1490
  /**
1512
1491
  * Improves pathological planar triangulation with bounded legal diagonal flips.
1513
1492
  *
@@ -2243,7 +2222,7 @@ export declare interface ArcCurve3 {
2243
2222
  *
2244
2223
  * @example
2245
2224
  * ```ts
2246
- * const section = sampleCrossSection({
2225
+ * const section = sampleContour({
2247
2226
  * start: { x: 0, y: 0 },
2248
2227
  * segments: [
2249
2228
  * { type: "line", end: { x: 1, y: 0 } },
@@ -2253,10 +2232,10 @@ export declare interface ArcCurve3 {
2253
2232
  * }, { widthScale: 20, heightScale: 12 });
2254
2233
  * ```
2255
2234
  */
2256
- export declare function sampleCrossSection(curve: CrossSectionCurve, options?: SampleCrossSectionOptions): Loop2;
2235
+ export declare function sampleContour(curve: ContourCurve, options?: SampleContourOptions): Loop2;
2257
2236
 
2258
2237
  /** Physical scaling, subdivision policy, and output ceilings for one closed contour. */
2259
- export declare interface SampleCrossSectionOptions {
2238
+ export declare interface SampleContourOptions {
2260
2239
  /** Positive horizontal scale; normalized inputs span this width envelope. Defaults to 1. */
2261
2240
  readonly widthScale?: number;
2262
2241
  /** Positive vertical scale; normalized inputs span this height envelope. Defaults to 1. */
@@ -2365,6 +2344,16 @@ export declare interface ArcCurve3 {
2365
2344
  */
2366
2345
  export declare function sampleInternalCylindricalGearSpaceOutline(spec: CylindricalGearSpec, options?: CylindricalGearOutlineOptions): Loop2;
2367
2346
 
2347
+ /**
2348
+ * Samples the open top boundary of a finite rack in its XY pitch plane.
2349
+ *
2350
+ * X follows rack travel, Y is tooth height, and the pitch line is `Y = 0`.
2351
+ * The path begins and ends on the root line, omits duplicate adjacent points,
2352
+ * and leaves base thickness, mounting features, extrusion, and helical sweep to
2353
+ * the owning generator.
2354
+ */
2355
+ export declare function sampleRackToothPath(spec: RackPitchSpec, limits?: Partial<GeometrySamplingLimits>): Path2;
2356
+
2368
2357
  /**
2369
2358
  * Samples 1–31 line/cubic segments into a deeply immutable open [radius,height] polyline.
2370
2359
  * Anchors must progress strictly upward; nonnegative-radius cubic controls must have ordered
@@ -2380,16 +2369,16 @@ export declare interface ArcCurve3 {
2380
2369
  *
2381
2370
  * @example
2382
2371
  * ```ts
2383
- * const side = sampleOpenProfile({
2372
+ * const side = sampleSideProfile({
2384
2373
  * start: { radius: 0.5, height: 0 },
2385
2374
  * segments: [{ type: "line", end: { radius: 1, height: 1 } }],
2386
2375
  * }, { radiusScale: 12, heightScale: 30 });
2387
2376
  * ```
2388
2377
  */
2389
- export declare function sampleOpenProfile(curve: OpenProfileCurve, options?: SampleOpenProfileOptions): readonly Vec2[];
2378
+ export declare function sampleSideProfile(curve: SideProfileCurve, options?: SampleSideProfileOptions): readonly Vec2[];
2390
2379
 
2391
2380
  /** Physical scaling and bounded adaptive subdivision for an open profile. */
2392
- export declare interface SampleOpenProfileOptions {
2381
+ export declare interface SampleSideProfileOptions {
2393
2382
  /** Positive radius scale; use the desired maximum radius for normalized coordinates. Defaults to 1. */
2394
2383
  readonly radiusScale?: number;
2395
2384
  /** Positive height scale; use the desired total height for normalized coordinates. Defaults to 1. */
@@ -2402,16 +2391,6 @@ export declare interface ArcCurve3 {
2402
2391
  readonly limits?: Partial<GeometrySamplingLimits>;
2403
2392
  }
2404
2393
 
2405
- /**
2406
- * Samples the open top boundary of a finite rack in its XY pitch plane.
2407
- *
2408
- * X follows rack travel, Y is tooth height, and the pitch line is `Y = 0`.
2409
- * The path begins and ends on the root line, omits duplicate adjacent points,
2410
- * and leaves base thickness, mounting features, extrusion, and helical sweep to
2411
- * the owning generator.
2412
- */
2413
- export declare function sampleRackToothPath(spec: RackPitchSpec, limits?: Partial<GeometrySamplingLimits>): Path2;
2414
-
2415
2394
  /**
2416
2395
  * Samples a prepared text layout without shaping text again or loading a font.
2417
2396
  *
@@ -2449,6 +2428,39 @@ export declare interface ArcCurve3 {
2449
2428
  */
2450
2429
  export declare function scaleTransform3(factors: Vec3): Transform3;
2451
2430
 
2431
+ /** An open radius/height outline; consumers own closure, mounting geometry, and wall policy. */
2432
+ export declare interface SideProfileCurve {
2433
+ /** Initial radius/height anchor. */
2434
+ readonly start: SideProfilePoint;
2435
+ /** Ordered chain of 1–31 straight or cubic segments. */
2436
+ readonly segments: readonly SideProfileSegment[];
2437
+ }
2438
+
2439
+ /** Radius and upward height in millimetres, or in units converted by sampling scales. */
2440
+ export declare interface SideProfilePoint {
2441
+ /** Nonnegative distance from the revolution axis. */
2442
+ readonly radius: number;
2443
+ /** Upward axial coordinate; anchors progress strictly upward. */
2444
+ readonly height: number;
2445
+ }
2446
+
2447
+ /** One straight or cubic segment of an open, upward-progressing radius/height outline. */
2448
+ export declare type SideProfileSegment = {
2449
+ /** Straight segment discriminator. */
2450
+ readonly type: "line";
2451
+ /** Next strictly higher anchor. */
2452
+ readonly end: SideProfilePoint;
2453
+ } | {
2454
+ /** Cubic Bézier segment discriminator. */
2455
+ readonly type: "cubic";
2456
+ /** Outgoing control, with height between the start and second control. */
2457
+ readonly control1: SideProfilePoint;
2458
+ /** Incoming control, with height between the first control and end. */
2459
+ readonly control2: SideProfilePoint;
2460
+ /** Next strictly higher anchor. */
2461
+ readonly end: SideProfilePoint;
2462
+ };
2463
+
2452
2464
  /** Returns the signed area of a non-duplicated loop; positive means CCW. */
2453
2465
  export declare function signedAreaLoop2(loop: Loop2): number;
2454
2466