@metamesh/modeling 0.0.0-stage → 0.6.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 (130) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/LICENSE +200 -0
  3. package/README.md +314 -2
  4. package/THIRD_PARTY_NOTICES.md +153 -0
  5. package/dist/api/engine.d.ts +54 -0
  6. package/dist/api/geometry.d.ts +2912 -0
  7. package/dist/api/index.d.ts +1648 -0
  8. package/dist/api/text.d.ts +77 -0
  9. package/dist/engine/construction-operations.js +189 -0
  10. package/dist/engine/execution.js +227 -0
  11. package/dist/engine/export-3mf.js +100 -0
  12. package/dist/engine/extrusion-finishing.js +82 -0
  13. package/dist/engine/finalization.js +214 -0
  14. package/dist/engine/index.js +72 -0
  15. package/dist/engine/inspection-operations.js +52 -0
  16. package/dist/engine/kernel/LICENSE +201 -0
  17. package/dist/engine/kernel/manifold.js +2 -0
  18. package/dist/engine/kernel/manifold.wasm +0 -0
  19. package/dist/engine/loft-operations.js +156 -0
  20. package/dist/engine/mechanical-operations.js +51 -0
  21. package/dist/engine/modeling-context.js +38 -0
  22. package/dist/engine/native/adapter.js +20 -0
  23. package/dist/engine/native/context.js +209 -0
  24. package/dist/engine/native/copied-views.js +46 -0
  25. package/dist/engine/native/index.js +13 -0
  26. package/dist/engine/native/operations.js +115 -0
  27. package/dist/engine/native/ownership.js +98 -0
  28. package/dist/engine/native/regions.js +138 -0
  29. package/dist/engine/native/scoped-primitives.js +127 -0
  30. package/dist/engine/native/scoped-threads.js +34 -0
  31. package/dist/engine/native/threads.js +52 -0
  32. package/dist/engine/native/transforms.js +111 -0
  33. package/dist/engine/operation-environment.js +20 -0
  34. package/dist/engine/pattern-operations.js +36 -0
  35. package/dist/engine/pattern-placements.js +176 -0
  36. package/dist/engine/primitive-anchors.js +70 -0
  37. package/dist/engine/primitive-correspondence.js +74 -0
  38. package/dist/engine/primitive-operations.js +151 -0
  39. package/dist/engine/primitive-profile-types.js +1 -0
  40. package/dist/engine/primitive-profiles.js +250 -0
  41. package/dist/engine/profile-mesh.js +279 -0
  42. package/dist/engine/section-operations.js +93 -0
  43. package/dist/engine/shape-anchors.js +88 -0
  44. package/dist/engine/transform-operations.js +225 -0
  45. package/dist/engine/types.js +1 -0
  46. package/dist/geometry/anchors.js +226 -0
  47. package/dist/geometry/curves/evaluation.js +162 -0
  48. package/dist/geometry/curves/sampling.js +265 -0
  49. package/dist/geometry/curves/types.js +1 -0
  50. package/dist/geometry/cylinder.js +117 -0
  51. package/dist/geometry/edge-finishing.js +160 -0
  52. package/dist/geometry/errors.js +76 -0
  53. package/dist/geometry/extrusion.js +150 -0
  54. package/dist/geometry/heightfield.js +107 -0
  55. package/dist/geometry/index.js +42 -0
  56. package/dist/geometry/loft-correspondence.js +204 -0
  57. package/dist/geometry/loft-geometry.js +184 -0
  58. package/dist/geometry/loft-options.js +56 -0
  59. package/dist/geometry/loft-simple-mesh.js +92 -0
  60. package/dist/geometry/loft-triangulation.js +64 -0
  61. package/dist/geometry/loft.js +80 -0
  62. package/dist/geometry/math/vector3.js +41 -0
  63. package/dist/geometry/mechanical/gear-motion.js +94 -0
  64. package/dist/geometry/mechanical/gears.js +484 -0
  65. package/dist/geometry/mechanical/index.js +13 -0
  66. package/dist/geometry/mechanical/standards.js +67 -0
  67. package/dist/geometry/mechanical/thread-helices.js +44 -0
  68. package/dist/geometry/mechanical/thread-mesh-plan.js +358 -0
  69. package/dist/geometry/mechanical/thread-mesh.js +142 -0
  70. package/dist/geometry/mechanical/thread-profiles.js +368 -0
  71. package/dist/geometry/mechanical/thread-solids.js +230 -0
  72. package/dist/geometry/mechanical/thread-surface.js +433 -0
  73. package/dist/geometry/mechanical/threads.js +138 -0
  74. package/dist/geometry/mesh-planar.js +408 -0
  75. package/dist/geometry/mesh-quality.js +396 -0
  76. package/dist/geometry/mesh-signature.js +137 -0
  77. package/dist/geometry/mesh.js +300 -0
  78. package/dist/geometry/model-limits.js +50 -0
  79. package/dist/geometry/numeric.js +11 -0
  80. package/dist/geometry/paths/frames.js +118 -0
  81. package/dist/geometry/paths/helix.js +49 -0
  82. package/dist/geometry/paths/path.js +30 -0
  83. package/dist/geometry/paths/planar.js +135 -0
  84. package/dist/geometry/paths/resampling.js +124 -0
  85. package/dist/geometry/polygon-clipping.js +52 -0
  86. package/dist/geometry/primitive-options.js +1 -0
  87. package/dist/geometry/primitive-resolution.js +17 -0
  88. package/dist/geometry/primitive-resolvers.js +235 -0
  89. package/dist/geometry/profiles/matched.js +184 -0
  90. package/dist/geometry/profiles/open-profile.js +137 -0
  91. package/dist/geometry/profiles/profiles.js +70 -0
  92. package/dist/geometry/profiles/rectangle.js +235 -0
  93. package/dist/geometry/profiles/shapes.js +34 -0
  94. package/dist/geometry/profiles/span-sampling.js +28 -0
  95. package/dist/geometry/profiles/types.js +1 -0
  96. package/dist/geometry/profiles/validation.js +20 -0
  97. package/dist/geometry/regions.js +371 -0
  98. package/dist/geometry/resolution.js +236 -0
  99. package/dist/geometry/revolve/revolve-mesh.js +123 -0
  100. package/dist/geometry/sampling-limits.js +29 -0
  101. package/dist/geometry/stroke-path.js +181 -0
  102. package/dist/geometry/svg/errors.js +23 -0
  103. package/dist/geometry/svg/fill.js +172 -0
  104. package/dist/geometry/svg/index.js +1 -0
  105. package/dist/geometry/svg/matrix.js +130 -0
  106. package/dist/geometry/svg/parser.js +536 -0
  107. package/dist/geometry/svg/path.js +349 -0
  108. package/dist/geometry/svg/types.js +1 -0
  109. package/dist/geometry/svg-import.js +662 -0
  110. package/dist/geometry/sweeps/options.js +28 -0
  111. package/dist/geometry/sweeps/orientation.js +106 -0
  112. package/dist/geometry/sweeps/stations.js +161 -0
  113. package/dist/geometry/sweeps/sweep-closed.js +96 -0
  114. package/dist/geometry/sweeps/sweep-mesh.js +20 -0
  115. package/dist/geometry/sweeps/sweep-open.js +76 -0
  116. package/dist/geometry/sweeps/validation.js +116 -0
  117. package/dist/geometry/text-contours.js +32 -0
  118. package/dist/geometry/text-layout.js +1 -0
  119. package/dist/geometry/tolerance.js +53 -0
  120. package/dist/geometry/transform-geometry.js +41 -0
  121. package/dist/geometry/transform3.js +340 -0
  122. package/dist/geometry/types.js +1 -0
  123. package/dist/index.js +1 -0
  124. package/dist/model/execution-binding.js +30 -0
  125. package/dist/model/operations.js +152 -0
  126. package/dist/model/options.js +1 -0
  127. package/dist/model/types.js +1 -0
  128. package/dist/text/index.js +48 -0
  129. package/dist/text/vector-text-layout.js +279 -0
  130. package/package.json +100 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,105 @@
