brep-io-kernel 1.0.184 → 1.0.185

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.
@@ -141,7 +141,7 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
141
141
  <section class="card doc-card">
142
142
 
143
143
  <div class="prose">
144
- <h1><a href="https://BREP.io">BREP.io</a></h1><h1><a href="https://github.com/mmiscool/BREP">Source <a href="https://github.com/mmiscool/BREP" target="_blank" rel="noopener noreferrer">https://github.com/mmiscool/BREP</a></a></h1><ul><li><a href="https://www.npmjs.com/package/brep-io-kernel">NPM package: <code>brep-io-kernel</code> <a href="https://www.npmjs.com/package/brep-io-kernel" target="_blank" rel="noopener noreferrer">https://www.npmjs.com/package/brep-io-kernel</a></a></li><li><a href="https://BREP.io/apiExamples/index.html">Live API examples <a href="https://BREP.io/apiExamples/index.html" target="_blank" rel="noopener noreferrer">https://BREP.io/apiExamples/index.html</a></a></li><li><a href="https://discord.gg/R5KNAKrQ">Developer Discord <a href="https://discord.gg/R5KNAKrQ" target="_blank" rel="noopener noreferrer">https://discord.gg/R5KNAKrQ</a></a></li></ul><p>BREP.io is a browser-based CAD application and JavaScript kernel for feature-based solid modeling. At its core is a BREP-style modeler with explicit geometry/topology objects such as <code>Solid</code>, <code>Face</code>, <code>Edge</code>, and <code>Vertex</code>, paired with an editable feature-history pipeline. It also includes sketch workflows powered by a standalone 2D constraint solver, plus robust manifold booleans (<a href="https://github.com/elalish/manifold">manifold-3d</a>), mesh repair/import tooling, assembly constraints, PMI annotations, and embeddable CAD/sketcher APIs.</p><p>This project is in active development and APIs may continue to evolve.</p><h2>Workbenches</h2><ul><li><a href="workbenches__modeling.html">Modeling Workbench</a></li><li><a href="workbenches__import.html">Import Workbench</a></li><li><a href="workbenches__surfacing.html">Surfacing Workbench</a></li><li><a href="workbenches__sheet-metal.html">Sheet Metal Workbench</a></li><li><a href="workbenches__assemblies.html">Assemblies Workbench</a></li><li><a href="workbenches__wire-harness.html">Wire Harness Workbench</a></li><li><a href="workbenches__pmi.html">PMI Workbench</a></li><li><a href="workbenches__all.html">All Workbench</a></li></ul><h2>Screenshots</h2><p><img src="HOME.png" alt="Home" width="280" loading="lazy" /> <a href="modes__modeling.html"><img src="MODELING.png" alt="Modeling Mode" width="280" loading="lazy" /></a> <a href="modes__sketch.html"><img src="SKETCH.png" alt="Sketch Mode" width="280" loading="lazy" /></a> <a href="modes__pmi.html"><img src="PMI.png" alt="PMI Mode" width="280" loading="lazy" /></a> <a href="modes__sheets.html"><img src="SHEETS.png" alt="2D Sheets Mode" width="280" loading="lazy" /></a> <a href="features__image-to-face.html"><img src="features__image-to-face-2D_dialog.png" alt="Image to Face 2D" width="280" loading="lazy" /></a> <a href="features__image-to-face.html"><img src="features__image-to-face-3D_dialog.png" alt="Image to Face 3D" width="280" loading="lazy" /></a></p><h2>Documentation Index</h2><p>General:</p><ul><li><a href="getting-started.html">Getting Started</a></li><li><a href="developer-index.html">Developer Docs Index</a></li><li><a href="bug-reporting.html">Bug Reporting and Repro Test Cases</a></li><li><a href="highlights.html">Highlights</a></li><li><a href="whats-new.html">What&#39;s New</a></li><li><a href="api-examples.html">API Examples</a></li></ul><p>Core APIs:</p><ul><li><a href="brep-api.html">BREP API Export Map</a></li><li><a href="brep-kernel.html">BREP Kernel Reference</a></li><li><a href="solid-methods.html">Solid Methods</a></li><li><a href="part-history.html">Part History</a></li><li><a href="sketch-solver-2d.html">2D Sketch Solver</a></li><li><a href="cad-embed.html">Embeddable CAD (<code>CadEmbed</code>)</a></li><li><a href="sketcher2d-embed.html">Embeddable Sketcher (<code>Sketcher2DEmbed</code>)</a></li></ul><p>System docs:</p><ul><li><a href="history-systems.html">History Systems</a></li><li><a href="input-params-schema.html">Input Params Schema</a></li><li><a href="file-formats.html">File Formats: Import and Export</a></li><li><a href="plugins.html">Plugins and Examples</a></li><li><a href="inspector.html">Inspector</a></li><li><a href="inspector-improvements.html">Inspector Improvements</a></li></ul><p>Mode guides:</p><ul><li><a href="modes__modeling.html">Modeling Mode</a></li><li><a href="modes__sketch.html">Sketch Mode</a></li><li><a href="modes__pmi.html">PMI Mode</a></li><li><a href="modes__sheets.html">2D Sheets Mode</a></li></ul><h2>Modeling Feature Docs</h2><p>Feature index:</p><ul><li><a href="features__index.html">All Feature Docs</a></li></ul><p>Primitives and setup:</p><ul><li><a href="features__primitive-cube.html">Primitive Cube</a></li><li><a href="features__primitive-cylinder.html">Primitive Cylinder</a></li><li><a href="features__primitive-cone.html">Primitive Cone</a></li><li><a href="features__primitive-sphere.html">Primitive Sphere</a></li><li><a href="features__primitive-torus.html">Primitive Torus</a></li><li><a href="features__primitive-pyramid.html">Primitive Pyramid</a></li><li><a href="features__plane.html">Plane</a></li><li><a href="features__datum.html">Datum</a></li><li><a href="features__datium.html">Datium</a></li><li><a href="features__sketch.html">Sketch</a></li><li><a href="features__spline.html">Spline</a></li><li><a href="features__helix.html">Helix</a></li></ul><p>Solid operations:</p><ul><li><a href="features__extrude.html">Extrude</a></li><li><a href="features__sweep.html">Sweep</a></li><li><a href="features__tube.html">Tube</a></li><li><a href="features__loft.html">Loft</a></li><li><a href="features__revolve.html">Revolve</a></li><li><a href="features__mirror.html">Mirror</a></li><li><a href="features__boolean.html">Boolean</a></li><li><a href="features__fillet.html">Fillet</a></li><li><a href="features__chamfer.html">Chamfer</a></li><li><a href="features__hole.html">Hole</a></li><li><a href="features__offset-shell.html">Offset Shell</a></li><li><a href="features__remesh.html">Remesh</a></li><li><a href="features__transform.html">Transform</a></li></ul><p>Pattern, import, and generation:</p><ul><li><a href="features__pattern.html">Pattern (Legacy Combined)</a></li><li><a href="features__pattern-linear.html">Pattern Linear</a></li><li><a href="features__pattern-radial.html">Pattern Radial</a></li><li><a href="features__import-3d-model.html">Import 3D Model</a></li><li><a href="features__image-heightmap-solid.html">Image Heightmap Solid</a></li><li><a href="features__image-to-face.html">Image to Face</a></li><li><a href="features__text-to-face.html">Text to Face</a></li></ul><p>Assembly and sheet metal:</p><ul><li><a href="features__assembly-component.html">Assembly Component</a></li><li><a href="features__sheet-metal-tab.html">Sheet Metal Tab</a></li><li><a href="features__sheet-metal-contour-flange.html">Sheet Metal Contour Flange</a></li><li><a href="features__sheet-metal-flange.html">Sheet Metal Flange</a></li></ul><p>Additional implemented features in the codebase include collapse edge, edge smooth, offset face, overlap cleanup, sheet metal hem, and sheet metal cutout.</p><h2>Assembly Constraints</h2><ul><li><a href="assembly-constraints__solver.html">Assembly Constraint Solver</a></li><li><a href="assembly-constraints__coincident-constraint.html">Coincident</a></li><li><a href="assembly-constraints__distance-constraint.html">Distance</a></li><li><a href="assembly-constraints__angle-constraint.html">Angle</a></li><li><a href="assembly-constraints__parallel-constraint.html">Parallel</a></li><li><a href="assembly-constraints__touch-align-constraint.html">Touch Align</a></li><li><a href="assembly-constraints__fixed-constraint.html">Fixed</a></li></ul><h2>PMI Annotation Docs</h2><ul><li><a href="pmi-annotations__index.html">PMI Annotations Index</a></li><li><a href="pmi-annotations__linear-dimension.html">Linear Dimension</a></li><li><a href="pmi-annotations__radial-dimension.html">Radial Dimension</a></li><li><a href="pmi-annotations__angle-dimension.html">Angle Dimension</a></li><li><a href="pmi-annotations__leader.html">Leader</a></li><li><a href="pmi-annotations__note.html">Note</a></li><li><a href="pmi-annotations__hole-callout.html">Hole Callout</a></li><li><a href="pmi-annotations__explode-body.html">Explode Body</a></li></ul><h2>Quick Start</h2><p>Prerequisites:</p><ul><li>Node.js 18+</li><li><code>pnpm</code></li><li><code>git submodule update --init --recursive</code></li><li>Emscripten SDK (<code>emcmake</code>/<code>emcc</code> on <code>PATH</code>, or EMSDK installed at <code>$HOME/emsdk</code>)</li></ul><p>Install and run locally:</p><div class="doc-codeblock" data-code-language="bash">
144
+ <h1><a href="https://BREP.io">BREP.io</a></h1><h1><a href="https://github.com/mmiscool/BREP">Source <a href="https://github.com/mmiscool/BREP" target="_blank" rel="noopener noreferrer">https://github.com/mmiscool/BREP</a></a></h1><ul><li><a href="https://www.npmjs.com/package/brep-io-kernel">NPM package: <code>brep-io-kernel</code> <a href="https://www.npmjs.com/package/brep-io-kernel" target="_blank" rel="noopener noreferrer">https://www.npmjs.com/package/brep-io-kernel</a></a></li><li><a href="https://BREP.io/apiExamples/index.html">Live API examples <a href="https://BREP.io/apiExamples/index.html" target="_blank" rel="noopener noreferrer">https://BREP.io/apiExamples/index.html</a></a></li><li><a href="https://discord.gg/R5KNAKrQ">Developer Discord <a href="https://discord.gg/R5KNAKrQ" target="_blank" rel="noopener noreferrer">https://discord.gg/R5KNAKrQ</a></a></li></ul><p>BREP.io is a browser-based CAD application and JavaScript kernel for feature-based solid modeling. At its core is a BREP-style modeler with explicit geometry/topology objects such as <code>Solid</code>, <code>Face</code>, <code>Edge</code>, and <code>Vertex</code>, paired with an editable feature-history pipeline. It also includes sketch workflows powered by a standalone 2D constraint solver, plus robust manifold booleans (<a href="https://github.com/elalish/manifold">manifold-3d</a>), mesh repair/import tooling, assembly constraints, PMI annotations, and embeddable CAD/sketcher APIs.</p><p>This project is in active development and APIs may continue to evolve.</p><h2>Workbenches</h2><ul><li><a href="workbenches__modeling.html">Modeling Workbench</a></li><li><a href="workbenches__import.html">Import Workbench</a></li><li><a href="workbenches__surfacing.html">Surfacing Workbench</a></li><li><a href="workbenches__sheet-metal.html">Sheet Metal Workbench</a></li><li><a href="workbenches__assemblies.html">Assemblies Workbench</a></li><li><a href="workbenches__wire-harness.html">Wire Harness Workbench</a></li><li><a href="workbenches__pmi.html">PMI Workbench</a></li><li><a href="workbenches__all.html">All Workbench</a></li></ul><h2>Screenshots</h2><p><img src="HOME.png" alt="Home" width="280" loading="lazy" /> <a href="modes__modeling.html"><img src="MODELING.png" alt="Modeling Mode" width="280" loading="lazy" /></a> <a href="modes__sketch.html"><img src="SKETCH.png" alt="Sketch Mode" width="280" loading="lazy" /></a> <a href="modes__pmi.html"><img src="PMI.png" alt="PMI Mode" width="280" loading="lazy" /></a> <a href="modes__sheets.html"><img src="SHEETS.png" alt="2D Sheets Mode" width="280" loading="lazy" /></a> <a href="features__image-to-face.html"><img src="features__image-to-face-2D_dialog.png" alt="Image to Face 2D" width="280" loading="lazy" /></a> <a href="features__image-to-face.html"><img src="features__image-to-face-3D_dialog.png" alt="Image to Face 3D" width="280" loading="lazy" /></a></p><h2>Documentation Index</h2><p>General:</p><ul><li><a href="getting-started.html">Getting Started</a></li><li><a href="developer-index.html">Developer Docs Index</a></li><li><a href="bug-reporting.html">Bug Reporting and Repro Test Cases</a></li><li><a href="highlights.html">Highlights</a></li><li><a href="whats-new.html">What&#39;s New</a></li><li><a href="api-examples.html">API Examples</a></li></ul><p>Core APIs:</p><ul><li><a href="brep-api.html">BREP API Export Map</a></li><li><a href="brep-kernel.html">BREP Kernel Reference</a></li><li><a href="solid-methods.html">Solid Methods</a></li><li><a href="expressions.html">Expressions and Configurator</a></li><li><a href="part-history.html">Part History</a></li><li><a href="sketch-solver-2d.html">2D Sketch Solver</a></li><li><a href="cad-embed.html">Embeddable CAD (<code>CadEmbed</code>)</a></li><li><a href="sketcher2d-embed.html">Embeddable Sketcher (<code>Sketcher2DEmbed</code>)</a></li></ul><p>System docs:</p><ul><li><a href="history-systems.html">History Systems</a></li><li><a href="input-params-schema.html">Input Params Schema</a></li><li><a href="file-formats.html">File Formats: Import and Export</a></li><li><a href="plugins.html">Plugins and Examples</a></li><li><a href="inspector.html">Inspector</a></li><li><a href="inspector-improvements.html">Inspector Improvements</a></li></ul><p>Mode guides:</p><ul><li><a href="modes__modeling.html">Modeling Mode</a></li><li><a href="modes__sketch.html">Sketch Mode</a></li><li><a href="modes__pmi.html">PMI Mode</a></li><li><a href="modes__sheets.html">2D Sheets Mode</a></li></ul><h2>Modeling Feature Docs</h2><p>Feature index:</p><ul><li><a href="features__index.html">All Feature Docs</a></li></ul><p>Primitives and setup:</p><ul><li><a href="features__primitive-cube.html">Primitive Cube</a></li><li><a href="features__primitive-cylinder.html">Primitive Cylinder</a></li><li><a href="features__primitive-cone.html">Primitive Cone</a></li><li><a href="features__primitive-sphere.html">Primitive Sphere</a></li><li><a href="features__primitive-torus.html">Primitive Torus</a></li><li><a href="features__primitive-pyramid.html">Primitive Pyramid</a></li><li><a href="features__plane.html">Plane</a></li><li><a href="features__datum.html">Datum</a></li><li><a href="features__datium.html">Datium</a></li><li><a href="features__sketch.html">Sketch</a></li><li><a href="features__spline.html">Spline</a></li><li><a href="features__helix.html">Helix</a></li></ul><p>Solid operations:</p><ul><li><a href="features__extrude.html">Extrude</a></li><li><a href="features__sweep.html">Sweep</a></li><li><a href="features__tube.html">Tube</a></li><li><a href="features__loft.html">Loft</a></li><li><a href="features__revolve.html">Revolve</a></li><li><a href="features__mirror.html">Mirror</a></li><li><a href="features__boolean.html">Boolean</a></li><li><a href="features__fillet.html">Fillet</a></li><li><a href="features__chamfer.html">Chamfer</a></li><li><a href="features__hole.html">Hole</a></li><li><a href="features__offset-shell.html">Offset Shell</a></li><li><a href="features__remesh.html">Remesh</a></li><li><a href="features__transform.html">Transform</a></li></ul><p>Pattern, import, and generation:</p><ul><li><a href="features__pattern.html">Pattern (Legacy Combined)</a></li><li><a href="features__pattern-linear.html">Pattern Linear</a></li><li><a href="features__pattern-radial.html">Pattern Radial</a></li><li><a href="features__import-3d-model.html">Import 3D Model</a></li><li><a href="features__image-heightmap-solid.html">Image Heightmap Solid</a></li><li><a href="features__image-to-face.html">Image to Face</a></li><li><a href="features__text-to-face.html">Text to Face</a></li></ul><p>Assembly and sheet metal:</p><ul><li><a href="features__assembly-component.html">Assembly Component</a></li><li><a href="features__sheet-metal-tab.html">Sheet Metal Tab</a></li><li><a href="features__sheet-metal-contour-flange.html">Sheet Metal Contour Flange</a></li><li><a href="features__sheet-metal-flange.html">Sheet Metal Flange</a></li></ul><p>Additional implemented features in the codebase include collapse edge, edge smooth, offset face, overlap cleanup, sheet metal hem, and sheet metal cutout.</p><h2>Assembly Constraints</h2><ul><li><a href="assembly-constraints__solver.html">Assembly Constraint Solver</a></li><li><a href="assembly-constraints__coincident-constraint.html">Coincident</a></li><li><a href="assembly-constraints__distance-constraint.html">Distance</a></li><li><a href="assembly-constraints__angle-constraint.html">Angle</a></li><li><a href="assembly-constraints__parallel-constraint.html">Parallel</a></li><li><a href="assembly-constraints__touch-align-constraint.html">Touch Align</a></li><li><a href="assembly-constraints__fixed-constraint.html">Fixed</a></li></ul><h2>PMI Annotation Docs</h2><ul><li><a href="pmi-annotations__index.html">PMI Annotations Index</a></li><li><a href="pmi-annotations__linear-dimension.html">Linear Dimension</a></li><li><a href="pmi-annotations__radial-dimension.html">Radial Dimension</a></li><li><a href="pmi-annotations__angle-dimension.html">Angle Dimension</a></li><li><a href="pmi-annotations__leader.html">Leader</a></li><li><a href="pmi-annotations__note.html">Note</a></li><li><a href="pmi-annotations__hole-callout.html">Hole Callout</a></li><li><a href="pmi-annotations__explode-body.html">Explode Body</a></li></ul><h2>Quick Start</h2><p>Prerequisites:</p><ul><li>Node.js 18+</li><li><code>pnpm</code></li><li><code>git submodule update --init --recursive</code></li><li>Emscripten SDK (<code>emcmake</code>/<code>emcc</code> on <code>PATH</code>, or EMSDK installed at <code>$HOME/emsdk</code>)</li></ul><p>Install and run locally:</p><div class="doc-codeblock" data-code-language="bash">
145
145
  <div class="doc-codeblock-header">
