@snaptrude/plugin-core 0.9.13 → 0.9.14-networks-20261001.1

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 (72) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/api/core/geom/create/index.d.ts +935 -100
  3. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  4. package/dist/api/core/geom/query/brep.d.ts +59 -2
  5. package/dist/api/core/geom/query/brep.d.ts.map +1 -1
  6. package/dist/api/core/geom/query/curve.d.ts +59 -35
  7. package/dist/api/core/geom/query/curve.d.ts.map +1 -1
  8. package/dist/api/core/geom/query/edge.d.ts +2 -2
  9. package/dist/api/core/geom/query/face.d.ts +105 -0
  10. package/dist/api/core/geom/query/face.d.ts.map +1 -1
  11. package/dist/api/core/geom/update/contour.d.ts +2 -0
  12. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  13. package/dist/api/core/geom/update/curve.d.ts +5 -5
  14. package/dist/api/core/geom/update/profile.d.ts +3 -1
  15. package/dist/api/core/geom/update/profile.d.ts.map +1 -1
  16. package/dist/api/core/handles/index.d.ts +4 -2
  17. package/dist/api/core/handles/index.d.ts.map +1 -1
  18. package/dist/api/design/create/grids.d.ts +1 -1
  19. package/dist/api/design/family.d.ts +145 -10
  20. package/dist/api/design/family.d.ts.map +1 -1
  21. package/dist/api/design/index.d.ts +6 -0
  22. package/dist/api/design/index.d.ts.map +1 -1
  23. package/dist/api/design/networks.d.ts +530 -0
  24. package/dist/api/design/networks.d.ts.map +1 -0
  25. package/dist/api/design/query/geometry/index.d.ts +33 -5
  26. package/dist/api/design/query/geometry/index.d.ts.map +1 -1
  27. package/dist/api/design/query/grids.d.ts +3 -3
  28. package/dist/api/design/query/index.d.ts +47 -0
  29. package/dist/api/design/query/index.d.ts.map +1 -1
  30. package/dist/api/design/query/spaces.d.ts +5 -5
  31. package/dist/api/design/update/index.d.ts +99 -0
  32. package/dist/api/design/update/index.d.ts.map +1 -1
  33. package/dist/api/entity/referenceLine.d.ts +1 -1
  34. package/dist/api/entity/space.d.ts +4 -4
  35. package/dist/api/entity/story.d.ts +4 -4
  36. package/dist/api/presentation/aiInspiration.d.ts +5 -5
  37. package/dist/api/program/site.d.ts +4 -4
  38. package/dist/api/program/spreadsheet.d.ts +4 -4
  39. package/dist/handles.d.ts +13 -3
  40. package/dist/handles.d.ts.map +1 -1
  41. package/dist/index.cjs +3656 -2950
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +3591 -2950
  46. package/dist/index.js.map +1 -1
  47. package/dist/massParameters.d.ts +287 -0
  48. package/dist/massParameters.d.ts.map +1 -0
  49. package/dist/massParameters.ops.d.ts +138 -0
  50. package/dist/massParameters.ops.d.ts.map +1 -0
  51. package/package.json +2 -1
  52. package/scripts/check-dist-fresh.mjs +22 -0
  53. package/src/api/core/geom/create/index.ts +1030 -101
  54. package/src/api/core/geom/query/brep.ts +60 -2
  55. package/src/api/core/geom/query/curve.ts +26 -2
  56. package/src/api/core/geom/query/edge.ts +2 -2
  57. package/src/api/core/geom/query/face.ts +109 -4
  58. package/src/api/core/geom/update/contour.ts +2 -0
  59. package/src/api/core/geom/update/profile.ts +2 -0
  60. package/src/api/core/handles/index.ts +3 -2
  61. package/src/api/design/family.ts +145 -16
  62. package/src/api/design/index.ts +7 -0
  63. package/src/api/design/networks.ts +315 -0
  64. package/src/api/design/query/geometry/index.ts +35 -4
  65. package/src/api/design/query/index.ts +50 -0
  66. package/src/api/design/update/index.ts +106 -0
  67. package/src/handles.ts +18 -3
  68. package/src/index.ts +2 -0
  69. package/src/massParameters.ops.ts +246 -0
  70. package/src/massParameters.ts +427 -0
  71. package/test/massParameters.test.mjs +952 -0
  72. package/api-manifest.json +0 -8371
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # @snaptrude/plugin-core
2
2
 