1
+ # @metamesh/modeling
2
+
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Introduce standalone imported modeling operations with opaque handles, pure `/geometry`, host
8
+ `/engine`, and optional `/text` entry points. The shared executor owns Manifold initialization,
9
+ automatic resource checks, manufacturing finalization, captured-snapshot 3MF export, and cleanup.
10
+ - Unify rectangle construction and radius/diameter options. Primitive sections retain landmarks
11
+ for ordered station-based lofts; optional correspondence, distribution, refinement, and slice
12
+ controls support explicit geometric association alongside identified profiles.
13
+ - Add named shape anchors, selected box-edge treatments, independent cylinder ends, and bounded
14
+ straight convex extrusion-end finishing. Circular rounding, unequal chamfers, smooth transitions,
15
+ and custom local treatment profiles share one contract with explicit fit and sampling checks.
16
+ - Add sweep frame policies and twist progression, grid/path patterns, and count/spacing/length
17
+ line patterns. Physical sampling and exact counts respect selected allocation and work limits;
18
+ exact primitive facets remain intact when profile families use different sampling counts.
19
+
20
+ ## 0.5.2
21
+
22
+ ### Patch Changes
23
+
24
+ - 02a1692: Keep validation errors visible when aggregate issues exceed the reporting limit, reject generated
25
+ part array accessors and inherited entries, and reject region islands that touch or cross a hole
26
+ boundary. Correct bevel and miter stroke joins, including SVG import and miter-limit fallback.
27
+
28
+ Reject asynchronous results from synchronous WASM ownership scopes and consume later native
29
+ Promise rejections during cleanup. Prevent nonfinite Float32 loft/revolve meshes, overflowing
30
+ derived tolerances, and invalid anchor normalization. Validate finite legacy path and helix
31
+ sampling before returning invalid geometry or allocating unrepresentable arrays. Preserve path
32
+ distribution and helix sampling for large finite dimensions without intermediate arithmetic
33
+ overflow.
34
+
35
+ ## 0.5.1
36
+
37
+ ### Patch Changes
38
+
39
+ - Allow multiple saved curve-resolution parameters per definition so hosts can show their authored
40
+ labels together while Generators own each setting's curve and part mapping.
41
+
42
+ Handle floating-point turns consistently when triangulating densely sampled straight cap edges,
43
+ preserving matched-profile correspondence at finer curve resolutions.
44
+
45
+ ## 0.5.0
46
+
47
+ ### Minor Changes
48
+
49
+ - 0dc29c2: Add the portable numeric `curve-resolution` parameter role for model-owned physical curve
50
+ tolerance, with strict millimetre units, positive bounds, and one role per definition. Require
51
+ runtime 1.3.0 or later for packages declaring the role. Geometry and
52
+ Testkit follow the coordinated fixed Preview package release.
53
+ - 0dc29c2: Add a portable, versioned `profile` parameter for guided side outlines with line/cubic segments,
54
+ anchor editing modes, physical-dimension bindings, strict bounds, and deeply immutable defaults,
55
+ presets, and runtime values. Profile-capable packages require runtime 1.3.0 or later while retaining
56
+ package format 1.
57
+
58
+ Add Geometry's `sampleOpenProfile` operation to adaptively sample open radius/height curves with
59
+ physical scaling, chord-error limits, and explicit complexity failures. Expose it through the
60
+ compiled and Studio authoring APIs so profile parameters use the same geometry in preview and export.
61
+
62
+ ## 0.4.0
63
+
64
+ ### Minor Changes
65
+
66
+ - ad3bb49: Strengthen generator geometry with correct concave sweep caps, bounded region aggregation,
67
+ consistent finite input checks, protected copied-mesh scope exits, and shared primitive/extrusion
68
+ sampling. Add scoped hull, Minkowski sum, projection, slicing, and region revolution.
69
+
70
+ Compiled `MeshPart` now exposes `{ id, positions, indices, color? }`, directly compatible with SDK
71
+ `GeneratedPart`. Pass explicit `{ degrees }` or `{ radians }` to `rotationTransform3`, and rounded
72
+ rectangle sampling options as `{ segmentsPerCorner }` or `{ resolution }`.
73
+
74
+ Add `definePreparedGeneratorModule` for bounded, one-use validation/generation preparation while
75
+ preserving the five format-1 module exports. Authored `/v1` keeps its existing signatures and shares
76
+ the pure validation and sampling implementation with compiled modeling.
77
+
78
+ ## 0.3.0
79
+
80
+ ### Minor Changes
81
+
82
+ - e87357e: Add direct catalog-font text geometry and matching metrics through prepared synchronous font
83
+ scopes. Share vector layout with SVG outlining, use natural font line spacing by default, and
84
+ make whitespace measurable. Nonzero tracking disables optional ligatures to match browser text.
85
+ Compiled Generators can receive font services during validation as well as generation; packages
86
+ declaring font parameters require runtime 1.2.0. Text geometry requires an exact font selection;
87
+ host text services expose shared vector layout. Browser editing uses prepared vector measurements.
88
+ Compiled module calls require explicit execution services for validation and generation.
89
+
90
+ Use the shared transform functions for both 2D sections and 3D solids. Reuse core-validated immutable
91
+ loops, polygons, and regions when winding and tolerance policies match, avoiding repeated topology
92
+ validation without changing tessellation or accepting unvalidated caller geometry.
93
+
94
+ ## 0.2.0
95
+
96
+ ### Minor Changes
97
+
98
+ - 8b4e918: Add immutable font selections, font parameters and prepared text services, the optional Geometry
99
+ text engine, and reproducible font test services.
100
+
101
+ ## 0.1.0
102
+
103
+ ### Minor Changes
104
+
105
+ - Initial public Preview release of the Geometry root, Manifold, 3MF, and V1 entry points.
package/LICENSE ADDED
@@ -0,0 +1,200 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice.
187
+
188
+ Copyright 2026 MetaMesh
189
+
190
+ Licensed under the Apache License, Version 2.0 (the "License");
191
+ you may not use this file except in compliance with the License.
192
+ You may obtain a copy of the License at
193
+
194
+ http://www.apache.org/licenses/LICENSE-2.0
195
+
196
+ Unless required by applicable law or agreed to in writing, software
197
+ distributed under the License is distributed on an "AS IS" BASIS,
198
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199
+ See the License for the specific language governing permissions and
200
+ limitations under the License.
package/README.md CHANGED
@@ -1,3 +1,315 @@
1
- # Temporary Holding Version
1
+ # `@metamesh/modeling`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Standalone geometry foundations and a modeling engine for Node applications, browser Workers, and MetaMesh Generators.
4
+
5
+ > **Preview:** `0.x` minor releases may break compatibility. Patches remain compatible within the same minor line. Stable support requires an explicit `1.0.0` review.
6
+
7
+ Applications initialize one engine and build models with imported functions. Generator hosts provide that same execution scope; generators do not initialize WASM or dispose native values. No SDK or Testkit is required to use Modeling.
8
+
9
+ ## API discovery and ownership
10
+
11
+ | Entry point | Responsibility |
12
+ | ----------------------------- | ------------------------------------------------------------------------------------------- |
13
+ | `@metamesh/modeling` | Imported modeling functions, opaque handles, output descriptors, and finalized results |
14
+ | `@metamesh/modeling/geometry` | Pure math, paths, profiles, regions, transforms, meshes, mechanical kernels, and SVG import |
15
+ | `@metamesh/modeling/engine` | Host initialization, scoped modeling, finalization, resource limits, and snapshot export |
16
+ | `@metamesh/modeling/text` | Optional font-byte preparation and synchronous vector layout |
17
+
18
+ These four entrypoints are the complete workspace and published API. Pure helpers cannot import the engine, native kernel, browser APIs, Studio, or Generators. Fontkit and WOFF2 decoding remain optional peers used only by `/text`. Hosts own acquisition, worker lifecycle, and loading. API reports define supported symbols; consumer fixtures verify published use.
19
+
20
+ ## Modeling and lifecycle
21
+
22
+ Install the package and create an engine in the application:
23
+
24
+ ```bash
25
+ pnpm add @metamesh/modeling
26
+ ```
27
+
28
+ ```ts
29
+ import { box, cylinder, subtract } from "@metamesh/modeling";
30
+ import { createModelEngine } from "@metamesh/modeling/engine";
31
+
32
+ const engine = await createModelEngine();
33
+ const snapshot = engine.build(
34
+ () => {
35
+ const body = box({ size: [30, 20, 6] });
36
+ const bore = cylinder({ height: 8, radius: 3, sizing: "face" });
37
+ return [{ id: "plate", solid: subtract(body, [bore]), color: "#67e8f9" }];
38
+ },
39
+ { resolution: { maxChordError: 0.025 } }
40
+ );
41
+ const bytes = await engine.export3mf(snapshot.parts, { name: "Plate" });
42
+ ```
43
+
44
+ The package includes the pinned Manifold JS/WASM kernel and its license, without Manifold's CLI or glTF dependency tree. Node and unbundled browser modules resolve the installed WASM automatically. Browser bundlers must retain or emit the relative asset and can pass their emitted URL explicitly:
45
+
46
+ ```ts
47
+ import { box } from "@metamesh/modeling";
48
+ import { createModelEngine, modelingWasmUrl } from "@metamesh/modeling/engine";
49
+
50
+ const engine = await createModelEngine({ locateFile: () => modelingWasmUrl });
51
+ const snapshot = engine.build(() => box({ size: [10, 20, 30] }));
52
+ ```
53
+
54
+ Imported functions and explicitly supplied `ModelingContext` methods execute the same operations. Imports contain no kernel initialization. The host binds the active context through a versioned symbol shared across bundles, then clears it in `finally`. Calls outside `build` throw. Builds are synchronous and cannot nest, including across different engines in one JavaScript realm; asynchronous preparation belongs before `build`. Separate Workers have independent execution scopes. An engine also rejects builds or exports while its asynchronous exporter is busy.
55
+
56
+ `Solid` and `Section` are opaque immutable handles belonging to one synchronous build. Sections are native filled XY shapes, including holes and disconnected components. `union`, `subtract`, and `intersect` accept either Solid or Section operands and reject mixed dimensions. Offsets and Boolean operations retain native sections; `fromRegion` and `toRegion` are explicit conversion boundaries. Repeated sweeps and loft stations extract each Section once per execution; `toRegion` returns fresh immutable snapshots. Handles cannot cross builds or survive disposal. All native values dispose in reverse construction order from `finally`, including on failure. Installed bundles call host-owned methods, avoiding package-local native class or module identity.
57
+
58
+ Builds return a bare solid (part ID `model`) or named `{ id, solid, color? }` / `{ id, mesh, color? }` descriptors. IDs are unique lowercase kebab-case strings of at most 64 characters; colors are six-digit hex RGB. Direct meshes are copied and checked for finite, nondegenerate, oriented closed topology and kernel reconstructability without copying them back from the kernel. Native extraction preserves one bounded retry for collapsed Float32 stitches. Descriptors for the same Solid share one extraction, copied manufacturing buffers, and immutable facts. Public `toTriangleMesh` inspection returns independent copies; mutable mesh inputs are captured and validated afresh for every build. Finalized parts retain shared bounds, counts, signed volume, area, and topology facts. Render normals remain outside manufacturing data.
59
+
60
+ Default limits are 64 parts, 1,000,000 vertices, 2,000,000 triangles, and 96 MiB of unique backing storage. Trusted applications may configure higher or lower ceilings through `createModelEngine({ limits })`. Per-build limits may only lower those configured ceilings, and snapshot export uses them too. Generator hosts own ceilings; generators receive no engine. Predictable allocations preflight safe-integer counts. Algorithm-specific numeric limits remain documented by their operations. Complexity fails explicitly instead of reducing fidelity.
61
+
62
+ The same `limits` policy includes `maxPathPoints` (100,000), `maxProfilePoints` (100,000),
63
+ `maxSweepProfilePoints` (4,096), and `maxCircularSegments` (512). Pure helpers accept explicit
64
+ limits and use these defaults when omitted. Mesh constructors also accept the selected output
65
+ budgets. Engines supply their configured policy to bound operations; operation limits may lower
66
+ it. Exact samples override physical sampling without raising an allocation ceiling. Excessive
67
+ counts fail before predictable array or mesh-buffer allocation, with required and allowed counts.
68
+
69
+ SVG, text, strokes and gear outlines also honor these selected sampling ceilings. Separate SVG
70
+ source, XML and recursion bounds, region intersection work limits, and native implicit-field
71
+ work limits remain fixed operation safeguards.
72
+
73
+ `engine.export3mf` consumes selected finalized buffers without preparation or generation. Its lazy ZIP/XML serializer preserves exact selected vertices, triangle indices, semantic part names, and optional RGB display colors without a native or glTF conversion. Hosts own revisions, appearance overrides, filenames, delivery, and persistence.
74
+
75
+ ## Resolution and conventions
76
+
77
+ Primitive and pure loop factories share named options. These conventions apply across the applicable operations:
78
+
79
+ | Concept | Convention |
80
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
81
+ | Units | Lengths are millimetres; modeling rotations use degrees. Pure transform constructors require explicit `{ degrees }` or `{ radians }`. |
82
+ | Dimensions | `rectangle` / `rectangleLoop` take `size: number \| [width, depth]`. `circle` / `circleLoop` and `sphere` take exactly one `radius` or `diameter`. `ellipse` / `ellipseLoop` take exactly one XY `radius` tuple or full `size` tuple. |
83
+ | Cylinders | +Z height and exactly one `radius` or `diameter`; either a uniform scalar or `[bottom, top]` tuple. One tuple end may be zero for a cone. |
84
+ | Origins | Shapes are centered by default. `center: false` places the box/rectangle minimum corner or cylinder/tube bottom at zero. Circles, ellipses, spheres and regular polygons remain centered. |
85
+ | Radial sizing | Circle, cylinder and regular polygon `sizing` defaults to `"vertex"`; `"face"` compensates polygon faceting to reach the nominal dimension at faces. Physical clearance is separate from Boolean overtravel. |
86
+ | Treatments | Corners and supported rims share `round` (radius), `chamfer` (distance), `smooth` (tangent setbacks), and `profile` (explicit millimetre points). Offsets use lowercase `join: "round" \| "miter" \| "square"`. |
87
+ | Sampling | Exact local `segments` override physical `resolution`; selected allocation ceilings still apply. Pure circle/ellipse loops use physical defaults when `segments` is omitted. |
88
+
89
+ Applicable edges, corners and supported rims share `EdgeTreatment`. `{ kind: "round", radius }`
90
+ uses an actual circular radius; `{ kind: "chamfer", distance }` uses equal setbacks, or
91
+ `distance: [first, second]` for unequal setbacks. `{ kind: "smooth", distance }` uses the same
92
+ setbacks with a cubic transition whose curvature reaches zero at both straight joins.
93
+ Its size is a setback, rather than a circular radius. Round `segments` describes a complete
94
+ circle and must divide by four for rectangle corners; smooth `segments` is an exact cubic
95
+ interval count. Physical cubic sampling uses chord error and segment length.
96
+
97
+ Rectangles select a uniform treatment or a tuple ordered top-right, top-left, bottom-left,
98
+ bottom-right; the tuple accepts `{ kind: "square" }`. Boxes select a uniform treatment or a map
99
+ of named edges and groups, such as `treatment: { top: { kind: "round", radius: 1 }, bottom:
100
+ { kind: "chamfer", distance: 1 } }`. Groups select the four top/bottom rim edges or `vertical`
101
+ edges; individual names include `"top-front"` and `"front-left"`. Overlapping selections fail.
102
+ Named faces use +Z top, +Y front
103
+ and +X right. Selected edge masks meet by intersection; they do not promise spherical three-edge
104
+ blends. Omitted selection retains the spherical all-edge circular box treatment.
105
+
106
+ `ends: { bottom, top }` independently finishes cylinder/frustum rims and straight convex
107
+ extrusions. Cylinder rounds account for the actual sloped side's angle. Extrusion finishing
108
+ requires one strictly convex contour without holes, twist, top scaling or divisions. Inward
109
+ parallel offsets preserve its original edge correspondence; disappearing/reversed edges fail.
110
+ Use explicit loft profiles for concave or holed transitions.
111
+
112
+ Custom `{ kind: "profile", profile }` treatments use exact sampled points from `[positive, 0]`
113
+ to `[0, positive]`, with decreasing first and increasing second coordinates. These are setbacks
114
+ along the two inward surface directions, in millimetres. Cylinder/extrusion ends use cap inset
115
+ first and side setback second. Rectangle corners follow the incoming and outgoing CCW edges.
116
+ For a named box edge, the first coordinate lies on the first named face and the second on the
117
+ second named face. Samples are captured per call, checked for fit and bounded before allocation;
118
+ no analytic curve or outward moulding is inferred. Ordinary curve helpers can prepare the points.
119
+
120
+ Primitive `placement: { source, target, ... }` maps a named or explicit local anchor onto a world
121
+ anchor, with optional alignment, gap and degree spin. Placement follows local construction,
122
+ including `center`; Section placement must preserve the XY plane.
123
+
124
+ Rectangle round radii may vary from zero (square corners) through half the smallest dimension
125
+ (a capsule or circle). Saturated tangent endpoints are emitted once. Uniform rectangle chamfers
126
+ and all-edge box rounds/chamfers require positive sizes smaller than half every dimension.
127
+ Selected box treatments must leave positive flat space between opposing setbacks.
128
+
129
+ Authored box, cylinder/frustum, tube, sphere, torus, rectangle, circle and ellipse handles know
130
+ `center`, `left`, `right`, `back`, `front`, `bottom` and `top` anchors. `left/right` follow −X/+X,
131
+ `back/front` follow −Y/+Y and `bottom/top` follow −Z/+Z. Regular polygons and stars provide `center`.
132
+ These are nominal construction datums: sampling and finishing do not move them; tube cap and torus
133
+ axial centers may lie over an opening. A cone omits the cap anchor at its zero-radius apex.
134
+ `anchor(shape, name)` reads its immutable frame, and `attach(pin, "bottom", anchor(base, "top"))`
135
+ mates opposed directions by default. Affine transforms and patterns carry positions, outward
136
+ normals and roll tangents with the shape, including nonuniform scaling and reflection.
137
+
138
+ `withAnchors(shape, { mount: createAnchor3(position, direction, up) })` returns a new same-kind handle
139
+ with copied definitions, retaining existing names unless replaced. Each shape supports at most 128
140
+ lowercase kebab-case names of at most 64 characters. Looking up an absent name reports the available
141
+ names. Shape lookup requires the exact active build; the returned `Anchor3` is copied plain data.
142
+ Boolean and other geometry construction results require deliberate definitions rather than
143
+ inheriting anchors that may no longer describe their surfaces. Custom rigid frames remain useful;
144
+ pure `boxAnchor3` and `cylinderAnchor3` calculate dimension-based frames without a native shape.
145
+
146
+ `GeometryResolution` defaults to 0.05 mm maximum chord error and 16–512 segments per complete circle. Precedence is exact local segments, operation resolution, context-derived resolution, then engine defaults. `model.withResolution(policy)` and imported `modelingFunctions(policy)` return a local method set for the same build. Destructure those methods to apply the local policy; other imported operations retain the original build policy. There is no global resolution or font state. Exact counts express deliberate faceting or fixed correspondence; adaptive curves retain physical deviation and edge-length constraints.
147
+
148
+ Revolution `segments` describes a complete circle; partial revolutions scale that count to the
149
+ angular span and round up. Native filled revolutions need at least three intervals: adaptive
150
+ sampling refines to that minimum, while exact counts below it fail explicitly. Pure `revolveMesh`
151
+ supports one interval.
152
+
153
+ `resamplePolyline2` and `resamplePolyline3` share physical sampling options and return immutable points with directed unit tangents. Open paths retain both endpoints; `closed: true` includes the closing edge and omits a repeated seam vertex. Exact closed counts require at least three segments. `regularPolygonLoop({ radius, sides, rotationDegrees, sizing })` creates a centered CCW point loop with an implicit seam. Shared `RadialSizing` is `"vertex"` by default or `"face"` to compensate polygon faceting so the requested radius reaches the faces; `CylinderOptions` owns that same sizing option.
154
+
155
+ `normalizeLoop2`, `normalizePolygon2`, and `normalizeRegion2` return immutable geometry and may reuse internally validated results. External objects are validated even when frozen. Mutable mesh buffers are analyzed freshly at external boundaries; engine facts are reused inside their owner.
156
+
157
+ ## Profiles and mechanical construction
158
+
159
+ `sampleOpenProfile` samples upward radius/height line and cubic chains. Consumers own closure and product constraints. Point factories such as `circleLoop` and `rectangleLoop` return ordered loops; `Profile` owns identified components, contours and landmarks, and `CorrespondingProfile` retains their shared sampled slots. `rectangle`, `rectangleLoop` and `rectangleProfile` share `size`, `center` and `treatment` options. Use the root primitive for ordinary modeling; pure loop/profile construction serves custom data and explicit correspondence. Native filled sections do not promise stable vertex ordering.
160
+
161
+ For a closed planar XYZ path, map the canonical loop with
162
+ `rectangleLoop(options).map(([x, y]) => [x, y, 0] as const)`. Before sampling, cap its
163
+ `limits.maxProfilePoints` at the smaller selected profile and path point ceilings. This keeps
164
+ path allocation bounded and preserves all corner tangent endpoints and the implicit seam.
165
+
166
+ `extrude(shape, { height, ... })`, `revolve(shape, options)` and `sweep(shape, path, options)` accept a filled Section or CorrespondingProfile, including holes and disconnected components. Open sweeps have watertight end caps; `closed: true` joins the path back to its beginning. Sweep options share degree twist, positive uniform or XY scale, and an XY scale pair per normalized path station. Closed scales interpolate along the implicit closing edge. A rotational symmetry seam uses `seamProfileOffset`, a counterclockwise logical point advance that reverses for clockwise hole contours; every contour must geometrically match the total twist. Incompatible seams fail explicitly.
167
+
168
+ Adaptive extrusion sampling bounds the entire side triangles, including the interaction between
169
+ profile edges, twist and unequal top scaling. `resolveExtrusionDivisions(profile, height, options)`
170
+ accepts a `Loop2` or filled `Region2` and measures every outer and hole edge; it is an optional estimate
171
+ using the same policy as construction. Exact `divisions` and deliberate angular counts retain their
172
+ precedence. Tight physical requests reject at selected sampling or output ceilings.
173
+
174
+ Nonzero sweep twist inserts stations according to `resolution`, including the deviation of side
175
+ triangles across profile edges. A full turn on a two-point path remains a full turn. Original
176
+ path stations retain their scales, twist progression and orientation-guide indices; `twistBy`
177
+ defaults to `"length"`, so angular progression follows physical path travel, including the implicit
178
+ closing edge. Choose `"stations"` for a deliberately authored station schedule. Inserted
179
+ stations interpolate centers, scales and shortest frame rotations. Guides run once per original
180
+ normalized station. Zero twist preserves the supplied path's existing mesh sampling. Explicit
181
+ `resolution.circularSegments` selects deliberate angular faceting; allocation ceilings still
182
+ apply. Adaptive scale changes can require subdivisions independently of angular travel; those
183
+ gaps use the selected full-curve interval ceiling. Refinement checks path and mesh budgets before
184
+ allocating the added station arrays.
185
+
186
+ Sweep `orientation` is one explicit policy shared by pure, filled, open and closed construction:
187
+ `{ kind: "transport", initialNormal? }` (default), `{ kind: "fixed-normal", normal }`,
188
+ `{ kind: "guide", normal: (point, index) => vector }`, or `{ kind: "frenet" }`. Transport minimizes
189
+ rotation and initially projects +X, then +Y, then +Z when no preference is supplied. A preferred
190
+ normal sets profile X; fixed and guide normals remain directed and project perpendicular to each
191
+ local tangent. Guide signs are preserved. Frenet uses projected neighboring sampled tangent changes
192
+ as curvature normals. Zero curvature and parallel explicit normals reject instead of switching
193
+ policies. For a planar closed path whose profile X should stay vertical, request
194
+ `orientation: { kind: "transport", initialNormal: [0, 0, 1] }`. Closed policies use cyclic tangents
195
+ and the same first frame on their closing gap.
196
+
197
+ `loft(stations, options)` accepts a `profile` and exactly one horizontal `z` height or explicit
198
+ right-handed `frame` per station. Stations stay in input order. Ordinary primitives keep the
199
+ simple case at the root entry point:
200
+
201
+ ```ts
202
+ import { circle, loft, rectangle } from "@metamesh/modeling";
203
+
204
+ export function build() {
205
+ return loft([
206
+ { profile: circle({ diameter: 20 }), z: 0 },
207
+ { profile: rectangle({ size: [30, 15], treatment: { kind: "round", radius: 3 } }), z: 40 },
208
+ ]);
209
+ }
210
+ ```
211
+
212
+ With omitted `correspondence`, compatible rectangle stations, circle/ellipse rings, equal-sided
213
+ regular polygons and equal-pointed stars use their retained authored landmarks. Rectangle corners
214
+ can change among square, round and chamfer treatments, including collapsed or saturated rounds.
215
+ Circle/ellipse and rectangle stations also share those quadrant/corner landmarks: a circular
216
+ inlet becomes a rounded rectangle directly, without an authored saturated-square workaround.
217
+ Exact circular counts for this mixed family must divide by four; other deliberately faceted counts
218
+ need an explicit geometric method. Adaptive counts align upward within the selected ceilings.
219
+ XY affine transforms preserve these identities; this semantic path requires consistent handedness.
220
+ Other unlike retained primitive families use direct perimeter subdivision from their construction-local
221
+ +X ray seam. Every physical input vertex remains, including corner tangent endpoints. Retained
222
+ curves use the selected loft resolution under every method, accounting for transform magnification.
223
+ Exact primitive samples preserve deliberate faceting; `refine` can deliberately add collinear density.
224
+ When an exact primitive is paired with a finer member, a shared union of parameter knots retains
225
+ its original polygon and inserts only collinear points on its facets. Adaptive members retain
226
+ physical curve sampling. Circle face sizing uses the actual minimum facet support from the local
227
+ origin, so collapsed slots, unequal quarter counts and collinear refinements preserve nominal clearance.
228
+
229
+ Boolean, offset and import operations discard primitive identity. Their Sections and plain point
230
+ loops require an explicitly selected correspondence method. This choice associates ordered
231
+ contours by component and hole index; it does not identify arbitrary components or repair changed
232
+ topology. Use identified profiles when those identities matter. Explicitly choosing a method on
233
+ known primitives also runs that geometric method, rather than substituting semantic matching.
234
+
235
+ | `correspondence` | Association |
236
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
237
+ | `"direct"` | Preserve each seam and subdivide edges to a common count without dropping vertices. |
238
+ | `"reindex"` | Direct subdivision, then choose the next contour's cyclic phase with the least total world-space connection length. |
239
+ | `"fast-distance"` | Keep the supplied seams and minimize connection length over ordered closed vertex associations, repeating vertices for triangular fans. |
240
+ | `"distance"` | The same ordered optimization over every cyclic phase of the next contour. |
241
+
242
+ One method applies to every gap; an array supplies one per gap. `distribution` defaults to
243
+ `"perimeter"` for direct/reindex and `"segments"` when any distance method is present. It controls
244
+ where extra subdivisions go; distance methods require segments. `refine` is a positive integer
245
+ multiplier, uniformly or per input profile. `slices` is a nonnegative intermediate-profile count,
246
+ uniformly or per gap. Slices interpolate the corresponding placed world vertices, never frame axes.
247
+ Insertions propagate across a shared grid, so mixed methods retain each middle profile without
248
+ T-junctions. Phase ties keep the earliest phase; ordered optimization prefers diagonal, previous-only,
249
+ then next-only advances. Its objective sums connection lengths with the closing seam counted once.
250
+ No tangent/supporting-plane association is exposed: general concave and spatial stations do not
251
+ provide the convexity contract that such a method needs.
252
+
253
+ For precise custom correspondence, prepare `matchProfiles` over explicit `Profile` specifications.
254
+ It chooses the maximum physical interval count for each paired span across the family, including
255
+ span-local `resolution`; identified line, arc and cubic kinds may change while IDs, order and
256
+ connected endpoints remain valid. `CorrespondingProfile` landmarks are authoritative, so geometric
257
+ remapping methods are rejected; direct refinement preserves every paired slot. `rectangleProfile`
258
+ is the canonical identified rectangle factory. Changed IDs, winding or filled topology fail.
259
+ Lofting merges coincident world vertices, omits degenerate faces and triangulates hole caps natively.
260
+
261
+ All loft routes share `LoftOptions`. Pure `loftMesh` requires an explicit method and returns a
262
+ closed simple-loop mesh without an engine. Selected sampling/output budgets apply before expanded
263
+ grids and mesh buffers; fixed aggregate safeguards bound correspondence at eight million comparisons
264
+ and the complete grid at one million logical slots. Simple-loop cap triangulation also has an
265
+ eight-million-comparison work ceiling. Complexity rejects instead of reducing fidelity
266
+ or substituting another method. Pure counterparts also include `sweepMesh`, `extrudeMesh` and `revolveMesh`.
267
+
268
+ `linearPattern(shape, { count, length })` determines equal intervals from exactly two of `count`,
269
+ signed `spacing`, and signed total `length`; its direction defaults to +X. Length and spacing must
270
+ fit a whole interval count. `gridPattern(shape, { count: [3, 2], spacing: [10, 8] })` supports XY
271
+ or XYZ tuples, optional centering and an explicit frame; X varies fastest. `pathPattern(shape,
272
+ path, { count })` distributes copies by physical arc length, including both endpoints for open
273
+ paths and omitting a repeated closed seam. Its optional `orientation: "tangent"` aligns local +Z
274
+ to the containing segment by the shortest rotation from world +Z (a -Z tangent uses a +X half turn);
275
+ the default preserves source orientation. These placements transform the source's local origin.
276
+ All four pattern families, including `radialPattern`, accept a same-build Solid or an `(index) =>
277
+ Solid` factory for per-copy variation. Factories run once in ascending index order. The 100000-copy
278
+ algorithm ceiling and selected output budgets reject before predictable native copy allocation;
279
+ varying factories are checked cumulatively before each transform. Path input and placement counts
280
+ also obey `maxPathPoints`. Copies use the shared transform and lifetime checks.
281
+
282
+ Identified `ProfileSpan2` supports lines, arcs, and cubic Béziers with `start`, `control1`, `control2`,
283
+ and `end`. Cubics reuse the curve evaluator and physical subdivision policy, selecting one uniform
284
+ parameter grid for corresponding spans. Fully collapsed spans retain logical slots without moving
285
+ endpoints. Sampled contours and components use `CorrespondingContour` and `CorrespondingComponent`.
286
+ Pass the complete family to `matchProfiles` with optional `limits.maxProfilePoints`; its default is
287
+ 100,000 points per profile, while a separate one-million-slot family work bound remains in force.
288
+
289
+ `heightfieldMesh` and the modeling `heightfield` create a closed grid surface with explicit XY size, segment counts, and base Z. Heights are absolute Z values strictly above the base. Allocation is checked before sampling, and the height callback runs once per grid point.
290
+
291
+ Pure mechanical modules own thread profiles, sampling, printable fit, meshes, and allocation-free `preflightThreadedRod`, `preflightInternalThreadCutter`, and `preflightThreadedNut`. Engine methods own native construction. `pitch` is adjacent axial spacing; `lead = pitch × starts` is advance per turn. Internal cutters extend beyond requested faces and compensate faceting while preserving end treatments. Printable modeling forms are not certified thread classes or structural ratings.
292
+
293
+ `implicit` samples a finite positive-inside field within explicit bounds and grid spacing. Grid allocations and field evaluations are bounded. `components` returns same-build handles. `simplify` requires explicit millimetre tolerance and preserves native original-surface cleanup semantics.
294
+
295
+ ## Prepared text and SVG
296
+
297
+ Preparation shapes text once with the host's exact font service and retains immutable `VectorTextLayout`. Imported `textSection(layout, options)` consumes vector paths directly, without font shaping, fetching, or ambient providers. Paths and metrics use Y-up millimetres and a baseline origin. Empty layouts are measurable but cannot create sections. Font preparation remains optional and outside synchronous builds.
298
+
299
+ Install `fontkit` to use `prepareVectorFont` from `/text`, and `woff2-encoder` when decoding WOFF2. These optional peers are loaded only when preparing fonts. `sampleTextContours` from `/geometry` and `textSection` share bounded path sampling and need no font dependencies for an already prepared layout.
300
+
301
+ `svgSection` imports bounded painted SVG documents; `svgPathSection` imports filled path data. Y-down coordinates convert to Y-up; nonzero/even-odd filling preserves counters. Sampling applies after transforms and unit conversion. Basic shapes, groups, affine transforms, physical units, viewBox, fills, and strokes are supported. Text must be outlined. External resources, scripts, clipping, masks, filters, and unsupported content fail contextually. Pure parsers are shared with validation and the vector editor.
302
+
303
+ ## Final triangle topology
304
+
305
+ `analyzeTriangleMesh` validates and supplies bounds, counts, area, and signed volume in one traversal, with optional edge/component facts. Measurements, bounds, and signatures are independent immutable snapshots; external mutable buffers are inspected freshly on each call. Closed-edge checks require two oppositely wound faces per edge; they do not detect every geometric self-intersection. `createTriangleMeshSignature` adds quantized bounds, volume, topology, and a regression fingerprint, not a cryptographic digest.
306
+
307
+ The optional `meshTopologyMode: "optimized"` build setting runs bounded planar edge flips for either execution lane. It preserves vertices, boundaries, winding, closure, reconstructability, area, and volume. Models above 200,000 triangles skip optimization; unsupported or failed candidates preserve their original part. Equal shared mesh views reuse one optimized candidate. The selected buffers must still fit all execution ceilings; optimization that would exceed them preserves the original model. This is local connectivity cleanup, not general remeshing. Source buffers never change in place.
308
+
309
+ ## Quality gates
310
+
311
+ Follow the [workspace instructions](https://github.com/JasonKoolman/metamesh/blob/main/packages/modeling/AGENTS.md#verification) for required checks. Timing and sampled process memory are diagnostics, not deterministic assertions or WASM heap measurements. The [publication contract](https://github.com/JasonKoolman/metamesh/blob/main/docs/continuous-delivery.md#public-library-publication) owns tarballs, clean standalone Node/Worker consumers, and release identity. Installed dependency size and browser bundles are measured separately; ZIP serialization and optional font dependencies load only through their capabilities.
312
+
313
+ ## License
314
+
315
+ Apache-2.0. Bundled offline artifacts also carry `THIRD_PARTY_NOTICES.md`.