146
146
  <span class="doc-codeblock-lang">bash</span>
147
147
  <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
@@ -271,6 +271,7 @@ console.log(getAllLicensesInfoString()); <span class="tok-comment">// package
271
271
  <li><a href="./cylindrical-face-radius-embedding.html">Cylindrical Face Radius Embedding</a></li>
272
272
  <li><a href="./developer-index.html">Developer Docs Index</a></li>
273
273
  <li><a href="./dialog-screenshots.html">Documentation Screenshots</a></li>
274
+ <li><a href="./expressions.html">Expressions and Configurator</a></li>
274
275
  <li><a href="./extruded-sketch-radius-embedding.html">Radius Metadata for Extruded Sketches</a></li>
275
276
  <li><a href="./feature-dimension-gizmos.html">Feature Dimension Gizmos (Developer)</a></li>
276
277
  <li><a href="./features__assembly-component.html">Assembly Component</a></li>
@@ -168,7 +168,22 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
168
168
  multiple: <span class="tok-keyword">false</span>, <span class="tok-comment">// Optional</span>
169
169
  },
170
170
  };</code></pre></div>
171
- </div><p><code>SchemaForm</code> clones <code>default_value</code> when seeding <code>params</code>; when a default is omitted it falls back to <code>false</code> for booleans, <code>&#39;&#39;</code> for most text/select fields, <code>null</code> for single reference selections, <code>{ position:[0,0,0], rotationEuler:[0,0,0], scale:[1,1,1] }</code> for transforms, and <code>[0,0,0]</code> for vec3. Keys <code>id</code> and <code>featureID</code> are reserved and not rendered. You can override rendering with <code>renderWidget</code> or <code>widgetRenderer</code> (a function that receives <code>{ ui, key, def, id, controlWrap, row }</code>). PMI annotations also honor <code>defaultResolver({ pmimode, handler })</code> for dynamic defaults.</p><h2>Selection filters for references</h2><p><code>reference_selection</code> widgets call <code>SelectionFilter.SetSelectionTypes(def.selectionFilter)</code>. Valid tokens come from <code>SelectionFilter.TYPES</code>: <code>SOLID</code>, <code>COMPONENT</code>, <code>FACE</code>, <code>PLANE</code>, <code>SKETCH</code>, <code>EDGE</code>, <code>LOOP</code>, <code>VERTEX</code>, or <code>ALL</code> (to allow any scene pick).</p><h2>Widget types</h2><h3>string</h3><ul><li>Required: <code>type: &#39;string&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code></li><li>Behavior: single-line text box.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
171
+ </div><p><code>SchemaForm</code> clones <code>default_value</code> when seeding <code>params</code>; when a default is omitted it falls back to <code>false</code> for booleans, <code>&#39;&#39;</code> for most text/select fields, <code>null</code> for single reference selections, <code>{ position:[0,0,0], rotationEuler:[0,0,0], scale:[1,1,1] }</code> for transforms, and <code>[0,0,0]</code> for vec3. Keys <code>id</code> and <code>featureID</code> are reserved and not rendered. You can override rendering with <code>renderWidget</code> or <code>widgetRenderer</code> (a function that receives <code>{ ui, key, def, id, controlWrap, row }</code>). PMI annotations also honor <code>defaultResolver({ pmimode, handler })</code> for dynamic defaults.</p><h2>Expressions in dialogs</h2><p>For the dedicated user-facing Expressions panel guide, see <a href="expressions.html">Expressions and Configurator</a>.</p><p><code>SchemaForm</code> evaluates expression-capable fields against <code>partHistory.getExpressionsSource()</code>. That source includes:</p><ul><li>the default prelude (<code>resolution = 32;</code>)</li><li>the current configurator values object (<code>configurator</code>)</li><li>the user script from the Expressions panel</li></ul><p>In practice, dialog fields can reference:</p><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
172
+ <div class="doc-codeblock-header">
173
+ <span class="doc-codeblock-lang">javascript</span>
174
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
175
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
176
+ <svg viewBox="0 0 24 24" fill="none">
177
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
178
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
179
+ </svg>
180
+ </span>
181
+ </button>
182
+ </div>
183
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">width * 2
184
+ configurator.panelWidth
185
+ configurator.materialName</code></pre></div>
186
+ </div><p>Expression UI behavior:</p><ul><li><code>number</code> fields always accept expressions.</li><li><code>string</code> fields can opt in with <code>allowExpression: true</code>.</li><li>The form stores raw expression text in <code>params.__expr</code> and keeps the evaluated display value in the main field.</li><li>When expressions or configurator values change, open dialogs refresh so displayed values stay in sync.</li></ul><h2>Selection filters for references</h2><p><code>reference_selection</code> widgets call <code>SelectionFilter.SetSelectionTypes(def.selectionFilter)</code>. Valid tokens come from <code>SelectionFilter.TYPES</code>: <code>SOLID</code>, <code>COMPONENT</code>, <code>FACE</code>, <code>PLANE</code>, <code>SKETCH</code>, <code>EDGE</code>, <code>LOOP</code>, <code>VERTEX</code>, or <code>ALL</code> (to allow any scene pick).</p><h2>Widget types</h2><h3>string</h3><ul><li>Required: <code>type: &#39;string&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code>, <code>allowExpression</code></li><li>Behavior: single-line text box.</li><li>When <code>allowExpression: true</code>, the field can evaluate expression text and stores the raw expression in <code>params.__expr[key]</code>.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
172
187
  <div class="doc-codeblock-header">
