Commit Graph
946 Commits
Author SHA1 Message Date
Mateusz Sych 17db109c5d URDF export for robot simulators (#719) (#942)
A design with components and joints exports as a URDF robot description (file.export to .urdf, the MCP export tool, solidcraft-cli run --out, File > Export URDF...). It writes one binary STL per component in metres, links with mass, centre of mass and inertia from material density, and maps rigid, revolute, slider, cylindrical, pin-slot, planar and ball joints to URDF joints or short chains. Loops, broken joints and loose parts are reported as warnings. Options: mesh_prefix, effort, velocity. Docs in docs/urdf.md.
2026-10-13 21:52:30 -04:00
Irakli Kourtis d2e409f40c Surface walls named after their sketch curves (#757) (#850)
Each wall of a surface built from sketch curves (Surface Extrude, Revolve, Sweep and Loft) is now named after the curve it comes from, exactly rather than from geometry, so references to those faces survive edits.
2026-10-13 21:47:24 -04:00
bherbruckandClaude Opus 5.5 8746376ee9 Web: fetch the CJK font when Japanese text is drawn, whatever the UI language (#720) (#937)
The browser build fetched its Japanese fallback font only for a Japanese UI,
so a Japanese design name, file name or typed text showed as tofu with the UI
in English. After drawing each frame the web shell now looks through the
painted text for kana, CJK ideographs and full-width forms while no CJK font
is loaded, and fetches the same font once on the first hit. A failed fetch
with an English UI leaves the language alone and is not retried in a loop.
Sessions that never show such text download nothing extra.

Fixes #720

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 21:19:49 -04:00
bherbruckandClaude Opus 5.5 5808bcc0f0 Toolbar drop-downs show all their rows after a shorter list (#874) (#918)
* Toolbar drop-downs show all their rows after a shorter list (#874)

A panel's drop-down kept its size by an id made from the panel name alone,
so PLASTIC's MODIFY reused the one-row size of MESH's MODIFY and showed two
rows with a scroll bar. The id now includes the tab, and the rows' scroll area
may grow past the size the area remembered (up to the room below it), which
also covers the same panel collapsed and expanded.

Fixes #874

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Keep the Sketch Create menu's own sizing

Its rows sit in egui menus (also inside the overflow menu), where a minimum
height moved the rows between frames. Only the panel drop-downs need it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 21:19:45 -04:00
bherbruckandClaude Opus 5.5 d23593d3eb Clamp the window surface to the device's largest texture (#869) (#905)
Moving a window between monitors of different scale can briefly ask for a
surface larger than the device's largest texture (11512 x 6808 against 8192 in
the report), and Surface::configure failed validation, which wgpu turns into a
panic. The surface is now clamped to the device limit with its aspect ratio
kept, and egui draws the whole window at the matching smaller scale, so the
frame is only softer until the size settles. The device also asks for the
adapter's own texture limit (16384 on most desktop GPUs) instead of 8192, and
the resize path and an unsupported surface log instead of unwrapping.

Fixes #869

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 21:19:40 -04:00
Irakli Kourtis 897b7d93b5 Surface Loft: sheets through open or closed sections (#847)
Surface Loft lofts open or closed curve chains, one section per sketch in pick order, into surface bodies. Adds the SurfaceLoft feature (format 18 note), the surface.loft command, a dialog with Edit Feature support, and kernel and engine tests.

Part of #757.
2026-10-13 21:07:16 -04:00
bherbruckandClaude Opus 5.5 7c85970bfc Fillet and chamfer: refuse a smooth seam as having no corner to round (#936)
* Fillet and chamfer: refuse a smooth seam as having no corner to round

Picking the seams where R10 rounds run into the faces beside them, and asking for an R1
fillet there, failed with "not supported yet: blending a smooth edge (... both faces next
to the edge must be planar)". That reads like a missing feature, but the faces meet
tangentially at those edges and there is nothing to round.

An edge whose two faces are tangent along it is now refused as an invalid pick that names
the edge and asks for the sharp edges.

Fixes #896.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Robustness goldens: seed 72's smooth-seam fillet is now a rejected pick, not unsupported

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 21:02:06 -04:00
bherbruckandClaude Opus 5.5 8fb5742706 fix: imprinting a partial contact boxes faces by their control points (#929)
#825 chose the faces to split by boxing each face, dividing its curved edges down to the contact tolerance; on the sensor enclosure's lid that division never finished (press/pull and extrude on 18 faces grew past 24 GB and timed out in the action matrix, on CI as here). The boxes now come from the edges' control points, with no division; a face whose extent can't be found counts as near. A test holds the lid's press/pull to a time budget.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 20:52:35 -04:00
Irakli Kourtis aba57f1ca2 Surface Sweep: sheets carried from open curves and profiles along a path (#843)
Surface Sweep carries open curves and closed profile boundaries along a sketch path into surface bodies, with smooth walls along curved point paths. Adds the SurfaceSweep feature (format 18 note), the surface.sweep command, a dialog with Edit Feature support, and kernel and engine tests.

Part of #757.
2026-10-13 20:48:30 -04:00
Giovanni 57d738eac4 Join walls swept along splines in 2D (#908)
Walls swept along a spline have flat B-spline tops and bottoms, so booleans between them went to the general intersection, which fails on coincident spline faces. Such faces are now put on true planes, and two prisms of the same height and direction are decided in 2D with their spline outlines fitted by arcs within a micron. The result is kept only when its volume is plausible; otherwise the general boolean takes over. The free-form flag is cleared by a drop guard so an unwinding boolean can't leave it set.

Fixes #844.
2026-10-13 20:48:27 -04:00
selune 3f1c023563 Keep fine meshes whole at collapsed taper boundaries (#906)
The exact surface search could return an arbitrary parameter at a collapsed NURBS boundary, which corrupted the trimmed triangulation domain and lost volume on fine meshes of a fillet tapering to zero. Search results in the boundary projection are now validated, preferring a bounded parameter at a pole and snapping to a finite endpoint only when its transverse tangent has collapsed and the residual improves. Adds four regressions for decreasing chord tolerances, pole parameters, unbounded planar support and provisional preview.

Fixes #796.
2026-10-13 20:45:02 -04:00
Mqrius 7da7bbb335 Planar source matching looks only at planes with the same normal (#917)
Body::with_planar_sources compared every planar face of a result with every unsourced planar face of its inputs, so a boolean on an import with a few thousand facets ran out of its comparison budget before it started. The lists are now sorted by normal x and each face only compares with entries inside a narrow normal window found by binary search; the exact same_support test and the work budget are unchanged. Adds an engine test joining a pin onto a 4000-sided imported prism.
2026-10-13 20:44:58 -04:00
Irakli Kourtis 2eb292dd4a Surface Revolve: sheets turned from open curves and profiles (#824)
Surface Revolve turns open curves and closed profile boundaries about a sketch axis into surface bodies, with cone apexes and sphere poles where a chain ends on the axis, and a closed shell made solid. Adds the SurfaceRevolve feature (format 18 note), the surface.revolve command, a dialog with Edit Feature support and analytic kernel and engine tests.

Part of #757.
2026-10-13 20:30:41 -04:00
bherbruckandClaude Opus 5.5 b41ad23e3f Lip: run along the rim's opening, not the foot of a boss standing on the face (#933)
A lip picked on a face that isn't a shelled body's rim, such as the Sample Plate's top
face with its two holes and the boss standing on it, ran its band round the largest inner
edge. That was the boss's foot, so the band stood against the boss's wall and the join
failed with a boolean error about curved faces.

The band now goes round the face's opening (an inner edge with no material just over the
face inside it). A rim face that has a smaller hole in it still works. A face whose inner
edges are only where other features stand on it, or whose openings are alike in size (a
plate's holes), is refused with a plain message that names the rim face it needs.

Fixes #892.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 20:26:24 -04:00
bherbruck 2dcfea8df7 A generated many-part assembly: test and open-phase benchmark (#927)
Generates N parts of four primitive bodies, each moved into a placed component. The test (12 parts) checks the open, the world placement and the saved round trip; the ignored bench_generated_assembly prints parse, evaluation inside and outside the features, mesh warm-up and Measure.
2026-10-13 20:11:34 -04:00
bherbruckandClaude Opus 5.5 7135407268 Mesh a cylinder wall whose seam edges a cut split without fans across it (#921)
A boolean that cuts a pocket into the top of a cylinder (Shell does this) splits the
outer wall's straight seam edges at the pocket's floor. The wall's parameter grid has no
division along its rulings, so the triangulation fanned out from the two split vertices
to the far rims and its triangles cut through the part: the shelled Bolted Flange sample
drew and exported its rim cut off (mesh volume 29201 mm3 for a 40796 mm3 body).

Give the grid a line through each vertex that splits a boundary segment running along a
ruling, in a direction that needs no division of its own and within the grid budget.

Fixes #819.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 20:10:55 -04:00
Mateusz Sych 5f7ce80a93 MCP batch runs as one request in the app (#743) (#885)
The app's control protocol gets engine.batch: the steps run in one request (so one frame), each as engine.execute runs it, stopping at the first failure and rolling back to the checkpoint by default. The MCP batch tool sends it to a running app (with the control token), is never resent after a lost reply, and falls back to step-by-step when the app refuses (agent cursor shown, or a step loads a file). A batch may take up to an hour to answer.
2026-10-13 20:03:09 -04:00
Giovanni fdaf57daa3 Count the contact grid's own work, and test find_close_pair (#836)
find_close_pair's budget now counts the grid's own work too (each cell a triangle is filed under or visits), not only the pair tests, so a pathological pair of meshes can't spend unbounded time building and walking the grid. Adds tests for find_close_pair and the budget.
2026-10-13 20:03:05 -04:00
bherbruck 7eac1de9ee Open large designs faster: list each face's mesh vertices once when flagging seams (#914)
face_vertices lists each vertex once per face (first-met order) and normal_near measures each distance once; seam flags, merged topology and cone signatures are unchanged because the dropped repeats were identical entries.
2026-10-13 19:54:50 -04:00
Que fe07f79387 fix: a hole at sketch points drills into the part its sketch touches (#910)
Hole centres from a sketch now drill into the material on whichever side of the sketch plane it lies: material the spot starts in wins, then the nearest body ahead, else against the sketch normal as before. A sketch on a part's underside or below it now drills up into the part. Covers counterbores, through-all, edge and corner centres, patterns and reopening.
2026-10-13 19:53:21 -04:00
Irakli Kourtis b52d4390a0 face.delete heal: false leaves an open surface body (#861)
Delete Face takes heal (default true, as before). With heal: false the picked faces are removed and the gap stays open, leaving the remaining faces as a surface body (kernel remove_faces); deleting every face is refused. Saved only when false, noted under format 18.
2026-10-13 19:53:17 -04:00
bherbruck c616f50bd0 Open large designs faster: move bodies into components without copying the model (#915)
A body transfer works out the moved bodies first and puts them in place in the evaluator's own copy of the model, instead of copying every body of the model for each transfer.
2026-10-13 19:49:19 -04:00
bherbruck 6c61442bb2 Open large designs faster: meshes, face names and Measure on all cores (#916)
Display meshes after opening, the face names read when a feature finds a face by name, and inspect.measure over all bodies are now worked out per body on plain scoped threads (solidcraft_kernel::for_each_on_threads / map_on_threads), in body order and with the same results; the browser build stays serial.
2026-10-13 19:49:04 -04:00
bherbruck c333889fc0 Open large designs faster: index the previous bodies by name after each feature (#912)
After each feature the bodies before it are indexed by name once (first match first, as the linear searches were), feature components come from a map built once per evaluation, and Body::same compares shared face sources, paint and split lines by pointer first.
2026-10-13 19:45:18 -04:00
bherbruck 648f0ff768 Open large designs faster: count the cache budget without cloning wires (#911)
Body::retained_bytes counts face and edge uses on the borrowed boundaries (the same numbers, checked by a test), and each model body keeps the footprint measured when a feature made or changed it, so the evaluation cache's budget no longer walks every body's topology after every feature.
2026-10-13 19:44:46 -04:00
bherbruck eaab205302 Open large designs faster: name a moved body's faces only when asked (#913)
NameCell::same now refers to its source body and takes the source's names on first request, instead of naming every face of every moved or placed body up front. Names are unchanged.
2026-10-13 19:42:31 -04:00
Mqrius eea49922bd fix: face projection walks through pinch points (#899)
Where two boundaries of a projected face family touch at a single vertex, an even number of boundary edges meet there. The walk now stays on the face it came along (or takes the first edge in geometric order), so every loop closes; an odd count is still refused as a real branch. Adds a test with two squares meeting at a corner.
2026-10-13 19:27:47 -04:00
phanoob dd7790a43f Sketch text: bold and italic, text along a curve, alignment and spacing (#852)
A sketch text gets an optional style: bold and italic faces (a slanted fallback for italic), left/center/right alignment, letter and line spacing, and a path curve of the same sketch for the baseline to follow (reverse takes the other side). Edit Text gets B/I toggles, alignment, spacing fields and a Path chip, all live. The style is saved only when not plain and is noted under format 18.
2026-10-13 19:27:35 -04:00
bherbruckandClaude Opus 5.5 fe3717f2e4 fix: control port needs a per-launch token; MCP tool annotations tell the whole truth (#205) (#901)
solidcraft --control PORT writes a random per-launch token to a user-only file (<data>/control/PORT.token; 0700/0600 on Unix, icacls on Windows; SOLIDCRAFT_CONTROL_TOKEN overrides) and refuses any connection whose first request lacks it. mcp --connect, the demo and packaging smoke clients send it. MCP execute/batch/open/save/export/screenshot are annotated destructive and open-world, new_design destructive. Docs: control-protocol.md, mcp.md, AGENTS.md, pending release note in releasing.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 18:51:19 -04:00
bherbruckandClaude Opus 5.5 d9237d004e ci: the nightly and Run workflow get their own concurrency group (#877)
Only one run per concurrency group can wait. On a busy main each push replaced the waiting run, so the nightly and Run workflow runs on main were cancelled before they started. The group now includes the event.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 18:49:38 -04:00
JIJINBEI d8d54ded0d Renaming a body rewrites only the references to it (#875)
Renaming a body used to replace every string in later features equal to its old name, including sketch text, plane and feature names and expressions. Now only values under keys that name bodies (body, bodies, target, targets, tools) at any depth are rewritten, with a test that a sketch text spelling the body's name stays while a move follows the rename.
2026-10-13 18:47:10 -04:00
Igor Churmeev 95d394dcab Modeling skill: rim fillets after shell, slots along Y, boolean retry caveats (#879)
Corrects the modeling skill: an edge of the face a shell removes is rounded after the shell, a slot along Y is dimensioned horizontally, long shallow arcs measure to about 0.1%, and a boolean retry warning can hide wrong geometry when the volume does not match.
2026-10-13 18:46:47 -04:00
lunar-me 7ee351dc91 docs: perf.md grammar (one of the last features) (#895)
Fixes a plural in docs/perf.md.
2026-10-13 18:46:43 -04:00
lunar-me 9297f81501 docs: sheet metal guide grammar (corner relief size) (#894)
Says the rectangular relief is the size of the rule's corner relief.
2026-10-13 18:46:40 -04:00
lunar-me 2afc10fbd5 docs: sheet metal guide grammar (the base left beside a bend) (#893)
Adds a missing article in the sheet metal guide.
2026-10-13 18:46:37 -04:00
NOWN-DEV 5c98c1e24a A hole square to a folded sheet metal panel is flat machining (#656)
A hole drilled square to a flange's panel, not only the base's, is now a flat cut-out of the sheet: it unfolds with its panel to where the bend allowance puts it, shows in the flat pattern and DXF as a circle, and survives unfold and refold. A pocket tool spans the cut-outs already inside it (a counterbore's hole), so the order they are made in no longer matters. Fixes #560.
2026-10-13 18:46:11 -04:00
bherbruck 0040ce6bf2 Robustness goldens: record the seeds the 13 October kernel merges changed (#898)
Main has failed the full robustness goldens since #838, #839, #841, #855 and #856 landed together. Records the eleven seeds that now build differently (2, 6, 14, 22, 36, 43, 50, 63, 71, 73, 94), with a note. Shell now refusing seed 14, which used to build, is tracked in #897.
2026-10-13 18:46:00 -04:00
phanoob 1f7f37d1ef Cut an extrude's profiles that stand apart in one boolean (#848)
When an extrude cuts with profiles whose outlines stay more than 1 µm apart (the letters of a text), their tools are apart too, so they are joined and cut from the body in one boolean instead of one per profile. A ten-letter text cut drops from about 13 s to 1.5 s with the same result. Sheet metal targets and touching profiles keep cutting tool by tool. Tapered extrudes are unaffected.
2026-10-13 18:29:49 -04:00
Kevin Ravensberg 96f6424aec fix: confine MCP agents' files to allowed folders; recovery discard deletes only recovery entries (#205) (#578)
Agent tool calls (MCP, and bridged control requests carrying allow_paths) reach files only in the open design's folder (strictly inside home or the temporary folder, not in a hidden folder, and never its hidden files), the app's recovery folder, the server's private scratch folder and each --allow-path; --allow-any-path lifts the limit. Paths are resolved first, so .. and symlinks that lead out (including a save through a link, #845) are refused. On Windows, UNC, device, NT, verbatim non-drive, drive-relative, alternate-stream, reserved-device and 8.3 short-name paths are refused before any file system call, and the resolved path must be on a local drive. doc.recovery_discard and doc.recover {discard} delete only real recovery entries. Docs: mcp.md, control-protocol.md, README.
2026-10-13 18:24:08 -04:00
bherbruck 3d3f9b626f Robustness goldens: record seed 0 after the tessellation plans (#870)
#805 and the goldens (#826) landed side by side, so seed 0 was recorded before the new meshing reached main.
2026-10-13 17:30:16 -04:00
bherbruck c3ebe13991 Cargo.lock: solidcraft-gpu at the workspace version (#857)
Refreshes the solidcraft-gpu lock entry so --locked builds pass on main.
2026-10-13 16:48:43 -04:00
Irakli Kourtis b69cd2d0b7 feat: add and remove fillet spline points; handles on every edge (#855)
Double-click a fillet's radius curve to add a control point, or a handle to remove one; a spline fillet shows handles on all its edges.
2026-10-13 16:45:42 -04:00
Irakli Kourtis 753b0a2eab Unstitch and Reverse Normal (#856)
Unstitch takes a body's faces out as surface bodies; Reverse Normal turns a surface body's faces over. Both are saved in format 18. Closes #766.
2026-10-13 16:45:31 -04:00
bherbruck b702f0efde Fix live hinge animation and Drive Joint slider previews (#835)
Joint previews keep showing finished poses while the slider moves, and the latest value is still computed.
2026-10-13 16:34:09 -04:00
William Dunn 152418b624 A tool window for the circular sketch pattern (#801)
Circular sketch pattern gets a tool window with entities, center, quantity and total angle, replacing the click flow.
2026-10-13 16:34:00 -04:00
selune e99b3bd4e8 render: bounded cooperative HDR input foundation (#837)
A cancellable, bounded Radiance HDR decoder for render lighting input; reference images still accept PNG and JPEG only.
2026-10-13 16:33:51 -04:00
NOWN-DEV 8319c35a32 fix: a base trimmed for an edge flange keeps the arcs of its outline (#839)
A base trimmed for an edge flange keeps the arcs of its outline instead of falling back to a polygon.
2026-10-13 16:33:35 -04:00
froglemonade2 c3e0ea498a fix: joins, cuts and sketch profiles where outlines touch at a point (#841)
Fixes #588.
2026-10-13 16:33:24 -04:00
Mqrius b6e3a6c366 fix: contact and shell-grouping checks use a shared broad phase (#838)
Contact and shell-grouping checks find close triangle pairs through one shared grid instead of testing every pair. Refs #232.
2026-10-13 16:33:14 -04:00
Lasse Lian 4d8c80a86d fix: saving follows symbolic links and keeps the file's permissions (#845)
A save through a symbolic link replaces the file it points to and keeps the link; the saved file and its backup keep the original permissions.
2026-10-13 16:32:55 -04:00