Fork Build tests jobs were hitting the 45-minute limit while uploading their archive, after
the build had finished, and every one had to start over.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The trusted runs' test archive is still built on GitHub's ubuntu-24.04
runners; minisforum's newer glibc runs it unchanged, so shards 3-4 can join
1-2 on the self-hosted runners.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Fork pull requests now run on the untrusted self-hosted runners, which start
every job empty. Let them restore main's rust-cache like GitHub's runners do
(save-if stays main only, so a fork job never writes a cache).
Co-authored-by: Claude Opus 5.5 <[email protected]>
Lists and Packaging lint each took their own runner slot on every PR push. The list checks now run
in the existing checks job; Lists stays on main. Packaging lint skips PRs that only touch icons.
Co-authored-by: Claude Opus 5.5 <[email protected]>
With Windows off pull requests, GitHub's 20 runners sat idle while every
fork job queued for the self-hosted pool. Select checks, repository
checks, Clippy, doc tests and the summary go back to GitHub's runners;
Build tests and the test shards stay on the isolated self-hosted pool.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Pull requests now run the repository checks, Clippy, the affected
crates' tests in 2 shards, and the doc tests. Windows, the reference
tests and the robustness goldens run on pushes to main and in the
nightly, where a break is fixed forward. This is the split Bevy, Zed
and Ruff use, and it cuts each pull request's CI to about a third.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Fork pull requests, the nightly run, Run workflow, the test archive and
test shards 3-4 move from ubuntu-24.04 to blacksmith-<N>vcpu-ubuntu-2404
(16 vCPU for Clippy and the test archive, 8 for test shards, doc tests,
reference tests and cross-compiles). Trusted runs keep the self-hosted
routing. Blacksmith runners count as self-hosted to GitHub, so steps now
tell our own machines apart by runner name.
TEMPORARY: this branch routes its own run like a fork pull request.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: jyviko <[email protected]>
Every fork run waited in GitHub's shared queue just to start. The gate
and summary jobs now run on the isolated runners as well; the local
output stays false for forks so later jobs never pick the trusted pool.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Fork PRs were waiting hours for GitHub's shared runners. Their Linux
jobs (checks, Clippy, Build tests, the test shards, Doc tests, Reference
tests) now run on the ephemeral, network-jailed self-hosted-untrusted
runners, without the trusted runners' warm build directories.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The toolbar gives up room in small steps (labels shorten, then icons only, then panels hand buttons to their drop-down one at a time, then trailing panels go to the » menu) instead of collapsing whole panels, so medium-width windows no longer lose icons or leave a blank gap.
Preferences > Graphics grew a row (Grid follows the view, #2035), so the Colour vision
control now sits below the fold of the fixed-size page; the scenario scrolls to it.
The page itself already scrolls for real users.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Pull requests from branches of this repository share the work with the self-hosted runners like main does; fork pull requests stay on GitHub's runners. Select checks and ci run on a light self-hosted runner; the repository checks, Clippy, doc tests, reference tests and test shards 1-2 on the fast ones. The test archive is still built on GitHub's runners (glibc).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#1583 turned the grid to the upright origin plane in side views for
everyone. That is now Preferences > Grid follows the view, off by
default; headless pictures keep the ground grid.
Co-authored-by: Claude Opus 5.5 <[email protected]>
#1752 listed cs as complete, but it lacks messages added to en.json since,
which failed the completeness test on main. Missing messages fall back
to English until the catalog catches up.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The icon check from #853 requires every command to have one; #1900 added
inspect.clearance without, which failed Format and repository checks on
main and every PR.
Co-authored-by: Claude Opus 5.5 <[email protected]>
#853 recorded seeds 13, 71 and 94 with the face and edge counts its own branch built
(40/101, 19/50, 27/63). With main's kernel they still build as they did before #853
(41/103, 20/52, 26/61), so every full goldens run has failed since it landed. This
records them again; #853's seed 20 change and the other 93 seeds are unchanged.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Clippy, the doc tests and test shards 1-2 of pushes to main and merge-queue
groups run on the self-hosted runner, alongside GitHub's runners for
everything else. Pull requests, the nightly run and Run workflow stay on
GitHub's runners. Clippy and the doc tests keep warm build directories
outside the checkout (scripts/ci/warm-target.sh).
The test archive is still built on GitHub's runners: the self-hosted
machine has a newer glibc, so binaries built there don't start on
ubuntu-24.04.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Only the Windows jobs still wait for GitHub's runners on main and in the
merge queue. The Vulkan packages are preinstalled on the self-hosted
runner (no sudo), so that step runs only on GitHub-hosted runners.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Seed 31: #1581 refuses a fillet selection with an earlier round's smooth seam instead of re-rounding another nearby edge. Seed 83: #1316 was recorded before its branch took in #1495, whose shell keeps the wall beside a concave edge.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Pushes to main skip boolean_props (random inputs); the nightly property-tests job runs it. The three shrunk cases are ignored tests with their issues (#1647, #1648, #1649), and proptest's failure file is named outright.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Comment /claim on an issue to be assigned and get the in progress label; /unclaim releases it. A daily sweep frees claims with no PR after 72 h or with a PR idle for 14 days.
Check gh pr list --search "#N", then open a draft titled "<summary> (#N)" with an empty claim commit; the lowest-numbered open PR for an issue wins, and a draft with no pushes for 72 hours may be taken over after a comment. Agents on a shared machine check the load before a big build.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Message catalogs sorted one message per line (cargo xtask lists [--fix], checked in cargo xtask ci and the Lists workflow); the language list one per line, English first then by id; THIRD-PARTY-LICENSES.txt and docs/features.md rewritten on main by the Generated files workflow instead of in PRs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A PR that saves something new adds crates/doc/src/format/pending/<name>.rs (a note, and an upgrade step if older designs must be rewritten). The build writes the next format number while changes are pending and lists them in format_pending; scripts/fold-format-pending.sh fixes them as v<N>/ at release time. Formats 23 and 24 move into v23/ and v24/.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Clippy, the test archive and the test shards cover the packages a PR changes plus their dependents. Main, nightly and manual runs stay full.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
glTF files open, insert and drop like 3MF/STL/OBJ: a component named after the file, the node tree as nested rigid components, repeated meshes as occurrences, metres to mm, Y up turned to Z up by default (up: z keeps axes), materials as PBR appearances. Bounded, hostile-input tested reader; no new persisted data. Closes#1505.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Copy, cut and paste sketch geometry (Ctrl+C/X/V, context menu)
Sketch geometry had no copy or paste: Ctrl+C / Ctrl+X / Ctrl+V arrive as
clipboard events that nothing handled, and the sketch context menu had no
Copy, Cut or Paste.
- sketch.copy / sketch.cut / sketch.paste: lines, arcs, circles, ellipses,
splines, conics, points and text. Constraints and dimensions wholly among
the copied entities come along (each dimension gets its own parameter
with the same expression); ones that reach outside, fixes and pattern or
offset relations are dropped. Paste goes centred at `at`, by
`translate`, or offset from the original (same sketch) / at the same
coordinates (another sketch, on its plane). One undo step; the pasted
geometry is selected.
- Ctrl+C / Ctrl+X / Ctrl+V in a sketch (paste at the cursor), and Cut,
Copy and Paste in the sketch context menu. Outside a sketch Ctrl+C /
Ctrl+V copy and paste the selected timeline features. A copy also puts a
line of text on the system clipboard so the next Ctrl+V is delivered.
Fixes#1480
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep a pasted text's height and angle expressions, drop its place's
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Checked locally on main merged with this: cargo check --workspace and the ui-egui tests (the only failures are the local-only TexturesDelta ones that main has too).
The product preview asked the viewport executor for the full physical
viewport, so a maximised 4K window (~8 MP) was refused against the 4 MP
limit on every frame. The preview now draws at the largest size of the
same aspect the executor admits (RenderLimits::fit, scratch included)
and filters it up into the viewport through the existing offscreen
blit. Viewports within the limits still draw at full size.
PNG setups past the image limits now say what the limits are and the
largest size at that aspect, and the image panel offers to use it.
Co-authored-by: Claude Opus 5.5 <[email protected]>
The flat pattern now keeps a 2D view of its own, driven by navigation::handle with orbit off,
so pan, zoom to the cursor and reverse zoom follow the navigation preset. Input over it no
longer reaches the Design camera, and Fit and Home frame the pattern. Closes#1483.
* Agent chat prototype: drive an ACP agent the user already has from a side panel
A desktop-only chat panel (off by default) that starts a coding agent over the
Agent Client Protocol and gives it SolidCraft's MCP server, bridged to the open
window through the token-protected control channel with the default folder
limits. It finds installed agents (Claude Code and Codex adapters, Gemini CLI,
Copilot, Qwen, OpenCode, goose) with version and login state, streams text,
tool calls and plans, shows the agent's permission requests, and when an agent
isn't signed in shows its own login methods without handling any credential.
Design notes and findings: docs/design/in-app-agent-chat.md.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* docs: say only what the end-to-end run showed
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: gate, one undo per message, docking, process groups, discovery polish
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: Settings → AI, several agents with a switcher, OpenAI-compatible endpoints, permission modes, toolbar button
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: translations, tool cards, Add agent dialog fixes, test agent saves on its own
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: third-party licences for the keychain crates; clippy
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: badge text from the theme tokens
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Agent chat: Auto-allow model edits is the default permission mode
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Render preview uses the shared camera navigation
The Render workspace's product preview had its own hard-coded camera
controls. Camera input now lives in one component, navigation::handle,
which the modelling viewport and the Render preview both call (NavCaps:
orbit, pick). Render gets the navigation preset, Orbit around, zoom to the
cursor, the middle double-click and the axis view or navigation cube.
Flat pages can call it with orbit off. A test rejects pages that read the
wheel or move the camera themselves.
Fixes#1454
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Render panel hint says the camera moves as in Design
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Every other package (AppImage, deb, rpm, tar, Flatpak, Snap, MSI, portable zip, FreeBSD) already
puts solidcraft-cli next to the app; the macOS bundle only had it in a separate zip. The agent
chat starts it as its agent's MCP server and looks for it beside the running program.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Sketch: the first dimension scales a sketch drawn by eye (#1365)
Lines drawn by eye have no size of their own until a dimension gives them one, but the first
dimension kept every other drawn length and distorted the sketch to fit (a free construction
line through the origin turned instead of the shape moving). The dimension tool now scales
the whole sketch about its origin to the first length dimension, as long as nothing in the
sketch fixes a size yet: no other driving length dimension, nothing fixed, projected or
patterned. Every geometric constraint and angle holds on the scaled sketch. Later
dimensions size what they measure as before; sketch.dimension does this only with
scale_sketch: true, so scripts are unchanged.
Fixes#1365
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Scenario s01: dimension the box's height too, now that the first dimension scales the sketch
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Imports become components: a STEP assembly's tree as nested components (#1386)
Every imported file (STEP, IGES, 3MF, STL, OBJ: inserted, dropped, opened as a
design, or file.insert_step / file.insert_mesh / doc.open from scripts, the CLI
and MCP) now comes in as a new component named after the file, with its Import
feature inside it. A STEP assembly's products become nested components; a part
placed more than once is one component with an occurrence per placement, and
the Import feature skips the file's later copies (`skip`, format 21 note). The
contents are held as one rigid group (rigid joints, glyphs hidden); moving an
inner part is refused until component.unlock ("Unlock Contents") releases it.
Y up turns the import's component. Replies report component, component_name
and occurrence. Undo is one step; designs with loose imports are unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep an import's rigid group hidden when the window loads the file in the background
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Import instances' skip list is format 22: format 21 ships in 0.12.0
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Catalog entries for Unlock Contents
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* View-dependent display refinement: bodies seen up close are drawn from finer display plans (#1320)
Each frame the viewport works out every shown body's screen-space error (the display
quality's chord tolerance in pixels where the body is nearest the eye) and picks a
refinement step past the chosen display quality, each halving the chord, with hysteresis.
Steps are planned off the UI thread and swapped in when ready, within a triangle budget
and a cache size. Faces (GPU plan or CPU mesh), edges, silhouettes and highlights of a
refined body all come from the refined plan, so a highlight stays on the drawn triangles.
Planned bodies are chunked by content on the GPU, so a refinement re-evaluates only its
own chunk. Display only: the reference mesh, the B-rep and exports never change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Display refinement: only collect finished plans while the view stands still, time the choice, keep the web planning one step a frame
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Format
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep the Display quality note as it was (the longer one pushed the Colour vision list off the Graphics page)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Web app: read a STEP file a piece per frame, with progress and Cancel (#1376)
The kernel's STEP reader walks the file first and converts its solids afterwards,
and StepReading exposes those stages: parse and walk, then convert a solid (or a
batch) per step, then finish into the shared import cache. The web app's file
load drives it from the frame loop for about 30 ms a frame, shows the same
progress card and Cancel as the desktop, and then runs the insert or open, which
finds the file already read. The desktop path is unchanged in behaviour.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Web app: make the imported bodies' meshes a few per frame too (#1376)
After the read, the insert or open runs, and then the bodies' display meshes are
made a frame's worth at a time ("Preparing the view"), as the desktop worker
warms them, instead of all in the first frame that draws the design.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
component.insert_design (a saved part as a linked component) had no button, so an
assembly of separately saved parts looked impossible. It is now on the ASSEMBLE panel
of every tab and in the File menu; it asks for the file, and a STEP or mesh file picked
there is inserted as Insert STEP or Insert Mesh would.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Windows: resize border from the first frame, DPI-correct window moves (#1381)
- The egui resize zones were laid out after the start page's early return, so a launch without
a design had no resize edges at all. They now run on every page.
- Windows: the main window's procedure answers WM_NCHITTEST with the resize edges and corners,
Windows' own border width at the window's DPI (8 px at 100 %), so the OS shows its resize
cursors and runs its own resize (snap included) from the first message; no egui zones there.
- Windows: WM_GETDPISCALEDSIZE returns the size winit then applies (same logical size), so the
rect the OS suggests while the title bar is dragged onto a monitor with another scale is the
rect the window gets.
- Zone sizes and hit test shared in titlebar.rs and unit-tested; Windows CI checks the hit test
right after launch and a real edge drag.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Windows resize smoke: find the main window by its title
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Windows resize smoke: probe the maximized window at the screen's edge
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Measure now reads the picked item's exact shape (cylindrical faces, circular and arc edges,
sketch circles, arcs and lines, profiles, planes, points):
- A circle, hole or arc shows Ø, R and its length (circumference, or arc length and angle).
- A slot (a sketch profile, or a half-cylinder end of a slot in a solid) shows its width,
centre-to-centre length and overall length.
- Two items where one is round measure from the centre or axis by default (axis to axis,
axis to plane, edge or point), with the closest and farthest distances listed too; the
panel switches between centre, min and max, and the canvas line follows.
- inspect.measure and MCP `measure` (new `items` argument) add diameter, radius,
center_distance, min and max; existing fields are unchanged.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Fillet/chamfer: point the drag arrow into the corner on inside edges (#1384)
The radius/distance arrow always pointed against the faces' outward
bisector, which is into the body on an outside edge but away from the
corner on an inside one, where the blend adds material. The arrow and
the spline radius handles now take each edge's convexity into account,
so dragging out along the arrow grows the value on both kinds of edge,
and each edge of a mixed chain follows its own.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Tests: no unreachable! in the blend arrow helper
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
The groove's facets came in sweep order, and the BSP takes each list's first
polygon as its splitter, so the tree was as deep as the list: quadratic time and
memory. An M8 x 60 mm thread ran out of tree depth after 12.9 GB. A fixed shuffle
gives a shallow tree and the same result (volume and faces equal to 1e-9).
Co-authored-by: Claude Opus 5.5 <[email protected]>
A dimension to a line, or between two parallel lines, drew its extension lines from the
measured end point and its foot on the other line, so they ran the whole length of the
lines to wherever that end happened to be. They now start from the nearest point of each
line to the dimension line, and disappear where the dimension line already crosses it.
Fixes#1361
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Optional supersampling (SSAA) for the viewport, adaptive and within the texture limit (#1288)
Preferences ▸ Graphics ▸ Supersampling: Off (default), 1.5× or 2×. The frame is drawn into
textures of the viewport's own kind (format, depth/stencil, MSAA) at that multiple of its pixels,
over transparent black, then filtered down into the viewport with four bilinear taps (the exact
2 × 2 box at 2×) and composited premultiplied over the background. Lines keep their on-screen
width; silhouettes and edges come out smoother.
Adaptive (on by default): the view is drawn at full speed while the camera moves and
supersampled once it has held still for a quarter of a second.
The supersampled size stays within the device's largest texture side (#869) and a 384 MiB
budget for colour and depth (MSAA samples included); under 1.25× is not worth it and the frame
is drawn as usual.
Labels in en/de/ja/ko/zh; `ui.prefs` `supersampling` and `supersampling_adaptive`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Supersampling: factor and adaptive on one row; Off reads Off (1×)
The Graphics page grew past the colour vision menu in the preferences scenario, and a second
Off on the page took its click.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Preferences ▸ Graphics ▸ Display quality: Coarse, Normal, Fine, Ultra (#1287)
A viewing preference that sets how finely the viewport tessellates curved faces and edges:
chord tolerance relative to each body's size (3e-3, 1e-3, 3e-4, 1e-4) and the most a facet may
turn (30, 20, 12, 7 degrees). Normal is the tolerance the viewport has always used.
Bodies keep a display plan per level, so switching is a re-plan the first time and instant
after; the reference mesh the model reads (picks, holes, measuring) and exports are unchanged.
Away from Normal the model scene builds edges, and faces on the CPU path, from the plan at that
level, so silhouettes and edges get finer with the faces and a highlight still lies on the
displayed triangles.
The preference is saved with the others, set over the control channel (`ui.prefs`
`display_quality`), labelled in en/de/ja/ko/zh. `solidcraft-cli bench-open --display LEVEL
[--edit NAME EXPR]` times the plans at a level and after a parameter edit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Highlighted edges follow the display quality too
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
A modelled thread as other CAD systems write it to STEP has cylinder faces trimmed by helices
that turn several times around the shaft, and cylinder faces bounded by two circles with no
seam edge. The display planner refused any face whose boundary winds around its surface, so
the whole body fell back to the reference mesher, which drew those faces with triangles across
the solid.
The planner now cuts such a face along a parameter line into one period: every loop and its
copies a period apart are clipped to the strip, and the parts of the cut line inside the face
join the pieces into closed loops, with the seam nodes made once for both sides. The cut face
is meshed by Delaunay with sag refinement, and the sag check runs once more after shaping.
Bodies with a face trimmed by more than one turn take their reference mesh (picking, measuring,
the CPU viewport) from the plan too.
Tests: an ISO M10x1.5 and M12x1.75 thread built from helices, as made and after a STEP round
trip: the display mesh stays within the tolerance of its surfaces and the thread's volume, and
has no degenerate, sliver or flipped triangles.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Action matrix regressions of #1255: knuckle rounds, thin holes, a 45° flange hole, an axis after an edit
- Curve blends: past the end of a curved edge the run of sections along the end
tangent wrapped round the ring of centres; it is shortened while it still
crosses the end face (the hinge knuckle's cap rounds at 0.728 mm).
- Boolean retry guard: each body's volume is measured finer than its smallest
radius, and a volume out of bounds is measured again ten times finer before
it refuses (a 0.133 mm drill measured -30272 mm³; a plastic part's coarse
mesh was off by more than the slack).
- Sheet metal: a drill cap's certificate allows the evaluation noise its fitted
tilt shows (a hole square to a 45° flange).
- Construction geometry on a named face uses the face found by name, not a
second pick at its nearest point (an axis through a corner round after a
parameter moved it).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Retry guard: measure the target, tool and result at one tolerance
Measured at different tolerances, the chords' error on the faces they share
didn't cancel: a blind hole in a long D-profile bar measured 20 mm³ more than
the bar.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Action matrix baseline from this branch's full run: 37 actions pass again, none fewer
Blessed with cargo xtask action-matrix --from DIR --bless from the 16 shards of
run 38673859774.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Title bar: inactive tabs without outlines, File menu, Help on the right
Inactive tabs go back to the plain bar colour (the Home tab's readable
hover stays). The separate Home button and theme toggle are gone: Home is
a tab and the theme is in Preferences. The folder icon becomes a File text
menu, Save moves into it (Ctrl+S unchanged), and Help sits on the right
next to Report a bug. Tabs start right after File, Undo and Redo.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Title bar: File button hover uses the app bar hover token
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Smart Extrude: direction from the picked side, Cut into a body stays a Cut (#1257)
- A sketch profile (or a thin extrude's curve) extrudes toward the side it was
picked from: from the bottom view it goes down. Body faces still go outward.
- The automatic operation is latched per side of the profile: a drag that starts
into a body is a Cut and stays one past the far side; a Join does not become a
Cut when it reaches another body. Passing through zero decides afresh for the
new side.
- An explicit operation, Direction or Reverse ends the automatic choices.
- auto_operation also looks just past the profile, so a long cut through a body
reads as a Cut from the start (the engine's operation: "auto" too).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Scenario s07: the XZ profile seen from behind now extrudes toward the camera
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
#1164 joins a body that sits flush on a rounded rim into it. In seed 13 the
rectangular pattern's second box (x 5..7.5) sits flush on the half-ring's top
face with a 27 mm2 contact patch. It used to stay a separate shell (one body,
three shells); now it joins the ring (area -54 mm2, twice the patch). The
fillet edge and hole position the generator picks next come from the new
geometry, so the end state differs: 3 bodies, 2647.95 mm3 (was 4, 2300.91).
Every step stays a sound solid, and no other seed moves.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Action matrix: nightly shards cut by measured cost, heavy designs in slices, and a determinism check
The full matrix ran as four fixed quarters of the corpus and two of them hit the 60-minute
job limit. Now action_matrix_shard runs shard k of n (ACTION_MATRIX_SHARD=k/n), planned from
tests/action_matrix/costs.json: designs that take more than five minutes are split into slices,
and the pieces go largest first to the least loaded shard. The nightly runs 12 shards and uploads
each one's outcomes and timings; cargo xtask action-matrix --from DIR --bless records them in the
baseline and costs.json without running the matrix again. action_matrix_determinism runs a sample
twice and lists any action whose outcome changed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Action matrix: costs measured on runners, 10 shards, determinism on the lighter designs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Action matrix: baseline and costs from a full run on main, 16 shards, timeouts listed
The baseline is regenerated from the 10 shards' results of a full run on 01b1b705
(cargo xtask action-matrix --from DIR --bless): 8 new designs, 302 actions that pass now,
names that changed, and 40 actions that passed before and fail now, each listed in #1255
(22 fillets refused since #949, 4 hinge blends since #1101, 9 on the loft cut, 5 single).
costs.json now holds every design's measured time, and the nightly runs 16 shards of about
17 minutes. An action that passes in the baseline and times out is listed but not judged,
and stays passing when blessed: two runs of the same build differed only on 10 actions that
took 50-84 s against the 90 s limit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Action matrix: slice heavy designs by a hash of each action's name
Slicing by index gave some slices only fillets on oracle 41 (28 slices, a multiple of the
actions per edge), three times the planned time; two shards ran past their limit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
A crash inside a graphics driver left only "an unclean exit between
commands": no backtrace, no module, no hint that it was at startup.
- The crash journal now keeps the startup step the app is in (window,
graphics instance, surface, adapter request, adapter chosen, device
creation, renderer and viewport shader compiles, surface configure,
first frame and its present, running) and the renderer as soon as the
adapter is picked. egui-wgpu tells the app about its steps through a
small hook. An unclean exit before the first frame names the step.
- Windows: an unhandled-exception filter (src/native_crash.rs, the one
Windows-only module allowed unsafe) writes the exception code, the
faulting module and offset, and a minidump next to the journal; the
next start puts them into the report.
- The Windows CI job runs a child that faults on purpose and checks the
report.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Publishing a non-prerelease release runs winget.yml, which opens the
winget-pkgs pull request for bherbruck.SolidCraft with Komac (pinned
2.16.0 binary, SHA-256 checked) from the three versioned MSIs. It skips
cleanly without the WINGET_TOKEN secret or before the package's first
version is in winget-pkgs. docs/releasing.md has the one-time token
setup; the README's Download section gains the winget install line.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Windows: start Direct3D 12 first, and Vulkan only without a D3D12 GPU
wgpu started Vulkan, D3D12 and OpenGL together and preferred Vulkan, so
every Windows start loaded all installed Vulkan drivers. An old Intel
Vulkan driver (igvk64.dll) crashed 0.10.1 at startup inside the driver.
The app now probes D3D12, then Vulkan, then OpenGL, one backend at a
time, and starts only the first with a hardware adapter (WARP when none
has one). WGPU_BACKEND still wins; graphics.json's "backend" sets the
order by hand; the software renderer (safe mode, the retry) uses D3D12
alone. A new Windows CI job starts the real app under several settings.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* CI: a test filter YAML parses
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* CI: the startup smoke test writes graphics.json where the app reads it
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* CI: run the WARP shader tests one at a time
WARP's shader JIT (d3d10warp.dll) crashed twice in 124 runs of the gpu
tests with four test threads, with a null read inside its own optimizer
while several devices compiled compute pipelines at once. Serial runs
did not crash.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
A large design showed nothing but a progress bar until it had rebuilt completely. While
it rebuilds, the evaluation now offers the model built so far (placed as the design
places it) every 1.5 s to a window that asks, and the open card draws it as a small
picture on a thread of its own, the way it shows a saved preview. The bodies' meshes
made for it are the ones the finished model shows, so little is done twice. A design
that opens within the first interval shows none.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Viewport: keep the model scene in blocks and upload only what changed
Every change rebuilt the whole model scene (every body's triangles and edges) and
uploaded all of it again, so a design an agent builds one body at a time paid for the
whole model on every command. The scene is now built in blocks of a few bodies, cut
where a body's own key says, and each block's bytes and GPU buffers are kept while the
block comes back unchanged. Body boxes (fit, picking, ground shadow) are kept per mesh.
Rendering is unchanged: the bicycle from bench-agent opens to a byte-identical
screenshot.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Browser: find an occurrence's placed bodies by name, not by search per row
Each body row of a placed component searched the placement's bodies for its own, every
frame: quadratic in the component's bodies (720 for the bench-agent bicycle's hardware).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
The reader converts each item once, but every instance made its own display mesh
(tessellation, seam and tangent flags), the most expensive step of opening a large
assembly. A later instance of an item now shows its first instance's mesh, placed by
the difference of the two placements. Only rigid placements share; split lines and
any operation drop the link. Measurements and export read each instance's own
geometry, so eval output is unchanged.
Generated assemblies: mesh phase 2,215 -> 139 ms (901 bodies) and 1,028 -> 85 ms
(5,401 bodies), with the same triangle counts.
Co-authored-by: Claude Opus 5.5 <[email protected]>
A design built over MCP is many small commands, and each one did work over the
whole design, so building or showing a 1,300-body design took minutes:
- moved components were transformed and meshed again after every change; world_state
now reuses each placed body whose definition and placement are unchanged
- next_d_name searched the design once per candidate number
- Document::eval evaluated every parameter for every expression; now only when the
expression names one
- param_rows' used_by was quadratic; the desktop no longer gathers completions on every
change while no text box has focus
solidcraft-cli bench-agent builds a generated ~1,300-body bicycle command by command
and times it (241 s -> 16 s here). Eval output is unchanged apart from timings.
Co-authored-by: Claude Opus 5.5 <[email protected]>
Startup no longer stops at a bad settings file or a missing GPU: a settings file that fails to load is set aside, a failed GPU start retries with the software renderer, and a safe mode starts with defaults. Adds a troubleshooting page to the guide.
* Refuse fillets and chamfers that run past their faces or cross each other (#1080)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Blend fit: chamfers keep their old acceptance of crossed loops; skip the volume bound along tangent chains
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Blend fit: one selection per check, a coarse volume pass first; record the refused oversize blends in the action matrix baseline
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Where SolidCraft can replace itself safely, the Update window gets Update now:
- AppImage: the new AppImage is downloaded next to the old one, verified and renamed over
it; Restart now starts it as SolidCraft exits.
- Windows MSI: the verified .msi starts (msiexec /i … /passive) once SolidCraft has closed,
after the usual questions about unsaved designs.
- Windows portable zip / standalone exe: the running solidcraft.exe is renamed to .old, the
new one takes its name (solidcraft-cli.exe too), Restart now; .old goes at the next start.
- macOS: the verified .dmg is opened (the app is ad-hoc signed and not notarized, so it isn't
replaced behind the user's back).
- Flatpak, Snap, deb, rpm, tar.gz: never replaced; the window shows the command.
Every package's SHA-256 must match the release's SHA256SUMS.txt (HTTPS, same release); a
mismatch deletes the download and changes nothing. With PUBLIC_KEY set in update/install.rs,
SHA256SUMS.txt.minisig must also verify (minisign-verify, MIT) with a trusted comment naming
the release. release.yml signs the list when the UPDATE_SIGNING_KEY secret exists and fails
when the app expects signatures but the secret is missing; docs/releasing.md has the steps.
Co-authored-by: Claude Opus 5.5 <[email protected]>
* Straight edges stay one edge after cuts (#1049)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Robustness goldens: cuts join straight edges along untouched walls (#1049)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fmt
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Robustness goldens note: what each changed seed shows when replayed on both builds
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
* GPU tessellation: a pipeline the device cannot build falls back to CPU meshing instead of crashing (#1098)
Build the tessellation compute pipeline inside error scopes; TessGpu::new returns an error,
and the viewport logs it and meshes bodies on the CPU. A Windows CI job builds the pipeline
with D3D12's FXC on the WARP adapter.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Tessellation shader: basis functions in one-dimensional local arrays, so D3D12's FXC compiles it (#1098)
FXC has to unroll loops that write an array inside a struct (Basis.n0/n1) or a 2-D array
(ndu) by a counter, and cannot with run-time trip counts (X3511). A2.2 basis functions in a
local 1-D array returned whole; derivatives from the degree p-1 functions; the pole step
offsets computed rather than indexed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
At start, and at most once a day, a background thread asks GitHub for the latest stable
release (one HTTPS GET to releases/latest, nothing else sent; 15 s timeout; silent when
offline; GitHub's rate limit respected). When it is newer than this build, an Update button
appears next to Report a bug. It opens a window with the version, the release notes and
Download (the asset that fits this installation), Skip this version and Remind me later.
- Versions compare as semver; a nightly counts as the release it was built after, so it is
offered only a newer stable release.
- The installation is detected (AppImage, Flatpak, Snap from the store or a file, deb, rpm,
tar.gz, Windows MSI/portable/exe, macOS app); Download picks the fixed-name asset.
Development builds and the Flatpak (no network permission) never check.
- Preferences > General > Updates: Check for updates automatically (on) and Check now.
- HTTP via ureq + rustls with the operating system's certificates (desktop app only).
- docs: Updates and privacy page.
Co-authored-by: Claude Opus 5.5 <[email protected]>