173
188
  <span class="doc-codeblock-lang">javascript</span>
174
189
  <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
@@ -186,6 +201,24 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
186
201
  default_value: <span class="tok-string">&#39;My feature&#39;</span>, <span class="tok-comment">// Optional</span>
187
202
  hint: <span class="tok-string">&#39;Shown in the tree&#39;</span>, <span class="tok-comment">// Optional</span>
188
203
  }</code></pre></div>
204
+ </div><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
205
+ <div class="doc-codeblock-header">
206
+ <span class="doc-codeblock-lang">javascript</span>
207
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
208
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
209
+ <svg viewBox="0 0 24 24" fill="none">
210
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
211
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
212
+ </svg>
213
+ </span>
214
+ </button>
215
+ </div>
216
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">text: {
217
+ type: <span class="tok-string">&#39;string&#39;</span>,
218
+ label: <span class="tok-string">&#39;Text&#39;</span>,
219
+ allowExpression: <span class="tok-keyword">true</span>,
220
+ default_value: <span class="tok-string">&#39;configurator.label&#39;</span>
221
+ }</code></pre></div>
189
222
  </div><h3>textarea</h3><ul><li>Required: <code>type: &#39;textarea&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code>, <code>rows</code>, <code>placeholder</code></li><li>Behavior: multi-line text area with optional placeholder.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
