* 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]>
New frame::add_outlined adds a button that draws its own outline with the theme's outline width set to the same width in every state, so its padding no longer drops a pixel on hover. Used by the dialogs' Select chip, Sketch Text's Path chip and the bug report's Open GitHub draft button. New dialog_chip_hover test. Fixes the second point of #1335.
New Body extrusions and Offset Face previews show successful intermediate distances from the same setup while a distance drag runs, then compute the latest one (tool previews keep streaming as before; errors still need exact inputs). The drag arrow and value box are painted from this frame's pointer, removing a frame of lag. Drag regression tests and a perf note added.
List menus open below-right of the cursor and flip to end at the cursor where they don't fit (shared context_menu::place / show for viewport, browser, toolbar and Select Other). Right-clicking a plane in the viewport, a construction plane row or an origin plane row (new menu with Create Sketch and Show/Hide) offers Create Sketch on that plane. Fixes#1354.
scenario::scratch_dir builds the harness folder under solidcraft_engine::io::vfs::temp_dir() (long names), so a short 8.3 TEMP on Windows no longer trips the short-name refusal before the scope checks the scenarios test. Fixes#1385.
joint.motion_link offset is read in the linked value's units (degrees or mm, or an expression); links are still stored in radians, so saved designs open unchanged. A new joint whose values fall outside its limits starts at the nearer limit, stores it, and says so in warnings. Loop dof also counts at a nearby pose, so a part at a dead point of its loop keeps its mobility. The mechanisms skill is updated to match.
* 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]>
Preferences ▸ Navigation ▸ Orbit around now offers View centre (the default, as before), Origin and Point under the cursor. A saved orbit_cursor preference migrates to the cursor option, and the control channel still accepts the old key.
Thanks to @kuraneko1 for this.
Co-authored-by: kuraneko1 <[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]>
A new face-based Extrude Join (and outward Press Pull) joins the picked face's body by default and stores that scope, so an edge-touching neighbour is no longer tried first or absorbed. Explicit targets and participants still win. Related to #226.
The Joint and As-built Joint dialogs explain why picks make no joint and offer Create Components from Bodies when every pick is on one component; joint.create and joint.as_built suggest component.from_bodies. Labels in all catalogs. Fixes#1239.
Offscreen GPU test devices start the backend the app would choose (WGPU_BACKEND, else one hardware backend on Windows) instead of every backend at once. Test-only. Fixes#1330.
The Midpoint Line tool previews the line from the cursor's mirror image through the middle to the cursor, which is what the second click commits. Fixes#1358.
Fixes#1187. New parameters.move {name, before|after} reorders user parameters (the design's own params order, so it is saved with no format change, and undoable); the Parameters dialog's user rows get up/down buttons. Label in every catalog. I merged main in. Checked on main + this branch: cargo check --workspace, the engine parameters tests, the UI parameter_order test, and docs/features.md regenerates unchanged.
Fixes#1167. While a sketch is edited, a body that a rolled-off, unsuppressed Remove deletes is not shown (unless the sketch is built on it); the history stays rolled back, only the view changes. Drawing, picking, screenshots, thumbnails and the browser's Bodies folder agree; document.inspect reports removed_later. Checked on main + this branch: cargo check --workspace, the engine sketch_edit_removed/occurrences tests and the UI viewport/browser tests.
Part of #771 and #772. solid.sweep and surface.sweep take orientation (perpendicular, parallel or a direction), twist (up to 4 turns) and end scale (0.01 to 100), applied about the profile's normal through the path's start; default options run the old sweep, so existing sweeps are unchanged. New fields are optional, left out when unset and noted under format 21; twist and scale are model parameters. Both sweep dialogs get Orientation, Twist and End Scale rows; labels in every catalog. Checked on main + this branch: cargo check --workspace, kernel/engine/UI sweep tests, the doc suite and the robustness goldens.
One docked Save as mesh dialog replaces Export STL / 3MF / 3MF with face tags, with an optional Send to slicer that lists the slicers installed on this machine. Engine: file.save_mesh and file.slicers; the Convert Mesh dialog goes (mesh.convert and the MeshConvert feature stay, so existing designs open). Strings in all catalogs; screenshots in the PR. Checked on main + this branch: cargo check --workspace, the engine slicer/mesh/file tests, the UI catalog and menu tests and scenario s14 (the one local colour-token failure is epaint's TexturesDelta panic, which main shows on this machine too).
Fixes#1075. sketch.constraint.symmetry takes a centre point (the origin or any sketch point) as well as a line; the Symmetry tool's third pick may be the origin point or the sketch's own X/Y origin axis. Checked on main + this branch: cargo check --workspace, the engine cmd::sketch tests (257) and the UI symmetry pick tests.
* 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]>
solidcraft-cli snapshot takes --camera JSON and --view with a saved view name (through view.apply, as the MCP screenshot does), plus --no-grid and --no-axes; the MCP screenshot and ui.render take grid/axes, the headless render skips a hidden origin axis, and the app's ui.render follows the Grid and Origin switches. Closes#1245.
Drive Joints opens on the joint picked in the browser, else the first joint that moves, and won't start on a rigid joint. ui.start takes params: joint.drive opens on a joint (id or name) at given values, driving nothing until OK; a command or param it doesn't take is refused.
file.insert_step and doc.open on a STEP file take `up` (turn a Y-up file so its up is +Z) and `names` (names for the imported bodies). The MCP tool and the app's control requests pass them through; an import without them works as before. Tests in the kernel's STEP reader, the engine, MCP and the file-load UI; docs/step-import.md and docs/mcp.md describe both.
While Draft, Accessibility or Curvature Map analysis is on, a legend at the bottom left of the viewport says what each colour means and which values it stands for, with the theme's analysis colours and stripes. Labels translated in en/de/ja/ko/zh. Fixes#973.
A control-channel method that reads the orbit camera, sets any of target/yaw/pitch/roll/distance, and fits listed occurrences (or everything) keeping the direction. Its reply passed back sets the same view again; a refused field changes nothing.
joint.drive answers moved, and a reason (with unconnected) when the joint can move nothing; motion.play answers moved and unmoved; joint.list answers floating chains. joint.drive values come back in joint.list's shape (deg/mm). quiet: true trims joint answers and motion.play poses. A single value keeps a joint's other values. Drive Joints shows the floating case (drive.unconnected, all locales).
* 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]>
The empty design shown at launch, New on a design that is still empty, file.new and the blank design left when the last tab closes all take the Units of new designs preference. Opened files and the sample part keep their own units. Fixes#1205.
Co-authored-by: raythurman2386 <[email protected]>
Section Analysis clipped the origin and construction planes and axes along with the model. They now draw from their own unclipped lists, with the same depth and blending; bodies, edges, sketches and highlights are clipped as before. Fixes#1229.
Co-authored-by: DuBearte <[email protected]>
A symmetric solid extrude of 10 mm is now 10 mm thick, 5 mm each side of the sketch plane, and switching from One Side to Symmetric keeps the thickness entered. Under format 21 the extent records its convention; designs saved without it keep the per-side reading, so their geometry and parameters don't change. Fixes#1236.
Co-authored-by: Karl-VonRichter <[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]>
An opt-in Touchpad navigation preset: Shift + pointer motion pans, Alt/Option + motion orbits, vertical scroll zooms, all without a mouse button. Existing presets are unchanged; view.navigate gains continuous motion for the control channel and scenarios.
Extend works on any surface: natural (continuing the face's own surface), tangent (G1 run-off) or curvature (G2 run-off), by a distance, up to a plane or face, or back to the surface's bounds, with neighbouring edges lengthened to meet. Untrim and Extend share face parameter-loop helpers. The new SurfaceExtend fields are noted under format 21. Closes#760.
The labelled Report a bug button takes its translated label's width, so longer translations no longer run over the Preferences gear; narrow bars still fall back to the compact icon. Fixes#1145.
Browser rows that are names someone gave (bodies, sketches, components, joints, views...) show as typed instead of being translated as UI labels; default names like Sketch1 are still translated. Fixes#1228.
Ruled Surface: strips off an edge chain in normal, tangent, angle or direction mode, exact planes/cylinders/cones where possible, mitred or round corners, stitched into one surface body. SurfaceRuled is noted under format 21. Closes#762.
* 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]>