3
+ ## 0.9.14
4
+
5
+ ### Patch Changes
6
+
7
+ - 22c919b: Curved-geometry contracts — spline curves, primitive solids, curved-surface reads, and the shared mass-parameter record.
8
+ - **`spline` handle kind** — `SplineHandle` joins `CurveHandle` (`line | arc | spline`), so every `core.geom.query.curve` member and `profileFromCurves` take a spline, and joins `ArenaKind`, so `core.handles.release`, `releaseAll("spline")` and `endScope`'s `retain` list accept one. Closed spline loops never exist as a single handle: a closed run is authored directly as a profile.
9
+ - **`core.geom.create.splineFromPoints`** — an open NURBS curve passing exactly THROUGH 3..256 ordered points (interpolated, not control points).
10
+ - **`core.geom.create.profileFromSplinePoints`** — the closed counterpart: a smooth closed profile through the points, ready for `contourFromProfile` → extrude/loft/sweep. No mixed straight/spline input in v1 — compose those with `profileFromCurves`.
11
+ - **Primitive solids** — `brepFromSphere`, `brepFromCylinder`, `brepFromCone` (optional `topRadius`, default 0 = apex) and `brepFromTorus`. Positional plain `{x, y, z}` args matching the `brepFromRevolution` family; `base` is the bottom-cap centre for cylinder/cone, `centre` for sphere/torus. Each result carries an exact analytic surface and a creation recipe.
12
+ - **`core.geom.create.brepFromSweep`** — `options.transition` gains `"round"` beside `"miter"` and `{ bevel }`: corners carried around a tangent circular arc, so the corner patch is a real curved surface.
13
+ - **`core.geom.create.brepFromRevolution`** — JSDoc rewritten to the implemented gate: segments may run at any angle to the axis (an incline revolves into a cone, an arc into a sphere or torus section). Two rules, checked in this order: the axis must lie in the profile's plane or run parallel to it (a parallel axis offset from the plane is judged by its projection into the plane, as 0.9.13 built it; a skew axis is `PRECONDITION_FAILED`), then the whole profile must stay on one side of the axis — touching it is legal (dome poles, cylinder inner edges), crossing it is not (`VALIDATION`).
14
+ - **`core.geom.query.brep.getEdgeCurve`** — a fourth `"spline"` variant (`degree`, `controlPoints`, expanded `knots`, endpoints, `length`), so reading back a spline edge no longer throws.
15
+ - **`core.geom.query.brep.getVolume`** — exact enclosed volume integrated from the surfaces, free of tessellation error.
16
+ - **`core.geom.query.face.getSurfaceKind`** — `"plane" | "cylinder" | "cone" | "sphere" | "torus" | "spline" | null`: the one read that tells a real curved face from a faceted approximation of one.
17
+ - **`core.geom.query.curve`** — class JSDoc gains the per-member spline support table; unsupported members refuse with `PRECONDITION_FAILED` rather than answering wrongly.
18
+ - **`design.query.getParameters`** — read a mass's creation-parameter record (`kind` + values, world coordinates), or `null` for geometry with no honest recipe.
19
+ - **`massParameters`** (new module, exported from the package root) — `MassParametersRecord` / `ContourRecord` / `ProfileRecord` / `CurveRecord` / `XYZ` types and Zod schemas, shared verbatim by plugin-core, the host and the agent runtime. Pure JSON, one `{x, y, z}` point shape, array bounds as contract (through-points ≤ 256, spline poles ≤ 512, sweep path ≤ 512, loft sections ≤ 32, profile curves ≤ 256, contour holes ≤ 64).
20
+
21
+ Editing what was made, and rounding it:
22
+ - **`design.update.parameters(component, patch)`** — the write pair of `design.query.getParameters`: patch a parametric mass's creation recipe and the solid rebuilds in place, keeping its id, storey, materials, position and linked copies. `patch` is a partial of the record's `values` (keys you omit are unchanged; each key you send replaces that value whole — a scalar, a point, a list or a record (`contour`, `profile`, `sections`, `path`, `options`, `operations`) alike — so send the complete value you read) or the whole record read back and edited; `kind` and `version` are immutable; the reply is the complete post-edit record in world coordinates. `PRECONDITION_FAILED` when the component is not a mass (a family instance: use `design.family.setParameters`), when the mass carries no live recipe, when it was scaled (undo the scale and call again), when it or a linked copy is locked (unlock them — the recipe is intact, and `getParameters` cannot see the lock), when a recorded operation's selectors no longer resolve, or when the edit is the first twist or taper, or the straightening, of an extrusion that carries a shell, fillet or chamfer (the faces renumber: send the twist keys with `operations: []` first, then re-apply), `VALIDATION` for argument errors, `OPERATION_FAILED` for a kernel refusal that leaves the model unchanged.
23
+ - **`core.geom.create.splineFromControlPoints(controlPoints, { degree? })`** — an open NURBS curve DEFINED BY 3..512 control points (pulled toward, not through, the interior ones), degree 2 or 3, clamped uniform knots computed host-side. It is the write pair of a `splinePoles` curve record, so a curve read back off a mass can have its poles moved and be rebuilt.
24
+ - **`brepFromFillet` / `brepFromChamfer` / `brepFromShell` / `brepFromOffset` accept CURVED solids.** The straight-edges-only and no-shared-vertex rules are gone: edges may be straight, circular or spline, and adjacent edges (corner blends) are allowed. The JSDoc carries the rim-selection recipe — `brep.listEdges` → `edge.listFaces` → `face.getSurfaceKind` on both faces (`listEdgesBetween` takes two VERTEX indices and is not a face-pair lookup) — and the new refusals: `VALIDATION` where there is no crease (a seam, or two patches of one smooth surface), and — for `brepFromFillet` alone, the one operation with a per-edge kernel verdict — `PRECONDITION_FAILED` naming the edge the kernel could not blend. An over-size chamfer, shell or offset is `OPERATION_FAILED` with a hint asking for a smaller distance/thickness and no edge or face named. Selection caps are RECORD caps, not call caps: the wire schemas accept any selection size, exactly as 0.9.x did — a fillet/chamfer of more than 64 edges or a shell opening more than 32 faces still builds, but the result carries no parameter record (the recipe-less fallback).
25
+ - **`MassParametersRecord` gains an optional `operations` list** (`version` stays 1) — a fillet, chamfer, shell or offset of a recorded solid keeps the record, with `kind` still the base constructor and the operation appended. `OperationRecord`, `EdgeSelector`, `FaceSelector`, `TopologyCounts`, `SurfaceKind`, `CurveKind`, `ParameterPatchValue` and `MassParametersPatch` join the module, with caps `MAX_OPERATIONS` 8, `MAX_OPERATION_EDGES` 64, `MAX_OPERATION_FACES` 32. Selectors are TOPOLOGICAL (edge index + its face pair + curve kind; face index + surface kind + edge count) so they survive a scalar edit of the base and trip on a reorder.
26
+ - **`design.query.geometry.getBrep`** — additive `options.frame` (`"local"` default, unchanged 0.9.x behaviour; `"world"` places the solid where it sits in the scene, for booleans between scene masses and for fillet/shell/offset/chamfer results committed back beside their source).
27
+
28
+ Freeform surfaces, sweeps, patches and variable blends:
29
+ - **`core.geom.create.brepFromSweepAlongCurve(profile, path, options?)`** — sweeps a cross-section along a SMOOTH path of 1..64 curves (splines, arcs and lines chained end to end), where `brepFromSweep` takes a polyline. `options.orientation` picks how the profile turns: `"upright"` (default) keeps its up aligned with world up, `"frenet"` rolls it with the curvature, `"fixed"` carries the authored frame along unchanged — which is a pure translation, and so is also how a footprint is bent along an arc. `options.rail`, a second guide curve, carries the profile along a second path; a closed rail, or a rail together with `orientation`, is `VALIDATION`, and a railed sweep records nothing (`getParameters` answers `null`). Otherwise it records as the one new kind `sweepAlongCurve` (`{ profile, path: CurveRecord[], options? }`, `version` still 1), so the orientation stays editable through `design.update.parameters`; the shipped `sweep` kind and its `XYZ[]` path are untouched.
30
+ - **`core.geom.create.brepFromPatch(boundary, thickness, options?)`** — stretches a surface across a closed loop of 3..16 boundary items and thickens it into a SOLID in one call: a roof over four curves, a canopy between two rails, a blend across a gap. A boundary item is a curve or an `OwnedEdge` (`{ edge, brep, face? }` — an edge handle cannot name its own solid, and one patch may meet two of them). `options.continuity: "tangent"` leaves the named face smoothly and then REQUIRES `face` on every item, because a solid edge lies between two faces and only the caller knows which one to continue; `interiorPoints` (≤ 64) pull the surface through them, and `side` picks which way the solid grows. There is no sheet handle and no surface object: only solids reach the canvas. The result carries no recipe — `design.query.getParameters` is `null` and the mass label is its provenance.
31
+ - **`core.geom.create.brepsFromSplitByFace(brep, toolFace, toolBrep)`** — the curved twin of `brepsFromSplit`, which cuts with a plane: cuts a solid with a FACE of another solid and returns the pieces largest first. Both breps must be in the same frame — read scene masses with `getBrep(x, { frame: "world" })`. A cut that does not pass all the way through is a `VALIDATION`, not a silent single piece.
32
+ - **`core.geom.create.curvesFromProjection(curve, face, faceBrep)`** — drops a curve onto a face along its normal and returns the runs that land on it, one curve per connected run, or `[]` when the curve misses the face; `VALIDATION` when the curve's midpoint lies on the face's surface (no drop direction).
33
+ - **`core.geom.query.face.getArea(face, brep)` / `.getCentroid(face, brep)`** — exact area (internal units squared) and centre of area of one face, integrated off its surface rather than its facets. These are the two reads that tell freeform faces apart, where every face answers `"spline"` and a kind census returns nothing. Both take the parent brep, owner last, exactly like `listVertexPositions(face, brep)`.
34
+ - **`brepFromLoft`** gains `options.smoothing` — `"ruled"` (default) is today's straight-sided loft byte for byte; `"smooth"` lofts every section in ONE pass, so the sides curve continuously through the intermediates. `LoftOptions` carries it into the record.
35
+ - **`brepFromExtrusion`** gains a trailing `options?: { twistInDegrees?, topScale?, levels? }`, and the shipped `extrusion` record gains the same three optional values (`version` still 1) — a twisted or tapered tower stays the SAME kind, so "twist this tower" is an edit rather than a delete-and-rebuild. `twistInDegrees` is an angle and `topScale` a ratio: neither is ever converted by a unit factor. `levels` is a count (each step may turn at most 22.5°), resolved at create time and written into the record, so an existing mass regenerates from the record and never from a heuristic that may change under it. All three absent is the straight extrusion, byte for byte.
36
+ - **`brepFromFillet`** gains a trailing `options?: { endRadius?, radii? }` — a VARIABLE blend. `endRadius` interpolates linearly from `radius` along the whole tangent chain the one edge you pass belongs to (an open chain: on a closed rim a law whose two ends differ is refused, for `endRadius` and `radii` alike). `radii` is the sampled form instead: 2..32 rows of `{ position, radius }` with `position` the normalised ARC LENGTH along that contour from the passed edge's start — a ratio, never converted — strictly increasing. Either form takes exactly ONE edge, they are mutually exclusive, and both round-trip on the fillet `OperationRecord`.
37
+ - **Face and edge selectors gain `at?`** — where the face or edge sits inside its solid, its centroid (an edge's midpoint) over the solid's bounding-box extent, a ratio per axis. It is written only when index, kind and counts cannot tell two of them apart, which on a freeform solid is the common case, and it is verified — never searched — on replay, so a record written without it resolves byte-identically.
38
+ - **`ParameterPatchValue`** widens with `SweepAlongCurveRecordOptions` and `CurveRecord[]` (the `sweepAlongCurve` path). It only ever widens; every value it took before it still takes.
39
+ - **`massParameters.ops` — a second record module.** `EdgeSelector`, `FaceSelector`, `TopologyCounts`, `OperationRecord`, `ParameterPatchValue` and the operation caps (plus the new `MAX_FILLET_LAW_SAMPLES` 32) move into `src/massParameters.ops.ts` and are re-exported from `massParameters` and from the package root — no import path changes. The split keeps each module small enough for an agent to read whole. New caps beside the shipped ones: `MAX_PATH_CURVES` 64, `MAX_TWIST_LEVELS` 64, and — on the creator, because a patch has no record — `MAX_PATCH_BOUNDARY_CURVES` 16 and `MAX_PATCH_INTERIOR_POINTS` 64.
40
+ - **`design.family.getParameters`** gains an optional `parts: PluginFamilyPart[]` — each placed part's `name`, the `engine` that built it (`"kernel"` for a curved sketch built exactly, `"mesh"` otherwise) and, on kernel parts, a read-only part-local `brep` for the face-kind census. `design.query.geometry.getBrep` keeps returning `null` for a family.
41
+
3
42
  ## 0.9.13
4
43
 
5
44
  ### Patch Changes