190
223
  <div class="doc-codeblock-header">
191
224
  <span class="doc-codeblock-lang">javascript</span>
@@ -204,7 +237,7 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
204
237
  rows: 3, <span class="tok-comment">// Optional</span>
205
238
  placeholder: <span class="tok-string">&#39;Enter notes…&#39;</span>, <span class="tok-comment">// Optional</span>
206
239
  }</code></pre></div>
207
- </div><h3>number</h3><ul><li>Required: <code>type: &#39;number&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code>, <code>step</code>, <code>min</code>, <code>max</code></li><li>Behavior: numeric input that flips to text when the value looks like an expression.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
240
+ </div><h3>number</h3><ul><li>Required: <code>type: &#39;number&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code>, <code>step</code>, <code>min</code>, <code>max</code></li><li>Behavior: numeric input that flips to text when the value looks like an expression.</li><li>Number fields can reference variables from the Expressions panel and configurator values through <code>configurator.fieldName</code>.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
208
241
  <div class="doc-codeblock-header">
209
242
  <span class="doc-codeblock-lang">javascript</span>
210
243
  <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
@@ -224,6 +257,25 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
224
257
  min: 0, <span class="tok-comment">// Optional</span>
225
258
  max: 100, <span class="tok-comment">// Optional</span>
226
259
  }</code></pre></div>
260
+ </div><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
261
+ <div class="doc-codeblock-header">
262
+ <span class="doc-codeblock-lang">javascript</span>
263
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
264
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
265
+ <svg viewBox="0 0 24 24" fill="none">
266
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
267
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
268
+ </svg>
269
+ </span>
270
+ </button>
271
+ </div>
272
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">width: {
273
+ type: <span class="tok-string">&#39;number&#39;</span>,
274
+ label: <span class="tok-string">&#39;Width&#39;</span>,
275
+ default_value: <span class="tok-string">&#39;configurator.panelWidth&#39;</span>,
276
+ min: 0,
277
+ step: 0.1
278
+ }</code></pre></div>
227
279
  </div><h3>boolean</h3><ul><li>Required: <code>type: &#39;boolean&#39;</code>, <code>label</code></li><li>Optional: <code>default_value</code>, <code>hint</code></li><li>Behavior: checkbox storing a boolean.</li><li>Example:</li></ul><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
228
280
  <div class="doc-codeblock-header">
229
281
  <span class="doc-codeblock-lang">javascript</span>
@@ -141,7 +141,7 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
141
141
  <section class="card doc-card">
142
142
 
143
143
  <div class="prose">
144
- <p><img src="MODELING.png" alt="Modeling Mode" loading="lazy" /></p><h1>Modeling Mode</h1><p>Modeling Mode is the default workspace for solid construction. The scene shows the active history tree, 3D viewport, and main toolbar controls. Add primitives, booleans, and editing features to the timeline, then drag or edit them to re-run the part. Selection filters and gizmos in this mode operate directly on bodies, faces, and edges to drive feature inputs.</p><h2>Live Demos</h2><ul><li>Examples hub: <a href="https://BREP.io/apiExamples/index.html">https://BREP.io/apiExamples/index.html</a></li><li>Embeded CAD: <a href="https://BREP.io/apiExamples/Embeded_CAD.html">https://BREP.io/apiExamples/Embeded_CAD.html</a></li></ul><p>Key tools:</p><ul><li>Main toolbar (Save, Zoom to Fit, Wireframe, Import/Export, About)</li><li>Feature history panel for creating primitives, sketches, and operations</li><li>Inspector for per-face metrics like area and owning feature</li></ul><p>Use Modeling Mode to position solids, apply patterns, and manage global transforms before switching to specialized modes.</p>
144
+ <p><img src="MODELING.png" alt="Modeling Mode" loading="lazy" /></p><h1>Modeling Mode</h1><p>Modeling Mode is the default workspace for solid construction. The scene shows the active history tree, 3D viewport, and main toolbar controls. Add primitives, booleans, and editing features to the timeline, then drag or edit them to re-run the part. Selection filters and gizmos in this mode operate directly on bodies, faces, and edges to drive feature inputs.</p><h2>Live Demos</h2><ul><li>Examples hub: <a href="https://BREP.io/apiExamples/index.html">https://BREP.io/apiExamples/index.html</a></li><li>Embeded CAD: <a href="https://BREP.io/apiExamples/Embeded_CAD.html">https://BREP.io/apiExamples/Embeded_CAD.html</a></li></ul><p>Key tools:</p><ul><li>Main toolbar (Save, Zoom to Fit, Wireframe, Import/Export, About)</li><li>Feature history panel for creating primitives, sketches, and operations</li><li>Expressions panel for global variables and configurator widgets</li><li>Inspector for per-face metrics like area and owning feature</li></ul><p>The Expressions panel supports two related workflows:</p><ul><li><code>expressions</code>: a shared JavaScript-style scratchpad for variables such as <code>width = 20;</code></li><li><code>configurator</code>: a UI-driven set of widgets (<code>slider</code>, <code>number</code>, <code>select</code>, <code>string</code>) whose values are injected into expressions as <code>configurator.fieldName</code></li></ul><p>If configurator widgets exist, the generated configurator form appears above the expression editor. Those values are stored in part history, survive save/load, and can be referenced by feature dialogs through normal expression entry.</p><p>Use Modeling Mode to position solids, apply patterns, and manage global transforms before switching to specialized modes.</p>
145
145
  </div>
146
146
  </section>
147
147
  </main>
@@ -141,7 +141,7 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
141
141
  <section class="card doc-card">
142
142
 
143
143
  <div class="prose">
