Save only lens parameters on existing CPU/GPU jobs while keeping unrelated
draft settings dirty. Retain pinned checkpoints through preview and status,
and release host-only snapshots outside the status lock.
Use the admitted PNG bound for registered-executor checkpoint slots. Preserve
executor work credits, final publication and regrade ownership. Add regression
coverage and align help, translations and capability documentation.
* claim: #8201
* Sketch Mirror: use an origin axis that is not in the sketch plane (#8201)
A sketch on a part face does not hold the world X, Y or Z axis, so Mirror refused the pick. It now mirrors about the axis's projection into the sketch plane and keeps that line linked as fixed reference geometry. An axis perpendicular to the plane stays refused because it has no line in the plane. The sketch's own X and Y axes keep working as before.
* claim: #8220
* Agent chat: Custom instructions in Preferences, added to the system note (#8220)
Preferences > AI gets a multi-line Custom instructions field, saved with
the other AI preferences (agent_instructions, kept by page resets like
other user-written text). The chat adds the text after its own system
note when a session starts, by the routes #9811 set up: ACP session/new
(the Claude adapter's _meta key, the standard systemPrompt field, the
Antigravity key) and the system message or field of every API protocol.
Connect and New chat set it, so an edit applies from the next chat and
never changes the one running. Blank text adds nothing; at most 4000
characters are kept, in the field, over ui.agent_chat and from a hand-
edited settings file. ui.agent_chat takes and reports `instructions`.
* Custom instructions: typing in the field stays in the field
The text area did not report itself to Preferences search as a key sink, so with
the field focused, search took the typed characters and moved focus away. The
field now notes the sink while it has focus, like the other preference fields,
and the #8220 test types into it.
---------
Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com>
* claim: #10428
Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
* Primitives: a pick field waits for its pick and says what it is for
Clicking Face, Reference 1 or 2 in the Cylinder window, or Point in the
Box, Sphere and Torus windows, and then clicking something the field
does not take (empty space, the cylinder's own preview) gave the
keyboard to Diameter, so the field no longer looked active and nothing
said why the click picked nothing. A pick field clicked into now keeps
the keyboard until a click picks something, and a click it does not
take leaves a note under the form saying what the field is for.
These fields also get their own tooltips: Face is the face or vertex
the cylinder stands on, Reference 1 and 2 are straight edges of that
face the distances below are measured from, and Point is a vertex,
edge, face, sketch point or the origin whose point fills X, Y and Z.
Fixes#10428
Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
---------
Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
* claim: #6818
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Hole: the handle drawn with the shared marker (#6818)
A Single hole's drag handle (Move holes by clicking or dragging) is drawn with the placement
marker from place_gizmo/look.rs instead of its own ring and cross, so a hole and a Rest on the
same model show one language for the same action. place_gizmo::marker is the one crate-visible
door: it runs the marker's hover and drag motions under the handle's id and draws the crosshair,
never dimmed. Hole keeps its snapping, the click that takes a hole out, its handle names and its
hover text.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Hole: hole_handle removed (#6818)
The shared marker draws the handle now; nothing else used it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Hole: the marker takes no colours it does not use (#6818)
place_gizmo::marker took a &Tokens only to hand it to crosshair, which reads its colours itself,
so the hole's show fetched tokens nothing read. The argument and that fetch go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Hole: a test sees the handle drawn as the shared marker (#6818)
The hole tests found the handle by its published position, which the look does not change. This
one reads what the frame paints round it: the white dot and four dashed arms at rest, no ring
round the centre, arrowheads when pointed at, solid shafts while it drags. It fails with the old
ring and cross back on the call line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Place handles: marker hover eases in 120 ms, drag in 220 ms (Refs #6818)
The marker answered the pointer in 220 ms and a drag in 360 ms, which felt slow on review. Both
stay in look.rs as the one place a later preference can read them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* claim: #9236
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* GPU path tracer: don't rerun a setup that crashed in the driver (#9236)
A driver that takes the process down while it compiles the path tracer
(RADV on an RX 7600) is beyond error scopes and unwind guards. A running
setup now keeps gpu-path-setup.json (its adapter key) in the settings
folder, removed when the setup answers or the app closes normally. A
launch that finds it for the same adapter leaves the setup failed with an
explanation and a Try again button; CPU ray tracing stays available, and
a driver update changes the key and so tries again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Appearance: a picture of your own behind the model
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Background picture: a label that fits its row
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Arabic: view-mode name, face term and Fillet command name in the hidden-edge selection preference
* Arabic: translate the sketch tool hints and errors, clearer Fillet phrase in the hidden-edge selection help
* claim: #8768
* feat: Browser folders start closed and find a body only when asked, behind a preference
Preferences › Layout › Browser rows start closed (`browser_rows_start_closed`, off by
default) starts the Browser's folders closed, and placements too whatever "Components start
open" (#9274) says. Rows then open with their arrow, Expand All or Find in Browser, which opens
just the rows down to its body and closes again the ones the last find opened. A body picked in
the 3D view leaves the Browser as it is, and only the body Find in Browser found has the rows
above it marked, so a large assembly's placements are not named again after each edit.
With the preference off, folders start open, placements start as "Components start open"
says, and a pick in the 3D view opens the Browser down to its body, as on main. Find in Browser
looks the body's placement up once and opens its rows before drawing, instead of each row
testing the revealed path while it is drawn.
* Browser tests: read the row order from the Browser's content frame
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* claim: #10220
* Web app: keep unsaved work in the browser instead of the leave-page box (#10220)
A new preference, off by default, on Preferences > General > Saving (web
app only): "Keep unsaved work in this browser instead of asking when the
tab closes". With it on, each open design with unsaved changes keeps a
copy in the browser's private storage (keep-<page>-<design>.sc/.json),
written once the design has been still for 0.8 s (at most 4 s after the
first change it lacks) and again on pagehide or when the page is hidden.
While every copy is current, beforeunload doesn't ask. A copy goes when
its design is saved, closed, or the preference is turned off.
The next visit offers the copies newer than their design's last save in
SolidCraft's own window, "Restore unsaved design: <name>, changed
<time>?", one window for several, with Restore, Open saved version, and
Discard. A page holds a Web Lock while it runs, so another open tab's
copies are never offered or removed.
With the preference off, the single autosave and the browser's prompt
work exactly as before.
* Web app: the restore window comes from the UI kit's recovery module (#10220)
The kit's text and divider helpers are private to the UI crate, so the
"Restore unsaved design?" window moves to recovery_ui
(browser_copies_window), beside the desktop recovery window, and the web
shell only maps its answer. Also keeps the window handle for the page
listeners instead of using the one moved into the app.
* Web app: restore window buttons sit in one row (#10220)
* Web app: keep unsaved work and still ask, unless told not to (#10220)
Keeping a copy in the browser no longer replaces the browser's leave-page
box by itself. A second option, shown once work is kept and on by default,
leaves the box in place; off, the box appears only while a copy isn't current.
* Web app: kept-copy review fixes (#10220)
A failed write of a kept copy waits 30 s before the next try, a recovery
copy is dropped only after the remembered saved file has opened, the
preference is documented under its current label, and the ui.prefs list
is sorted again.
* claim: #10223
* Quick-access bar: pin ribbon commands to the application bar (#10223)
A command's menu (a ribbon button, a section drop-down row or a command
search result) has Add to Quick Access: the command's own icon joins the
application bar after Save, Undo and Redo. A click starts it as its
ribbon button does, a drag along the bar reorders the buttons, and the
button's menu has Remove from Quick Access. Empty, and so not drawn, by
default; it holds up to 24 commands.
The list is kept with the toolbar's customisations (`quick_access` in
the toolbar's saved document), so it is saved, exported with the
keyboard shortcuts and carried by settings profiles.
* Quick access: a pinned family variant no longer replaces the ribbon choice
A quick-access click now starts the pinned command with start_pinned, so it
starts exactly that command and leaves the sketch family remembered choice
(the main ribbon button) unchanged.
* Inspect menu: Component Colors is a normal on/off item
The Component Colors entry in Inspect > Check was labelled "Enable Component Colors" and
swapped to "Disable Component Colors" with a different icon while on. It is now labelled
"Component Colors" in both states, keeps one icon, and shows a check mark when on, like Draft
Analysis and the other toggles beside it. The command id and parameters are unchanged.
The now-unused "disable" strings and the colored_components_off icon are removed. Other
languages' old "Enable ..." wording is dropped so they fall back to English until retranslated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep the Component Colors label in the fully translated catalogs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Checkable menu rows tell screen readers whether they are on
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Georgian: Component Colors loses its Enable/Disable wording
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* claim: #3413
* feat(gpu): extend viewport AO to the virtual ground
* test(gpu): retain measured AO render attachments
* perf: initialize ground AO pipeline with concurrent jobs
* fix(gpu): size ground AO receiver for the current frame radius
* fix(viewport): retain orbit caches when ground AO visibility changes
* claim: #7191
* Report a bug: limit answers by characters and show the room left (#7191)
The answers were cut to 2,000 bytes, silently: 666 characters of
Chinese or Japanese. They now keep 2,000 characters, as the text field's
own limit counts them, in the form, in the report and in a crash draft.
Under 200 characters left, an answer says how many there are. The
report's budget grows so three full answers in any script still fit
beside the technical details.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Report a bug: leave the crash draft's description as it was
It is the app's own English text, well under the limit in bytes as in
characters; leaving the line alone keeps it apart from #7189's change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Locales: Arabic and Hebrew for the new strings
ar and he are complete catalogs on main now (#3458): every new message
needs them. The pending-messages test compares right-to-left messages in
display order once #7532 lands (#7527).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Locales: Vietnamese for the new strings
Vietnamese became a complete catalog on main (#5823), so every new English
message needs it too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Claim #9557
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Navigation: a middle or right drag keeps the mode it started with (#9557)
The mode of a middle or right drag was worked out again from the keys
held on every frame, so letting go of Shift partway through a Fusion
Shift+middle orbit turned the rest of the drag into a pan. It is now taken
when the drag starts and kept until its button is released, as a left
drag with the mapping's keys already was. Preferences > Navigation > "A
drag keeps the navigation it started with" (on) turns it off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* test: the file chooser says when it is not the desktop's own (#10159)
rfd falls back to zenity in silence when the XDG portal is not there, and the
user gets a foreign window with no explanation. The host must be able to say so.
RED: the test fails with 'without a D-Bus session bus the file chooser is not the
desktop's own: the user has to be told'.
* fix: say when the file chooser is not the desktop's own (#10159)
rfd opens the file chooser through the XDG desktop portal; without the portal it
falls back to zenity, a window that does not belong to the app, and the app never
says so. The user gets a foreign window and no explanation.
The host now asks the session bus, on a thread of its own, whether the portal is
there, and keeps the answer. When a file is opened and the chooser is not the
desktop's own, the reason goes to the session log (Help > Messages), which is
where a user looks for it.
* fix: the file chooser messages read as notices, not assertions (#10159)
The maintainer asked for two things on the pull request: the strings of the
pending catalogue read like a test assertion ("the user has to be told...")
rather than a notice a person would see, and the doc comment above
desktop_chooser_fallback was there twice.
The three reasons are now plain messages, in every locale of the file: they
say what the chooser is and why, and stop there. The doc comment of the
function is now the only one, and it says what it did.
* English: command labels in title case, other labels in sentence case (#9085)
The rest of #9085 after #9194 (the plural and the spelling) and #9907
(the Preferences page names). Command labels are in title case (422 of
430 were already); the seven in sentence case follow, and Fix/UnFix
reads Fix/Unfix. The UI text skill states the rule. The user docs name
the Preferences footer's button by its current label, Restore page
defaults (#10295).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Navigation bar menu test: the echo names the command by its own label
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* UI text skill: state the case rule in one short sentence, under the 3600 limit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Localization doc: the case rule in full, with examples
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Localization doc: the example button is Restore page defaults now
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: make engine errors translatable
Engine errors (`EngineError::BadParams` and the offset/path errors the kernel
returns) were shown in English regardless of the active locale.
- Add `tr_engine_error`, which maps the known messages to `sketch.error.*`
keys and returns anything unknown unchanged.
- Normalise the `invalid parameters for `<command>`: ` prefix before matching,
and interpolate the offset id into the translated message.
- Route `friendly_error` through `tr_engine_error`.
- Avoid redundant status writes in `run_points`/`run_entities`.
- Ship the es-ES pending strings for the sketch tool hints.
* Spanish (es-ES): catch up with en.json
Translate the 734 messages `es.json` was missing and fix `ui.project`
("Proyecto" → "Proyectar", the action behind the sketch project tool).
The catalogue now matches `en.json` key for key (5,591 entries), keeps every
placeholder intact and stays alphabetically sorted. That includes the 61
messages added upstream since the last catch-up (92a9a5e0).
Terminology: "Turntable" → «Plato giratorio», "hover" → «pasar el puntero»,
"card" → «tarjeta».
* i18n: attribute the sketch hints and keep the offset error neutral
The pending sketch hints file adds an asset, so it gets its own row under
attribution/pending rather than editing ATTRIBUTION.md.
The engine reuses the offset-ends error for trim, extend and break, so the
message no longer tells the user to trim: it asks them to edit the source
curves instead.
* i18n: translate shortcut-started tool hints and fix the break message
Shortcuts are handled in logic(), before ui() installs the language scope, so a
tool started by its key stored the English hint even with another language
selected. Install the scope for the whole frame.
The engine has nothing to break, so say so: "nothing to break here".
* i18n: scope a tool start so its hint uses the app language
A direct start can run outside the frame scope (and a shortcut runs in logic),
so the hint was built with the thread default. Open the scope where the tool
starts.
* Spanish (es-ES): translate the 30 new messages
The blur preferences, the dimension step settings and the fillet turn modes
arrived upstream after the last catch-up.
* i18n: scope command errors and use US spelling in the hints
The native menu runs Undo and Redo before the frame scope exists, so an error
from them was translated in the thread default language.
The pending hints mixed British spellings into the English source; the English
catalog is US-spelled, so the fallbacks say center and en-GB keeps centre.
* Allow optional hidden-edge picking in Shaded with hidden edges
Keep visible-only picking as the default. Cover the preference, hover cache,
section and body visibility, and Fillet inputs in the existing UI tests.
Use platform-absolute fixture paths in the Windows CI argument-parser test.
* Respect section caps and visible-edge ties in hidden-edge picking
* Keep section caps as occluders behind nearer kept faces
* Arabic: rim term and the shell-first step in the Lip help
* Arabic: Up/Down keys in the dimension step preferences, frame-rate note matches the English
Added as assets/locales/pending/finnish-catch-up-2026-11.json so it
folds after merge: help texts, the redesigned Preferences (sketch,
navigation, dimension values, panel blur), fillet corner, setback and
turn options, threads, import report, browser and viewport messages.
cargo xtask i18n lists nothing missing for fi.
Co-authored-by: Janiz-zzz <267742026+Janiz-zzz@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* View navigator: a custom body as the navigator, and a right-click menu to switch types
A right-click anywhere on the view navigator opens a menu with its three types: Axes, Cube and
Custom. Custom opens the Custom View Navigator panel (a feature panel with OK and Cancel): pick a
body in the view, its texture (Themed: the cube's colours; Modeled: the body's own appearance and
the view's edge colour), and whether the cube's rotation arrows and Home button go around it. The
navigator previews the panel's choices while it is open; Cancel leaves it as it was.
The custom navigator draws the body at the cube's size through a small depth-buffered raster, so
hidden faces stay hidden; hovering a face highlights it, a click looks straight at it (and frames
the model with navigator_fit on), a drag orbits. Until a body is chosen it draws the cube.
The body is kept as a packed snapshot (16-bit, base64) with the preferences and in settings
profiles, so it stays across runs and designs and travels with an exported profile. Bodies over
10,000 triangles, and long or flat ones (thinnest width under a fifth of the widest), are refused.
New command view.navigator (style, body, texture, arrows, home) does the same without opening
anything; new preferences navigator_texture, navigator_arrows and navigator_home, and a Custom
choice for navigator_style. Defaults are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: a hovered face in Modeled takes the view's selection colours
In the Modeled texture the face under the pointer is filled and outlined the way the view selects
a face of the model (sel_face, sel_edge), not in the cube's hover blue and accent, which Themed
keeps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: a hovered face in Modeled lights up as the view's mouse-over does
The face under the pointer keeps its own colour, a little lighter (hover_face_lift) and still
shaded, with its edges in the view's mouse-over edge colour (hover_edge), as the 3D view shows a
face under the pointer; not the selection colours. Themed keeps the cube's hover blue and accent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: rotation arrows and Home on by default
navigator_arrows and navigator_home start on, so a new custom navigator has the cube's arrows and
Home button around it; the Custom View Navigator panel turns either off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: the strings in every complete language, and test fixes
- The new messages in Arabic, Hebrew and Vietnamese (complete catalogs, like Japanese and Chinese).
- The navigator's raster goes through one colour helper, listed with its reason among the files
allowed colour literals (the design's appearance shaded into pixels).
- nav_settings joins the requested-icon manifest (the view.navigator command's icon).
- A visible edge piece is kept only when the stretch seen with it, across the edge's segments, is
at least two samples long: a hidden edge no longer shows a sliver at a silhouette corner.
- The navigator layout test treats Custom without a body as the cube it draws; the panel and
size tests no longer assume an empty undo list, the style before opening, or a coarse sphere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: profiles carry its texture, arrows and Home
Settings profiles keep a fixed set of preference keys (#9907), which the custom navigator's newer
settings are not part of. They travel in the profile's own `view_navigator` entry, next to its
body (`view_gizmo`): captured, checked (a value this version can't read is left out) and applied,
leaving the fixed key set unchanged. The cube's arrow inversion (#10286) applies to the custom
navigator's arrows too, through the shared arrows().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: follow main's Vec3 move and fallible world_state
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: list view.navigator in the rig's EXEMPT, refuse a stored body that can't save again, right-click without a widget over the navigator
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: keep the body unless picked again, save only a profile that reads back, no navigator menu through a popup
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: refuse a stored body with a triangle past its points
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: a stored body meets the triangle and aspect limits a picked one does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Custom view navigator: a body at the 5:1 limit stays inside it once packed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(uk): translate the 80 messages main gained after batch 11
* i18n(uk): translate the messages main gained after 2 November
Add Ukrainian for the 158 English messages upstream added since the last
sync, and update 10 existing translations whose English text changed.
The new messages go in assets/locales/pending/uk-sync-2-nov.json, as the
locale files are not edited for new messages. The changed English text is
updated in assets/locales/uk.json, because a pending file cannot change an
existing message.
* i18n(uk): translate the messages main gained after the 3 November sync
Add Ukrainian for the 174 English messages upstream added since the last
sync, and update 56 existing translations whose English text changed.
The new messages go in assets/locales/pending/uk-sync-2-nov.json, as the
locale files are not edited for new messages. The changed English text is
updated in assets/locales/uk.json, because a pending file cannot change an
existing message.
* i18n(uk): apply CodeRabbit review fixes
Use the catalog's established wording: 'вибрати' in the keyboard hint,
name the linked component in the double-click help, and use the command
labels 'Упор', 'Бобишка' and 'Клацкове з'єднання' in the placement group.
* i18n(uk): use "Защіпкове з'єднання" for Snap Fit
The catalog called the plastic snap-fit joint "Клацкове з'єднання", a
calque of "snap". Use the standard "Защіпкове з'єднання" and
"защіпковий гачок" in the command label, help, sample description and
the design tools placement group. The drag hint already said "защіпку".
* i18n(uk): replace calques and outdated terms
Use "збіг" for coincident, "виступ" for lip, "ступиця" for hub, "шаблон" for preset, and "наддискретизація" for supersampling. Render and panel host texts now say "рендерер" or "середовище"/"вікно" instead of "хост".
* Sketch: an ellipse comes with its axes, and D measures its half-axes
An ellipse could only be sized by its minor radius, drawn like a circle's
radius, and there was no way to give its full axes. sketch.ellipse now also
adds the major and minor axes as construction lines through the centre.
The major axis runs from the major end to the point opposite it; the minor
one is perpendicular to it, ends on the ellipse, and both are bisected by
the centre. That adds six coordinates and six equations, so the ellipse
keeps its five degrees of freedom, and it needs no new constraint kind and
no format change.
With the axes in place every ellipse size is an ordinary dimension. D on an
axis line gives its length, the whole axis. D on the outline gives a half-
axis, the distance from the centre to an axis end, chosen the way a line
chooses horizontal or vertical but in the ellipse's own frame: text pulled
across the major axis measures along it (the major half-axis), text pulled
out past an end of it measures across it (the minor one). The end on the
text's side is used. Near the boundary between the two, a dimension being
placed keeps the half-axis it had (sketch.dimension's previous_axis, which
the Dimension tool sends), so the preview does not flip. A half-axis and
its whole axis determine each other, so the second becomes a driven
dimension through the existing redundancy path.
Deleting the ellipse leaves its axes, as deleting a Center Rectangle's
edges leaves its construction diagonals. Ellipses without axes, from
existing designs, keep the minor radius as before, and type radius still
gives it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Guide: an ellipse's axes and half-axis dimensions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: test that an ellipse's half-axis preview keeps its axis near the boundary
The Dimension tool sends the half-axis its last preview chose, so near the
boundary between the major and the minor half-axis the preview keeps it.
This covers that path from the tool, from both sides of the boundary.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's axes select and drag with it, as a rectangle's diagonals do
A double-click on a Center Rectangle's edge or diagonal selects its edges
and both diagonals, and dragging a diagonal moves the rectangle without
changing it, because its lines share corner points. An ellipse's axes are
held by constraints instead, so a double-click selected only the ellipse
(and Delete then left the axes behind), and dragging the major axis moved
the ellipse but stretched its minor half-axis.
Sketch::ellipse_axes now finds an ellipse's construction axes (the
detection sketch.dimension already used, moved into the sketch crate).
Sketch::chain treats an ellipse and its two axes as joined, so a
double-click on any of them selects all three. Dragging either axis moves
the ellipse and both axes as one, keeping both half-axes. Dragging the
outline still sets the minor half-axis.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a corner test reads its line's id instead of assuming l1
sketch.ellipse now adds two axis lines, which take the first line ids, so
the extend test reads the id of the line it draws from the reply.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's axes cut a trim, as a Center Rectangle's diagonals do
Trim, extend and break take every other curve as a cutter, construction
lines included, so an ellipse's construction axes stop them as a Center
Rectangle's diagonals do. A test now states it for both shapes, and the
guide says it. The freeform cutter test keeps the axes it used to delete
and asserts the piece a trim removes: from where the major axis crosses
the circle to where the ellipse does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: test dragging an ellipse's outline with its axes present
Dragging the outline sets the minor half-axis, and the minor axis line,
held on the ellipse at one end, follows it; the centre and the major
half-axis stay.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: other dimension types on an ellipse with axes keep the minor radius
Only auto, major and minor give a half-axis on an ellipse drawn with its
axes. Any other type (radius, diameter, horizontal and the rest) gives
what it gives on an ellipse without axes, as the parameter doc says,
instead of quietly becoming a half-axis chosen by the text. The arm for
a missing text_at is dropped: with no text the rule already picks the
minor half-axis.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: test an ellipse's half-axis dead zone from the major side too
The tests only showed a previous minor half-axis being kept near the
boundary; the point they used on the major side is major by geometry
alone. A point inside the band where geometry says minor now shows a
previous major half-axis kept, in the engine and in the Dimension
tool's preview.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a placed ellipse half-axis is the one its preview showed
On an ellipse already sized, a half-axis is added as a driven dimension
on the click, and that command left out the half-axis the preview kept
near the boundary, so the click could place the other one. It now
passes it as the preview does.
The remembered half-axis also comes only from a draft whose text was
placed (one without text is the minor half-axis by default and biased
the first placement), is kept per sketch as well as per picks, and is
forgotten once a dimension is placed or the picks are cleared.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: say how an ellipse's axes are recognised and what that costs
The axes are read from the constraints, with no mark in the design, so
the doc comment says which lines count, that deleting the midpoint or
point-on-curve constraint leaves an ellipse without axes, and that each
lookup scans curves times constraints.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse with one axis deleted still picks its half-axis by the text
With one construction axis deleted, D on the ellipse fell back to the minor radius wherever the
text was pulled, because the half-axis choice needed both axes. It now reads what is left of
them and chooses as before: the major half-axis goes to the major end (also from the far side,
when the point opposite is gone with its line), the minor one to its axis end, or as the minor
radius when the minor axis is the one deleted. An ellipse with neither axis keeps the minor
radius.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the one-axis half-axis test checks what is measured to
The test for an ellipse with one axis deleted checked only the reply's axis and value, which
both ends of an axis give alike. It now checks the dimension's kind and end: the axis end on
the text's side, the major end from either side once the point opposite is gone, a radius once
the minor axis is. With the major axis deleted and no text the reply names the minor axis and
measures to its end, where it used to be a radius with no axis named.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's minor radius is drawn as its half-axis, without R
A radius on an ellipse is the minor half-axis, and it was drawn as a circle's radius: one
leader from the centre towards the text, marked R, which measures nothing a reader can see.
It is now drawn as the distance from the centre to the minor axis end on the text's side,
the way the half-axis is drawn while the ellipse has its axes, and labelled with the length
alone. This is what D gives once the minor axis line is deleted, and on an ellipse with no
axes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's half-axis keeps a radius's stored text
The half-axis frame read the stored text from the middle of the half-axis, so a radius placed
on an ellipse in an existing design would show its text somewhere else. The text is stored from
the centre again, as a radius's always was, and the side drawn to follows it. An unplaced one
sits where a linear dimension to the minor axis end puts its text, and stacked texts step out
from the centre as a radius's do. A view test reads the painted label, so the drawing cannot
go back to R unnoticed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse moved, turned or scaled takes its axes along
Move, Sketch Transform and Scale moved only the curves picked, so an ellipse moved without its
axes left them where they were: its centre no longer halved them, the minor end left the
ellipse, and the sketch stayed unsolved. A Center Rectangle's diagonals share its corners and
always go along; an ellipse's axes share only the major end. The axes now go with the ellipse,
as they do when it is dragged. Copy is unchanged: it copies no constraints, for a rectangle
either.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a preference draws ellipses without their axes, as before
Drawing an ellipse with its construction axes changes what the Ellipse tool makes out of the
box, so the old ellipse stays one setting away: Preferences › Sketch › Draw ellipses with their
axes, on by default. Off, the tool draws the ellipse alone. sketch.ellipse takes axes: false
for the same, and keeps drawing the axes when it is not given.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: sketch.ellipse refuses an axes value that is not true or false
A string such as "false" was read as not given, so the axes were drawn; it is now refused as
the text commands refuse a non-boolean bold or italic. The move test also covers an ellipse
whose minor axis was deleted: the major axis left goes along.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: D picks a half-axis on an ellipse without axes too
An ellipse with no axis lines (both deleted, a mirrored copy, one from an older design) gave the
minor radius wherever the text was pulled, so its major half-axis could not be dimensioned on
it. The half-axis is now chosen by where the text is on every ellipse: the major one to the
ellipse's own major end, the minor one as its minor radius. With no text it is the minor
radius, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: with one half-axis dimensioned, D on the ellipse gives the other
D on an ellipse chose the half-axis by where the text was pulled even when that half-axis was
already held by a dimension, so the second D usually guessed the one already there and was
refused as over-constrained. With a driving dimension already on one half-axis (to an axis
end, the minor radius, or the whole axis along its line or between its ends), D with no type
now gives the other, in either order and with or without the axis lines. With both held it
chooses as before; an explicit major or minor is kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the held half-axis rule is documented and its cases tested
The Dimension command's parameters and the guide now say that with one half-axis held, D on
the ellipse gives the other. Tests cover the whole axis held as a distance between its ends
and as its line's length with the other axis deleted, and check that a mirrored ellipse has
no axes. The placement test undoes its first dimension, so its second half still tests where
the text is rather than the held half-axis.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: Transform previews an ellipse with its axes
OK in Sketch Transform moves, turns and scales an ellipse's axes with it, but the window drew
where OK would leave only the picked curves, so the axes stayed put in the preview until OK. An
ellipse picked alone is now drawn with the axis lines it has.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the typed-radius ellipse test counts the ellipse's axes
Main's #10282 test drew an ellipse with typed radii and expected one curve; with the
ellipse_axes preference on by default the tool also draws the two axes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's remaining axis still drags and selects it
With one axis deleted, dragging the other axis did not hold the ellipse (with the minor axis
left, the drag squashed it), and a double-click on the ellipse or that axis selected only the
one curve. The drag and Sketch::chain now read whichever axes are left through
ellipse_axis_lines, as Transform and Move already do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: drop the unreachable third arm of the held half-axis check
A distance from the centre to the major end or the point opposite it is already matched by the first arm, so the third arm and its major_end closure never ran.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: D on an ellipse's axis line is the whole axis wherever the value is pulled
An axis line took the free line's rule, so on a turned ellipse a value pulled beside or above the box the axis spans gave its horizontal or vertical distance. An ellipse's axis is a construction axis, so auto now always gives its length, which the held half-axis check already counts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's axis is never a side of a Fillet or Chamfer corner
A line drawn from an ellipse's major end shares that point with the major axis, so Fillet or Chamfer there took the two as a corner (two lines skip the construction filter) and rounded the line into the axis. The axes are left out of a corner, picked by its point or as a and b.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: test the move reply, extend and the one-axis Transform preview for ellipse axes
The reply of sketch.move, sketch.transform and sketch.scale lists the axis lines, Extend stops at an axis, and Sketch Transform previews an ellipse with the one axis left after the other was deleted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: with Draw ellipses with their axes off, D on an ellipse is its minor radius as before
The preference brought back the old drawing only; D on an ellipse had changed with no way back. sketch.dimension takes half_axes (default true, refused when not true or false); false makes auto on an ellipse the minor radius wherever the text is. The Dimension tool and the context menu's Sketch Dimension pass it from the preference, and with it off a radius on an ellipse is drawn and labelled R as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: read an ellipse's axes in one pass over the constraints
ellipse_axis_lines scanned every constraint for every curve, so 500 ellipses with their axes (1500 curves, 2000 constraints) took 1.6 s to read and Move on all of them 2.0 s. It now collects the lines the centre bisects first: 3 ms and 0.36 s.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the dimension and corner parameters say how an ellipse's axis lines take part
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Preferences: Draw ellipses with their axes says D gives the minor radius when off
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: ask only the ellipses centred on a line's midpoint whether it is their axis
is_ellipse_axis read every ellipse's axes to answer for one line. An axis is bisected by its ellipse's centre, so it now asks only the ellipses centred on a point that bisects the line. The answer is the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a horizontal or vertical dimension across a level major axis holds it for D on the ellipse
half_axes_held counted a distance, a length and a radius, but not a horizontal or vertical dimension across the major axis, which is its length when the axis lies that way. D on the outline could then take the held major half-axis and be refused as determined; it now gives the minor one. Across a slanted axis such a dimension is only a projection and does not count.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Dimension: a draft on an ellipse is drawn with the axes preference it was made with
The frame read the preference as it is now, while the dimension added is the draft's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a horizontal or vertical dimension across an upright minor axis holds it too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: drop the unused Sketch::ellipse_axes; ellipse_axis_lines says how the axes are read
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse's own axes do not cut it, so Trim takes a lone ellipse whole and stops at real crossings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: Fillet and Chamfer offer no corner at an ellipse's axis end, as the engine takes none
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a deleted ellipse leaves its centre on its axes, as a Center Rectangle's centre stays
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: ellipse axis docs say what they do, and the corner picker tests a curve's ends before its axis role
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the trim-at-a-crossing test checks that part of the ellipse is left
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: an ellipse axis moved, turned or scaled on its own takes its ellipse along, as a drag does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: a selection dragged by an ellipse axis takes the ellipse along, as the axis alone does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Docs: the Sketch preferences page lists Draw ellipses with their axes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Sketch: the ellipse axes help text says D gives the minor radius, drawn and labelled R as before, wherever the value is pulled
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* claim: #11103
* Hole: Bridge option for counterbores (#11103)
A counterbore hole takes an optional `bridge` length: two 3D-printing
layers that thick below the counterbore's floor, a slot along X across
the counterbore and then a square, both 0.02 mm wider than the hole, so
a printer bridges the step instead of sagging into it. Empty (the
default) keeps a plain counterbore.
The clearance keeps the bore, cut straight through both layers as for a
plain counterbore, clear of their sides: at exactly the hole's width it
ran tangent along them and broke through. The command and the geometry
refuse a layer that is not a positive length, layers that don't fit in
the hole below the counterbore, and a bridge on any other hole type.
The Hole dialog shows a Bridge field below Drill Point for counterbores.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Hole: translate the Bridge label for the complete catalogs (#11103)
Arabic, Hebrew, Japanese, Vietnamese and Chinese carry every English
message, so `cargo xtask i18n --check` needs the new label in each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Hole: bridged counterbores refuse layers past a through hole's exit, too narrow a counterbore and a malformed bridge (#11103)
- Through all, the second bridge layer must end inside a body (exact point classification),
short of the exit face; the tool's reach is no measure of the material.
- A bridged counterbore must be at least 0.04 mm wider than the hole, so the slot's ends have
room on its wall (no square root of a negative number reaches the extrude).
- `solid.hole` refuses a `bridge` that is given but not a length expression (`true`, `[]`, `""`)
instead of making a plain counterbore; `null` still leaves it out.
- Loop2 and Seg2 now come from solidcore_record (main moved them).
- The "nothing saved" check looks for the `"bridge"` key: `format_pending` names
`bridged-counterbore` in every design.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Unit defaults test: solid.hole has the bridge field too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Adds assets/branding/logo with the static mark (colour, one-colour
black and white), transparent 512/1024/2048 px PNGs, an outlined
wordmark and a horizontal lockup, all drawn from the app icon's
blue cutout layer. assets/branding/README.md covers use, colours,
clear space, minimum size and the name.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Box, Sphere and Torus: a sketch point picks where they go (#9403)
The Point input of the Box, Sphere and Torus windows took a vertex, a point on an edge or face
and the origin, but not a sketch's points, so a sphere could not be centred on a point drawn in a
sketch. It now takes the points of every shown sketch (POINTS | EXTERNAL_POINTS, as Measure
does): a click fills X, Y and Z with where the sketch puts the point in the world, and a point
selected before the window opens places the primitive there, as a vertex does. The input's chip
names the point and its sketch as Select Other does ("Point 2 · Marks").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Box, Sphere and Torus: the sketch point chip label for every complete locale
Main's i18n check wants each message in the complete catalogs (ar, he, ja,
vi, zh); the label has no words, so each carries the same "{point} · {sketch}".
With main's new selection kinds and this one, every Sel variant has its arm,
so the catch-all arm is unreachable (clippy) and goes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Primitive at a sketch point: a point picked in the sketch being finished still places it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
A Georgian catalog (assets/locales/ka.json) carrying every English message,
registered in crates/ui-egui/src/i18n.rs, with a row in the new-language test,
a pending attribution file and a terminology note in docs/localization.md.
The catalog is Mkhedruli only; egui's built-in Hack already draws it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Design tabs: the tooltip says when a saved design has unsaved changes (#11408)
A tab marks unsaved changes with a bullet after the design's name, and a
long name cut short by the tab hides it. The tab's tooltip, which says
where the design is saved, now adds "Unsaved changes" below for a saved
design with changes not saved yet. A design never saved already says
"Not saved yet". The new string is in a pending locale file, with ten
translations taken from the same words elsewhere in the catalogs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Design tabs: the unsaved line in every complete catalog (#11408)
Arabic, Hebrew and Vietnamese are complete catalogs, which must carry
every English message: they get the words they already use for
"Unsaved changes" elsewhere.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>