Skip to content

Releases: awv-informatik/smlibpy

smlibpy 0.3.4

Choose a tag to compare

@drcmda drcmda released this 16 Oct 18:18
e5e7544

Three fixes in the MCP's live view, all in a sketch.

Fixed

  • A sketch's constraint badges show their signs. On WebGPU each badge was an empty circle: its disc covered its sign. The signs were also drawn too thin, and read faintly elsewhere.
  • The badges stay as the view is zoomed. In a slanted view of a dense sketch they came and went while zooming.
  • Every dimension label is drawn where the browser has no WebGPU. On WebGL2 most of them were missing.

The app is @buerli.io/buerligons 0.1.0-beta.20261016171031, pinned with its hash as before, and the same build the ClassCAD MCP 0.5.2 carries. Buerligons now has its own version line, so its number drops from 2.0.0 to 0.1.0. The modeling kernel is unchanged; @classcad/smlibwasm moves to 0.3.4 with it.

smlibpy 0.3.3

Choose a tag to compare

@drcmda drcmda released this 16 Oct 12:02
7ebf76a

Two fixes in the MCP's live view.

Fixed

  • Edges can be picked in the realistic look. The live view's app, Buerligons, opens in its realistic look, which switches the edges off, and a body whose edges were off had none to point at. So "fillet the edges I selected" found only faces. The edges are now there undrawn, and show when hovered or picked.
  • Menus read in the dark theme. Save as listed its formats in near black on the dark menu, all but the one under the pointer.

The app is @buerli.io/buerligons 2.0.0-beta.20261016112850, pinned with its hash as before, and the same build the ClassCAD MCP 0.5.1 carries. The modeling kernel is unchanged; @classcad/smlibwasm moves to 0.3.3 with it.

smlibpy 0.3.2

Choose a tag to compare

@drcmda drcmda released this 16 Oct 11:08
4aeff4b

The MCP's live view is the new Buerligons.

Changed

The live view's app is Buerligons 2. The app the MCP opens for a session (view, and the link after the first script) is now the Buerligons of the buerli monorepo:

  • React 19 and the WebGPU stage;
  • the realistic look by default (the flat look is a switch away);
  • Save as with smlibpy's formats, as before (STEP, STL, glTF, OBJ, USD, SMLib).

It comes from its own npm package, @buerli.io/buerligons (2.0.0-beta.20261016102111, its mcp build), no longer from the copy inside @classcad/mcp. As before, it is downloaded once, checked against the hash smlibpy pins and kept in the cache; SMLIBPY_APP_DIR still names a folder with another one.

The modeling kernel and the JavaScript package are unchanged; @classcad/smlibwasm moves to 0.3.2 with it.

smlibpy 0.3.1

Choose a tag to compare

@drcmda drcmda released this 15 Oct 09:17
bb35aea

Two fixes for files that go to and come from other software: USD files now show in any USD viewer, and STEP files with fillets on tori read with their exact volume.

Changed

USD files carry a mesh of every body. export_usd (exportUsd in JavaScript) writes a Mesh prim next to each body's exact BrepArray prim, so the part shows in any USD viewer: online viewers, Blender, Apple's Quick Look, usdview. Until now only usd-brep's usdview plugin and Omniverse drew anything of the default file. mesh=False writes the exact B-reps alone, for the tools that draw BrepArray prims themselves and would show each body twice. The MCP's save and the live view's Save write the mesh too.

The meshes are leaner than those of mesh=True in 0.3.0: a normal per point, and floats with no more digits than they hold. A filleted plate with holes is 61 kB instead of 114 kB, and 15 kB without the mesh.