144
- <h1>PartHistory Reference</h1><p><code>PartHistory</code> lives in <code>src/PartHistory.js</code> and is the core modeling history manager. It owns the feature list, the shared Three.js scene, the expression scratchpad, PMI views, metadata, and the assembly constraint history. It can rebuild geometry deterministically by replaying feature entries, serialize and restore part state, and maintain undo/redo via JSON snapshots.</p><h2>Live Demos</h2><ul><li>Examples hub: <a href="https://BREP.io/apiExamples/index.html">https://BREP.io/apiExamples/index.html</a></li><li>Embeded CAD: <a href="https://BREP.io/apiExamples/Embeded_CAD.html">https://BREP.io/apiExamples/Embeded_CAD.html</a></li><li>Embeded CAD Integration Test: <a href="https://BREP.io/apiExamples/Embeded_CAD_Integration_Test.html">https://BREP.io/apiExamples/Embeded_CAD_Integration_Test.html</a></li></ul><h2>Responsibilities</h2><ul><li>Manage the ordered list of modeling features (<code>features</code>).</li><li>Own and mutate the shared Three.js <code>scene</code>.</li><li>Evaluate parameter expressions via a user-defined expression script.</li><li>Run the history to (re)build geometry from feature inputs.</li><li>Persist and restore feature history, PMI views, metadata, and assembly constraints.</li><li>Track and apply undo/redo snapshots.</li><li>Sync and update assembly component data.</li></ul><h2>Constructor</h2><h3><code>new PartHistory()</code></h3><p>Creates a new history manager and initializes:</p><ul><li><code>features</code>: empty array</li><li><code>scene</code>: <code>new THREE.Scene()</code></li><li><code>featureRegistry</code>: <code>new FeatureRegistry()</code></li><li><code>assemblyConstraintRegistry</code>: <code>new AssemblyConstraintRegistry()</code></li><li><code>assemblyConstraintHistory</code>: <code>new AssemblyConstraintHistory(this, registry)</code></li><li><code>pmiViewsManager</code>: <code>new PMIViewsManager(this)</code></li><li><code>metadataManager</code>: <code>new MetadataManager()</code></li><li><code>expressions</code>: default example script string</li><li><code>callbacks</code>: empty bag for optional hooks</li><li>Undo/redo state in <code>_historyUndo</code></li></ul><p>The constructor also soft-overrides <code>scene.remove</code> and <code>scene.add</code> to aid debugging and to block removal of objects with <code>userData.preventRemove</code>.</p><h2>Data model</h2><h3>Feature entry shape</h3><p>Each entry in <code>features</code> is a plain object with at least:</p><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
144
+ <h1>PartHistory Reference</h1><p><code>PartHistory</code> lives in <code>src/PartHistory.js</code> and is the core modeling history manager. It owns the feature list, the shared Three.js scene, the expression scratchpad, configurator state, PMI views, metadata, and the assembly constraint history. It can rebuild geometry deterministically by replaying feature entries, serialize and restore part state, and maintain undo/redo via JSON snapshots.</p><h2>Live Demos</h2><ul><li>Examples hub: <a href="https://BREP.io/apiExamples/index.html">https://BREP.io/apiExamples/index.html</a></li><li>Embeded CAD: <a href="https://BREP.io/apiExamples/Embeded_CAD.html">https://BREP.io/apiExamples/Embeded_CAD.html</a></li><li>Embeded CAD Integration Test: <a href="https://BREP.io/apiExamples/Embeded_CAD_Integration_Test.html">https://BREP.io/apiExamples/Embeded_CAD_Integration_Test.html</a></li></ul><h2>Responsibilities</h2><ul><li>Manage the ordered list of modeling features (<code>features</code>).</li><li>Own and mutate the shared Three.js <code>scene</code>.</li><li>Evaluate parameter expressions via a user-defined expression script.</li><li>Store configurator widget definitions and current configurator values.</li><li>Run the history to (re)build geometry from feature inputs.</li><li>Persist and restore feature history, PMI views, metadata, and assembly constraints.</li><li>Track and apply undo/redo snapshots.</li><li>Sync and update assembly component data.</li></ul><h2>Constructor</h2><h3><code>new PartHistory()</code></h3><p>Creates a new history manager and initializes:</p><ul><li><code>features</code>: empty array</li><li><code>scene</code>: <code>new THREE.Scene()</code></li><li><code>featureRegistry</code>: <code>new FeatureRegistry()</code></li><li><code>assemblyConstraintRegistry</code>: <code>new AssemblyConstraintRegistry()</code></li><li><code>assemblyConstraintHistory</code>: <code>new AssemblyConstraintHistory(this, registry)</code></li><li><code>pmiViewsManager</code>: <code>new PMIViewsManager(this)</code></li><li><code>metadataManager</code>: <code>new MetadataManager()</code></li><li><code>expressions</code>: default example script string</li><li><code>configurator</code>: <code>{ fields: [], values: {} }</code></li><li><code>callbacks</code>: empty bag for optional hooks</li><li>Undo/redo state in <code>_historyUndo</code></li></ul><p>The constructor also soft-overrides <code>scene.remove</code> and <code>scene.add</code> to aid debugging and to block removal of objects with <code>userData.preventRemove</code>.</p><h2>Data model</h2><h3>Feature entry shape</h3><p>Each entry in <code>features</code> is a plain object with at least:</p><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
145
145
  <div class="doc-codeblock-header">
146
146
  <span class="doc-codeblock-lang">javascript</span>
147
147
  <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
@@ -170,7 +170,63 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
170
170
  effects?: { added: [], removed: [] },
171
171
  previouseExpressions?: Object <span class="tok-comment">// Cached evaluated numeric inputs</span>
172
172
  }</code></pre></div>
173
- </div><p>IDs are normalized and kept in sync:</p><ul><li><code>feature.inputParams.id</code> and <code>feature.id</code> are strings.</li><li>A non-enumerable <code>feature.inputParams.featureID</code> property is defined as an alias of <code>id</code> for legacy compatibility.</li></ul><h3>Feature class contract</h3><p>A feature class (from <code>FeatureRegistry</code>) is expected to provide:</p><ul><li><code>static inputParamsSchema</code> describing inputs and defaults.</li><li><code>run(partHistory)</code> which returns <code>{ added, removed }</code>.</li><li>Optional <code>longName</code>, <code>shortName</code>, <code>name</code> for display.</li><li>(Sketch only) <code>hasSketchChanged(feature)</code> for dirty detection.</li></ul><h3>Result artifacts</h3><p><code>run()</code> should return an object with:</p><ul><li><code>added</code>: array of objects to add to the scene</li><li><code>removed</code>: array of objects to remove from the scene</li></ul><p>Objects are expected to be compatible with Three.js scene nodes. If they implement <code>free()</code> and/or <code>visualize()</code>, those are called automatically.</p><h2>Expressions</h2><p><code>expressions</code> is a user-editable script string. Numeric inputs can reference it.</p><ul><li>Static helper: <code>PartHistory.evaluateExpression(expressionsSource, equation)</code></li><li>Instance helper: <code>partHistory.evaluateExpression(equation)</code></li></ul><p><code>evaluateExpression</code> uses <code>Function()</code> to execute the script and return an evaluated value. It returns <code>null</code> on error. Treat expression input as code (do not evaluate untrusted content).</p><h2>Execution flow</h2><h3><code>runHistory()</code></h3><p>Rebuilds the scene by replaying <code>features</code> in order.</p><p>High-level flow:</p><ol><li>Clear the scene and dispose resources, preserving lights, cameras, and transform gizmos.</li><li>Iterate features in order:</li><p>- Normalize ID linkage for each feature. - Stop after <code>currentHistoryStepId</code> (if set) but keep later features in the list. - Resolve the feature class from the registry; if missing, mark <code>lastRun</code> with a MissingFeature error and continue. - Copy <code>persistentData</code> into the feature instance. - Remove any existing scene children with <code>owningFeatureID === featureId</code> (rerun case). - Compute <code>dirty</code> state based on: - changed input params - feature timestamps vs. upstream features - newer referenced objects - expression evaluation changes - Sketch change detection - If dirty: - call <code>run()</code> - record <code>lastRun</code>, <code>timestamp</code>, <code>effects</code>, <code>lastRunInputParams</code> - Apply <code>effects</code> via <code>applyFeatureEffects()</code>.</p><li>Run assembly constraints.</li><li>Call optional callbacks.</li></ol><p>Notes:</p><ul><li><code>currentHistoryStepId</code> is not cleared inside <code>runHistory()</code>.</li><li>Any feature error stops the run and logs the error.</li><li><code>runHistory()</code> returns <code>this</code>.</li></ul><h2>Scene integration and selection</h2><p>When adding objects:</p><ul><li><code>applyFeatureEffects()</code> calls <code>free()</code> and <code>visualize()</code> if present.</li><li>Each added object and its descendants get <code>timestamp</code> and <code>owningFeatureID</code>.</li><li>Each object gets an <code>onClick</code> handler that uses <code>SelectionFilter.toggleSelection</code>.</li></ul><p>Objects with <code>userData.preventRemove</code> are not removed when the scene is cleared.</p><h2>Serialization</h2><h3><code>toJSON()</code></h3><p>Returns a pretty-printed JSON string containing:</p><ul><li><code>features</code> (type, inputParams, persistentData, timestamp)</li><li><code>idCounter</code></li><li><code>expressions</code></li><li><code>pmiViews</code> (via <code>PMIViewsManager</code>)</li><li><code>metadata</code> (from <code>MetadataManager</code>)</li><li><code>assemblyConstraints</code> and <code>assemblyConstraintIdCounter</code></li></ul><p>Before export, assembly component transforms are synced into feature input params.</p><h3><code>fromJSON(jsonString, options)</code></h3><p>Restores state from a JSON string. Behavior:</p><ul><li>Migrates legacy <code>featureID</code> fields to <code>id</code>.</li><li>Rehydrates PMI views and metadata.</li><li>Loads assembly constraints into <code>AssemblyConstraintHistory</code>.</li><li>Resets undo/redo history unless <code>options.skipUndoReset</code> is <code>true</code>.</li></ul><h2>Undo / redo</h2><p><code>PartHistory</code> maintains a JSON snapshot stack:</p><ul><li><code>_historyUndo.undoStack</code> and <code>_historyUndo.redoStack</code></li><li>Debounced snapshot capture (<code>debounceMs</code>, default 350ms)</li><li>Max snapshot count (<code>max</code>, default 50)</li></ul><p>Key methods:</p><ul><li><code>queueHistorySnapshot({ debounceMs, force })</code></li><li><code>flushHistorySnapshot({ force })</code></li><li><code>undoFeatureHistory()</code></li><li><code>redoFeatureHistory()</code></li><li><code>canUndoFeatureHistory()</code></li><li><code>canRedoFeatureHistory()</code></li></ul><p>Undo/redo restores by calling <code>fromJSON()</code> and re-running <code>runHistory()</code>.</p><h2>Assembly components and constraints</h2><ul><li><code>assemblyConstraintHistory</code> owns constraints and runs the solver.</li><li><code>runAssemblyConstraints()</code> delegates to <code>AssemblyConstraintHistory.runAll()</code>.</li></ul><p>Assembly component utilities:</p><ul><li><code>hasAssemblyComponents()</code>: returns true if any feature is an assembly component.</li><li><code>syncAssemblyComponentTransforms()</code>: copies scene transforms into feature input params.</li><li><code>getOutdatedAssemblyComponentCount()</code>: counts components whose source data changed.</li><li><code>updateAssemblyComponents({ rerun = true })</code>: refreshes component data and optionally re-runs history.</li></ul><h2>Public properties</h2><ul><li><code>features: Array&lt;Object&gt;</code></li><li><code>scene: THREE.Scene</code></li><li><code>idCounter: number</code></li><li><code>featureRegistry: FeatureRegistry</code></li><li><code>assemblyConstraintRegistry: AssemblyConstraintRegistry</code></li><li><code>assemblyConstraintHistory: AssemblyConstraintHistory</code></li><li><code>pmiViewsManager: PMIViewsManager</code></li><li><code>metadataManager: MetadataManager</code></li><li><code>expressions: string</code></li></ul><p>- <code>currentHistoryStepId: string | null</code></p><ul><li><code>callbacks: Object</code> (optional hooks)</li><li><code>_historyUndo: Object</code> (internal state)</li></ul><h3>Callbacks</h3><p><code>callbacks</code> is a simple bag of optional functions:</p><ul><li><code>callbacks.run(featureId)</code> - called before each feature runs (awaited).</li><li><code>callbacks.reset()</code> - called after <code>reset()</code> clears scene (awaited).</li><li><code>callbacks.afterRunHistory()</code> - called after <code>runHistory()</code> completes.</li><li><code>callbacks.afterReset()</code> - called after <code>reset()</code> finishes.</li></ul><h2>API reference</h2><h3>Static</h3><p>#### <code>PartHistory.evaluateExpression(expressionsSource, equation): any | null</code></p><p>Evaluates <code>equation</code> using <code>expressionsSource</code> as the preamble. Returns <code>null</code> on error.</p><h3>Instance</h3><p>#### <code>evaluateExpression(equation): any | null</code></p><p>Same as static helper but uses <code>this.expressions</code>.</p><p>#### <code>getObjectByName(name): Object3D | null</code></p><p>Delegates to <code>scene.getObjectByName</code>.</p><h4><code>reset(): Promise&lt;void&gt;</code></h4><p>Clears features, resets managers, clears the scene, and resets undo/redo. Calls <code>callbacks.reset</code> and <code>callbacks.afterReset</code>.</p><h4><code>runHistory(): Promise&lt;PartHistory&gt;</code></h4><p>Replays features, rebuilds the scene, runs constraints, and calls <code>callbacks.afterRunHistory</code>.</p><h4><code>applyFeatureEffects(effects, featureId, feature): Promise&lt;void&gt;</code></h4><p>Applies <code>added</code>/<code>removed</code> artifacts to the scene, sets timestamps/ownership, and attaches selection handlers.</p><h4><code>toJSON(): Promise&lt;string&gt;</code></h4><p>Serializes the full part history and related state.</p><h4><code>fromJSON(jsonString, options?): Promise&lt;void&gt;</code></h4><p>Restores from a serialized history string.</p><h4><code>generateId(prefix): Promise&lt;string&gt;</code></h4><p>Increments <code>idCounter</code> and returns <code>${prefix}${idCounter}</code>.</p><h4><code>sanitizeInputParams(schema, inputParams): Promise&lt;Object&gt;</code></h4><p>Normalizes and evaluates input params based on schema types:</p><ul><li><code>number</code>: evaluates expressions</li><li><code>reference_selection</code>: resolves object names to scene objects</li><li><code>boolean_operation</code>: normalizes op and target list, optional bias/offset</li><li><code>transform</code>: evaluates position/rotation/scale arrays</li><li><code>vec3</code>: evaluates 3-vector entries</li><li><code>boolean</code>: normalizes to boolean</li><li>default: pass-through</li></ul><h4><code>newFeature(featureType): Promise&lt;Object&gt;</code></h4><p>Creates a new feature entry, seeds defaults from schema, assigns an ID, and appends it to <code>features</code>.</p><h4><code>removeFeature(featureId): Promise&lt;void&gt;</code></h4><p>Removes any feature with matching ID.</p><h4><code>resetHistoryUndo(): void</code></h4><p>Clears undo/redo stacks and internal flags.</p><h4><code>queueHistorySnapshot(options?): void</code></h4><p>Debounced snapshot capture.</p><h4><code>flushHistorySnapshot(options?): Promise&lt;void&gt;</code></h4><p>Forces a snapshot immediately.</p><h4><code>undoFeatureHistory(): Promise&lt;boolean&gt;</code></h4><p>Restores the previous snapshot if available.</p><h4><code>redoFeatureHistory(): Promise&lt;boolean&gt;</code></h4><p>Reapplies the next snapshot if available.</p><h4><code>runAssemblyConstraints(): Promise&lt;Array&gt;</code></h4><p>Runs the assembly constraint solver.</p><h4><code>hasAssemblyComponents(): boolean</code></h4><p>Checks if any feature is an assembly component.</p><h4><code>syncAssemblyComponentTransforms(): void</code></h4><p>Writes current scene transforms into feature input params.</p><h4><code>getOutdatedAssemblyComponentCount(): number</code></h4><p>Returns number of outdated components.</p><h4><code>updateAssemblyComponents(options?): Promise&lt;{ updatedCount, reran }&gt;</code></h4><p>Refreshes assembly component data; optionally re-runs history.</p><h3>Internal helpers</h3><p>These methods are intended for internal use:</p><ul><li><code>_coerceRunEffects</code>, <code>_attachSelectionHandlers</code>, <code>_safeRemove</code></li><li><code>_commitHistorySnapshot</code>, <code>_applyHistorySnapshot</code></li><li><code>_sanitizePersistentDataForExport</code>, <code>_collectAssemblyComponentUpdates</code></li><li><code>#runFeatureEntryMigrations</code>, <code>#linkFeatureParams</code>, <code>#prepareFeatureEntry</code>, <code>#prepareFeatureList</code></li><li><code>#disposeSceneObjects</code>, <code>#disposeObjectResources</code>, <code>#disposeMaterialResources</code></li></ul><h2>Related helper</h2><h3><code>extractDefaultValues(schema)</code></h3><p>Exported alongside <code>PartHistory</code>. Returns a deep-cloned object of <code>default_value</code> for each schema key.</p><h2>Usage examples</h2><h3>Basic feature run</h3><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
173
+ </div><p>IDs are normalized and kept in sync:</p><ul><li><code>feature.inputParams.id</code> and <code>feature.id</code> are strings.</li><li>A non-enumerable <code>feature.inputParams.featureID</code> property is defined as an alias of <code>id</code> for legacy compatibility.</li></ul><h3>Feature class contract</h3><p>A feature class (from <code>FeatureRegistry</code>) is expected to provide:</p><ul><li><code>static inputParamsSchema</code> describing inputs and defaults.</li><li><code>run(partHistory)</code> which returns <code>{ added, removed }</code>.</li><li>Optional <code>longName</code>, <code>shortName</code>, <code>name</code> for display.</li><li>(Sketch only) <code>hasSketchChanged(feature)</code> for dirty detection.</li></ul><h3>Result artifacts</h3><p><code>run()</code> should return an object with:</p><ul><li><code>added</code>: array of objects to add to the scene</li><li><code>removed</code>: array of objects to remove from the scene</li></ul><p>Objects are expected to be compatible with Three.js scene nodes. If they implement <code>free()</code> and/or <code>visualize()</code>, those are called automatically.</p><h2>Expressions</h2><p>For the user-facing guide focused specifically on the Expressions panel and configurator workflow, see <a href="expressions.html">Expressions and Configurator</a>.</p><p><code>expressions</code> is a user-editable script string stored on <code>partHistory.expressions</code>. Expression-aware inputs evaluate against a shared source built from:</p><ul><li>the default prelude (<code>resolution = 32;</code>)</li><li>the current configurator values object (<code>configurator</code>)</li><li>the user script in <code>expressions</code></li></ul><p>This means feature dialogs can reference both scratch variables and configurator fields:</p><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
174
+ <div class="doc-codeblock-header">
175
+ <span class="doc-codeblock-lang">javascript</span>
176
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
177
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
178
+ <svg viewBox="0 0 24 24" fill="none">
179
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
180
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
181
+ </svg>
182
+ </span>
183
+ </button>
184
+ </div>
185
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">width = 20;
186
+ height = width * 2;</code></pre></div>
187
+ </div><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
188
+ <div class="doc-codeblock-header">
189
+ <span class="doc-codeblock-lang">javascript</span>
190
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
191
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
192
+ <svg viewBox="0 0 24 24" fill="none">
193
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
194
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
195
+ </svg>
196
+ </span>
197
+ </button>
198
+ </div>
199
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">configurator.panelWidth
200
+ configurator.materialName</code></pre></div>
201
+ </div><ul><li>Static helper: <code>PartHistory.evaluateExpression(expressionsSource, equation)</code></li><li>Instance helper: <code>partHistory.evaluateExpression(equation)</code></li></ul><p><code>evaluateExpression</code> uses <code>Function()</code> to execute the script and return an evaluated value. It returns <code>null</code> on error. Treat expression input as code (do not evaluate untrusted content).</p><h3>Configurator</h3><p><code>configurator</code> is stored on <code>partHistory.configurator</code> and has this normalized shape:</p><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
202
+ <div class="doc-codeblock-header">
203
+ <span class="doc-codeblock-lang">javascript</span>
204
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
205
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
206
+ <svg viewBox="0 0 24 24" fill="none">
207
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
208
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
209
+ </svg>
210
+ </span>
211
+ </button>
212
+ </div>
213
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">{
214
+ fields: [
215
+ {
216
+ name: <span class="tok-string">&#39;panelWidth&#39;</span>,
217
+ label: <span class="tok-string">&#39;Panel Width&#39;</span>,
218
+ type: <span class="tok-string">&#39;slider&#39;</span>, <span class="tok-comment">// slider | number | select | string</span>
219
+ defaultValue: 42,
220
+ min: 0,
221
+ max: 100,
222
+ step: 1
223
+ }
224
+ ],
225
+ values: {
226
+ panelWidth: 42
227
+ }
228
+ }</code></pre></div>
229
+ </div><p>Behavior in the Expressions sidebar:</p><ul><li>The live configurator form is shown above the expression editor only when at least one configurator field exists.</li><li>The Edit Configurator session can add, remove, and edit widgets of type <code>slider</code>, <code>number</code>, <code>select</code>, and <code>string</code>.</li><li>While the editor is open, the live configurator form previews the draft widget set in real time.</li><li>The model is not re-run for those draft edits until the edit session is closed or saved.</li><li>After the edit session is committed, <code>runHistory()</code> is triggered and the resulting configurator values become available through <code>configurator.fieldName</code>.</li></ul><h2>Execution flow</h2><h3><code>runHistory()</code></h3><p>Rebuilds the scene by replaying <code>features</code> in order.</p><p>High-level flow:</p><ol><li>Clear the scene and dispose resources, preserving lights, cameras, and transform gizmos.</li><li>Iterate features in order:</li><p>- Normalize ID linkage for each feature. - Stop after <code>currentHistoryStepId</code> (if set) but keep later features in the list. - Resolve the feature class from the registry; if missing, mark <code>lastRun</code> with a MissingFeature error and continue. - Copy <code>persistentData</code> into the feature instance. - Remove any existing scene children with <code>owningFeatureID === featureId</code> (rerun case). - Compute <code>dirty</code> state based on: - changed input params - feature timestamps vs. upstream features - newer referenced objects - expression evaluation changes - Sketch change detection - If dirty: - call <code>run()</code> - record <code>lastRun</code>, <code>timestamp</code>, <code>effects</code>, <code>lastRunInputParams</code> - Apply <code>effects</code> via <code>applyFeatureEffects()</code>.</p><li>Run assembly constraints.</li><li>Call optional callbacks.</li></ol><p>Notes:</p><ul><li><code>currentHistoryStepId</code> is not cleared inside <code>runHistory()</code>.</li><li>Any feature error stops the run and logs the error.</li><li><code>runHistory()</code> returns <code>this</code>.</li></ul><h2>Scene integration and selection</h2><p>When adding objects:</p><ul><li><code>applyFeatureEffects()</code> calls <code>free()</code> and <code>visualize()</code> if present.</li><li>Each added object and its descendants get <code>timestamp</code> and <code>owningFeatureID</code>.</li><li>Each object gets an <code>onClick</code> handler that uses <code>SelectionFilter.toggleSelection</code>.</li></ul><p>Objects with <code>userData.preventRemove</code> are not removed when the scene is cleared.</p><h2>Serialization</h2><h3><code>toJSON()</code></h3><p>Returns a pretty-printed JSON string containing:</p><ul><li><code>features</code> (type, inputParams, persistentData, timestamp)</li><li><code>idCounter</code></li><li><code>expressions</code></li><li><code>configurator</code></li><li><code>pmiViews</code> (via <code>PMIViewsManager</code>)</li><li><code>metadata</code> (from <code>MetadataManager</code>)</li><li><code>assemblyConstraints</code> and <code>assemblyConstraintIdCounter</code></li></ul><p>Before export, assembly component transforms are synced into feature input params.</p><h3><code>fromJSON(jsonString, options)</code></h3><p>Restores state from a JSON string. Behavior:</p><ul><li>Migrates legacy <code>featureID</code> fields to <code>id</code>.</li><li>Rehydrates PMI views and metadata.</li><li>Loads assembly constraints into <code>AssemblyConstraintHistory</code>.</li><li>Resets undo/redo history unless <code>options.skipUndoReset</code> is <code>true</code>.</li></ul><h2>Undo / redo</h2><p><code>PartHistory</code> maintains a JSON snapshot stack:</p><ul><li><code>_historyUndo.undoStack</code> and <code>_historyUndo.redoStack</code></li><li>Debounced snapshot capture (<code>debounceMs</code>, default 350ms)</li><li>Max snapshot count (<code>max</code>, default 50)</li></ul><p>Key methods:</p><ul><li><code>queueHistorySnapshot({ debounceMs, force })</code></li><li><code>flushHistorySnapshot({ force })</code></li><li><code>undoFeatureHistory()</code></li><li><code>redoFeatureHistory()</code></li><li><code>canUndoFeatureHistory()</code></li><li><code>canRedoFeatureHistory()</code></li></ul><p>Undo/redo restores by calling <code>fromJSON()</code> and re-running <code>runHistory()</code>.</p><h2>Assembly components and constraints</h2><ul><li><code>assemblyConstraintHistory</code> owns constraints and runs the solver.</li><li><code>runAssemblyConstraints()</code> delegates to <code>AssemblyConstraintHistory.runAll()</code>.</li></ul><p>Assembly component utilities:</p><ul><li><code>hasAssemblyComponents()</code>: returns true if any feature is an assembly component.</li><li><code>syncAssemblyComponentTransforms()</code>: copies scene transforms into feature input params.</li><li><code>getOutdatedAssemblyComponentCount()</code>: counts components whose source data changed.</li><li><code>updateAssemblyComponents({ rerun = true })</code>: refreshes component data and optionally re-runs history.</li></ul><h2>Public properties</h2><ul><li><code>features: Array&lt;Object&gt;</code></li><li><code>scene: THREE.Scene</code></li><li><code>idCounter: number</code></li><li><code>featureRegistry: FeatureRegistry</code></li><li><code>assemblyConstraintRegistry: AssemblyConstraintRegistry</code></li><li><code>assemblyConstraintHistory: AssemblyConstraintHistory</code></li><li><code>pmiViewsManager: PMIViewsManager</code></li><li><code>metadataManager: MetadataManager</code></li><li><code>expressions: string</code></li><li><code>configurator: { fields: Array&lt;Object&gt;, values: Object }</code></li></ul><p>- <code>currentHistoryStepId: string | null</code></p><ul><li><code>callbacks: Object</code> (optional hooks)</li><li><code>_historyUndo: Object</code> (internal state)</li></ul><h3>Callbacks</h3><p><code>callbacks</code> is a simple bag of optional functions:</p><ul><li><code>callbacks.run(featureId)</code> - called before each feature runs (awaited).</li><li><code>callbacks.reset()</code> - called after <code>reset()</code> clears scene (awaited).</li><li><code>callbacks.afterRunHistory()</code> - called after <code>runHistory()</code> completes.</li><li><code>callbacks.afterReset()</code> - called after <code>reset()</code> finishes.</li></ul><h2>API reference</h2><h3>Static</h3><p>#### <code>PartHistory.evaluateExpression(expressionsSource, equation): any | null</code></p><p>Evaluates <code>equation</code> using <code>expressionsSource</code> as the preamble. Returns <code>null</code> on error.</p><h3>Instance</h3><p>#### <code>evaluateExpression(equation): any | null</code></p><p>Same as static helper but uses <code>this.getExpressionsSource()</code>, which includes the default prelude and the current configurator values.</p><h4><code>buildExpressionSource(expressionsSource = this.expressions): string</code></h4><p>Builds the executable expression preamble from the default <code>resolution</code>, the current configurator values, and the user script.</p><h4><code>getExpressionsSource(): string</code></h4><p>Returns the fully assembled expression source used by dialogs and evaluators.</p><h4><code>getConfiguratorState(): { fields: Array&lt;Object&gt;, values: Object }</code></h4><p>Returns a normalized copy of the current configurator definition and values.</p><h4><code>getConfiguratorValues(): Object</code></h4><p>Returns the normalized <code>configurator.values</code> object that is injected into the expression runtime.</p><p>#### <code>getObjectByName(name): Object3D | null</code></p><p>Delegates to <code>scene.getObjectByName</code>.</p><h4><code>reset(): Promise&lt;void&gt;</code></h4><p>Clears features, resets managers, clears the scene, and resets undo/redo. Calls <code>callbacks.reset</code> and <code>callbacks.afterReset</code>.</p><h4><code>runHistory(): Promise&lt;PartHistory&gt;</code></h4><p>Replays features, rebuilds the scene, runs constraints, and calls <code>callbacks.afterRunHistory</code>.</p><h4><code>applyFeatureEffects(effects, featureId, feature): Promise&lt;void&gt;</code></h4><p>Applies <code>added</code>/<code>removed</code> artifacts to the scene, sets timestamps/ownership, and attaches selection handlers.</p><h4><code>toJSON(): Promise&lt;string&gt;</code></h4><p>Serializes the full part history and related state.</p><h4><code>fromJSON(jsonString, options?): Promise&lt;void&gt;</code></h4><p>Restores from a serialized history string.</p><h4><code>generateId(prefix): Promise&lt;string&gt;</code></h4><p>Increments <code>idCounter</code> and returns <code>${prefix}${idCounter}</code>.</p><h4><code>sanitizeInputParams(schema, inputParams): Promise&lt;Object&gt;</code></h4><p>Normalizes and evaluates input params based on schema types:</p><ul><li><code>number</code>: evaluates expressions</li><li><code>string</code> with <code>allowExpression: true</code>: evaluates expressions and coerces the result back to a string</li><li><code>reference_selection</code>: resolves object names to scene objects</li><li><code>boolean_operation</code>: normalizes op and target list, optional bias/offset</li><li><code>transform</code>: evaluates position/rotation/scale arrays</li><li><code>vec3</code>: evaluates 3-vector entries</li><li><code>boolean</code>: normalizes to boolean</li><li>default: pass-through</li></ul><h4><code>newFeature(featureType): Promise&lt;Object&gt;</code></h4><p>Creates a new feature entry, seeds defaults from schema, assigns an ID, and appends it to <code>features</code>.</p><h4><code>removeFeature(featureId): Promise&lt;void&gt;</code></h4><p>Removes any feature with matching ID.</p><h4><code>resetHistoryUndo(): void</code></h4><p>Clears undo/redo stacks and internal flags.</p><h4><code>queueHistorySnapshot(options?): void</code></h4><p>Debounced snapshot capture.</p><h4><code>flushHistorySnapshot(options?): Promise&lt;void&gt;</code></h4><p>Forces a snapshot immediately.</p><h4><code>undoFeatureHistory(): Promise&lt;boolean&gt;</code></h4><p>Restores the previous snapshot if available.</p><h4><code>redoFeatureHistory(): Promise&lt;boolean&gt;</code></h4><p>Reapplies the next snapshot if available.</p><h4><code>runAssemblyConstraints(): Promise&lt;Array&gt;</code></h4><p>Runs the assembly constraint solver.</p><h4><code>hasAssemblyComponents(): boolean</code></h4><p>Checks if any feature is an assembly component.</p><h4><code>syncAssemblyComponentTransforms(): void</code></h4><p>Writes current scene transforms into feature input params.</p><h4><code>getOutdatedAssemblyComponentCount(): number</code></h4><p>Returns number of outdated components.</p><h4><code>updateAssemblyComponents(options?): Promise&lt;{ updatedCount, reran }&gt;</code></h4><p>Refreshes assembly component data; optionally re-runs history.</p><h3>Internal helpers</h3><p>These methods are intended for internal use:</p><ul><li><code>_coerceRunEffects</code>, <code>_attachSelectionHandlers</code>, <code>_safeRemove</code></li><li><code>_commitHistorySnapshot</code>, <code>_applyHistorySnapshot</code></li><li><code>_sanitizePersistentDataForExport</code>, <code>_collectAssemblyComponentUpdates</code></li><li><code>#runFeatureEntryMigrations</code>, <code>#linkFeatureParams</code>, <code>#prepareFeatureEntry</code>, <code>#prepareFeatureList</code></li><li><code>#disposeSceneObjects</code>, <code>#disposeObjectResources</code>, <code>#disposeMaterialResources</code></li></ul><h2>Related helper</h2><h3><code>extractDefaultValues(schema)</code></h3><p>Exported alongside <code>PartHistory</code>. Returns a deep-cloned object of <code>default_value</code> for each schema key.</p><h2>Usage examples</h2><h3>Basic feature run</h3><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
174
230
  <div class="doc-codeblock-header">