Fixed

  • STEP import of fillets on tori (#3). A few writers mark the boundary of a fillet face reversed. On a torus, around a hole, a boss or a knob, the import then cut the face apart and lost 2 to 30 % of the volume, while is_valid() still said True. The importer now lets the neighbouring faces decide which way such a loop runs. 40 test files of such fillets, also mirrored and turned, all read back with the exact volume; 12 did before.
  • Binary USD hints. Asking export_usd for a .usdz said to use usdcat, which cannot write packages. The error now names usdzip, and for both binary formats the Python calls of usd-core (which installs no command-line tools).

smlibpy 0.3.0

Choose a tag to compare

@drcmda drcmda released this 14 Oct 11:10

Kernel tools that SMLib has and smlibpy did not offer yet: USD files with the exact bodies, rays and selecting by a ray, surfaces fitted to point clouds, Booleans of any mesh, parts made of cells, curve tools and blends between surfaces. All of them are in smlibwasm too, with the same tests. And the MCP's live view is now Buerligons, the ClassCAD app.

New

Buerligons as the live view. The MCP server shows the session in Buerligons, served on 127.0.0.1 in view mode: you turn the model, select and measure faces and edges, and save it as STEP, STL, glTF, OBJ, USD or SMLib's format. What you select reaches the agent: get_selection gives each face, edge or vertex with its measurements and the expression that reaches it in a script (plate.faces()[6]), so "fillet the edge I selected" works; set_selection highlights what the agent means. A selection lasts until the model changes. The app comes from the npm package @classcad/mcp at a pinned version and hash, downloaded on first use and cached; smlibpy's own three.js viewer page is gone.

USD. export_usd writes each body as a BrepArray prim, the B-rep of NVIDIA's usd-brep (its omniSolid schema), with its exact surfaces and curves, its name and its color; usd-brep, its usdview plugin and Omniverse read them as solids. mesh=True adds a Mesh prim per body for viewers that only draw meshes. import_usd reads the bodies back, also files from usd-brep. The conversion is usd-brep's own, compiled in without OpenUSD; files are text (.usda), and usdcat converts them to .usdc or .usdz. The tests check the files with NVIDIA's validator and OpenUSD. export, load and the MCP's save and load take .usda too.

export_usd([bracket, cover], "assembly.usda")
parts = import_usd("assembly.usda")

Rays. raycast(origin, direction) on parts, sheets, faces and meshes gives the exact points where a ray meets them, nearest first, with the distance, the face and the outward normal at each.

part = Box(40, 30, 20) - Cylinder(5, 30)
[h.distance for h in part.raycast((-50, 0, 0), (1, 0, 0))]    # [30.0, 45.0, 55.0, 70.0]

Selecting by a ray. faces().hit_by(origin, direction) selects the faces a ray meets, nearest first, and chains with the other selectors: part.faces().hit_by(...).first is what the ray sees first. On a list of parts it picks the parts the ray meets.

Surfaces through point clouds. surface(points) with points in any order (a scan) fits a surface to them: 2,000 points in 3 ms, 20,000 in 30 ms. controls= and smoothing= set how closely it follows them; for noisy points, more smoothing or fewer control points make it follow the shape, not the noise. Its normal points up.

Mesh Booleans on any mesh. +, - and & of closed meshes from STL files, Mesh(...) and tessellate now give closed meshes: the polygons with holes that the kernel leaves are triangulated, and the normals come from the triangles.

Parts of cells. merge(a, b) makes one part in which overlaps become cells of their own and touching cells share their faces, as for models of several materials. cells() gives each cell as a solid. USD keeps the cells together; STEP writes one solid per cell.

Curve tools. edge.nurbs() gives the degree, knots, control points and weights of any edge; make_compatible(a, b, ...) turns curves into B-splines of one degree and one knot vector; edge.remove_knots() takes out the knots a curve does not need.

Blends between surfaces. surface_fillet(a, b, radius, sides=(1, 1)) rounds between two sheets that are no part of one body, such as two crossing pipes, and returns the blend as a sheet.

The skill has a tested guide for each, the MCP finds them by plain words, and the docs and the feature sheet on the website show them.

smlibpy 0.2.3

Choose a tag to compare

@drcmda drcmda released this 13 Oct 13:33

smlibwasm is on npm, and every release publishes it from now on.

New

@classcad/smlibwasm on npm. smlibpy for JavaScript and TypeScript, on the kernel compiled to WebAssembly: npm install @classcad/smlibwasm. Releases publish it to npm through trusted publishing, with provenance, and attach the package and the WebAssembly module (smlibwasm.wasm, smlibwasm.mjs) to the GitHub release. Its STEP import reads files as smlibpy does, NX and tool-catalog files included, and readStep(path) and fromStepModel(data) give a StepModel with the file's coordinate systems, curves and points.

The JavaScript docs have what a browser loads (1.8 MB with brotli), the setup for Vite and the whole API in TypeScript. The README links to the documentation on the website.

Fixed

  • STEP import: checking a body's B-spline faces for missing seams leaked the mesh it made for that.

smlibpy 0.2.2

Choose a tag to compare

@drcmda drcmda released this 13 Oct 12:59

STEP files from NX and from tool catalogs import right, and smlibpy comes to JavaScript.

New

smlibwasm. smlibpy for JavaScript and TypeScript: the same API on the same kernel, compiled to WebAssembly. It runs in the browser and in Node, has no dependencies, and loads about 1.8 MB over the wire (brotli). It is on npm as @classcad/smlibwasm (npm install @classcad/smlibwasm); the package and its WebAssembly module are attached to this release. See smlibpy in JavaScript.

import { Box, Cylinder, GridLocations, Z, toStep } from '@classcad/smlibwasm'

let plate = Box(80, 60, 10)
plate = plate.fillet(plate.edges().parallelTo(Z), 8)
plate = plate.cut(GridLocations(60, 40, 2, 2).mul(Cylinder(4, 10)))
const step = toStep(plate)

read_step(path) returns a StepModel: the bodies, and the coordinate systems, curves and points of the file that belong to no body, with their names and products, at their place in the assembly. render() and the live viewer draw them.

Fixed

  • STEP files from NX: extrusions of ellipses (small roundings) no longer raise, and faces of cylinders, cones, spheres, tori, revolutions and extrusions that NX writes without their seam get it from the kernel. A drill that came out with three different volumes is valid now.
  • STEP files from tool catalogs (58 files that other importers failed on): faces that lie across the seam of a closed B-spline surface, faces whose orientation flag contradicts their loops, loops with a slit cut into the face, and solids with cavities (built as void regions, as the file has them). All 58 import as valid solids, with the faces OpenCASCADE reads and volumes within 0.04 % of its.
  • A surface model whose faces lack their seam no longer fails to import.
  • The live viewer meshes each body once and cuts the mesh by face, so a face the kernel cannot copy out of its body no longer drops the whole body. Face.to_shell() and stitch() work on such faces too.
  • Kernel patch: an offset whose faces collapse (thicken, shell) read faces and edges it had already removed, which could crash.
  • DXF: spline fit-point tangents kept only their x; a file that starts with a UTF-8 byte order mark is read.

smlibpy 0.2.1

Choose a tag to compare

@drcmda drcmda released this 13 Oct 09:07

Face drafts, and fixes found while every function was drawn from its own example for the website's feature sheet.

New

Draft. part.draft(faces, angle, neutral_plane) tilts faces by a draft angle about a neutral plane, so that a molded or cast part comes out of its mold. The plane's normal is the pull direction: a positive angle narrows the part along it and widens pockets and holes. Planes can be drafted, and cylinders and cones whose axis runs along the pull direction (a cylinder becomes a cone). A fillet between two drafted walls is drafted with them.

core = RoundedRectangle(56, 40, 6).extrude(26)
core = core.draft(core.draft_analysis(Z).vertical, 3, Plane.XY)

The agent guide and the MCP know it: the skill has a guide for drafts, the mold check recipe drafts the walls it finds, and a search for "add draft to the walls" finds part.draft.

Fixed

  • faces().facing(direction) also picked the walls of holes: it judged a curved face at its area centroid, which for a full cylinder lies on the axis. A curved face now counts only when its normal qualifies everywhere on it.
  • silhouette, project, extrude(direction=…) and Helix take an Axis such as Z, as the selectors do.
  • intersection_curves returned a curve twice where faces of the two bodies lie in one plane.
  • EllipticalArc failed for arcs across 0°, such as 300° to 60°.
  • The mesh of a single face (tessellate(face), and exports of single faces) faced into the part where the face runs against its surface, as loft walls do.
  • The API reference lists start and end of twist, taper and bend as parameters of their own.

smlibpy 0.2.0

Choose a tag to compare

@drcmda drcmda released this 13 Oct 02:02

A large release: sheet metal, deformations, a new set of 2D tools, text, DXF, and fixes from testing every function against the kernel. Windows wheels are back: the kernel is now compiled once per platform, so Windows builds in under an hour instead of five.

New

Sheet metal. Fold a plate along a line with an exact bend of given radius and K-factor, add flanges to edges, and unfold the part into its flat pattern with bend lines, ready for DXF.

blank = Box(100, 40, 2, align=(Align.CENTER, Align.CENTER, Align.MIN))
bracket = blank.fold(Axis((20, 0, 2), (0, 1, 0)), 90, radius=2)
pattern = flat_pattern(bracket)
export_dxf(pattern.outline, "bracket.dxf")

Deformation. Twist, taper and bend finished parts, or deform them freely with a lattice of control points. The results are valid solids with exact NURBS surfaces (twists and bends within 1e-6 mm).

blade = Box(20, 4, 100).twist(90)
handle = Cylinder(6, 150).rotate(Y, 90).bend(90, radius=30)

2D tools. Profile draws outlines with tangent arcs, corner fillets and chamfers inline, and mirrors a half into a symmetric outline. New shapes Triangle, ArcSlot, Hull and Stroke; fillet=, chamfer= and rotation= on every shape; exact offsets with round, sharp or chamfered corners; corners selected like edges (sketch.vertices().concave()).

Text. Text("smlibpy", 8) gives the exact outlines of a font (Lato is included), with kerning, several lines and text along a curve, for engraving and embossing.

DXF. import_dxf reads lines, arcs, circles, polylines with bulges, splines and blocks into a sketch; export_dxf writes sketches and sections with exact arcs and splines. The MCP saves DXF too.

Simplifying parts. part.remove_fillets() takes fillets out and makes the edges sharp again, also on imported parts; part.remove_faces() takes out holes, bosses and pockets. part.faces().fillets() finds the fillets.

Molding. part.draft_analysis(Z, min_angle=1) sorts the faces into those with enough draft, too little, vertical and undercut; part.parting_line(Z) gives the parting line as exact curves.

Fixed

  • 2D Booleans could return a wrong union without an error when the left shape was a moved circle or ellipse. Booleans of many holes are also much faster (180 holes: 6.6 s to 0.4 s).
  • The kernel's sheet metal bend and unbend were broken in several ways; smlibpy rebuilds them from the kernel's own steps.
  • Volumes, areas, centers and inertia are now integrated by smlibpy with an error estimate, correct to seven significant digits by default and faster than before. The kernel's integration controlled only the area: a swept spring's volume was off by 3e-5. accuracy= now means what it says.
  • Edge.length and point_at could count a span of a curve as zero (the outline of a cylinder had 30 mm lines instead of 60).
  • Meshes of twisted faces (twisted parts, ruled lofts between different curves) were up to 15 % off in volume, because the kernel's tessellator put one facet across such a face. STL, glTF and pictures of such parts are now within the tolerance; other parts get the same meshes as before.
  • Four defects in the kernel are fixed in patched copies of two of its files (third_party/patches): every Boolean wrote into freed memory, fillet removal removed nothing, and gluing vertices freed curves still in use.
  • The live viewer closes its socket.

Changed

  • fold and unfold for sheet metal; bend, twist, taper are deformations.
  • Rectangle(w, h, fillet=r) replaces RoundedRectangle (which still works).
  • Profile.line_to(30) with a single number is an error; write line_to(x=30).
pip install -U smlibpy

Docs: https://smlibpy.classcad.ch/docs/

smlibpy 0.1.4

Choose a tag to compare

@drcmda drcmda released this 12 Oct 22:55

Two ways to judge surface quality, in the renderer and in the MCP's snapshot tool. They make the curvature-continuous (G2) fillets visible.

  • Zebra stripes: render(part, zebra=True) reflects parallel light stripes on the surfaces. Stripes break at a gap, kink at a tangent (G1) joint and run on smoothly across a G2 joint. Options set the stripe count, width and direction.
  • Curvature maps: render(part, curvature="mean") (or "gaussian", "max", "min") colors the surfaces by their curvature, blue for concave and red for convex, with a legend in 1/mm. The values come from the exact surfaces, evaluated by the kernel at every point of the mesh, not from the triangles.

Both work in single views and sheets, together with highlights and markers. The verification guide shows agents how to prove a G2 blend with them.

pip install -U smlibpy

Docs: https://smlibpy.classcad.ch/docs/