175
231
  <span class="doc-codeblock-lang">javascript</span>
176
232
  <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
@@ -203,6 +259,29 @@ a{color:var(--accent);text-decoration:none} a:hover{text-decoration:underline}
203
259
  <div class="doc-codeblock-body"><pre><code class="language-javascript">history.expressions = <span class="tok-string">&quot;x = 10; y = x * 2;&quot;</span>;
204
260
  feature.inputParams.depth = <span class="tok-string">&quot;y + 5&quot;</span>;
205
261
  <span class="tok-keyword">await</span> history.runHistory();</code></pre></div>
262
+ </div><h3>Configurator-backed expressions</h3><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
263
+ <div class="doc-codeblock-header">
264
+ <span class="doc-codeblock-lang">javascript</span>
265
+ <button type="button" class="doc-codeblock-copy" data-copy-code aria-label="Copy code" title="Copy code">
266
+ <span class="doc-codeblock-copy-icon" aria-hidden="true">
267
+ <svg viewBox="0 0 24 24" fill="none">
268
+ <rect x="9" y="3" width="12" height="16" rx="2" stroke="currentColor" stroke-width="2"></rect>
269
+ <rect x="3" y="9" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2"></rect>
270
+ </svg>
271
+ </span>
272
+ </button>
273
+ </div>
274
+ <div class="doc-codeblock-body"><pre><code class="language-javascript">history.configurator = {
275
+ fields: [
276
+ { name: <span class="tok-string">&#39;panelWidth&#39;</span>, label: <span class="tok-string">&#39;Panel Width&#39;</span>, type: <span class="tok-string">&#39;number&#39;</span>, defaultValue: 24, step: 1 }
277
+ ],
278
+ values: {
279
+ panelWidth: 24
280
+ }
281
+ };
282
+
283
+ feature.inputParams.width = <span class="tok-string">&quot;configurator.panelWidth * 2&quot;</span>;
284
+ <span class="tok-keyword">await</span> history.runHistory();</code></pre></div>
206
285
  </div><h3>Save / load</h3><div class="doc-codeblock doc-codeblock-js" data-code-language="javascript">
207
286
  <div class="doc-codeblock-header">
208
287
  <span class="doc-codeblock-lang">javascript</span>