Compare commits

..

123 Commits

Author SHA1 Message Date
bherbruck f56114219b STEP: delete the step-import crate; the goldens and step-export read through the record's Part 21 parser (#14194)
* Move geom's pcurve, label and check into solidcore::eval (pure git mv)

crates/geom/src/brep/{pcurve,pcurve_tests,label,check}.rs move unchanged to
solidcore/crates/solidcore/src/eval/. The next commits retype them to the kernel's evaluation
types and switch their callers; this commit is the move alone so their history follows them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval: pcurve, label and check on the kernel's evaluation types

The moved files take eval::geometry's Curve, Curve2, Surface and Frame (the record's kinds,
field for field) and the kernel's evaluator, in place of the record's types and
solidcraft-geom's evaluator. What reads a record as a record leaves: the structural checks
(counts, budgets, a use's interval in its curve's natural range), the edge and face readers
(edge_curve_interval, form_turns on a Face) and the trim request types go to solidcore-ops,
which converts. Results are unchanged: the pcurve keeps its own pole test (the evaluator's
speed rule), knot span search and B-spline cut, not the kernel's collapse; the 80 eval tests
pass, the pcurve suite among them.

Lint-driven rewrites that keep each result: checked indexing, no pre-reserving from input counts,
the loop rotation without a remainder, a clamp that cannot panic on a reversed domain. The
hostile-record cases that depend on the record's checks are kept as no-panic checks here and as
refusals in ops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-ops: pcurve, label and record_check over the record

The record's side of the moved kernel routines: each checks the record's structure as the
record's validation does (one budget per face, a use's interval in its curve's natural range, a
given pcurve as a 2D B-spline), converts through solidcore-convert, calls solidcore::eval and
converts back. The trim request types (TrimFace, TrimEdge, TrimUse, Trims) hold records, so they
live here. No arithmetic: ops' float-arithmetic and geometry-method lints pass unchanged.

The hostile-record refusals the record checks give (empty and non-finite intervals, a NaN
coordinate, a circle of no radius) are tested here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Call pcurve, label and the record checks through solidcore-ops

geom, kernel, smlib and step call solidcore_ops::{pcurve, label, record_check} where they called
solidcraft_geom::brep::{pcurve, label, check}, which moved into solidcore::eval. One
implementation of each remains, in the kernel; geom's brep module no longer declares them.
solidcore-ops becomes a workspace dependency of the four crates (the seam check's public list
already allows it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move geom's record agreement check into solidcore::eval (pure git mv)

crates/geom/src/brep/geometry.rs moves unchanged to solidcore/crates/solidcore/src/eval/agreement.rs
(the kernel's eval already has a geometry module). The next commit retypes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval::agreement on a plain view; ops reads a record into it

The moved check reads a record through agreement::View (edges, vertices, faces and their uses,
in the kernel's evaluation types) in place of the record's Brep, which the kernel never sees.
solidcore-ops' record_check::agreement converts a record's curves, surfaces and pcurves into the
view and calls it; Mismatch, Problem and Record keep their wording. The pole test is the
pcurve's speed rule, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check record agreement through solidcore-ops

kernel, smlib, step and geom's tests call solidcore_ops::record_check::agreement where they
called solidcraft_geom::brep::geometry::check, which moved into solidcore::eval::agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave kernel/src/tess on geom's pcurve path until the tess move

crates/kernel/src/tess is moving into solidcore-tess in its own pull request, so its three
pcurve::eval call sites are not edited here: geom::brep::pcurve re-exports
solidcore_ops::pcurve::eval for them, and goes when the tess move switches them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore/bench/step: the STEP reader bake-off harness

fetch.sh builds the corpus at run time from pinned sources (SolidCraft's STEP tests,
dan335/step-conformance, solidcore's fixtures, cadmpeg's fixtures, the NIST PMI and STEP Tools
sets through their SHA-256 pinned fetch scripts), folded by SHA-256; nothing downloaded is
committed. run.py runs readers in the solidcraft-cli eval shape with a timeout and writes
per-file.tsv and summary.md: opened, refused, timed out, all bodies closed, reference volumes
within 0.1% (references.tsv, from formulas), and wall time.

On main cc55f59bf2: 319 files, 195 opened, 135 with every body closed, 23 of 24 reference
volumes, median 0.20 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move SolidCraft's STEP reader into solidcore (pure git mv)

crates/step moves unchanged to solidcore/crates/solidcore-step, and its Part 21 parser to
solidcore-record/src/step/p21.rs, where it takes the place of record's earlier port of this same
file (from a5b71ca2). This commit is the move alone, so the files keep their history and
authors; the next commits make them build in their new places and switch SolidCraft to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-record: the Part 21 parser keeps record's hardening

The moved parser takes back what record's port added in review (#2591): typed errors with the
same messages, entities in id order (BTreeMap), capped parameter and record counts, linear-time
decoding of unterminated escapes, a byte order mark skipped. The file's content is record's as
before the move; its history now runs through SolidCraft's parser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: the moved reader as a solidcore workspace crate

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: evaluate and form records through the kernel

The moved reader called solidcraft-geom's record evaluator, exact forms and vector helpers. It
now calls the kernel's: solidcore::eval's CurveEval, SurfaceEval, face_flux and form, through a
private `kernel` module that converts records with solidcore-convert, and the kernel's vector
measures on the record's Vec3 (`vec`). geom's form was a copy of the kernel's, function for
function; the face box (`extent`) is the kernel's with poles taken exactly. The B-spline cut is
the kernel's (eval::pcurve::segment), the pole test the pcurve's speed rule, both made public
for this. Profiling spans, which were SolidCraft's, are left out.

The crate keeps SolidCraft's formatting (its own rustfmt.toml) and lints under solidcore's hard
rules: no unsafe, unwrap, expect, panic or unchecked indexing (the 33 indexing sites are
rewritten with iterators and checked access, results unchanged). The step-conformance test reads
SolidCraft's tests/step-conformance where the tree has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* SolidCraft reads and writes STEP through solidcore-step

crates/kernel's STEP import (step_in), STEP export (step_out) and IGES export (iges_out) call
solidcore_step where they called solidcraft_step; crates/step is gone. The Part 21 parse error is
the record's typed error, shown with the same message. solidcore-step joins the crates
SolidCraft may use directly (xtask/solidcore-public.txt) until its build is kernel primitives
under an ops recipe (RFC 0003, 1.6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: bound faces with the pcurves' pole test (form::extent_by)

The bake-off showed the reader on the kernel's form::extent refusing 7 STEP Tools parts
(304-310 boxy_with_*: "loop encloses no (u, v) area") and reading the large parts 2-8x slower
(rear 37.8 s against 18.4 s): extent's exact collapse test classifies the boundary points
differently from the speed rule the reader's faces were always bounded with, and costs a
collapse search per point (the cost in #13655). extent's body now takes the pole test
(form::extent_by; extent keeps the exact one), and the reader passes the pcurves' speed rule.
On those files the result and time are base's again: boxy_with_cylindricity 174839.178,
nist_ftc_06 3323556.516, rear 14.0 s against 16.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Kernel rig: drop the gone crates/step paths

crates/step moved to solidcore/crates/solidcore-step, which the shared core (PATHS-ALL:
solidcore/**) already covers: the import and crash areas' PATHS and kernel-rig.yml drop it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a seam round the tube for a torus face winding around its axis

A torus face bounded by two circles about its axis (a half torus between its rims, the fillet
round a bore) was refused: "a face winding around a torus ... without a seam edge". It now gets
a seam as a band on a cylinder or sphere does, a tube circle at a vertex's angle, running from
the loop the face lies above up the tube to the other loop, so on the face's side whichever half
of the tube that is. On the bake-off 9 bodies that were open shells close: torus_ring (4934.802,
its reference), turbine, nist_ctc_05 (both editions), nist_ftc_06 rd, nist_ftc_11 (both),
nist_stc_06, nist_stc_10; every body closed goes 135 -> 145, reference volumes 23 -> 24 of 24.

bench/step/run.py takes a probe-shaped reader (LABEL=probe:COMMAND, one JSON line) for a
library without SolidCraft's CLI, and runs every reader on a file together so they meet the same
load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: short entity names, POLY_LOOP, FACETED_BREP and plain FACE

What solidcore's step-import read and this reader refused:
- Part 21 short names (CRTPNT, FCSRF, PLYLP, ...) read as their long names, in the record's
  parser (step-import's table, #2582). STEP Tools' clip and socks are written that way.
- A POLY_LOOP bound is a closed polygon: one vertex per point and one line edge per side, an edge
  shared by every loop with the same two points.
- A FACETED_BREP is a manifold solid of such faces (calo, cylcub).
- A plain FACE, with no surface, lies on the plane of its loops (Newell's normal, refused where
  the loop leaves the plane by more than the tolerance).

Tests: a faceted tetrahedron closes with 6 shared edges; short names parse to long ones; the
torus band seam from the commit before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP: read topology outside representations, lines by their vertices, inner loops by area

Topology-first reading, as solidcore's step-import and step-brep read files (#2583):
- Topology no representation lists (bare geometry files): crates/kernel reads the file's
  unlisted solids, then its unlisted shells and faces (each face a one-face sheet), through
  solidcore_step::topology::roots, in the file's one representation context. A representation's
  own shell and face items stay out (a presentation's are not bodies).
- A LINE edge whose vertices lie off its LINE (a direction or magnitude written wrong) is the
  segment between its vertices, which the faces it bounds share; other curves still refuse a far
  vertex.
- An inner loop written the way its outer loop runs, on a face whose loops close in (u, v), is
  run the other way.
- More Part 21 short names (product structure, representations, units, FACETED_BREP).

Bake-off (319 files, 220 opened by some reader): opened 195 -> 212, every body closed 135 ->
148, reference volumes 24 of 24 (core 22); median time unchanged (0.123 s -> 0.119 s).
kernel-cases/import 35/35; the kernel's step_in, IGES and lump tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a sphere face bounded by vertex loops at its poles is the whole sphere

A face of a sphere whose bounds are vertex loops alone, at its poles (cadmpeg's
ap242_vertex_loop), was refused as "a face without an edge loop". It is the whole sphere: its
loop becomes a meridian from the south pole to the north and back, which the slit completion
keeps as its seam, as a ball bounded by its seam alone already is. Any other face without an
edge loop is still refused. Test: a ball bounded by vertex loops at its poles closes with one
seam edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: a face SMLib refuses is named and left out; a face used twice is one piece

Opening a file never fails over faces that cannot be made: the face is left out, the rest come in
as an open body, and the import's warnings name each face left out with why.
- SMLib's refusal of a record face by its index ("flat arrays: face 90: a NURBS form that is not
  its analytic surface") now names the file's face (face #1202), so it is left out like a face
  the reader refuses. NIST CTC 02 (AP203) opens: 480 of its 487 faces as an open body, the 4
  faces 622 mm off their surfaces and the one SMLib refuses named in the warnings.
- A face the solid's shells use more than once (cadmpeg br02: one face as the outer shell and two
  voids) is read once, and its further uses are named as left out.
- One face read alone is the sheet itself (nothing to stitch).

bench/step/run.py counts the files opened with faces left out, from the import warnings.
Test: a face SMLib refuses by its index is named as the file's face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: a solid whose only face cannot be made says which face, why and how far

A file whose one face cannot be made (cadmpeg's pc01, pc03 and tp06 non-coplanar fixtures:
edges 1 to 10 mm off the face's surface) has nothing consistent to open. Its error now reads
"the solid's only face, #30, cannot be made: an edge lies 1 mm off the face's surface" in place of
the count of faces whose pcurves failed. Test: a disk whose circle lies 1.5 mm off its plane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: an unclamped B-spline curve is read clamped to its domain

A closed curve written as an unclamped B-spline (uniform knots past its ends, its first points
repeated at its end: cadmpeg's N04 recipes, periodic writers) had no closed-form pcurve on a
plane, so its faces were left out: "no exact pcurve of a B-spline on a plane". It is now read
as the same curve over [knots[p], knots[n]], clamped there by exact knot insertion
(eval::pcurve::segment), as every evaluator and pcurve takes a spline. recipe N04a and N04b open
as 3 closed solids each (5000 and 6000 mm³, as solidcore's step-brep reads them).

Test: a disk bounded by an unclamped periodic quadratic reads, its edge clamped to [0, 4].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a seam round the axis for a torus face winding round its tube

A torus face bounded by two circles round its tube (an elbow's wall between its two ends) was
refused: "a loop winding around a surface more than once or in v". Its loops wind in v, so it
gets a seam the other way about: a circle about the axis at a vertex's angle round the tube,
running from the loop that winds up the tube towards −u (the face lies to the left of its loops)
to the other. band_seam and crossing take the parameter the loops wind in. In STEP Tools'
jack_in_the_box 14 bodies that were open shells close (34 -> 48 of 56).

Test: a quarter elbow closes with a quarter-circle seam about its axis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move step-brep's export mapping into step-export, its fixtures into solidcore-step (pure git mv)

brep_to_model (a kernel body as step-import's model, for the writer) moves to step-export, which
RFC 0003 item 1.7 measures against SolidCraft's writer; the two STEP fixtures move to
solidcore-step's tests. The move alone, so their history follows them; the next commit deletes
step-brep's import side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Delete step-brep's STEP import: one STEP reader, solidcore-step

solidcore had two STEP readers; solidcore-step (SolidCraft's, moved in #13979) now reads what
step-brep's topology-first build read, but the faces it would have to build inconsistently
(#14038's gate). step-brep's import side goes: its build, constructor and UV trims (lib.rs,
constructor.rs, pcurves.rs) and their tests. What it kept for the writer, brep_to_model, is
step-export's now (RFC 0003 item 1.7); its round-trip cases that read back through the deleted
importer go with it. The panic-site list drops step-brep's rows and moves brep_to_model's.

Ported, with their names: the Discord fillet operand reads as one closed solid, and a face no
shell lists is a one-face sheet (crates/kernel step_in tests); rod_doubled_edge names the face
of its folded rim (solidcore-step). The fixtures moved with their history. The reading cases of
step-brep's tests, written by Brennen Herbruck (topology_first, issue_2580_winding_faces,
issue_2581_faceted_brep, issue_2583_topology_first, discord_fillet), are covered by
solidcore-step's tests of seams, tori, faceted solids, unlisted topology and the bake-off.

step-import stays for the goldens and step-export until #14123. Core's code for the 7
jack_in_the_box bodies still open (#14130) is at 2a96a046ca.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP: port step-brep's import panic fuzz onto solidcore-step

step-brep's tests/panic_fuzz.rs (#2490, by Brennen Herbruck) went with its import. Its cases
come back with their names:
- panic_fuzz_step_import (solidcore-step): the same mutations (truncation, flipped bytes,
  hostile numbers, broken and cyclic references, dropped and repeated lines, swapped entity
  names, deep nesting) of the Discord fillet and tetra fixtures and of primitives this crate's
  writer writes. Each is parsed, read into records, checked as the kernel takes them, made into
  kernel bodies and written again. Also entity_edit_lands_on_an_entity_name, and a check that
  the written bases read back as solids, so the mutations reach the whole path.
- panic_fuzz_step_flat_decode (step-import, whose flat arrays it decodes).

Run: 3 seeds of 20 000 import cases and 5 000 flat cases, 0 findings, 0 hangs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: rustfmt the panic fuzz harness's doc

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* panic fuzz harness: keep solidcore's formatting where solidcore-step includes it

solidcore-step formats with SolidCraft's rustfmt.toml, which reached the harness through its
#[path] include; the include is #[rustfmt::skip] now, and the harness is solidcore's as on main
but its doc naming the fuzzes that share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP and pcurves: topology short names; a use's interval refused when empty or not finite

From review:
- The record's parser maps the AP203 short names of the topology too (ADVFC, EDGCRV, EDGLP,
  FCBND, MNSLBR, ORNEDG, VRTPNT): a file written with them had its faces refused.
- solidcore::eval::pcurve refuses a use whose interval is empty, reversed or not finite before
  anything else: a given pcurve was checked against the interval, which a NaN end passed, so
  exact_pcurves returned it as a pcurve. Tests: those intervals are Invalid with and without a
  given pcurve; VRTPNT and FCBND read as their long names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-record: short names checked against ISO's short-names file

Every pair of the table is as http://standards.iso.org/iso/10303/tech/short_names/short-names.txt
gives it, the source cited beside it. One was wrong, from step-import's table: CMCRSG is
COMPOSITE_CURVE_SEGMENT, not COMPOSITE_CURVE (CMPCRV, added).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: retire the step-import crate; one STEP parser, the record's p21

step-import's Part 21 parser is gone: the goldens' SMLib comparison, the
--step-corpus run and step-export read through solidcore-record's p21. The
neutral model moves to solidcore-record::step::model (plain data), the mapper
from p21 to that model moves to step-export (it computes frames and angles, so
it cannot live in the record), and the constructor script and flat arrays move
into the goldens crate, their only users.

p21's Exchange now keeps the HEADER's file name, authors and so on (step-export
reads them back). The brep_constructor golden is unchanged (185 of 185 cases).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Cargo.lock: solidcraft-step is now solidcore-step

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* io: the model cache key no longer names crates/step

The reader moved to solidcore/crates/solidcore-step, which the cache already keys as part of the solidcore tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: a whole turn a rounding short of a quarter line has its form from it (#12760)

Port of #13535's fix in crates/geom's form to the kernel's form, which the STEP reader now uses: a cylinder, cone, sphere or torus face of one whole turn whose seam reads back a rounding short of a quarter line started its form a quarter early, and a tube read back through STEP measured 14 % over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* pcurve docs: a pcurve without a closed form is refused, not fitted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bench/step: a malformed --reader is an error; a reader's bad JSON is a refusal, not a crash

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: SMLib's first refusal names the file's face, on a turned sheet too

A solid SMLib refused by a face's record index ("flat arrays: face 12") had that index named as a file face only on the reads that left faces out, not the first, so where every face read alone nothing was left out and the faces were stitched instead. solid_part names it, with the face order of the record SMLib was given (a sheet's turned faces reorder it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bench/step: a reader or corpus file that cannot be run is a crashed row, not a stopped run

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: a styled or layered loose shell or face is still read

roots() took any reference to a shell or face as its topology's, so a bare face a STYLED_ITEM or a layer assignment names was skipped and the file read as having no bodies. A presentation's references (styles, layers, invisibility) no longer count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:27:56 -05:00
austin62jake 2215a9a50a Ruled Surface: input and output schemas for surface.ruled (#13134) (#13135)
surface.ruled gets SurfaceRuledParams in a new schema/surface_ruled.rs and replies
with FeatureResult. mode and corners are keyword types in schema/types.rs with the
handler's messages; edges, direction, face and far get types of their own that keep
its messages (far is read in order, so the first bad item gives the same message).
angle and direction are checked whenever given; which mode needs them stays the
handler's.

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-10 17:16:14 +00:00
bherbruck 182d2c6bd8 solidcore-ops: cancel ops calls with a scoped token (solidcore#3247) (#14660)
solidcore_ops::cancel::within runs work under a CancelToken. Every ops call
it makes on that thread runs with the token on the session's kernel, whose
long loops already poll it; once cancelled, the running call stops at the
kernel's next check and later calls are refused before they wait for the
kernel, each with Error::Cancelled.

A cancelled call leaves no partial state: an edited body is put back by the
session's rollback, no result is returned even if the kernel finished
first, the kernel is replaced as after a panic, and nothing reaches the
failure callback. Nested scopes stop with either token
(CancelToken::either in the kernel).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:59:20 +00:00
bherbruck 126e91f95b STEP: one reader: topology-first reading in solidcore-step, step-brep's import deleted (RFC 0003, 1.6) (#14038)
* Move geom's pcurve, label and check into solidcore::eval (pure git mv)

crates/geom/src/brep/{pcurve,pcurve_tests,label,check}.rs move unchanged to
solidcore/crates/solidcore/src/eval/. The next commits retype them to the kernel's evaluation
types and switch their callers; this commit is the move alone so their history follows them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval: pcurve, label and check on the kernel's evaluation types

The moved files take eval::geometry's Curve, Curve2, Surface and Frame (the record's kinds,
field for field) and the kernel's evaluator, in place of the record's types and
solidcraft-geom's evaluator. What reads a record as a record leaves: the structural checks
(counts, budgets, a use's interval in its curve's natural range), the edge and face readers
(edge_curve_interval, form_turns on a Face) and the trim request types go to solidcore-ops,
which converts. Results are unchanged: the pcurve keeps its own pole test (the evaluator's
speed rule), knot span search and B-spline cut, not the kernel's collapse; the 80 eval tests
pass, the pcurve suite among them.

Lint-driven rewrites that keep each result: checked indexing, no pre-reserving from input counts,
the loop rotation without a remainder, a clamp that cannot panic on a reversed domain. The
hostile-record cases that depend on the record's checks are kept as no-panic checks here and as
refusals in ops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-ops: pcurve, label and record_check over the record

The record's side of the moved kernel routines: each checks the record's structure as the
record's validation does (one budget per face, a use's interval in its curve's natural range, a
given pcurve as a 2D B-spline), converts through solidcore-convert, calls solidcore::eval and
converts back. The trim request types (TrimFace, TrimEdge, TrimUse, Trims) hold records, so they
live here. No arithmetic: ops' float-arithmetic and geometry-method lints pass unchanged.

The hostile-record refusals the record checks give (empty and non-finite intervals, a NaN
coordinate, a circle of no radius) are tested here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Call pcurve, label and the record checks through solidcore-ops

geom, kernel, smlib and step call solidcore_ops::{pcurve, label, record_check} where they called
solidcraft_geom::brep::{pcurve, label, check}, which moved into solidcore::eval. One
implementation of each remains, in the kernel; geom's brep module no longer declares them.
solidcore-ops becomes a workspace dependency of the four crates (the seam check's public list
already allows it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move geom's record agreement check into solidcore::eval (pure git mv)

crates/geom/src/brep/geometry.rs moves unchanged to solidcore/crates/solidcore/src/eval/agreement.rs
(the kernel's eval already has a geometry module). The next commit retypes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval::agreement on a plain view; ops reads a record into it

The moved check reads a record through agreement::View (edges, vertices, faces and their uses,
in the kernel's evaluation types) in place of the record's Brep, which the kernel never sees.
solidcore-ops' record_check::agreement converts a record's curves, surfaces and pcurves into the
view and calls it; Mismatch, Problem and Record keep their wording. The pole test is the
pcurve's speed rule, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check record agreement through solidcore-ops

kernel, smlib, step and geom's tests call solidcore_ops::record_check::agreement where they
called solidcraft_geom::brep::geometry::check, which moved into solidcore::eval::agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave kernel/src/tess on geom's pcurve path until the tess move

crates/kernel/src/tess is moving into solidcore-tess in its own pull request, so its three
pcurve::eval call sites are not edited here: geom::brep::pcurve re-exports
solidcore_ops::pcurve::eval for them, and goes when the tess move switches them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore/bench/step: the STEP reader bake-off harness

fetch.sh builds the corpus at run time from pinned sources (SolidCraft's STEP tests,
dan335/step-conformance, solidcore's fixtures, cadmpeg's fixtures, the NIST PMI and STEP Tools
sets through their SHA-256 pinned fetch scripts), folded by SHA-256; nothing downloaded is
committed. run.py runs readers in the solidcraft-cli eval shape with a timeout and writes
per-file.tsv and summary.md: opened, refused, timed out, all bodies closed, reference volumes
within 0.1% (references.tsv, from formulas), and wall time.

On main cc55f59bf2: 319 files, 195 opened, 135 with every body closed, 23 of 24 reference
volumes, median 0.20 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move SolidCraft's STEP reader into solidcore (pure git mv)

crates/step moves unchanged to solidcore/crates/solidcore-step, and its Part 21 parser to
solidcore-record/src/step/p21.rs, where it takes the place of record's earlier port of this same
file (from a5b71ca2). This commit is the move alone, so the files keep their history and
authors; the next commits make them build in their new places and switch SolidCraft to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-record: the Part 21 parser keeps record's hardening

The moved parser takes back what record's port added in review (#2591): typed errors with the
same messages, entities in id order (BTreeMap), capped parameter and record counts, linear-time
decoding of unterminated escapes, a byte order mark skipped. The file's content is record's as
before the move; its history now runs through SolidCraft's parser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: the moved reader as a solidcore workspace crate

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: evaluate and form records through the kernel

The moved reader called solidcraft-geom's record evaluator, exact forms and vector helpers. It
now calls the kernel's: solidcore::eval's CurveEval, SurfaceEval, face_flux and form, through a
private `kernel` module that converts records with solidcore-convert, and the kernel's vector
measures on the record's Vec3 (`vec`). geom's form was a copy of the kernel's, function for
function; the face box (`extent`) is the kernel's with poles taken exactly. The B-spline cut is
the kernel's (eval::pcurve::segment), the pole test the pcurve's speed rule, both made public
for this. Profiling spans, which were SolidCraft's, are left out.

The crate keeps SolidCraft's formatting (its own rustfmt.toml) and lints under solidcore's hard
rules: no unsafe, unwrap, expect, panic or unchecked indexing (the 33 indexing sites are
rewritten with iterators and checked access, results unchanged). The step-conformance test reads
SolidCraft's tests/step-conformance where the tree has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* SolidCraft reads and writes STEP through solidcore-step

crates/kernel's STEP import (step_in), STEP export (step_out) and IGES export (iges_out) call
solidcore_step where they called solidcraft_step; crates/step is gone. The Part 21 parse error is
the record's typed error, shown with the same message. solidcore-step joins the crates
SolidCraft may use directly (xtask/solidcore-public.txt) until its build is kernel primitives
under an ops recipe (RFC 0003, 1.6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: bound faces with the pcurves' pole test (form::extent_by)

The bake-off showed the reader on the kernel's form::extent refusing 7 STEP Tools parts
(304-310 boxy_with_*: "loop encloses no (u, v) area") and reading the large parts 2-8x slower
(rear 37.8 s against 18.4 s): extent's exact collapse test classifies the boundary points
differently from the speed rule the reader's faces were always bounded with, and costs a
collapse search per point (the cost in #13655). extent's body now takes the pole test
(form::extent_by; extent keeps the exact one), and the reader passes the pcurves' speed rule.
On those files the result and time are base's again: boxy_with_cylindricity 174839.178,
nist_ftc_06 3323556.516, rear 14.0 s against 16.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Kernel rig: drop the gone crates/step paths

crates/step moved to solidcore/crates/solidcore-step, which the shared core (PATHS-ALL:
solidcore/**) already covers: the import and crash areas' PATHS and kernel-rig.yml drop it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a seam round the tube for a torus face winding around its axis

A torus face bounded by two circles about its axis (a half torus between its rims, the fillet
round a bore) was refused: "a face winding around a torus ... without a seam edge". It now gets
a seam as a band on a cylinder or sphere does, a tube circle at a vertex's angle, running from
the loop the face lies above up the tube to the other loop, so on the face's side whichever half
of the tube that is. On the bake-off 9 bodies that were open shells close: torus_ring (4934.802,
its reference), turbine, nist_ctc_05 (both editions), nist_ftc_06 rd, nist_ftc_11 (both),
nist_stc_06, nist_stc_10; every body closed goes 135 -> 145, reference volumes 23 -> 24 of 24.

bench/step/run.py takes a probe-shaped reader (LABEL=probe:COMMAND, one JSON line) for a
library without SolidCraft's CLI, and runs every reader on a file together so they meet the same
load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: short entity names, POLY_LOOP, FACETED_BREP and plain FACE

What solidcore's step-import read and this reader refused:
- Part 21 short names (CRTPNT, FCSRF, PLYLP, ...) read as their long names, in the record's
  parser (step-import's table, #2582). STEP Tools' clip and socks are written that way.
- A POLY_LOOP bound is a closed polygon: one vertex per point and one line edge per side, an edge
  shared by every loop with the same two points.
- A FACETED_BREP is a manifold solid of such faces (calo, cylcub).
- A plain FACE, with no surface, lies on the plane of its loops (Newell's normal, refused where
  the loop leaves the plane by more than the tolerance).

Tests: a faceted tetrahedron closes with 6 shared edges; short names parse to long ones; the
torus band seam from the commit before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP: read topology outside representations, lines by their vertices, inner loops by area

Topology-first reading, as solidcore's step-import and step-brep read files (#2583):
- Topology no representation lists (bare geometry files): crates/kernel reads the file's
  unlisted solids, then its unlisted shells and faces (each face a one-face sheet), through
  solidcore_step::topology::roots, in the file's one representation context. A representation's
  own shell and face items stay out (a presentation's are not bodies).
- A LINE edge whose vertices lie off its LINE (a direction or magnitude written wrong) is the
  segment between its vertices, which the faces it bounds share; other curves still refuse a far
  vertex.
- An inner loop written the way its outer loop runs, on a face whose loops close in (u, v), is
  run the other way.
- More Part 21 short names (product structure, representations, units, FACETED_BREP).

Bake-off (319 files, 220 opened by some reader): opened 195 -> 212, every body closed 135 ->
148, reference volumes 24 of 24 (core 22); median time unchanged (0.123 s -> 0.119 s).
kernel-cases/import 35/35; the kernel's step_in, IGES and lump tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a sphere face bounded by vertex loops at its poles is the whole sphere

A face of a sphere whose bounds are vertex loops alone, at its poles (cadmpeg's
ap242_vertex_loop), was refused as "a face without an edge loop". It is the whole sphere: its
loop becomes a meridian from the south pole to the north and back, which the slit completion
keeps as its seam, as a ball bounded by its seam alone already is. Any other face without an
edge loop is still refused. Test: a ball bounded by vertex loops at its poles closes with one
seam edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: a face SMLib refuses is named and left out; a face used twice is one piece

Opening a file never fails over faces that cannot be made: the face is left out, the rest come in
as an open body, and the import's warnings name each face left out with why.
- SMLib's refusal of a record face by its index ("flat arrays: face 90: a NURBS form that is not
  its analytic surface") now names the file's face (face #1202), so it is left out like a face
  the reader refuses. NIST CTC 02 (AP203) opens: 480 of its 487 faces as an open body, the 4
  faces 622 mm off their surfaces and the one SMLib refuses named in the warnings.
- A face the solid's shells use more than once (cadmpeg br02: one face as the outer shell and two
  voids) is read once, and its further uses are named as left out.
- One face read alone is the sheet itself (nothing to stitch).

bench/step/run.py counts the files opened with faces left out, from the import warnings.
Test: a face SMLib refuses by its index is named as the file's face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: a solid whose only face cannot be made says which face, why and how far

A file whose one face cannot be made (cadmpeg's pc01, pc03 and tp06 non-coplanar fixtures:
edges 1 to 10 mm off the face's surface) has nothing consistent to open. Its error now reads
"the solid's only face, #30, cannot be made: an edge lies 1 mm off the face's surface" in place of
the count of faces whose pcurves failed. Test: a disk whose circle lies 1.5 mm off its plane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: an unclamped B-spline curve is read clamped to its domain

A closed curve written as an unclamped B-spline (uniform knots past its ends, its first points
repeated at its end: cadmpeg's N04 recipes, periodic writers) had no closed-form pcurve on a
plane, so its faces were left out: "no exact pcurve of a B-spline on a plane". It is now read
as the same curve over [knots[p], knots[n]], clamped there by exact knot insertion
(eval::pcurve::segment), as every evaluator and pcurve takes a spline. recipe N04a and N04b open
as 3 closed solids each (5000 and 6000 mm³, as solidcore's step-brep reads them).

Test: a disk bounded by an unclamped periodic quadratic reads, its edge clamped to [0, 4].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: a seam round the axis for a torus face winding round its tube

A torus face bounded by two circles round its tube (an elbow's wall between its two ends) was
refused: "a loop winding around a surface more than once or in v". Its loops wind in v, so it
gets a seam the other way about: a circle about the axis at a vertex's angle round the tube,
running from the loop that winds up the tube towards −u (the face lies to the left of its loops)
to the other. band_seam and crossing take the parameter the loops wind in. In STEP Tools'
jack_in_the_box 14 bodies that were open shells close (34 -> 48 of 56).

Test: a quarter elbow closes with a quarter-circle seam about its axis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move step-brep's export mapping into step-export, its fixtures into solidcore-step (pure git mv)

brep_to_model (a kernel body as step-import's model, for the writer) moves to step-export, which
RFC 0003 item 1.7 measures against SolidCraft's writer; the two STEP fixtures move to
solidcore-step's tests. The move alone, so their history follows them; the next commit deletes
step-brep's import side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Delete step-brep's STEP import: one STEP reader, solidcore-step

solidcore had two STEP readers; solidcore-step (SolidCraft's, moved in #13979) now reads what
step-brep's topology-first build read, but the faces it would have to build inconsistently
(#14038's gate). step-brep's import side goes: its build, constructor and UV trims (lib.rs,
constructor.rs, pcurves.rs) and their tests. What it kept for the writer, brep_to_model, is
step-export's now (RFC 0003 item 1.7); its round-trip cases that read back through the deleted
importer go with it. The panic-site list drops step-brep's rows and moves brep_to_model's.

Ported, with their names: the Discord fillet operand reads as one closed solid, and a face no
shell lists is a one-face sheet (crates/kernel step_in tests); rod_doubled_edge names the face
of its folded rim (solidcore-step). The fixtures moved with their history. The reading cases of
step-brep's tests, written by Brennen Herbruck (topology_first, issue_2580_winding_faces,
issue_2581_faceted_brep, issue_2583_topology_first, discord_fillet), are covered by
solidcore-step's tests of seams, tori, faceted solids, unlisted topology and the bake-off.

step-import stays for the goldens and step-export until #14123. Core's code for the 7
jack_in_the_box bodies still open (#14130) is at 2a96a046ca.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP: port step-brep's import panic fuzz onto solidcore-step

step-brep's tests/panic_fuzz.rs (#2490, by Brennen Herbruck) went with its import. Its cases
come back with their names:
- panic_fuzz_step_import (solidcore-step): the same mutations (truncation, flipped bytes,
  hostile numbers, broken and cyclic references, dropped and repeated lines, swapped entity
  names, deep nesting) of the Discord fillet and tetra fixtures and of primitives this crate's
  writer writes. Each is parsed, read into records, checked as the kernel takes them, made into
  kernel bodies and written again. Also entity_edit_lands_on_an_entity_name, and a check that
  the written bases read back as solids, so the mutations reach the whole path.
- panic_fuzz_step_flat_decode (step-import, whose flat arrays it decodes).

Run: 3 seeds of 20 000 import cases and 5 000 flat cases, 0 findings, 0 hangs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: rustfmt the panic fuzz harness's doc

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* panic fuzz harness: keep solidcore's formatting where solidcore-step includes it

solidcore-step formats with SolidCraft's rustfmt.toml, which reached the harness through its
#[path] include; the include is #[rustfmt::skip] now, and the harness is solidcore's as on main
but its doc naming the fuzzes that share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP and pcurves: topology short names; a use's interval refused when empty or not finite

From review:
- The record's parser maps the AP203 short names of the topology too (ADVFC, EDGCRV, EDGLP,
  FCBND, MNSLBR, ORNEDG, VRTPNT): a file written with them had its faces refused.
- solidcore::eval::pcurve refuses a use whose interval is empty, reversed or not finite before
  anything else: a given pcurve was checked against the interval, which a NaN end passed, so
  exact_pcurves returned it as a pcurve. Tests: those intervals are Invalid with and without a
  given pcurve; VRTPNT and FCBND read as their long names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-record: short names checked against ISO's short-names file

Every pair of the table is as http://standards.iso.org/iso/10303/tech/short_names/short-names.txt
gives it, the source cited beside it. One was wrong, from step-import's table: CMCRSG is
COMPOSITE_CURVE_SEGMENT, not COMPOSITE_CURVE (CMPCRV, added).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Cargo.lock: solidcraft-step is now solidcore-step

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* io: the model cache key no longer names crates/step

The reader moved to solidcore/crates/solidcore-step, which the cache already keys as part of the solidcore tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: a whole turn a rounding short of a quarter line has its form from it (#12760)

Port of #13535's fix in crates/geom's form to the kernel's form, which the STEP reader now uses: a cylinder, cone, sphere or torus face of one whole turn whose seam reads back a rounding short of a quarter line started its form a quarter early, and a tube read back through STEP measured 14 % over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* pcurve docs: a pcurve without a closed form is refused, not fitted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bench/step: a malformed --reader is an error; a reader's bad JSON is a refusal, not a crash

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* STEP import: SMLib's first refusal names the file's face, on a turned sheet too

A solid SMLib refused by a face's record index ("flat arrays: face 12") had that index named as a file face only on the reads that left faces out, not the first, so where every face read alone nothing was left out and the faces were stitched instead. solid_part names it, with the face order of the record SMLib was given (a sheet's turned faces reorder it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bench/step: a reader or corpus file that cannot be run is a crashed row, not a stopped run

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:21:45 -05:00
bherbruck 54e5190955 Overlapping cylinders' round builds again: the rail end starts from the round's own section (#13538) (#13898)
* claim: #13537 and #13538, rim cut and overlapping-cylinder fillet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: a rail's end at a side edge starts from the round's corner section (#13538)

A round of either crossing edge of two crossing cylinders (SolidCraft's
fillet_the_edges_between_two_overlapping_cylinders, R 13) was refused with
status 1001: CalcFilletIntSideFace found no intersection of the round with
the cap. With the walls' offsets continued as themselves (whole circles),
the faces hold two balls at each cap edge, the round of each crossing.
CalcRailIntEdgeuse's first guess on the small wall's cap edge, upstream's
radius fraction along the edge, solved the rail end onto the other
crossing's ball (contact at (4.02, 20.35) instead of (18.98, 8.37)), so the
cap curve between the two rail ends did not exist.

The first guess is now where the ball's section through the filleted
edge's end touches the side edge: the section is solved from the edge
point on both faces, so it is the ball of this round (the start of a
rolling-ball march; Choi and Ju 1989). The section solve is
ball_fit::edge_section, shared with ball_fits_its_faces. Upstream's other
guesses follow unchanged.

This also covers #3045 (the plate's arc end): its test passes with the
face-domain clamp on the drop removed, and that clamp is what broke this
case at a445bdaac6..c0d3cc0124 (b11c5554b3): it moved the drop's guess to
the face's end, from where the solve also found the other ball. One
construction, so the clamp goes.

Goldens, blend.fillet_executive_p3, 12 cases moved (every other blend
unit unchanged):
- radius-supported-at-limit-accepted: built (volume 2199.999313) ->
  refused 1001 (input kept, 2200). The rail end moves one ulp
  (29.999920000080003 -> 29.99992000008); the case sits at the radius
  limit. The old body was off its closed form (2200 - 4e-8) by 6.9e-4.
- stubs4-coons_01_03_29-e0-r0.5: refused 1001 -> built (8 vertices, 12
  edges, 5 faces; mass status 1007 before and after: not a solid).
- ten others: same status and counts; mass properties move at most
  4e-9 relative; in four (issue_2176 tab side, issue-880 half-arc 1-1 and
  1.4437, stubs4-coons e3) the curves' and surfaces' digests change too
  (the rail ends' parameters converge to other roundings).

New test: solidcore-ops round_between_crossing_cylinders (R 6 at each
crossing, both, and R 13), closed-form volumes; fails without this change
(R 13: Status(1001)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: a variable round too large for a box edge is refused with the radius that fits

a_failed_variable_radius_fillet_keeps_its_error_and_a_current_body (radius
0.5 to 30 along an edge of the 10 x 20 x 30 box) was refused with a bare
status 1001; with the rail end continued from the corner section it is
refused as FilletRefused, same status, naming radius 10 as the largest
that builds (the 10 wide side). The body is kept as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Known failing: the overlapping cylinders' round builds again (#13538)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: a rail end on an offset continued as itself is solved on its closed turn (#13538)

solidcore's issue_1945_rail_uv_trim top_edge_round_is_valid failed after
the rail end started from the round's corner section: the round of the
bar's top edge, ending on the boss's arc round, was refused ("a round's
rail leaves the face it rolls on into the body's material"). The rail
end's solve found the right point (side-edge parameter 0.99805 as before)
but named it on the arc round's offset one generator turn away: v
-3.3445 instead of 0.6555, which the face's trim reads as off the face.

LoadInitialValues solved the other surface on its base domain grown by
SetupOffsetExtension, several turns of a surface that continues as
itself. The extension names each point once inside its closed turn: round
the axis it wraps past the turn (WR-650), and along a circle generator (a
torus's, a revolved circle's) the closed circle holds every point. Those
directions are now solved there (closed_turn): round the axis periodic on
the turn, along the generator bounded half the gap past either end (its
extension spans are quarter turns, the base's need not be, so it is not
wrapped).

Every blend unit's goldens are unchanged from the previous commit's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: drop the import main's definition change left unused (#13538)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Merge origin/main; goldens: the round at the minimum radius is known failing (tangency-labs/solidcore#3245)

radius-supported-at-limit-accepted depends on rounding: the round and its
end arcs lie r(sqrt 2 - 1) = 3.3e-5 from the corner they replace, inside
the 5e-5 of the corner vertex's and the fillet's tolerances, so whether the
end arcs are imprinted flips with ulp-level changes (it came out
[1001,8,12,6] on the merge with main where it was blessed [1001,12,18,8]).
It is listed in known_failing.json, without a golden line, until #3245.
PASS blend.fillet_executive_p3 cases=798 changed=0 known_failing=5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:05:07 -05:00
bherbruck 6ca950789c Extruding a long outline: its end faces build about 1.5× faster (a face edit no one listens to skips the edge-use walk) (#14329) (#14454)
* solidcore: building a cap face of a long outline stops walking the whole face for each edge (#14329)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: an unheard face edit skips walking the face's edge uses (#14329)

Each edge added to a face notifies the face (PostEdit), which walked every
edge use and vertex use of the face. An edge use's PostEdit changes nothing
and only a context notify callback can see it, so without one the edge-use
walk is skipped. Building the cap of an outline of N lines was O(N^2) in
that walk; the cap of a 12,000-line outline builds in 10.4 s instead of
15.2 s, with the same face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:40:56 +00:00
Andrzej Błasik 89e3cb13b1 Faster rebuilds: extrusions, revolutions and sweeps name their new faces from exact geometry instead of meshing the body (#14646)
Each new face of an extrusion, revolution, sweep, loft or screw sweep is
named (start cap, end cap, or the wall swept from a sketch segment) so later
features find it again. The kernel meshed every new body to work the names
out; on extrusion-heavy designs that mesh was about a third of the rebuild.

The names now come from the exact body: a cap is a face on the start or end
plane, the start one where a profile point lies on it; a wall comes from each
segment whose middle lies on its edge in the sketch plane, or whose point
half-way along lies on the face (solidcore-ops `Body::face_distances`, the
kernel's trimmed face closest point). Edges and faces SMLib built to its own
tolerance are matched to it. The smlib_sweeps roles line leaves
xtask/mesh-decisions.txt (RFC 0003, item 3.3).
2026-11-10 16:37:51 +00:00
Ben Davis 87400c80ef Threads: select a whole thread flank with one click (#519) (#11737)
* claim: #519 thread flank continuity

* Threads: keep each flank as one curved face

* Threads: preserve saved flank faces when rebuilding old designs

Keep historical thread faces and construction order when a saved feature
has no continuous_flanks field. New threads use continuous flanks by
default, with a preference for the historical layout. Redefine and dialog
reopen retain the feature's saved choice. Generic coils and hole features
keep their existing construction.

Captured pre-change flank names and points remain on the original faces,
including both chamfered ends. All 49 engine thread tests, the UI dialog
regression, and both SMLib guard checks pass. Independent Astra review
found no correctness findings. Required cargo xtask ci passed repository
validators and strict workspace Clippy; its full native test build was
stopped because the available disk cannot hold the remaining binaries.
All 14 selected crates pass cargo xtask wasm. The sweep group retains one
documented baseline cylinder-section failure.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* Threads: a new Thread dialog leaves the default flank layout out of the command

The Thread dialog put `continuous_flanks` into every new command, so the
untouched dialog no longer sent only its face and
`dialogs_thread::tests::every_option_reaches_the_command` failed. Continuous
flanks are the command's default, so the dialog now sends the option only when
the `thread_continuous_flanks` preference asks for the historical half-turn
faces. Editing a saved thread still sends its saved layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Threads: continuous flanks are not a preference; record the ladder's thread cases

New modeled threads always get continuous flank faces. The
`thread_continuous_flanks` preference, its Design page row, its message
catalog strings and its control-protocol entry are removed. A saved
thread still keeps its own `continuous_flanks` field, so an old design
reopens and rebuilds with its half-turn faces, and editing it keeps them.
The dialog test now checks that a new Thread dialog leaves the field out
and that reopening a saved thread keeps its layout.

Kernel ladder: 29 cases make fewer faces, edges and vertices because each
flank is one face: 06-threads/001 to 017 and 019 to 028, and
11-cumulative-parts/003 and 004. Their volume and area match the old
golden to 4e-9 relative and every check passes. Run with
`continuous_flanks: false`, all 29 make exactly the old counts. Only those
29 entries change; the ladder's order and report stay as on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Benjamin Davis <benjamindavis@Benjamins-Mac-mini.local>
Co-authored-by: OpenAI Codex <noreply@openai.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:16:55 +00:00
austin62jake d4e8c0b034 sweep: refuse a pipe whose radius reaches past a bend's centre (part of #13766) (#14640)
* sweep: test that a pipe reaching past a bend's centre is refused (#13766)

A pipe whose radius reaches the centre of a bend in its path folds its wall
through itself on the inside of that bend. The test sweeps pipes along an
ellipse with semi-axes 2 and 4 (tightest bend radius 1) and a circle of
radius 2, and expects radii 1% or more past the bend refused as InvalidInput
and radii 1% within it built as manifold solids.

On main 3e2cc277e it fails at radius 1.01: create_pipe_sweep builds the pipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* sweep: refuse a pipe whose radius reaches past a bend's centre (#13766)

create_pipe_sweep checked only that the radius is above zero, as upstream
does (SmApiBrep.cpp:1385). Where the path bends with a radius smaller than
the pipe's, the circles of neighbouring sections cross on the inside of the
bend and the swept wall folds through itself; the pipe surface is singular
wherever the radius reaches 1/kappa of the path (Maekawa, Patrikalakis,
Sakkalis and Yu, "Analysis and applications of pipe surfaces", CAGD 15(5),
1998). The panic fuzz's face_ops case 3447330831849305406 built such a
pipe (radius 5.05 along an ellipse whose tightest bend is 1.62), and its
silhouette ran past the hang limit.

path_bends_within measures the path's curvature at 16 samples per knot span,
both span ends included, and create_pipe_sweep refuses the pipe as
InvalidInput when a sample's bend radius is at most the pipe's. A refusal is
proved by the sample; a bend between two samples is missed and that pipe is
built as before. The upstream defect is recorded as WR-774.

general_path_sweep's ledger test swept its 0.75 pipe along the balance
wire's points fitted closed, which bends with radius 0.041 near its start
and 0.045 near its end. Fitted open, as the wire runs, the spline still
bends with radius 0.564 near its far end, so that case's pipe is now 0.5.
Its walls are bare B-spline faces as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: austin62jake <340374338+austin62jake@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:16:19 +00:00
yoyomaimai 595bc8069c Update zh-TW.json (#14641)
I've updated it:
"Counterbore Ø":
"Ø " was mistakenly typed as "O" by me.
2026-11-10 16:08:35 +00:00
PapaEcho 44fe6a0f24 Navigation: zoom horizontally with Maya Alt-right drag (#10973) (#10992)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 16:03:43 +00:00
dudedagger42 12a9a7f0f9 Preferences: turn the control channel on and off at once, with a port (#5736) (#13981)
* Preferences: turn the control channel on and off at once, with a port (#5736)

"Let AI agents connect" moves to Preferences > Assistant > Agents through
MCP and gets a Port field (default 27878, as before). Turning it on or
off, or changing the port, now takes effect without a restart: the
listener closes with its connections, token file and discovery file, and
opens again where the setting asks. A port another program holds shows a
message under the field. --control / SOLIDCRAFT_CONTROL_PORT still win for
the run; the setting then waits for the next launch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Preferences: "Let AI agents connect" is off by default

A new install no longer opens the control channel at launch: the switch
in Preferences > Assistant > Agents through MCP starts off, and turning it
on opens the channel at once, on its port. Preferences saved with it on
keep it on; --control and SOLIDCRAFT_CONTROL_PORT still open it for a run.
The docs and tests follow the new default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: dudedagger42 <dudedagger42@users.noreply.github.com>
2026-11-10 15:59:46 +00:00
bherbruck 3749c14ad1 sweep: a loft guided by rails, its guided edges certified within the caller's tolerance (tangency-labs/solidcore#3140) (#14204)
Rebased onto main after tangency-labs/solidcraft#13688 merged: its own change from 13688's last head (bdcebb49), three-way per file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:36:50 +00:00
rugbymauri 9c4970d2b2 Sketch: constraint glyphs can be made larger and their hover label stays clear of the cursor (#10794) (#11032)
* claim: #10794

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

* Sketch: constraint glyphs can be drawn larger, and their label stays clear of the cursor

Constraint glyphs are a fixed 15-pixel badge with a small letter or
icon, so zooming never made them easier to read, and the label that
names a hovered glyph sat 12 px below and right of the pointer, where
the cursor arrow covers it.

Preferences > Sketch gets "Constraint glyph size" (constraint_glyph_scale,
100% to 300%): badge, letter, icon, spacing and the hover reach grow
together. The default of 100% is the size they always had. The hover
label now goes above the glyph and the pointer, or to their left near
the top of the view, and only below them past the cursor's reach when
neither fits.

Fixes #10794

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

---------

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
2026-11-10 15:36:10 +00:00
bherbruck 8d13350c30 issue_3093: require the defeated body's volume to be proved positive (#14623)
volume_of() accepted Positive, Negative and Undecided enclosures alike, so a sign failure would pass. positive() panics unless soundness proves the volume Positive; the overlap and containment asserts are unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:20:55 +00:00
bherbruck 995b80a78f sweep: a cornered sweep built piece by piece, meeting at its corners' mitres (#3191) (#14621)
sweep::cornered::cornered_sweep sweeps a closed planar profile along a path
with corners. Each piece is swept on its own (lines as degree-1 skins between
shared sections, arcs by the rotational sweep) and sewn as sweep::segments
sews; a corner's mitre section is asked once and shared by the runs it joins.
Twist, rails, helices, an arc with an end scale or ending at a corner, and a
closed path with an end scale or closing at a corner are refused by name.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:20:52 +00:00
ancient_astronaut_theorist 7d271b3252 Move: Ctrl/Shift+click adds more bodies after Move has gone on to From, Point or Axis (#14205) (#14218)
* claim: #14205

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gr84VuQWHKtTwJ7cC3CP3W

* Move: Ctrl/Shift+click adds bodies after the dialog goes on (#14205)

In Point to Point, Point to Position and Rotate, a body pick moves the
dialog on to From, Point or Axis (#6170), so each further body needed a
click back into Bodies. A Ctrl or Shift click on a body now adds it to
Bodies (or takes it out if picked already), as Ctrl/Shift+click adds to
the selection in the view, and the dialog stays on the input it was on.
Plain clicks behave as before.

Fixes #14205

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gr84VuQWHKtTwJ7cC3CP3W

* Move: add-only Shift keeps a picked body; Bodies hold while OK computes

Review follow-up for #14205. With Shift adding only (Preferences), a
Shift click on a body Move has picked already now keeps it in Bodies;
Ctrl still takes it out. While OK computes, a Ctrl or Shift click leaves
Bodies as it is, as dialog_pick holds the other inputs. The test setup
moves to a helper shared by the three tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gr84VuQWHKtTwJ7cC3CP3W

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:19:06 +00:00
rugbymauri a3dcc9ca55 Agent chat: Ctrl+A selects the whole conversation, not one Markdown block (#10676) (#11033)
* claim: #10676

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

* Agent chat: Ctrl+A in the transcript selects the whole conversation

Each Markdown block of a reply is a label of its own, and egui's label
selection cannot be set from code, so Ctrl+A only selected the block the
selection was in. While the chat owns the keyboard and no text box has
focus, Ctrl+A (Cmd+A) now selects every prompt and answer of the retained
conversation: their text is drawn over the selection colour, and Copy
puts them on the clipboard in order, as they read, each under who wrote
it. Thoughts, tool cards, plans, notices and the composer are left out.
Esc or a click ends it; a focused composer keeps its own Select All.
Docked, floating and popped out.

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

* Agent chat: outline the select-all highlight so it shows on a prompt bubble

The selection fill is the same colour as the user bubble, so in the dark
theme a selected prompt looked unselected. Each highlighted block now also
gets a 1 px outline in the selection stroke colour.

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

---------

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
2026-11-10 15:16:31 +00:00
jyviko 2874e782fe UI kit: the app bar and built-in themes work under another host's name and tabs (#14612)
* App bar: Home follows the app's name as drawn

Home sat at a fixed 128 pt from the bar's edge, sized for "SolidCraft", so
a host with a longer name drew it under Home. The bar now lays the name
out in the font it is drawn in (semibold at the heading size) and places
Home a 6 pt gap after it, with 128 as the least place.

128 came from SolidCraft's name: it starts at 36 and is 65.1 pt wide in
Plex Sans semibold 14, ending at 101.1; Home's button starts at 108, 6.9
after it. The gap is rounded down to 6 so SolidCraft's bar does not move
(36 + 65.1 + 6 + 20 = 127.1 < 128).

Tests: app_bar::tests::home_follows_a_long_app_name (a long name's text
ends before Home; on the old code it ended at 249 with Home at 108) and
titlebar::tests::home_keeps_its_place_after_solidcrafts_name (SolidCraft's
Home stays 88 pt right of the name's start, as before). No expected
values changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Theme files: built-in themes load under any host's tab table

A theme's `tabs` names tabs of the host's tab table, and reading one that
named a tab the table lacked failed the whole file. The look's built-in
themes key Onyx's per-tab surfaces by SolidCraft's tab names, and one
failed built-in empties the list, so under another host's tab table
every built-in theme but Light and Dark was missing.

Design: the strictness now depends on who wrote the file. Built-ins
(read_builtin) still check every `tabs` entry's surfaces and colours, but
leave out an entry for a tab the host lacks. Files a user imports, saves
or loads from a profile (from_value, parse, set_tabs, resolve_for_tab)
are read exactly as before, so SolidCraft's errors for a misspelt or
extra tab are unchanged and saved themes load as before.

Keying the tints by accent ramp instead would let another host's tabs
pick up Onyx's surfaces, but it changes the theme file format and needs
migration of saved and imported files; this change needs neither. Its
cost: a host whose tab names differ gets no per-tab surfaces from Onyx.

Tests: theme_files::tests::a_builtin_keeps_only_the_hosts_tabs_and_a_
users_file_is_still_refused (old code: "theme tinted: `tabs` has too many
entries") and look's every_builtin_theme_loads_under_a_host_with_other_tabs
(old code: read_builtin failed). The look tests' host tab table changes
from SolidCraft's seven tabs, which only let the built-ins load, to three
tabs it does not have (DRAW, SHAPE, PAINT); install_gives_the_kit_...
asserted 25 built-ins against it and failed (0) on the old code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

---------

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
2026-11-10 15:07:47 +00:00
bherbruck d8113d096c STEP reader: move SolidCraft's reader into solidcore with its history (RFC 0003, 1.5) (#13979)
* Move geom's pcurve, label and check into solidcore::eval (pure git mv)

crates/geom/src/brep/{pcurve,pcurve_tests,label,check}.rs move unchanged to
solidcore/crates/solidcore/src/eval/. The next commits retype them to the kernel's evaluation
types and switch their callers; this commit is the move alone so their history follows them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval: pcurve, label and check on the kernel's evaluation types

The moved files take eval::geometry's Curve, Curve2, Surface and Frame (the record's kinds,
field for field) and the kernel's evaluator, in place of the record's types and
solidcraft-geom's evaluator. What reads a record as a record leaves: the structural checks
(counts, budgets, a use's interval in its curve's natural range), the edge and face readers
(edge_curve_interval, form_turns on a Face) and the trim request types go to solidcore-ops,
which converts. Results are unchanged: the pcurve keeps its own pole test (the evaluator's
speed rule), knot span search and B-spline cut, not the kernel's collapse; the 80 eval tests
pass, the pcurve suite among them.

Lint-driven rewrites that keep each result: checked indexing, no pre-reserving from input counts,
the loop rotation without a remainder, a clamp that cannot panic on a reversed domain. The
hostile-record cases that depend on the record's checks are kept as no-panic checks here and as
refusals in ops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-ops: pcurve, label and record_check over the record

The record's side of the moved kernel routines: each checks the record's structure as the
record's validation does (one budget per face, a use's interval in its curve's natural range, a
given pcurve as a 2D B-spline), converts through solidcore-convert, calls solidcore::eval and
converts back. The trim request types (TrimFace, TrimEdge, TrimUse, Trims) hold records, so they
live here. No arithmetic: ops' float-arithmetic and geometry-method lints pass unchanged.

The hostile-record refusals the record checks give (empty and non-finite intervals, a NaN
coordinate, a circle of no radius) are tested here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Call pcurve, label and the record checks through solidcore-ops

geom, kernel, smlib and step call solidcore_ops::{pcurve, label, record_check} where they called
solidcraft_geom::brep::{pcurve, label, check}, which moved into solidcore::eval. One
implementation of each remains, in the kernel; geom's brep module no longer declares them.
solidcore-ops becomes a workspace dependency of the four crates (the seam check's public list
already allows it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move geom's record agreement check into solidcore::eval (pure git mv)

crates/geom/src/brep/geometry.rs moves unchanged to solidcore/crates/solidcore/src/eval/agreement.rs
(the kernel's eval already has a geometry module). The next commit retypes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore::eval::agreement on a plain view; ops reads a record into it

The moved check reads a record through agreement::View (edges, vertices, faces and their uses,
in the kernel's evaluation types) in place of the record's Brep, which the kernel never sees.
solidcore-ops' record_check::agreement converts a record's curves, surfaces and pcurves into the
view and calls it; Mismatch, Problem and Record keep their wording. The pole test is the
pcurve's speed rule, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Check record agreement through solidcore-ops

kernel, smlib, step and geom's tests call solidcore_ops::record_check::agreement where they
called solidcraft_geom::brep::geometry::check, which moved into solidcore::eval::agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Leave kernel/src/tess on geom's pcurve path until the tess move

crates/kernel/src/tess is moving into solidcore-tess in its own pull request, so its three
pcurve::eval call sites are not edited here: geom::brep::pcurve re-exports
solidcore_ops::pcurve::eval for them, and goes when the tess move switches them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore/bench/step: the STEP reader bake-off harness

fetch.sh builds the corpus at run time from pinned sources (SolidCraft's STEP tests,
dan335/step-conformance, solidcore's fixtures, cadmpeg's fixtures, the NIST PMI and STEP Tools
sets through their SHA-256 pinned fetch scripts), folded by SHA-256; nothing downloaded is
committed. run.py runs readers in the solidcraft-cli eval shape with a timeout and writes
per-file.tsv and summary.md: opened, refused, timed out, all bodies closed, reference volumes
within 0.1% (references.tsv, from formulas), and wall time.

On main cc55f59bf2: 319 files, 195 opened, 135 with every body closed, 23 of 24 reference
volumes, median 0.20 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move SolidCraft's STEP reader into solidcore (pure git mv)

crates/step moves unchanged to solidcore/crates/solidcore-step, and its Part 21 parser to
solidcore-record/src/step/p21.rs, where it takes the place of record's earlier port of this same
file (from a5b71ca2). This commit is the move alone, so the files keep their history and
authors; the next commits make them build in their new places and switch SolidCraft to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-record: the Part 21 parser keeps record's hardening

The moved parser takes back what record's port added in review (#2591): typed errors with the
same messages, entities in id order (BTreeMap), capped parameter and record counts, linear-time
decoding of unterminated escapes, a byte order mark skipped. The file's content is record's as
before the move; its history now runs through SolidCraft's parser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: the moved reader as a solidcore workspace crate

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: evaluate and form records through the kernel

The moved reader called solidcraft-geom's record evaluator, exact forms and vector helpers. It
now calls the kernel's: solidcore::eval's CurveEval, SurfaceEval, face_flux and form, through a
private `kernel` module that converts records with solidcore-convert, and the kernel's vector
measures on the record's Vec3 (`vec`). geom's form was a copy of the kernel's, function for
function; the face box (`extent`) is the kernel's with poles taken exactly. The B-spline cut is
the kernel's (eval::pcurve::segment), the pole test the pcurve's speed rule, both made public
for this. Profiling spans, which were SolidCraft's, are left out.

The crate keeps SolidCraft's formatting (its own rustfmt.toml) and lints under solidcore's hard
rules: no unsafe, unwrap, expect, panic or unchecked indexing (the 33 indexing sites are
rewritten with iterators and checked access, results unchanged). The step-conformance test reads
SolidCraft's tests/step-conformance where the tree has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* SolidCraft reads and writes STEP through solidcore-step

crates/kernel's STEP import (step_in), STEP export (step_out) and IGES export (iges_out) call
solidcore_step where they called solidcraft_step; crates/step is gone. The Part 21 parse error is
the record's typed error, shown with the same message. solidcore-step joins the crates
SolidCraft may use directly (xtask/solidcore-public.txt) until its build is kernel primitives
under an ops recipe (RFC 0003, 1.6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore-step: bound faces with the pcurves' pole test (form::extent_by)

The bake-off showed the reader on the kernel's form::extent refusing 7 STEP Tools parts
(304-310 boxy_with_*: "loop encloses no (u, v) area") and reading the large parts 2-8x slower
(rear 37.8 s against 18.4 s): extent's exact collapse test classifies the boundary points
differently from the speed rule the reader's faces were always bounded with, and costs a
collapse search per point (the cost in #13655). extent's body now takes the pole test
(form::extent_by; extent keeps the exact one), and the reader passes the pcurves' speed rule.
On those files the result and time are base's again: boxy_with_cylindricity 174839.178,
nist_ftc_06 3323556.516, rear 14.0 s against 16.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Kernel rig: drop the gone crates/step paths

crates/step moved to solidcore/crates/solidcore-step, which the shared core (PATHS-ALL:
solidcore/**) already covers: the import and crash areas' PATHS and kernel-rig.yml drop it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Cargo.lock: solidcraft-step is now solidcore-step

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* io: the model cache key no longer names crates/step

The reader moved to solidcore/crates/solidcore-step, which the cache already keys as part of the solidcore tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: a whole turn a rounding short of a quarter line has its form from it (#12760)

Port of #13535's fix in crates/geom's form to the kernel's form, which the STEP reader now uses: a cylinder, cone, sphere or torus face of one whole turn whose seam reads back a rounding short of a quarter line started its form a quarter early, and a tube read back through STEP measured 14 % over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* pcurve docs: a pcurve without a closed form is refused, not fitted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* bench/step: a malformed --reader is an error; a reader's bad JSON is a refusal, not a crash

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 15:07:44 +00:00
bherbruck 023b55277f Booleans skip the curve intersection of straight edges whose boxes are apart: same results, joins of prisms about 1.5× faster (#14329) (#14585)
* solidcore: a boolean skips curve intersections of proto edges whose boxes are apart (#14329)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: a boolean skips curve intersections of proto edges whose boxes are apart (#14329)

A boolean splits its proto edges where they cross by intersecting every pair
of them. Two lines go to IntersectWithLine, whose first test answers "no
solution" when the segments' boxes (one grown by the tolerance) are apart.
That test now runs before the intersection's setup, through the same helper,
so the pairs it rules out cost a box test instead of an intersection. With
two coincident outlines of thousands of lines nearly every pair is such a
pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* solidcore: clippy for the proto edge box test, and the counts it saves in its test (#14329)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:59:48 +00:00
0rdnungsamt 3e2cc277ee About: the licences under Licences are indented so they read as its contents (#14442)
* claim: #14388 (indent the licences under Licences in About)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* About: indent the licences under Licences so they read as its contents

NOTICE, MIT, Apache 2.0 and Third-party licences sat at the same indent as
Licences, so after opening it they looked like more sections beside it.
They are now indented by the theme's 14 pt spacing, as the Model
Parameters groups are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:48:01 +00:00
PapaEcho 5f46248771 Construct: group tools by planes, axes and points (#10149) (#10236)
* claim: #10149

* fix: group Construct tools by entity type (#10149)

* fix: make Construct menu grouping opt-in
2026-11-10 14:45:36 +00:00
SS-EN 176ba5464f Engine: selection.get reads the selection, resolved (read-only) (#3760)
An agent driving the app through MCP asked for selection.get and got
"unknown command": the selection was only reachable inside the large
document.inspect output (raw) or the UI-only ui.selection control method.

selection.get returns {count, items}: each item as select.set takes it
(so it can be fed back), with kind and, unless detail: false, what it
resolves to: faces' persistent name, surface (plane normal / cylinder
axis+radius / cone / sphere / torus) and area; edges' persistent name,
curve (line/circle/arc), length, ends and centre/radius; bodies' volume,
creating feature and visibility; component and occurrence path in an
assembly; sketch entities' sketch and entity kind. It changes nothing
(no revision bump, no undo step) and the agent chat gate classes it as
read-only. Documented in docs/control-protocol.md; tests sit with the
other selection commands' in cmd/edit_tests.rs.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:38:08 +00:00
Tyler Ward 1ab3a5b179 Preferences: an Export file name template names the file each export offers (#14293) (#14294)
* Preferences: an Export file name template, with {design} and {body}, names the file each export offers

Preferences › Design has a new Export section with an Export file name field.
File › Export (STEP, OBJ, URDF) and Save As Mesh (STL, 3MF) offer the name
it makes: {design} is the design's name and {body} the exported body's (the
first one when an export holds several). Characters file names cannot hold
become `_`. Left empty, as it is by default, each export offers the name it
did before. Scripts set it with `ui.prefs {"export_name": ...}`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export file name: Design Properties are placeholders, and the help lists every placeholder

{project}, {part_number}, {revision}, {author}, {organization}, {description}
and {license} take the design's properties, from the same key list the Design
Properties window uses; a property that is not set is left out. Placeholders
are filled in one pass, so a name holding braces is kept as it is. The help
next to Export file name lists every placeholder with its label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export file name: a body's right-click Export… offers the name the template makes

The Export… item in a body's right-click menu built its own name from the
body alone. Every export of a design or its bodies now takes its name from
one place (`export_name::offered`): File › Export, Save As Mesh and the
body's Export…. The export test covers the right-click item too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export file name: a long name fits the file name byte limit, and a Windows device name gets a `_` in front

A template of wide characters (emoji, CJK) could stay under the 200-character
cap but pass the 255-byte file name limit of ext4 and APFS once the extension
was added. The name is now also cut at 240 bytes, between whole characters.
A name that Windows keeps for a device (CON, PRN, AUX, NUL, COM1-9, LPT1-9,
in any case, with any extension) can't be saved there, so it gets a `_` in
front. An empty template still offers the old name as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:23:34 +00:00
ChrisNo 2b26c1729e Kernel: all farthest pairs of two identical ellipse arcs are found (#13964)
* fix: certify finite All maxima for identical open ellipse arcs

Adds projected_pair_ellipse, a finite All constructor for identical
native open ellipse arcs, wired from the p9 projected dispatch. Lead
case gen0472: main returns 5.010571561172592 where 6.327472493603755 is
attainable.

Uses these #3077 items: projected_pair::{bounded_domain, dot,
norm_squared, project, square, sub, Candidate, Cell, Definition, Piece,
Query} and projected_pair_all::accumulate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: bless gen0472 identical ellipse All maximum

curve.curve_p9 gen0472: main returns two answers at 5.0105715611725925;
the finite ellipse construction returns the attainable 6.3274724936037545
at native parameters (1, 0.38120962513757384) and its swap. It is the only
changed record against #3077's expected files; 282 other units pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: ChrisNourse <16234527+ChrisNourse@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:11:22 +00:00
Brett Lawson 99270af8d4 solidcore: the G^n certificate bounds the feet over wide pieces with Taylor models (#14405) (#14535)
* solidcore: claim the G^n certificate's feet enclosures with Taylor models (#14405)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: the G^n certificate bounds the feet over wide pieces with Taylor models (#14405)

The interval enclosure of the feet over a piece (gn_enclose_over) takes the
feet's box, the faces' partials and the leader as independent ranges, so on
rational faces its top Taylor coefficient, which the Hermite remainder carries,
is 1e3 to 1e10 times its true range. feet_tm::gn_enclose_tm encloses the same
feet as Taylor models in s over the piece: a tube about the middle's Taylor
polynomial proved by Krawczyk's operator for every s (and holding the middle's
root, so it is the same branch), then the coefficients order by order with a
defect bound, all in outward-rounded intervals.

Each piece's fourth terms are the tighter of the interval and Taylor-model
terms, and the arc's rows are taken from the met series. The fork's interval
terms keep steering the levels, so a verdict only goes from reject to accept.
The models are taken only where they can bring a level to the target: for a
piece the interval enclosure does not prove (once the level's other pieces are
in) and for a level still over the target after the arc's rows, and neither
where a rigorous floor of the level's bound (least values at the pieces'
middles, and each piece's terms without its remainder) is over the target.
Not on spans whose equal-area thumbweight varies: their rows' interval terms
keep those levels over the target either way (2.7x slower with them).

Tests: the models hold every one of 127260 sampled coefficients on 24 random
curved-face pieces (plane against rational cylinder or sphere, fixed seed),
where the interval enclosure fails on 17 and is a median 9.5e9 times wider
elsewhere, and the met terms are never above the interval ones. Fewer spans
moved four pins, each checked against its definition or exact surface by
dense sampling (round on a round 30 -> 29 spans; the wedge round 164 -> 113
inner knots; the B-spline round's volume within area x bound of the exact
torus; wr697's volumes within their nets' bounds).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:10:09 +00:00
Rec0iL 4647e30acf Agent chat: Pick context takes History and Browser steps into Features and lists its picks (#11318) (#11383)
* Agent chat: hovering a chip lights its target; chips of things that are gone are struck through (#2286)

The chip under the pointer (in the tray or on a sent message) lights what it
stands for in the model while the pointer is on it. A chip whose body,
feature, face or edge has left the design is struck through with a note on
hover; faces and edges are told apart by their persistent names, which
survive edits (the block for the agent now says so). Worked out when the
design or the chips change, not every frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a pick is a pill in the message, where the caret was (#2286)

Pick context (and typing @) now puts the pick into the message as a pill, `«1: Plate · 3 faces»`,
at the caret, instead of a tray above the box. Several picks are several pills, so "make A match B"
says which is which. A pill is text in the box (so editing, selection, paste and input methods are
the text field's own), drawn as a pill by the field's layouter; Backspace/Delete next to it takes it
whole; hovering it lights its target; one whose target has gone is struck through. When the message
is sent the marks are numbered 1, 2, 3 in reading order and the agent gets each numbered group after
the message; Attach selection stays an end-of-message block, listed apart. Queued messages that go
as one prompt keep their numbers apart.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: hovering a pill in a sent message lights its group; chips only for what is not a pill (#2286)

The pills in a sent message light what they stand for while the pointer is on them, as the chips
below did; those chips are now shown only for the items that are not in a pill (Attach selection).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat control: send_input sends the message box as Enter does; the status shows the box (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a pill or chip lights its face by persistent name, not by the number it had (#2286)

After an edit renumbers the faces, the stored face number points at another face: hovering a sent
pill lit the wrong one. The target is now looked up by its persistent name (what has gone lights
nothing), in the box, in sent messages and for the chips.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: review fixes for the pills (#2286)

- The lit target is cached while the pointer rests on a pill; edge names are only worked out for
  edges; sent messages without pills no longer copy their context every frame.
- A sent pill lights only where the pointer really is (clip rect and layers respected).
- Editing a queued message renumbers its marks and un-places the groups whose mark was taken out.
- New chat keeps the draft's picks; queued messages get their own handles and chips light too.
- Empty persistent names are ignored; docs and a doc link fixed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: the control status adds the box and its pills to main's second step (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: replacing the design takes the pills out of the box (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a model that cannot be placed counts as there, now that world_state can fail (#2286)

Main made Session::world_state return a Result. The checks that decide whether a picked
body, face or edge has left the design now treat a model that cannot be placed as unable to
tell: the pill is not struck through and its picks are kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a test builds its face point with solidcore_record's Vec3, as main now does (#2286)

Main moved the point type of a face pick out of solidcraft_engine::geom. The test that
lights a chip's face by persistent name now builds its points the way main's own tests do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: what a pill or chip lights is kept only for the very same items (#2286)

The cache of what hovering lights was keyed by the items' text and persistent names, not by
what they stand for. Two items that read the same, such as two bodies picked under one name,
could then light the other one's geometry. The key now includes the selection itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: taking a pill out of a queued message drops its pick, as in the message box (#2286)

Editing a queued message and deleting one of its pills used to keep that pill's pick as an
unplaced chip, which the queued message cannot remove and which was still sent to the agent.
The pick is now dropped, as when a pill is deleted in the message box. What Attach selection
added was never placed in the text and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a pick that was also attached stays when its pill is taken out of a queued message (#2286)

A thing picked as a pill and also selected with Attach selection on is one item, under its pill.
That item is now marked as attached too, so taking its pill out of a queued message keeps it,
once, as not placed, instead of dropping what Attach selection added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a face picked as a pill and selected at another point is listed once (#2286)

Telling whether a selected thing is already a pill compared the pick point too, so the same
face clicked at two points was listed under its pill and again as not placed. Faces and edges
now match by body and index, as the selection does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a message with pills stays in a selection scrolled out of view, as main's messages do (#2286)

Main draws the conversation's messages through its selectable label, so a message scrolled out
of view keeps its part of a text selection and of Copy (#11527). A message's text with pills was
drawn as a plain label; it now goes through the same one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: the pill ids use egui 0.37's Id::unique, as main now does (#2286)

Main moved to egui 0.37, where Id::new is a deprecated name for Id::unique. The two ids this
PR adds (the message box and the cache of what a pill lights) now use Id::unique; the ids are
the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat control: the status still lists the picks as `picked`, next to `pills` (#2286)

Before the pills, `ui.agent_chat` listed what was picked as `picked`, a flat list of label and
detail. The status now gives that list again, made from the items of the box's pills, so
scripts that read it keep working; `pills` adds the grouping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: Pick context takes History and Browser steps into Features (#11318)

A step clicked in either History bar or in the Browser's Features folder now
goes into the picker's Features list, and a body clicked in the Browser into
Bodies, whichever list is active; the edit selection is left alone. A second
plain click on a picked step takes it out again, as the model view does. The
Features field's hint names the History and the Browser instead of faces. The
picked items are listed by name under the arrow beside each field, as in every
dialog since #3683. Other dialogs keep their active-input rule; a Browser
feature row now reaches any dialog whose active input takes features (a
pattern's Objects list), as a History row already did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a pill in a sent message takes the theme's chip colour, not a colour literal (#2286)

main allows no colour literals in agent_chat/panel.rs (colour_tokens_tests). The pill inside a
sent message, whose bubble is the accent colour, now uses the theme's filled-chip token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 14:08:57 +00:00
bherbruck b34844c34b Windows resize smoke: wait for the window to follow the drag and to maximize, and try the drag once more (#14606)
The 'Resize border from the first frame' step failed batches with 'dragging the bottom edge down 80 px resizes the window (height +0)' and then 'the window maximizes', for PRs that do not touch the window. The script checked the window half a second after the drag, and after a fixed half second for the maximize, on a loaded GitHub runner where the window handles messages late. It now waits up to 10 s for the window to be where it was put and to follow the drag, tries the drag once more if it did not take, and waits up to 10 s for the maximize.

Changes a default: no

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 14:08:06 +00:00
bherbruck be098f3ac5 Service worker: a page never gets another build's files (#14593)
A page's files come from the build it started. When the page's record was missing, the worker answered with its own build, which after an update is a newer build than the page's, and a page of one build then ran another build's files and never started. Now a page with no remembered build, or whose build's copy is gone, gets a visible 503 telling the user to reload. Pages open when a worker first takes over are remembered as started from the network, and a record is kept for ten minutes for a page not yet listed among the clients. The offline test checks that the open page keeps getting its own build after an update and that a lost record fails visibly. Fixes #14591.

Changes a default: no

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:44:19 +00:00
Igor Bronovskyi 66b7d77e65 Ukrainian: translate 58 new interface strings (#14594) 2026-11-10 13:31:30 +00:00
cronos 7f00422057 Windows local CI: serialize more tests that open a GPU device (#14588) 2026-11-10 13:26:50 +00:00
Brett Lawson 472bacb16f solidcore: primitive failures carry a typed reason instead of bare statuses (part of #13790) (#14561)
* solidcore: claim typed primitive errors (part of #13790)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: primitive failures carry a typed reason instead of bare statuses (part of #13790)

The primitive API (api_curves, api_curve_ops, api_primitives, api_surface_ops) and
primitive_creation (model, model/merge, p1, p1/boolean, p1/offset_profile,
p2/access, curve_sweeps, planar_path, rotational, skin, taper, taper_walls,
p3/access, construct, geometry, ruled, sweeps) return a PrimitiveFailure under the
new Reason::Primitive instead of a bare Upstream status: Failed (SM_ERR) and
Missing (SM_ERR_NULL_POINTER), each with a phrase saying what failed;
HelixDeviates { deviation, tolerance } (SM_ERR_NOT_WITHIN_TOLERANCE) for
create_helix; AxisInsideFace (SM_ERR_AXIS_INSIDE_FACE, 1025) for a revolution
whose axis runs inside its face. Operation path, entity (none), comparison status
and kind are those of the Upstream each replaces, so sm_status(), kind(),
is_port_failure() and is_status_answer() answer as before; no cause is kept, so
no port failure is newly wrapped. upstream_status() answers for a
PrimitiveFailure as for an Upstream, so geometry's fallback on a 1001 from
compute_crvs_normal behaves as before.

The two SMLib names go: boolean_trees' operation is
primitive::primitive_creation::p2::boolean_trees (was SmMerge::BooleanTrees) and
split_curves_on_axis says "not a B-spline curve". Held: p1/primitives.rs (an open
change edits it) and one site in p3/ruled.rs on the line before another open
change's edit; a ratchet test pins every other converted file at no bare status.

The primitive goldens runners that recorded an Upstream code read
solidcore::error::upstream_status, so every row stays as it was. SolidCraft's
status() passes a PrimitiveFailure on as its status, as it did the Upstream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* goldens: the sweep API runner reads a primitive failure's status as the Upstream it replaced (part of #13790)

sweep.api_brep recorded the Upstream status of the repeated linear and rotational
sweeps (capped with zero repetitions, the axis inside the face); it reads
solidcore::error::upstream_status, so its 9 rows stay as they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: ruled_surface_from_offset's last bare status is typed too (part of #13790)

The out-of-range other generator in ruled_surface_from_offset was held while the
flag retirement that rewrote the next line was open; it has merged, so the site
is a PrimitiveFailure::Failed like the rest and the ratchet holds every converted
primitive file at no bare status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:25:33 +00:00
Jens 6a9318bd73 Assemblies: origin and construction datums as joint sides, on one DatumRef model (#10056) (#10056)
Joint sides can now be an origin datum of any placement - the side's own
component's, the root's, or another component's - resolved at every solve;
the same DatumRef model is what the browser PR (#12466) builds on.
Reworks #10056 in place; its review threads close here, including the
datum-occurrence ambiguity (a side resolves side-locally through its own
occurrence, never "assigned to the root occurrence") and the open
joint.edit re-pick thread.

The model lives in doc, next to ConstructGeom and GeoRef, where reference
identity already lives:

- DatumItem (parse, geom) and DatumRef (key, parse_key) with the strict  browser-key grammar: canonical non-zero decimal occurrence ids, depth  at most 64, length at most 2048; a repeated id in a path is refused  where the path is walked (Document::placement_frame). `c0/origin`,  `o:0/...` and `o:01/...` are refused, and the empty path is never a  datum. The root keeps PlaneRef::Origin, GeoRef::Origin, Plane::named  and Visibility::hidden_origin exactly as they were, so old designs  round-trip byte-compatibly.
- Document::placement_frame, promoted from EmbossFace::component_frame  with the same work limits: the world frame of one exact placement,  walked down its path without expanding every occurrence.
- PlaneRef::Datum and GeoRef::Datum, re-resolved per evaluation and  mapped into the consumer's frame (the sketch's component's, the  construction feature's, the joint side's), so a moved component moves  its sketch planes, construction references and joints with it.
- The one resolution order at the side resolvers (plane_side, axis_side,  and where a bare side sits: side_occurrence, origin_from_name): a  construction feature named exactly first, then a datum key, then the  origin aliases - a construction plane named like a datum key stays  reachable, and a bare side sits on the feature's own component. A bare  string side stays a shorthand (a named origin, an origin alias, or a  feature by name); a datum key is given through the plane/axis form.

Joints:

- Snap::Plane and Snap::Axis carry datums, parsed from a bare item (`XY`  - the side's own component's datum) or a full key (`o:2/origin/XY` -  any placement's datum). A plane datum points z along its normal, an  axis datum along the axis. Re-resolved on every solve, so the joint  follows the component the datum names; a side on a repeated component  reads the exact placement it names, not the component's first one.
- A joint on a plane or axis side starts where its parts are - the same  capture relations and loop-closing joints get - so a planar joint to a  datum, a construction plane or an origin alias keeps the part's  in-plane place instead of jumping to the geometry's origin.
- The datum wave: the spanning tree keeps its FIFO tie-break, and when a  datum snap is present every fixed occurrence but the root is walked to  exhaustion before the root's joints - a chain out of a grounded  occurrence keeps its edges and a datum joint competing for the same  part closes the loop instead of stealing it. Assemblies without datum  snaps solve in exactly the order they did before.
- joint.edit reads a re-picked datum side exactly as joint.create reads  it: the side left out is taken from the joint being edited, the datum  resolves through the same path create uses, and a re-picked side turns  the least it must (0 or pi, whichever mismatches less), as every  edit does. No side is ever re-anchored to where the other side sits: a  datum side without a pick point means the datum's own origin, at  create and at edit alike, so a stored side never depends on the pose  at edit time.
- The Joint and Edit Joint dialogs take the new kinds; the world state  is built per pick kind, so a datum pick never builds it; datum picks  never resolve to sketch curves.
- The schema's strict origin check keeps the command's wording: what  `param_check: Strict` reports for a bad origin names the new kinds  too - "a joint origin needs face, circle, edge, point, plane, axis  or frame [x, y, z], or a face's name" - so strict and off fail the  same bad origin with the same text.
- The typed input schemas the joint commands publish read the new  sides the way the handlers do: joint.create's side type takes a  `plane` or an `axis` (a name or datum key, or a definition object),  joint.origin's parameters gain the two keys, and a call with only a  plane or an axis passes the required-forms check - `param_check:  Strict` admits every origin the handler does, not just the ones the  schema knew first.

Format:

Two new pending files: component-origin-datums.rs (PlaneRef::Datum /
GeoRef::Datum as saved references) and joint-plane-and-axis-snaps.rs
(the Snap kinds). SAVED_REFS gains "datum" and never gains "line".
Older designs get nothing new and round-trip unchanged; a newer design
warns in the last release and keeps what it cannot read.

Changes a default: no. The browser's Origin folders and visibility are
not here - they are PR #12466's rework, built on this model. Nothing
touches crates/kernel, crates/geom or vendor/, so the kernel freeze does
not apply.

Tests: datum_refs_parse_strictly, placement_frame_matches_the_occurrence_walk,
resolve_datum_places_nested_and_repeated (doc);
resolve_plane_and_axis_origins (doc/src/joints.rs);
bare_shorthand_means_the_sides_own_component [PIN],
datum_sides_resolve_in_the_side_component_frame [PIN],
construction_datums_stay_bound_to_their_component,
joint_edit_repicked_datum_side_matches_create,
datum_joints_keep_the_chain_fifo_tiebreak,
root_versus_grounded_joint_keeps_the_pre_change_tree,
joint_sides_take_origin_datums, joint_with_construction_plane_and_axis,
feature_named_like_a_datum_key_stays_reachable (joints_tests.rs);
the_types_read_each_key_as_the_handlers_do [PIN],
strict_keeps_todays_errors (schema);
joint_dialog_picks_origin_plane_and_axis,
edit_joint_preserves_plane_and_axis_sides, joint_sides_refuse_sketch_curves,
measure_still_takes_sketch_curve_picks (dialogs_assembly_tests.rs).

CI fixes folded in (the PR's check run came back red on them):

- schema/joints_tests: `the_remaining_schemas_take_what_the_handlers_read`
  pins MakeJointOriginParams' required-forms `anyOf` at 5; `plane` and
  `axis` make it 7. The datum forms' conformance cases join its table: a
  name or key takes, a number or a bool refuses.
- schema/joints_tests: `the_remaining_types_read_each_key_as_the_handlers_do`
  still expected the pre-datum origin wording; it now reads the handler's
  new message, and the datum forms and their refusals join its tables.
- doc/joints: two plane or axis datums mate ALIGNED. Each side's frame
  points along the geometry's own normal rather than out of a body, so the
  origins mate without the mated flip and each part keeps its side of the
  datum; `flip` asks for the mated relation, as joint.create's line now
  says. A copy jointed to the same external datum as its original lands
  with its own offset instead of mirrored onto the far side, and
  `datum_sides_stay_distinct_across_repeated_components` passes as
  authored. A joint with a face or circle side keeps the mated flip, as
  every joint between body surfaces did.
2026-11-10 13:24:03 +00:00
rugbymauri 21c6faa4e9 Sketch: setting the diameter of a sketch's only circle keeps its centre where it is (#11438) (#11601)
* claim: #11438

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

* Sketch: setting a lone circle's diameter keeps its centre in place

The Dimension tool asks for the first length dimension of a sketch to
scale the whole sketch about its origin (#1365), so a shape drawn by eye
keeps its proportions. A sketch whose only curve is a circle qualified
too. A diameter or radius cannot distort a circle, so the scaling only
moved the circle's centre toward the origin by the same factor as the
radius.

scaled_for_first_dimension now takes the new dimension and leaves a
sketch whose only curve is a circle alone when that dimension is a
radius or diameter: it changes the radius and the centre stays where it
was drawn. Any other first dimension on a lone circle, such as a
distance from the origin to its centre, and sketches with more curves
scale as before.

Fixes #11438

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

---------

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
2026-11-10 13:23:48 +00:00
Karl Von Richter a7fc90bd70 Kernel: a circular round's section is the ball's exact circle by default; retire the arc flags (moved from solidcore#2893) (#13946)
* test: the default kernel's round sections are the ball's exact circle (failing, #2330)

A variable round (the box 20 x 30 x 20, its edge y = 30, z = 20 rounded by the linear law 1
to 5) stays a B-spline on every kernel, and its end sections are stations of its skin: in
the end plane, the quarter circle tangent to both faces. On the default kernel today they are
2.34e-4 off that circle (the approximated arcs); only `fillet_exact_arc_sections` (WR-708)
makes them the exact circle. This fails until that is the default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend: a circular round's section is the ball's exact circle; the arc flags are retired (WR-708, WR-711, #2330)

A kernel built with the default fixes now builds every circular round's sections as the
ball's exact rational circle, all of one arc count, as SolidCraft's set already did.
`UpstreamFixes::fillet_exact_arc_sections` (WR-708) and `fillet_exact_arc_spans` (WR-711)
are removed with no way back to the approximated arcs: the executive's and
`MakeConstantRadiusFillet`'s circular generators take the exact circle, and the standard
solver's one arc count (`ArcCounts`) and point sections apply to every exact circle. An
explicit request for approximated arcs (the cross-section type 1 of the API options) still
gets them.

Tests that set the flags drop the setting; those that compared them on and off keep the on
half. Values that held only for the approximated arcs move:
- fork ea59e9c's great-circle mark (no G^n section): 0.0168 off the cone and 11955.6489,
  the 0.0023 more material the exact circles keep on the cone too (0.0166, 11955.6466);
- the great circles' removed volume: 44.351 (44.353);
- the progressive cubic on the G^n kernel takes the spans that follow its law
  (`fillet_variable_span_follows_fillet`): without them its exact circles are 5.0e-4 off
  its balls between stations and its volume 1.2e-7 over the envelope's;
- the folded law without the G^n section is no longer built folded: its sheet reaches every
  face of the body and the crease trim refuses it, untyped (the G^n section refuses it as a
  fold, naming the radius);
- the progressive spline round on every fix is graded against its balls' envelope (3.1e-8)
  rather than fork 5e8c9c1's mixed arc counts.
The fork 5e8c9c1 values of the linear round on its cone and the five cliff overflows still
hold, to 1e-9 and 1e-12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* blend tests: the values the exact circles move, re-derived (WR-708, #2330)

The full suite on the default kernel's exact circles moves five tests beyond those in the
retirement commit; each is graded again, not loosened:
- wr669's traced rounds (without the exact conic classes) were told from the exact sweep by
  being non-rational; a skin of exact circles is rational too. They are now told by their
  distance off the ball's spine: 2.6e-5 and 2.1e-5, where the exact sweep is on it to 1e-12.
  The pole and cone's spine and volume are lifted into `pole_and_cone_round`, as the peg's
  are in `plate_and_peg_round`.
- wr609's great-circle variable round (2 to 10) is 5822.595815 with and without the flag
  (5822.58649 with upstream's approximated arcs).
- 1207 step 4 keeps the fork's topology and a clean check; its volume is 49712.42816838713,
  8.1e-5 over fork 68fb9162's, whose rounds were approximated arcs (the fork's own are exact
  circles from 523bc25 on).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style: cargo fmt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* records: WR-708 and WR-711 addenda for the retired arc flags (#2330)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* smlib: drop the retired arc flags from SolidCraft's preset

UpstreamFixes no longer has fillet_exact_arc_sections or
fillet_exact_arc_spans: exact circular sections are the kernel's
default, so the preset stops setting them (it did not build: E0609).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: #2704's round removes the union of its balls, 22.594877

The expected volume was the approximated arcs' 22.596105, 1.2e-3 more
than the round the law defines. Integrating the envelope of the balls
slice by slice (radius 4 to 0 along the 20 mm edge, Gauss-Legendre in
both directions, converged to 1e-12) gives 22.5948765; the exact
circles take 22.594863, within 1.4e-5 of it. The tolerance stays 1e-4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* tests: grade the exact circles on #13945's union of balls (#2330)

Rebased onto #13945, which makes the variable round the union of its balls on
every kernel, three tests still described upstream's approximated arcs:

- wr708's evidence test looked for end sections in the end planes; the end
  sections are now the touch circles, square to the centre line. It measures
  each end section off the circle through its ends and middle: here 1.36e-11,
  as main 52ea418 gives with `fillet_exact_arc_sections`; main's default
  kernel (the polynomial arcs) 3.26e-4.
- wr631's variable cliff overflows were pinned to the fork's d01d7b0, the
  approximated arcs. They are graded instead against the box less the balls'
  cone in closed form (Gauss-Legendre per slice; 5 and 10 panels agree to
  1e-9; 2 -> 11 is CLIFF_2_11_VOLUME within its 1e-5), at the same 1e-7: the
  builds are within 3.3e-8. The fork's 5e8c9c1 (every fix) is 1.2e-7 off the
  2 -> 50 build of this test's kernel, so it is not the reference.
- wr609's comment: both skins within 1.6e-5 of the removed volume and 2.1e-8
  apart (the arcs: 5.5e-5, 1.5e-4). The assertion is main's, unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* records: the WR-708 and WR-711 addenda on #13945's union of balls

#13945 retired the G^n section's flag, so the addenda's no-G^n cases (the
great-circle mark, the folded law built folded) are gone from the tests.
The addenda name the values this PR moves on that main instead, and the
evidence test's measurement: the end sections are the balls' touch circles,
3.26e-4 off a circle on main's default kernel and 1.36e-11 here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* goldens: bless blend.fillet_executive_p3 on the exact circles (#2330)

Blessed on Ubuntu 24.04 (CI's glibc) on main 10c8fb66c1, after #14228
(a failed fillet leaves the body as it was). 46 of 798 cases move; every
other unit passes.

- 43 builds whose values move by 1e-8 to 2e-6 relative volume: the
  approximated arcs were up to 2.34e-4 of the radius off the ball's
  circle. sweep5-nurb_box1-all-r0.5 rounds every edge of the box and
  moves +1.2e-4.
- issue-2349-teardrop-corner_edges-r0.5: the corner edges' samples, on
  the exact circle.
- stubs4-coons_01_03_29-e0-r0.5 builds (1001 before): 8 vertices, 12
  edges, 5 faces, check_brep clean.
- sweep4-native-crash-sphere_diff_3cylinders-e30-r0.1 is refused with
  1006 from intersect::curve_class::p6 instead of 1001 from
  session::finish. Both leave the body as it was (25/39/8, the same
  volume); that input already fails ValidatePointers.

Lines that agree with main within 1e-9 keep main's text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:14:16 +00:00
bherbruck f2207de0a0 Web offline test: start the other tab's update only after this launch has begun (#14592)
The 'update in another tab' step started the update on the first build.json check the server saw after the step began. On a loaded machine another tab's own check could be that one, so the new worker took over before the launch had loaded its files and the launch never started the expected build (launch 13 timed out after 240 s). The updater now counts only checks made after the launch's navigation is issued.

Changes a default: no

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:05:57 +00:00
ChrisNo ddacb344b4 Kernel: projected point/face maxima are measured on the face's own surface (#13729) (#13965)
* refactor: native affine definitions enclose equal-weight spline points

The point/face maximum needs enclosures of native edge points beyond
analytic Lines: equal-weight degree-1 spline points, and an exact sign
for a sum of four products, used to prove a trim is an exact rectangle.

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: projected point/face maxima return the face's true maximum

A single projected point/face maximum measured a fitted 3D silhouette, so
it could miss the face's maximum or report none (#13729). It now
evaluates trimmed UV silhouettes on the source surface as proposals with
native knot-cell seeds, and returns a candidate only when an
outward-rounded bound over the whole face domain fits the candidate's own
enclosure. An unresolved bound refuses and restores the solver state.

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: share the exact expansion arithmetic for trim corner products

Move the local operation's private error-free expansion module (`mod exact`
in topology/brep/local_operation.rs: two_sum, grow, add, sub, product with
its LEAST_EXACT_PRODUCT range, scale, cross, dot, det3, is_zero and their
tests) unchanged into the crate-internal geom::expansion; the local
operation imports it as `exact`, with no behaviour change.

Delete native_affine's big-integer helper (dyadic_four_products_zero,
dyadic_products_zero, dyadic_product_order). Its replacement,
exact_four_products_zero, sums the four signed products as an expansion
and answers false whenever a product is out of the proven exact range
(overflow, a subnormal or non-finite factor, or a product that could
underflow), so such a trim is not shown rectangular and is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: projected residual bounds use the shared interval type

projected_residual.rs had its own interval arithmetic (next_up, finite,
outward, add, sub, mul, div_positive). Those are now one-ulp operations on
Ivl itself (is_finite, outward_ulp, add_ulp, sub_ulp, mul_ulp, div_ulp),
documented with their soundness note, and the private copies are deleted.
Ivl's own + - * / were tried first, but their relative 2.3e-16|x| step and
1e-300 widening of exact zeros keep three exactly attained certificates
from closing (the N = 0 projection, the planar face maximum and the seven
analytic fixtures), so the tolerances are unchanged and the one-ulp path
is kept on Ivl.

The sub shortcut [x,x] - [x,x] = 0 now lives in Ivl::sub_ulp: a point
interval holds only the exact double x, and IEEE x - x is exactly 0. The
lerp shortcut a == b => a stays, now only for a fraction inside [0, 1]:
a convex combination of two values in one interval lies in that interval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: check the fixture's inaccurate sphere maximum in its own test

The shared face-projection helper asserted, for any Z view with an
expected value in (0.86, 0.87), that 0.8605419808705617 is not certified.
That check now lives in projected_sphere_band_original_maximum_is_not_certified,
on the analytic_face_sphere_band_5_15 case, and the helper returns its
kernel, net and domain for such checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: name the B-rep maximum test for what it checks, and share its setup

projected_brep_maximum_is_certified_against_the_final_candidate_in_either_order
passes with the per-face certification run early, so it does not show the
deferral. It checks two sphere faces in either order and a seam vertex
answer. It is renamed projected_brep_maximum_is_certified_in_either_face_order,
and its B-rep setup moves into brep_projected_maximum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor: certify each projected face maximum when it is found

Point queries over a B-rep or shape deferred each face's whole-face bound
to the query's final candidate. No test reaches a case where that changes
the result: a face's native proposals reach its own maximum, and a better
incumbent from another face already bounds it. Each face is now certified
when the face is solved. If a face's candidate ever fell short, the query
refuses instead of answering. certify_candidate stays as a test-only split
of certify's checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* goldens: bless the 7 vertex/face maxima on the analytic faces

Re-blessed on main 94ce45a1f (after #14327), from a Linux goldens-profile run.
Only intersect.topology_solver_p2 changes, these 7 entry-5 records, and the
values are the ones this branch carried before the restack. Old is main's
value (point (0.2, 0.3), view Z); new is measured on the face's own surface
at its native parameters. Main's answers name the two tree nodes they were
found in; these answers name none, since the whole-face bound finds them.

  cyl_x_5_15, halfcyl_x_5_15: no answer -> 1.063014581273465 (sqrt 1.13)
  cone_x_5_15: no answer -> 1.2039996853283075
  sphere_band_5_15: 0.8605419808705617 (fitted silhouette, below the true
    maximum) -> 0.8605551275463991 (sqrt 0.13 + 0.5)
  sphere_quarter_5_15: no answer -> 0.7615773105863908 (sqrt 0.58)
  torus_x_5_15: 1.5652926944322216 -> 1.565294643796591 (sqrt 1.73 + 0.25)
  torus_half_x_5_15: 1.5652946437965907 -> 1.565294643796591; same point to
    1e-16, now without tree nodes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: ChrisNourse <16234527+ChrisNourse@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:58:31 +00:00
jyviko 312454f899 Look: SolidCraft's icons, glyphs, UI fonts and themes as the shared crate solidcraft-look (follows #14251) (#14578)
* UI kit: an icon set can extend another host's masters with a host's own

IconSet::extended(data, extension) draws another host's IconData (the same
static tables, not a copy) with an IconExtension of the host's own masters,
aliases and default accents, in the data's colour roles and accents. For a
name both have the extension's master, alias or default accent wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Look: SolidCraft's icons, glyphs, UI fonts and built-in themes are the shared crate solidcraft-look

The icon masters and their build step, the code-drawn glyph painters, the UI fonts and the
built-in themes move into crates/look with history. SolidCraft's app installs its look from
the crate, as another app can. The workspace tab table stays the app's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Look: the end-cap icons' attribution rows and the style guide's path follow the move

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Licence: SolidCraft's brand and interface are under LICENSE-BRAND

The UI kit, the look (interface icons, glyphs, built-in themes), the theme's tokens and palettes,
and the SolidCraft name, logo, app icon and brand kit are SolidCraft's brand. They may be used,
changed and contributed to as part of SolidCraft; using them in another program or product needs
the maintainers' written permission. Geometry and the rest of the code stay MIT OR Apache-2.0,
and third-party fonts keep their own licences.

The three crates declare the licence with `license-file`, which `xtask shared` now accepts when
the file sits inside the crate; the generated licence list names it; ATTRIBUTION rows for the
look's artwork and the branding name it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

---------

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:06:00 -05:00
MarkusRe a347568301 Setback scale search: each attempt fills degree 9 first, as the corner's fill does (#13739) (#14092)
* test: the setback scale search's attempts fill as the corner does, degree 9 first

An attempt of the search fills its model with Probe { fill: true }, which
graph_gk tries from degree 3 up to 9, while the corner's own fill tries 9
first and stops where 9 proves the sector conditions unmet (#2344(b)). So
a failing attempt solves five programmes where the fill solves one; on
aarch64 the fork's 20b1c01, which counts as main does there, spent 120,513
of the first corner's 129,085 steps in one degree-7 programme.

The new test asks that a search attempt's work equal the corner's fill's
at the same model, and that a failing attempt solve one programme. The
budget test takes the counts of degree 9 first (22, 26, 21, 30, 3, 2; the
fork's 3843ddb solves as many), checks the step budget on every target
again, and gives the r 5 corner's one attempt room for its degree-9
programme. Both fail on main: 35 programmes for the first corner, 5 for
its attempt at scale 1.

Refs #2929

Co-Authored-By: Claude Code <noreply@anthropic.com>

* fix: the setback scale search fills degree 9 first, as the corner's fill does

graph_gk tried a probe that asks the fill from degree 3 up to 9, the order
of the fork's old fill probe; the corner's own fill tries 9 first, keeps a
certified 9 while it looks for the least degree that certifies, and stops
where 9 proves the sector conditions unmet. The scale search's attempts are
such probes, so each failing attempt also solved every degree below 9: five
programmes where one decides, and on aarch64 one of them, of degree 7, took
120,513 of the first corner's 129,085 steps (the fork's 20b1c01).

Both now take the fill's order (#2344(b), the fork's 3843ddb). The verdict
is the same by degree raising: conditions met at a degree are met at the
next, so unmet at 9 means unmet below; the fold refusal is decided on the
projection, whose sign certificate degree raising keeps too. Scales,
attempts and the corner's fill are unchanged. On x86-64 the first corner's
search solves 22 programmes instead of 35, 6,537 steps instead of 9,347.
An attempt that certifies below 9 solves one programme more: r 5 set back
8 takes 3 instead of 2, 22 steps instead of 4.

Refs #2929

Co-Authored-By: Claude Code <noreply@anthropic.com>

* findings: the setback scale search's degree order, with its schematic

The record of the change before it: why a failing attempt solved five
programmes, why degree 9 first keeps every verdict, the counts before and
after on x86-64, and what stays open (platform-dependent step counts, an
unproven degree 9 still trying 3 to 8). The schematic shows a search
attempt's degrees before and after, its VectorCraft source beside it.

Refs #2929

Co-Authored-By: Claude Code <noreply@anthropic.com>

* blend_setback: the degree order's comments and record say what was measured

The r 5 corner's comment gives its own count (three programmes, 22 steps)
instead of the fork's. Probe::fill's doc names the curved fill's order,
least degree first. The record states the fold refusal one way only: a
fold at 9 is a fold below, but a lower degree's failed sign where 9's holds
would now go on to the programmes, where it refused before; no corner is
known to do so. It also says why the curved fill keeps its own loop.

Refs #2929

Co-Authored-By: Claude Code <noreply@anthropic.com>

* findings: the degree order's counts before are measured on main

All six corners' counts before the change, measured at main a445bdaac
(the same as the validation run they were quoted from).

Refs #2929

Co-Authored-By: Claude Code <noreply@anthropic.com>

* blend_setback: the degree order's comments and record name the moved issues

The issue and design hub moved from tangency-labs/solidcore to solidcraft under new
numbers; the code comments drop the number, the record names the new ones.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* findings: the degree order's record names the loop's errors, the schematic its topic

The record named the fold refusal as the one exit the new order meets
differently; degree 9's errors (programme, certificate, nets off the faces)
end an attempt earlier too, as in the corner's own fill. The step budget's
comment says it rejects the old order on aarch64, and the QP counts on every
platform. The schematic's title names its topic, not the old issue number.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 12:48:16 +00:00
Jackson Oursland b8cb6eecd6 Operations panel: progress and Cancel for long operations in the view (#9460)
Long operations under way show in a panel in the view's bottom-right
corner, above the frame-rate readout: the operation's short name, a
progress bar with the step it is on of how many, and a red X that
cancels it. A new operation goes on top; one that ends fades out and
the rows above it slide down into its place.

The rows are read each frame from the work itself: the file operation
running and those queued behind it, a feature dialog's OK computing,
history commands and a delete's check computing off the window thread
(and those waiting their turn), opening a feature's editor, an agent's
command with its batch step, a save, and an opened design's bodies
being meshed. Work reports progress and learns it was cancelled
through the existing doc::progress::Progress and the kernel's Watch;
the history and delete-check workers now report into one and stop at
their next feature when cancelled. Queued history commands and file
requests carry a serial so each row keeps its key while it waits,
runs and runs again.

The panel replaces the computing toast, the agent's Stop chip and the
"Loading parts" note. Preferences > Interface > "Show operations in
the view" (operations_panel, on) brings those back when off.

The control channel lists and cancels operations with ui.operations.

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 12:31:48 +00:00
Homero Thompson 9b97d8dc8f Project: a nested face name is written in parentheses so it reads one way (#5857) (#11359)
* Doc: a nested name goes inside parentheses, so it is not ambiguous (#5857)

* Names: a non-ASCII curve id does not panic a blend face name

A curve id may hold a character outside ASCII (F2:side:曲), and the name of
a blend face holds the curve id of the edge it replaced
(F5:blend(F2:side:曲|F2:top)). face_name_end walked the name a byte at a time
and sliced the text at each byte, so the slice started inside that character
and panicked; blend_seams calls it for every blend face.

It walks the name by character now, so the byte it returns is always the start
of one, and a name in ASCII is read exactly as before.

The names written into saved designs change: a face name that holds another
face's name writes it in parentheses (F5:blend(F2:side:l2|F2:top)), where
before it followed a colon. The pending format note says so.

* fix: canonicalize legacy names before the piece checks

A name saved in the older form (F5:blend:F2:+x|F2:+z) names the same face as
today's F5:blend(F2:+x|F2:+z), but only the exact check compared the two
forms. The piece, alias, synonym and stem checks compared the text, so a
stored name of a face that was split since found nothing. The name is written
in today's form before those checks.

* Names: read the nested name of the form upstream's test writes

Upstream's #7703 added a test that asserts the offset face of a thickened
surface is named `F3:inner:F2:side:l1` and that its edge walls start with
`F3:blend:`. This branch writes those names in parentheses, so the test
failed on the merge ref and the known-failing check read it as a
regression. The names follow the format this branch writes; the test and
the doc that names them follow the format too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: keep the kernel rig out of a docs change

crates/kernel/src/history.rs is in tests/kernel-cases/PATHS-ALL, so the one-line
doc change (F7:blend:... -> F7:blend(...)) made the plan select every kernel rig
area and the ladder. The name-format change itself is right and stays; only the
kernel file goes back to main, so the PR touches no kernel area.

* Names: a blend mark only at the outer role, and no parentheses in a curve id (#5857)

* Project: a nested face name with a non-ASCII character reads without a panic (#5857)

* Doc: the pending format note says a curve id may be outside ASCII

A curve id may hold a character outside ASCII (F2:side:曲), and the name of a blend
face holds the curve id of the edge it replaced (F5:blend(F2:side:曲|F2:top)). The
note said what is saved and what an older design gets without it; it now says
that the name holds such a character whole, so the note covers the whole of
what this build writes.

* Names: a piece of a blend face is found in either name form (#5857)

The lookup of a piece of a blend face came back with main, and it read
the mark of the older form only (`:blend:`), so a blend written in
today's form (`F3:blend(side|start)`) was no blend's name at all. A name
read from the older form was compared in today's form as well, against a
face whose own name was written in the older one, and the two never met.

The lookup reads the mark in either form now, and a face's own name is
compared in today's form as the stored name is, so a name saved before
the parentheses still finds the piece it names (#5857).

* Tests: the blend of an edge is named in today's form (#5857)

A test that came with main names the blend of an edge the older form
wrote it (`F3:blend:F2:side:l1|F2:top)`). A blend is written in today's
form now, so the test looks for that name, and for the mark of today's
form.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: vdirienzo <vdirienzo@users.noreply.github.com>
2026-11-10 11:56:30 +00:00
selune fcf16720d4 Graphics: choose the startup API and restart safely from Preferences (#14097)
Persist the selected API before device creation. Guard startup changes until
the first presented frame, preserve unsaved designs during restart, and
restore the prior API after an interrupted or rejected start.

Replace the earlier shader-memory scope of PR #14097. Keep shader readiness,
rendering math and resource limits unchanged.

Validation: 393 focused tests and native Linux interaction passed.
The full gate was invoked on identical sources; UI (5356 tests) and GPU
(228 tests) passed. Engine/SMLib/CLI failures remain and the kernel run is
still active. No Windows or macOS runtime validation is claimed.
2026-11-10 11:37:51 +00:00
Lars Jansen dfa47ab18a Dialogs in the left column: the design tree over the view (#6710) (#6715)
* claim: #6710

* feat(dialogs): the design tree over the view while a dialog holds the left column (#6710)
2026-11-10 11:35:22 +00:00
Brett Lawson 1f207899b4 solidcore: retire eight result-changing UpstreamFixes flags (corrected path becomes the only path) (#14486)
* solidcore: claim retiring eight result-changing UpstreamFixes flags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: retire eight result-changing UpstreamFixes flags

The corrected behaviour becomes the only path for WR-1 (two-context mark
lock), WR-10 (least-squares best-fit line), WR-19 (unclamped Newton step
without an interval), WR-6 (empty periodic extent takes the interval),
WR-9 (region-to-arc polar domain), WR-94 (integration failures propagate)
and #483 (pivot and path-extension statuses). WR-14 is deleted keeping the
unprojected tight-box angles, which differ from the projected ones only by
roundoff.

With WR-10 collinear point sets are Linear, so the tight pseudo box's
hull-edge alignment now runs for Linear sets as well as Planar ones: no
tight box is larger than either the old result or the line fix alone.

Goldens blessed (rows): geom.context 763, geom.geom_utility_p1 84,
geom.geom_utility_p2 29, geom.local_solve1d 139, geom.periodic_extent1d 6,
geom.point_set 111, geom.polar_box 1, mass.integrator 3,
primitive.primitive_creation_p1 4. SolidCraft set all eight ON; its preset
lines go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: drop the removed best-fit line variants from the layer lists; fmt and doc fixes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: WR-14 retires ON; the tight box measures chords on projected points

Across all 1378 geom.point_set tight boxes the projected path is never
larger than the unprojected one (1295 identical, 83 at roundoff), every
changed box holds its points, and no golden row in any unit changes. At
an exact tie with points 4e5 off the plane the unprojected chords' roundoff
picks the chamfer and leaves a box about 30% larger; the restored unit test
asserts the projected box's rotation, area and volume.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 11:35:08 +00:00
rbousigues88 10c8fb66c1 Cut: warn when it leaves a closed cavity instead of opening on a face (#7317) (#7319)
A Cut whose tool stops short of every face of a body leaves a closed void
inside it and said nothing. It now adds a feature warning naming the body
and the volume the cut took. The check lives in the document evaluation
and uses the kernel's existing shell_count, lumps and exact measure_mass:
a body's voids are its shells beyond one per piece. The operation lookup
it shares with the Join-apart note is now `feature_operation`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 11:28:13 +00:00
N3MI-DG 3cb35fe8c4 Browser: right-click the History folder to step through or play History (#14521) (#14522)
* claim: #14521

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Browser: right-click the History folder to step through or play History (#14521)

With History in the browser the History bar is hidden, and with it the
controls that move the History marker and play History. The History
folder's right-click menu now lists those controls: Go to beginning, Go
back one step, Play History (Stop History while playing, only while the
Play button is shown), Go forward one step and Go to end, then the bar's
own controls menu.

An entry that would leave the marker where it is is greyed out. Play
History keeps its existing reasons when it cannot run. The entries run
the bar's own timeline::run_transport; its step calculation moved into
a shared step_position so the menu can tell which entries would move.

The four step entries use the icon names timeline_first, timeline_back,
timeline_forward and timeline_last, which have no artwork yet and draw
the placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 11:22:59 +00:00
Rec0iL 017c47a402 Agent chat: put each picked face or part into the message text where you mention it (#2286) (#2321)
* Agent chat: hovering a chip lights its target; chips of things that are gone are struck through (#2286)

The chip under the pointer (in the tray or on a sent message) lights what it
stands for in the model while the pointer is on it. A chip whose body,
feature, face or edge has left the design is struck through with a note on
hover; faces and edges are told apart by their persistent names, which
survive edits (the block for the agent now says so). Worked out when the
design or the chips change, not every frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a pick is a pill in the message, where the caret was (#2286)

Pick context (and typing @) now puts the pick into the message as a pill, `«1: Plate · 3 faces»`,
at the caret, instead of a tray above the box. Several picks are several pills, so "make A match B"
says which is which. A pill is text in the box (so editing, selection, paste and input methods are
the text field's own), drawn as a pill by the field's layouter; Backspace/Delete next to it takes it
whole; hovering it lights its target; one whose target has gone is struck through. When the message
is sent the marks are numbered 1, 2, 3 in reading order and the agent gets each numbered group after
the message; Attach selection stays an end-of-message block, listed apart. Queued messages that go
as one prompt keep their numbers apart.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: hovering a pill in a sent message lights its group; chips only for what is not a pill (#2286)

The pills in a sent message light what they stand for while the pointer is on them, as the chips
below did; those chips are now shown only for the items that are not in a pill (Attach selection).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat control: send_input sends the message box as Enter does; the status shows the box (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a pill or chip lights its face by persistent name, not by the number it had (#2286)

After an edit renumbers the faces, the stored face number points at another face: hovering a sent
pill lit the wrong one. The target is now looked up by its persistent name (what has gone lights
nothing), in the box, in sent messages and for the chips.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: review fixes for the pills (#2286)

- The lit target is cached while the pointer rests on a pill; edge names are only worked out for
  edges; sent messages without pills no longer copy their context every frame.
- A sent pill lights only where the pointer really is (clip rect and layers respected).
- Editing a queued message renumbers its marks and un-places the groups whose mark was taken out.
- New chat keeps the draft's picks; queued messages get their own handles and chips light too.
- Empty persistent names are ignored; docs and a doc link fixed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: the control status adds the box and its pills to main's second step (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: replacing the design takes the pills out of the box (#2286)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a model that cannot be placed counts as there, now that world_state can fail (#2286)

Main made Session::world_state return a Result. The checks that decide whether a picked
body, face or edge has left the design now treat a model that cannot be placed as unable to
tell: the pill is not struck through and its picks are kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Agent chat: a test builds its face point with solidcore_record's Vec3, as main now does (#2286)

Main moved the point type of a face pick out of solidcraft_engine::geom. The test that
lights a chip's face by persistent name now builds its points the way main's own tests do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: what a pill or chip lights is kept only for the very same items (#2286)

The cache of what hovering lights was keyed by the items' text and persistent names, not by
what they stand for. Two items that read the same, such as two bodies picked under one name,
could then light the other one's geometry. The key now includes the selection itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: taking a pill out of a queued message drops its pick, as in the message box (#2286)

Editing a queued message and deleting one of its pills used to keep that pill's pick as an
unplaced chip, which the queued message cannot remove and which was still sent to the agent.
The pick is now dropped, as when a pill is deleted in the message box. What Attach selection
added was never placed in the text and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a pick that was also attached stays when its pill is taken out of a queued message (#2286)

A thing picked as a pill and also selected with Attach selection on is one item, under its pill.
That item is now marked as attached too, so taking its pill out of a queued message keeps it,
once, as not placed, instead of dropping what Attach selection added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a face picked as a pill and selected at another point is listed once (#2286)

Telling whether a selected thing is already a pill compared the pick point too, so the same
face clicked at two points was listed under its pill and again as not placed. Faces and edges
now match by body and index, as the selection does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a message with pills stays in a selection scrolled out of view, as main's messages do (#2286)

Main draws the conversation's messages through its selectable label, so a message scrolled out
of view keeps its part of a text selection and of Copy (#11527). A message's text with pills was
drawn as a plain label; it now goes through the same one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: the pill ids use egui 0.37's Id::unique, as main now does (#2286)

Main moved to egui 0.37, where Id::new is a deprecated name for Id::unique. The two ids this
PR adds (the message box and the cache of what a pill lights) now use Id::unique; the ids are
the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat control: the status still lists the picks as `picked`, next to `pills` (#2286)

Before the pills, `ui.agent_chat` listed what was picked as `picked`, a flat list of label and
detail. The status now gives that list again, made from the items of the box's pills, so
scripts that read it keep working; `pills` adds the grouping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Agent chat: a pill in a sent message takes the theme's chip colour, not a colour literal (#2286)

main allows no colour literals in agent_chat/panel.rs (colour_tokens_tests). The pill inside a
sent message, whose bubble is the accent colour, now uses the theme's filled-chip token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 11:07:13 +00:00
CaRLymx ce79b4a3c3 Catalan (ca): translate 129 messages (#14301)
Catch-up with `en.json` at `42918fe51`.

Co-authored-by: carlymx <24634598+carlymx@users.noreply.github.com>
2026-11-10 11:00:17 +00:00
Ehuntabi b0fc4c4cc5 Coil: say the turns touch when the section equals the pitch (#14540)
* Coil: say that touching turns are the problem when the section equals the pitch

A section exactly one pitch wide was refused with "the pitch must exceed the
section", which reads as if the profile were wrong. The message now says the
neighbouring turns touch and suggests a slightly smaller section. A section
wider than the pitch keeps its message.

Refs #14490

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Coil: keep the zero-pitch error and show a precise smaller example

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 11:00:03 +00:00
Brett Lawson 89ad5ad172 solidcore: intersect failures carry a typed reason instead of bare statuses (part of #13790) (#14495)
* solidcore: claim typed intersect errors (part of #13790)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: intersect failures carry a typed reason instead of bare statuses (part of #13790)

curve_class, point_class, ray_tracer, surface_drop_lib, surface_drop_curve,
adv_surface_intersector, api_intersectors, surface_silhouette and surface_tracer
return an IntersectFailure under the new Reason::Intersect instead of a bare
Upstream status: Failed (SM_ERR), Missing (SM_ERR_NULL_POINTER), OutsideDomain
(SM_ERR_OUTSIDE_OF_DOMAIN) and Inconsistent (SM_ERR_ASSERT_FAILURE), each with a
phrase saying what failed. The operation path, entity (none), comparison status
and kind are those of the Upstream it replaces, so sm_status(), kind(),
is_port_failure() and is_status_answer() answer as before; no cause is kept, so
no port failure is newly wrapped.

upstream_status() moves to error.rs and answers for an IntersectFailure as for
an Upstream (nurbs::upstream_status stays as a re-export), so the callers that
branch on an upstream status (check_seam_jump's caller, the drop status_of
helpers) behave as before. surface_intersector and topology_solver are held for
their open PRs.

The intersect goldens runners that recorded an Upstream code read
solidcore::error::upstream_status, so every row stays as it was. SolidCraft's
status() passes an IntersectFailure on as its status, as it did the Upstream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* goldens: the B-rep merge runners read a point classification failure's status as the Upstream it replaced (part of #13790)

topology.brep_p7 and topology.brep_p9 recorded PointClassification::merge_into_object's
Upstream status; they read solidcore::error::upstream_status, so their rows stay as they
were. IntersectFailure's Display joins its two phrase-only arms (clippy match_same_arms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:38:41 +00:00
jiiimi 875e30a321 Improve French translations (#12739)
* Improve French translations

* Improve French translations

* Sort French locale messages
2026-11-10 10:31:46 +00:00
PaddleStroke 3c81f9ece6 Sketches: a sketch hidden with its eye stays hidden when it is the last step before the History marker (#12125) (#12706)
* claim: #12125

* wip: a sketch hidden with its eye stays hidden at the History marker (#12125)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:31:44 +00:00
Ahmad Khan 1449d50420 Assistant: the panel says No design access instead of Ready when solidcraft-cli is missing (#12283) (#12389)
* claim: #12283

* Test: an Assistant agent without the design tools is not shown as Ready (#12283)

* Assistant: No design access instead of Ready when the agent runs without SolidCraft's tools (#12283)

Without solidcraft-cli beside the app the agent starts with no bridge to
the design, but the panel badge and the application bar mark said Ready.
The badge now says No design access in the warning colour, its hover text
says how to get solidcraft-cli, and the application bar mark shows the
warning dot with the same words in its tooltip.

* Assistant: No design access names its cause (endpoint or solidcraft-cli), in the application bar's tooltip too, and the folded panel's dot turns to the warning colour (#12283)

* Assistant: when solidcraft-cli was found but its tools did not start, No design access says so instead of saying the CLI is missing (#12283)

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-10 10:31:42 +00:00
Frank 1aa2136c1b Insert SVG and DXF: a preference raises the sketch size limit, so a dense drawing can go into one sketch (#10874) (#13533)
* claim: #10874

* Sketch: Preferences > Sketch > Largest sketch raises the 20000-point limit (#10874)

Insert SVG and Insert DXF refused any drawing with more than 20000 points
or curves. The limit in force now lives in solidcraft_sketch::limits and
can be raised up to 200000 from a new preference; the default is
unchanged. Every check that adds points, curves or constraints asks it.
Opening a design checks the 200000 ceiling instead, so a design made
with a raised limit opens anywhere. The refusal message names the
limit and the setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:31:28 +00:00
MarkusRe fd40424900 Setback fill: a round's rows in the section's standard form across (#13775) (#14041)
* test: a setback fill is its rounds' geometry's, not their parametrization across (#13775)

The box corner's rounds r 2, 3, 4, filled once as they are and once with
their sections moved across by a Moebius map (the weights w_j rho^j, the
same surfaces). The fill must be the same, patch for patch, to 1e-12 of
the corner's size. Six cases, each its own test; the rounds as they are
must fill (the precondition, with its own message):

- fill_is_the_geometry_across (G1, 1.7^j): on main refused, "no G1 fill
  up to degree 9 is certified convex at these setbacks"
- fill_is_the_geometry_across_mildly (G1, 1.001^j): on main certified,
  off by 2.094e-3 (allowed 6.3e-12); 1.003^j is refused already, the
  setbacks being the least that certify
- fill_is_the_geometry_across_changing_along (G1, 1.7^j to 1.2^j along):
  on main refused as above
- g2_fill_is_the_geometry_across (G2, 1.7^j): on main off by 1.341e0
  (allowed 6.0e-12)
- g2_fill_is_the_geometry_across_changing_along: on main off by 1.341e0
- g2_fill_is_the_geometry_across_beside_circles (G2 to the circles, G1 to
  the faces): on main off by 3.601e-2 (allowed 6.3e-12); its rows come
  from the arc already, its spoke not

fill_is_the_geometry_s (the fork's guard along the rails, fork main
8eac63c) passes on main: off by at most 4.8e-15.

These six fail until the next commit. Run on solidcore main b83367a49:
cargo test -p solidcore --profile goldens --test fork_870c970_blend_setback

Co-Authored-By: Claude Code <noreply@anthropic.com>

* fix: a setback fill takes its rounds' rows in the section's standard form across (#13775)

A round is one rational span across, so its rows fix its end section only
up to a Moebius map of the parameter across (w_j -> w_j c^j). round_jets
took the net's rows as they were, and the G2 fill measured its spoke at the
middle of the round's own parameter across: the fill depended on how the
round is parametrized, not only on what it is.

- round_jets puts the raw rows 0 to k in the section's standard form
  across (standard_form_across): column j times c^j, c = (W_0 / W_q)^(1/q)
  the ratio of the row's end weights, its derivatives along by Leibniz, so
  that both end weights are W_0 at every rail parameter to order k; then
  the weights' share and the rails' mean arc length as before. RoundJets
  no longer carries dt_ds.
- The G2 fill measures each spoke on the rows the patch takes (row_middle,
  now shared with curved.rs), not on the round's own evaluation.

Results: the box corner's G1 fills (r 2; r 2, 3, 4) and G2 fills (order-2
and G^n rounds r 2; order-2 r 2, 3, 4) are unchanged bit for bit (every
control point and weight, base solidcore b83367a49 against this commit). The fill G2
to circular rounds and G1 to the faces (FillOrders { rounds: 2, faces: 1 },
which nothing in the kernel calls) moves: its rows 0 and 1 come from
geometric_rows, whose row 1 has weight 0, so the speed of those rows at the
middle is 1 / w(1/2) and the patch's speed across there is now its whole
spoke, as the comment above the rows asks. Measured |R_u(0, 1/2)| of its
three setback patches at r 2, 3, 4: 4.2285, 4.1421, 4.7354 before;
3.6092, 3.5355, 4.0419 now (x 0.85355, the 90-degree arc's mean weight).

The in-module test geometric_rows_are_the_geometry asserted that two
parametrizations of one round (weights scaled 1, 2, 4 across) give
different jets; in the standard form they give the same, so it now asserts
that.

The six tests of the previous commit pass (off by at most 8.7e-14 against
6e-12); fill_is_the_geometry_s too. One Vec::with_capacity(n) of
fill_hole_with goes with dt_ds, so its row leaves plan/panic-sites.tsv.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 10:28:42 +00:00
Pieter Willekens db01a69625 3MF export: a thumbnail, so file managers show the part (#9449) (#9450)
* claim: #9449

* feat(io): embed the design thumbnail in 3MF exports (#9449)

A 3MF export carries the picture a design save draws as its package
thumbnail (/Metadata/thumbnail.png, the standard metadata/thumbnail
relationship and a png content type), so file managers and slicers show
the part. Without a picture the package is written as before.

* feat(engine): square, transparent 3MF thumbnail (#9449)

A 3MF export's thumbnail is 512x512 on a transparent background, as
slicers write theirs: the scene drawn over black and over white and
unblended with render::unblend, which render_transparent now shares.
The fit zoom is the Home picture's alone, so the square holds the whole
part; the design file's thumbnail is unchanged.

* fix(engine): unwrap world_state in the export thumbnail test

* fix(engine): warm display meshes before drawing a 3MF export thumbnail

* fix(engine): picture only the exported bodies in a 3MF thumbnail, within the scene limits

* fix(engine): picture every body in an unselected 3MF export, hidden ones too
2026-11-10 10:24:35 +00:00
austin62jake 87a50d01a2 plan: the WR-509 golden moves in curve.ellipse_p2 and query.face_p3, traced and checked (#14536)
The findings record for WR-509's ten moved goldens (#1518) left the three
curve.ellipse_p2 cases untraced and the query.face_p3 sector unchecked. This
addendum records the trace on main bf5cd7a88: each ellipse case moves in one
angle, and the new angle equals the point's closed-form atan2 angle to
4.3e-14 degrees. The face_p3 case was rejected by the runner's zero-length
line check, because DropPoint put the crossing on the corner. Its
ShortInterval result follows from the 1.53e-8 line's length.

Co-authored-by: austin62jake <340374338+austin62jake@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:19:50 +00:00
Brett Lawson 43655eca67 solidcore: the G^n certificate bounds the arc's rows over wide pieces with Taylor models (#14458)
The arc's row terms over a piece (the ball's circle, n = 1) took the rails and the
centre, which move together, as independent interval ranges: on a long piece the
circle's radii reached length 0 or the rows' fourth derivatives came out orders of
magnitude over their true values, and a long variable round proved only on pieces a few
hundredths of it long. They are now also bounded by Taylor models in s - m over the
piece (blend::fillet_section::taylor_model, outward-rounded interval coefficients and
remainder), each term the tighter of the two. The levels are still steered by the
interval terms, so from a given first level a span certifies at the same level or a
coarser one; a level takes the Taylor models only where they can change its verdict.

The box-edge variable round of #14405: 113 span certificates and 8,592 enclosures
(10-13 s) become 3 and 66 (0.5-0.7 s), its net 23 inner knots 1.

Law-corner pieces' definition nets are put on one homogeneous weight scale before they
are joined: JoinSurface averages unmatched boundary rows, which moved the spans either
side of a joint off both pieces (latent while the certified end spans were short).

Part of #14405.


Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:08:53 +00:00
MarkusRe a0585c9d1f Kernel: a circular arc's length is its radius times its angle, not a quadrature estimate (#13642) (#14296)
* Tests: a circular arc's length is its radius times its angle

Curve::length integrates a circle's speed with the adaptive quadrature,
so an arc's length is only within the accuracy asked. These tests ask
for the closed form to rounding, at every accuracy: whole arcs (across
angle 0, inside out, small and large) and pieces of a circle whose
knot spans have known angles. They fail on main.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* Kernel: a circular arc's length is its radius times its angle

Curve::length integrated a circle as any B-spline, with the adaptive
quadrature, so an arc's length was an estimate within the accuracy
asked. A circle (an ellipse whose radii agree) now returns its radius
times the angle its NURB turns through. The interval is split at the
NURB's knots; each piece's angle is atan2(|a x b|, a . b) of its end
points about the centre. A span of a rational quadratic NURB with
positive weights is an arc of less than 180 degrees, so there is no
seam or period to resolve. Each end point about the centre is the
span's first control point about the centre plus the point about that
control point in difference form (SpanSpeed::from_first_point, new),
so the angle's rounding scales with the radius, not with the circle's
distance from the origin. Other ellipses, other NURBs and intervals
past the NURB's ends integrate as before.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* Goldens: boolean.api_brep arc lengths of circles are r x angle

Four arc_lengths cases move because their circular edges now measure
in closed form, and the arc-length search finds its point on the
exact length:
- sphere_box_intersection: the meridian arc's point at half its
  length, exact (sqrt 17.5, 0, -sqrt 7.5), was 9.4e-9 and 1.4e-8 off
  in x and z, now 4.8e-12 and 7.3e-12.
- sphere_box_difference and _intersection: y of the point on the
  z = 2 circle, exact 0, was 2.43e-9, now 5.6e-16.
- cylinder_cylinder_tee_difference_09: the points at 36 degrees on
  circles of radius 2 and 1.5 are within 5e-13 of 2 cos 36 and
  1.5 cos 36 (block sum moved 1.3e-7).
- box_cylinder_hole_union: the four 4 pi circles now tie exactly, so
  their rows sort by the point, not by rounding noise in the length
  (weighted block sum +84; sum -3.2e-10).
The other cases stay within tolerance and are not rewritten.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 09:49:32 +00:00
Christian Hammacher e54b379906 Assemblies: relink one placement of a linked component to another design (#12227) (#12242)
* Assemblies: relink one placement of a linked component (#12227)

A placement's Component menu gets Relink Source… above Relink Source (All
Instances)… when its component is placed more than once. component.relink
takes an optional occurrence: that placement then shows a component linked
to the chosen design, one already linked to it or a new one under the same
parent, and keeps its id, position, grounding and joints, which move to the
same faces of the new design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Assemblies: document the relink entry points (#12227)

relink, occurrence_items and start_selected get doc comments, and the
linked_source module header no longer claims that all placements share
one source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Assemblies: check that a relinked placement's joint keeps its face (#12227)

The joint test now creates its joint on a named face, as a script does,
instead of writing a pick at the box's corner, and checks that the joint
lands on the same face of the new design, not merely on one of its faces.
The face is the last one, so a mapping that answers the first face fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:37:05 +00:00
Christian Hammacher 9d468f900f Context menus: only the Appearance editor row shows the A key (#12209)
The quick looks and Remove override in the Appearance flyout each showed
"A" as their shortcut, since they run appearance.assign, which A is bound
to. Pressing A opens the editor and applies none of those looks, so their
rows now show no key.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:29:07 +00:00
Jackson Oursland 4d91782c69 Book: screenshots in the light theme too, shown when the book is light (#10733)
doc_shots.py --light makes every still again in the app's light theme as <name>.light.png.
Each page shows a pair (img.dark-ui and img.light-ui), and docs/book/theme/media.css shows the
one that matches the book's theme: the light pictures for light and rust, the dark ones for
coal, navy and ayu. The five stills (window tour, finished sketch, Parameters dialog, start
page, File menu) come in both. CONTRIBUTING.md says how.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:29:04 +00:00
Daniel 390db99255 Placement handles for the primitives: Box, Cylinder, Cone, Sphere, Torus and Coil (#4384) (#10420)
* Placement handles: a Spec with places, the dialog kept in the app (#6818)

A tool's handles stand at one place (a Rest) or at one per item of its first input (a marker on
each): `Spec::frame` becomes `places`, each with a key, and `move_to` and a new optional `click`
name the place by it. Every tool gates itself through `serves(app, d)`, so a tool can keep its own
preference instead of the shared one. `show` no longer takes the dialog out of the app: the pointer
is picked under with the dialog open, so a drag snaps as a click does, and the dialog is taken
out only around a change. `handle_move` takes those hits instead of picking itself.

`motion::grab` measures the gap from where the button went down, not from the pointer when the
drag starts: a handle that also takes clicks only knows it is dragged once the pointer has moved
a few points, and measured there the gap put every drag one step behind the pointer.

Rest, Boss and Snap Fit adapted; no change in what they do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: the markers are a Spec under place_gizmo (#6818)

Step 2 of #6818. A Single hole's handle is `place_gizmo/hole.rs`: a marker on each placed hole,
drawn and dragged by the shared mechanics, so a hole gets what a Rest has: the marker's press
area, the grab offset that keeps the hole where it was taken instead of jumping under the
pointer, the footprint of its mouth while it drags, the depth arrow starting past the marker and
the value box keeping off it, and the manipulator state while it drags. A click on a marker still
takes the hole out; the markers stay behind Create Hole › Move holes by clicking or dragging, not
the shared Placement handles setting, and holes on sketch points (Multiple) have none.

`hole_place.rs` keeps what is the hole's: its face and rim snaps, the moves of its face places
and the pick that moves a hole. Its handle loop and `place_gizmo::marker` go.

Tests: a press off the centre keeps its gap, one marker per hole and a drag moves only its hole,
a click within the marker's reach takes the hole out, the arrow's clearance follows the setting.
The 18 hole placement tests pass unchanged (`hole:<n>` names, snapping, preferences).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Placement handles, Hole: fixes from the review (#6818)

A hole being edited whose face no longer resolves keeps its marker: `hole::places` falls back to
the `direction` the edit restored, as a Rest's frame does (before, the marker vanished with the
face). A marker drag moves the hole only while the face input is the active one: the hits were
picked by the active input's rules. `place_gizmo::face_pick` is the one face pick for Rest, Boss,
Snap Fit and the hole. After a click took a place out, the markers' states are left alone for
that frame instead of going to the place that moved into the index. `Spec` says where the dialog
is while each callback runs.

Tests: the hole's markers follow Move holes by clicking or dragging, not Placement handles; a
hole whose face is gone keeps its marker through `direction`, and loses it with neither.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: a reference edge holds the hole to its line, and the marker shows how much is left to move (#6818)

With one reference edge picked, the hole's distance drives its place instead of following it: a
drag of the marker, or a pick elsewhere on the face, moves the hole along that edge at its typed
distance (`hole_refs::drag_to`, through `ReferenceFrame::place`), and the distance text, an
expression included, is left alone. With two edges the hole moves anywhere again and a move sets
both distances, as a move did before any edge was picked. Before, a move always measured the
distances again from wherever the hole landed.

The marker says so: a `Spec` tells how freely each place moves (`Freedom`: anywhere, along a
line, not at all), and the marker's arms follow it: the four screen cardinals, two along the edge
as the view shows it, or none, the dot alone stepped back, with no press area, hover or move
cursor. A line seen nearly end-on, or a face seen nearly edge-on where a pick is refused anyway,
counts as held: a drag there would move the hole by centimetres per pixel.

The marker's pick and move go by the place input whichever input is active, so a reference edge
input waiting for its edge no longer leaves the marker lit but dead.

Tests: one edge holds the hole to a line the marker drags along; a typed distance survives the
drag; a pick elsewhere on the face keeps a held hole on its line; two edges free it again and a
drag sets both distances.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: reference edges hold only the hole they place (#6818)

With several holes in one Hole dialog and one reference edge picked, every hole's marker and drag took the first hole's line: a drag of a hole on another face wrote a point on the first hole's line into it, off its own face, and a pick on that face did the same. The edges place the first face pick only (OK refuses them with more than one hole), so freedom and drag_to now go by the item index and hold that hole alone; any other hole moves anywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a marker's press, hover and look go by a stable id, not the place's index (#6818)

The markers' widget and animation ids were built from each place's key, the item's index in the first input. When a click took a hole out, the next hole took its index and with it the hover of the one taken out: egui hit-tests by the last frame's rect for that id, so the surviving marker was hovered on the next frame, drawn hot with the Move cursor, and eased back over 0.22 s. The guard meant to stop that (`settled`) could never be false after a removal.

Each place now has an id by its order, kept while it moves (its key can change as a round face's halves come and go) and renewed for every place when one is gone. The guard is removed. The marker's hot factor is published as `<name>:hot` for the scenario tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the marker tests prove what they claim (#6818)

The click test passed with the old 9 pt reach too: a click 14 pt off the centre that missed the marker went to the canvas pick, which takes out a hole picked within its 5 mm radius. The hole is now 0.5 mm across, so a pick that missed the marker would move it and only the marker takes it out. The grab test's comment said the grab was outside the old handle's reach; it was inside the old 18 pt square, and the test discriminates by the gap itself (about 0.9 mm without it, and also when the gap is measured where the drag starts instead of at the press).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a place held still takes no press, so the view keeps the pointer there (#6818)

A hole held by one reference edge seen nearly end-on (or its face edge-on) is drawn as the dot alone and registers no widget, but it was still listed as a drawn handle: navigation and the depth arrow yielded an 18 pt disc around it in which a drag did nothing. The drawn handles now say whether each takes a press; only those keep the pointer from navigation and the arrow, while the value box still keeps off every drawn dot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: tests for the marker's cursor, Select Other yielding to it and the dragged footprint (#6818)

The behaviour changes the change lists had no test: over a hole marker the cursor is Move (it was Grab), a press held still on it is the marker's and opens no Select Other list (without markers the same hold does), and the outline while a hole drags is its mouth, the counterbore's or countersink's diameter when it has one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a drag along one reference edge keeps the measured distance, not the rounded one in the field (#6818)

drag_to placed the hole at the distance field's text, which shows a measured value rounded to the document's precision, while OK sends the measured value. It now reads each distance as sync does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole's freedom follows a design change in the same frame (#6818)

freedom read the reference frame cached for the edges without its revision, so in the frame after the design changed it could still hold the hole to an edge that was gone. It now finds the frame again when the revision moved on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a pick a held hole's line cannot reach says why instead of doing nothing (#6818)

With one reference edge, a pick elsewhere on the face moves the hole along the edge's line. On a face the line leaves before the pick (an L-shaped face, say), the pick did nothing and said nothing; the dialog now says the line leaves the face there and how to move the hole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole that cannot follow says so on a drag too, until the inputs change (#6818)

The message for a pick the held line cannot reach is now set through the dialog's refusal, so a changed distance or edge clears it; the marker drag gives it as well; it is shown only when the line leaves the face, not when the distance does not evaluate (which has its own error); and it tells where to pick: where the line crosses the face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face keeps its marker, standing on the face's normal where it is (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a tapped hole's dragged outline is its tap drill, not the hidden Diameter field (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: where two markers' reaches overlap, the nearer one takes the press (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the held-line refusal reads as guidance, with no Create Issue (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face takes the face's normal before a stored direction, so Edit Feature does too (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the overlapping markers' test clicks its second hole clear of the first one's depth box (#6818)

egui 0.37 makes the depth box a little taller, so a second hole clicked level with the first
landed on it and was not placed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VYMtcRVatHGG6YWKYjp89v

* Hole: several holes on one face keep their markers through the shared Spec (#6818)

With Several holes on one face on, every hole on a face gets its own
placement marker, as it had its own handle before the markers moved to
place_gizmo. A drag moves that hole only, onto the face the other holes
are on too, and a click on the marker takes that hole out. The marker
names a hole by its item in the face input; hole_place maps it to the
hole's number for several_change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Spec says where its place is kept (#4384)

A tool's place has one declared source, `Spec.place: PlaceSource`, instead of two functions each
tool wrote itself. `Input(n)` is the common case: the place is the face item of the dialog's input
`n`, read from there and moved by replacing the item, with `direction` and the in-face `along`
carried onto the new face; the marker's pick follows that input's rules whichever input is active.
Rest, Boss and Snap Fit declare `Input(0)` and lose their `places` and `move_to` lines; the frame
and move they shared move from `dialogs_plastic` into `place_gizmo`, where the place lives. `Own`
keeps a tool's own two functions: the hole, with a place per item. Behaviour unchanged, no test
changed.

Refs #4384, groundwork for the primitives (third element).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* claim: #4384

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: Box, Cylinder, Cone, Sphere, Torus and Coil (#4384)

With Placement handles on, the primitives' dialogs get the shared move marker. It stands at the
dialog's place (a pre-selected face, the Cylinder's Face input, the typed corner, centre or base,
the edited feature's stored point, else the origin), and a drag places the primitive on the face
under the pointer, as a pre-selected face places it, from Edit Feature too: a Box, Cylinder, Cone
or Coil stands on it, a Sphere or Torus has its centre on it, as today. The footprint is the box's
side on the face, the base circle of a cylinder, cone or coil, the widest circle of a sphere and
the torus's outer circle lying flat, as the torus is made. No ring: the primitives do not turn in
their face. A Coil with a sketch profile has no marker: its place is the profile's.

The drag moves the place where the dialog keeps it: a Cylinder's Face input item and its place in
the same frame (its reference edge distances are measured again from there, as after a click), a
Box's typed corner or centre fields (to the micrometre; its Point pick is cleared), or the picked
place for the others. A Cylinder, Cone or Coil does not take a curved face, which has no one axis
to stand it on. A typed Box's side on its face is found from the model (the side lying on a planar
face that looks at it, its bottom first), so Edit Feature reopens it on a side face too. A Box at a
vertex is centred on it, so its marker is at its bottom. The Cylinder's canvas path returned before
the handles were drawn; it now draws them.

The Placement handles setting's description names the primitives, in every catalog that has it,
and the control protocol lists the primitive:position handle. The tip is a new string in
assets/locales/pending/primitive-handles.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a dropped Box is written in the design's unit

A Box dropped by its marker wrote its corner or centre in millimetres in every design, and a point
picked into the Box's input did too. Both now go through the design's length unit, kept to the
micrometre, as the fields show it elsewhere. A test drops a Box in a metre design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Control protocol: a Single hole's markers follow hole_moves, not Placement handles (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Box stands only on a face it overlaps, square to the world; a Cylinder lets go of edges it cannot reach (#4384)

A typed Box's side counted as on a face when it lay in the plane of any planar face, however far. It now has to overlap the face. A typed Box dropped on a curved face stands out from it when the way out is along an axis, and a tilted face, which has no outline, does not take it (a pre-selected face still places it as before). A Cylinder dropped on another body kept reference edges the command then refused; those are let go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Empty commit: GitHub did not register the push of 68c2a965c to this PR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a typed Box is not dropped where a round wall's way out is off the world axes (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Sphere, Torus, Cone or Coil moved by its marker drops its point pick too (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a dropped Box keeps its size expressions, so it stays centred when a parameter they name changes (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Cylinder held by one reference edge keeps its typed distance on a drag, as a hole does (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a dropped Box reads a bare size expression in the design's unit, as OK does (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: the marker reads a bare size in the design's unit, as OK does (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: an empty placement field is 0 for the marker, as OK sends it (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: the docs name Preferences > Tools and the nanometre the drop is kept to (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: the marker reads a size field as OK does, a decimal comma or a unitless expression included (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Cylinder held by one reference edge keeps its typed distance on a pick of its face too, as a hole does (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a typed Box's drop on a curved face asks every body for the way out, as hole_direction_at now takes a scope (#12067) (#4384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 09:29:01 +00:00
MarkusRe fadefe56ab solidcore: a failed fillet leaves the body as it was (#13689) (#14228)
* claim: #13689

Co-Authored-By: Claude Code <noreply@anthropic.com>

* solidcore: test that a failed round leaves the body as it was (#13689)

Rounding two of the three join edges of two cylinders joined at an angle
fails with status 1001 in the fillet session's finish. The body keeps the
edits made before the failure, and two of its edges then fail the Level 2
check. The test checks that the body checks clean after the call and, when
the call fails, is unchanged.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* solidcore: a failed fillet leaves the body as it was (#13689)

Every public fillet operation in blend/fillet_executive/api.rs that edits a
caller's body now runs under Brep::with_rollback: on any error, and on a
panic, each body it was given is put back as it was before the call.
Upstream keeps the edits made before the failure, which on two cylinders
joined at an angle left a body that fails the Level 2 check. Before, only
the non-manifold refusal put the body back, and only with
fixes.fillet_refuse_non_manifold_result on; that flag now only decides
whether the refusal happens. The cached topology fields are refreshed
whichever body the caller gets back, as before.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* solidcore: test the fillet rollback on a cancel and in surface_surface_fillet; WR-212 addendum (#13689)

The unit test a_fillet_fails_as_a_whole also fires the cancel token during
the fillet: the call returns Cancelled with the body put back. The
surface_surface_fillet error test checks that the caller's body is
unchanged. The snapshot's doc names both of its failures. A new WR-212
addendum records that every failure, not only the refusal, now leaves the
caller's body unchanged.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* solidcore: bless blend.fillet_executive_p3 for the fillet rollback (#13689)

52 cases fail (status 1001, one 1007) after the fillet has edited the
body. They now record the body as it came in: every failing case on the
same part records the same counts and geometry, and where an unmoved
failing case on that part already left the body alone (bottle, 18 cases;
sphere_diff_3cylinders; filleted_box) the new values equal its values.
Rows that moved by less than 1e-9 relative are kept.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 09:28:22 +00:00
ancient_astronaut_theorist 94ce45a1f2 Kernel: planar_face asks solidcore-ops whether a B-spline face is flat (follow-up to #14394) (#14509)
#14394 tested whether a B-spline face is flat with its own control-net
math in crates/kernel, but SolidCraft computes no geometry
(solidcore/docs/layers.md). planar_face now asks
solidcore_ops::Body::face_plane_normal, which runs SMLib's IsPlanar at
the face's tolerance and gives the outward normal, and makes the plane
through the face's first vertex. flat_net and net_fits are deleted. The
record's solidcore-ops body is made on first use and cached with the
body, shared by clones.


Claude-Session: https://claude.ai/code/session_01Gr84VuQWHKtTwJ7cC3CP3W

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:24:57 +00:00
MarkusRe 52c9f72249 Offset: the certified offset and the fold refusal are the default; shell_one_construction retires (#13827) (#14039)
* test: the parabolic sheet's S1 cases on the default kernel (#2350)

The thicken and fold tests of the parabolic sheet ran on a kernel with
shell_one_construction set. On Kernel::default() the t11 fold towards
the centre is not refused naming its apex radius 10: the default kernel
still runs SMLib's sampled N_SrfOffset fit and no fold refusal.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* offset: S1 by default: certified nets and the fold refusal; shell_one_construction retired

AGENTS.md §4b retires the port's flags. With shell_one_construction off
(the default) the shell replaced each implicit offset by N_SrfOffset's
fit, checked at samples, and built B-spline faces whose offset folds.
Now replace_implicit_offsets always takes certified_offset (within the
shell's tolerance at every parameter) and offset_face_prefix refuses a
folding face with OffsetFailure::Folds, naming the largest wall, for
every offset but the local operation. The N_SrfOffset branch and the
flag-off test go with the flag; fixes.json and the tests that listed it
drop the name. docs/offset-and-shell.md and its figure no longer call
S1 opt-in; WR-718 gets an addendum.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* offset tests: faces whose offset folds are refused naming their radius (D5)

With S1 the default, three upstream parts that built by deleting an
inside-out offset face are refused before anything is built, at the
face whose offset folds: Defeature/extrusion.smb face 2 inset 2
(largest 1.5331), Fillet/brepForFillet2.smb face 2 outset 5.6 and 11.2
(3.9580), Solids/extrusion_old.smb face 7 outset 2.5 (0.9689). The
tests assert those refusals. The collapse test keeps face 2 as a shell
face so face 5's collapse is still what it names. The lamina-edge
deletion stays covered by the extrudeHoles1 outset; the HANG-51 bound
loses its only known input.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* test: the swept bar's WR-545 shell keeps two marched edges under S1 (18 lines)

The two inner straight walls of the issue_1476 swept bar are offsets of
extrusions. N_SrfOffset's fit of them was recognised as an extrusion when
the shell was merged (bAddAnalytics), so make_edges_on_analytics_exact
made their edges with the planar end cap lines (20 lines). The certified
net is bicubic and not recognised, so those two edges stay marched (18
lines, as SolidCraft's configuration already gets). Measured with the
SSI of each candidate edge printed: at the base 28 and 30 become lines,
at the head they have one net face and are skipped; the other edges
(49, 54 lines; 33, 37, 40, 48 no SSI curve) are the same. The volume
moves from 1299.4876806943942 to 1299.4876807223006 (2e-11 relative),
inside the pin.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* goldens: offset p1 nets and p2 fold refusals under S1 (blessed)

offset.offset_executive_p1, 11 replace_* cases: the certified net keeps
the base's parametrisation, so natural_domain is the base's domain
([0,0,1,2], [0,-1,1,1], swapped [0,0,2,1], ...) where N_SrfOffset's fit
was reparametrised to [0,1]^2; the samples move with it. On a 41 x 41
grid each net is within its approx_tol of the exact offset S + d n at
the same (u, v) (worst 3.7e-6 of 1e-5, 3.6e-5 of 1e-4, 3.1e-4 of 1e-3,
4.3e-8 of 1e-7, 4.1e-10 of 1e-9; plane and line extrusion 2e-15).

offset.offset_executive_p2, 20 cases: a face whose offset folds is
refused (D5, Offset(Folds)) naming its least radius on that side; each
distance is past it. 16 built before by deleting the inside-out face;
4 were already refused and now stop at the folding face (fewer faces
in the executive's partial offset).
  defeature_extrusion_face0_inset2_5_extended          1001->1001  face 2  d  -2.5  largest 1.5331
  defeature_extrusion_face0_inset2_5_rounded           1001->1001  face 2  d  -2.5  largest 1.5331
  defeature_extrusion_face0_inset2_5_rounded_unstitched 1000->1001  face 2  d  -2.5  largest 1.5331
  defeature_extrusion_face0_inset2_extended            1001->1001  face 2  d  -2.0  largest 1.5331
  defeature_extrusion_face0_outset2_5_extended         1001->1001  face 2  d   2.5  largest 1.1264
  defeature_extrusion_face0_outset2_5_rounded          1000->1001  face 2  d   2.5  largest 1.1264
  fillet2_f0_d0_in_rnd                                 1000->1001  face 2  d  -5.6  largest 5.0738
  fillet2_f0_d0_out_rnd                                1000->1001  face 2  d   5.6  largest 3.9580
  fillet2_f0_d0_out_rnd_unmerged                       1000->1001  face 2  d   5.6  largest 3.9580
  fillet2_f0_d1_in_rnd                                 1000->1001  face 2  d -11.2  largest 5.0738
  fillet2_f0_d1_out_rnd                                1000->1001  face 2  d  11.2  largest 3.9580
  fillet2_f0_d1_out_rnd_unmerged                       1000->1001  face 2  d  11.2  largest 3.9580
  fillet2_f1_d0_in_rnd                                 1000->1001  face 2  d  -5.6  largest 5.0738
  fillet2_f1_d0_out_rnd                                1000->1001  face 2  d   5.6  largest 3.9580
  fillet2_f1_d1_in_rnd                                 1000->1001  face 2  d -11.2  largest 5.0738
  fillet2_f1_d1_out_rnd                                1000->1001  face 2  d  11.2  largest 3.9580
  fillet2_f2_d0_in_rnd                                 1000->1001  face 3  d  -5.6  largest 2.9088
  fillet2_f2_d0_out_rnd                                1000->1001  face 3  d   5.6  largest 5.0975
  fillet2_f2_d1_in_rnd                                 1000->1001  face 3  d -11.2  largest 2.9088
  fillet2_f2_d1_out_rnd                                1000->1001  face 3  d  11.2  largest 5.0975

Co-Authored-By: Claude Code <noreply@anthropic.com>

* test: the drilled plate's shell volumes under S1 (1795, 1950)

With the certified offset the default and #14347's intersect flags gone,
the plate shelled 2 inward builds the same 16/36/24 solid; its volume
moves within the integrator's accuracy, so three pins move:

  1795 open at z 27.5             9655.150697869625 -> 9655.150751213405
                                  closed form +2.54e-4 -> +3.07e-4
  1950 SolidCraft fixes, WR-545   10400.212354107192 -> 10400.212799756418
                                  closed form -1.97e-5 -> +4.26e-4
  1950 WR-545 alone               10400.212413698822 -> 10400.212854198868
                                  closed form +3.99e-5 -> +4.80e-4

The shell's non-analytic offsets are certified nets instead of
N_SrfOffset's fits. With WR-545 the volume is now within 1.5e-12 and
3.1e-10 relative of the volume without it (the pins without it hold);
the shell still runs the flag through the face-owned surfaces (#1950).

Co-Authored-By: Claude Code <noreply@anthropic.com>

* offset docs: where the certified net replaces an offset, and NotCertified

construction.rs said every implicit offset surface is replaced by its
certified B-spline; only the shell and the thicken replace them, the
plain offset keeps its implicit offset surfaces. The refusal of a face
not proved regular names NotCertified where no radius bounds the wall;
the refusal table in docs/offset-and-shell.md §4.2 now lists it beside
Folds. §8's invariant 2 names the two remaining exceptions (the revolved
generator's fit, the round offset as its net) instead of "the fitted
paths in §3 and §3.2".

Co-Authored-By: Claude Code <noreply@anthropic.com>

* findings: the folding offsets refused by default, with main's bodies

The p2 golden cases whose offset folds were built on main by deleting
the inside-out offset face (16 at status 1000, 4 failed later); D5 now
refuses them before any face is built. The record lists the counts main
built and carries before renders of brepForFillet2 (outset 5.6) and
Defeature/extrusion (outset 2.5): the input with the folding face
highlighted and main's result as a wireframe.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* findings: the p1 replace cases' certified nets keep the base's domain

The 11 replace_* cases of offset.offset_executive_p1 moved in the
goldens commit because the certified net keeps the base's
parametrisation where N_SrfOffset's fit was reparametrised to the unit
square. The record lists old and new domains and each net's worst gap
to the exact offset S + d n on a 41 x 41 grid against its tolerance.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 09:23:37 +00:00
0rdnungsamt c9d6a9f131 Sketch Dimension: the pointer ring no longer covers the value being placed (#14467)
* claim: #14231 (pointer ring over a dimension's value while placing it)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Dimension: the pointer ring no longer covers the value being placed

While a dimension is placed its value follows the pointer. The tool's
pointer ring is painted after the dimensions, so it sat in the middle of the
number. dim_view now remembers where it drew the value this frame, and the
Dimension tool leaves its ring out inside that box; elsewhere the ring stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Dimension: also leave out a pointer ring that would touch the value

A ring centred just outside the value's box still reached over its edge.
The check now counts the ring's largest radius and half its stroke.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:20:18 +00:00
Brett Lawson c50ebfdc5b Motion: find_limits' overlap check indexes the other part's triangles instead of testing every one at every sample (#14455)
* Claim: index the other part's triangles in find_limits' overlap check (#14450)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* Motion: find_limits' overlap check indexes the other part's triangles (#14450)

deepest tested every sample point and edge of one mesh against every
triangle of the other, at every sample of a sweep. It now builds one
solidcraft_geom::Bvh over the other mesh's triangles per call and answers
the nearest distance, the ray parity and the segment hits from it. The
boxes are grown by half the triangle's longest edge and a millionth of the
coordinate scale, and ill-shaped triangles are tested by every query, so
the answers are the scan's, bit for bit. The work counter is unchanged.

The slow test drops from 141 s to 20 s CPU locally (P-cores). Regression tests compare
the indexed depth and each query with the scan, on fixed-seed random meshes
and on the slow case's pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:20:16 +00:00
0rdnungsamt de1a8737a9 Agents and scripts: Loft Surface describes its exact parameters and reply (part of #2829) (#14306)
* claim: part of #2829 (surface.loft schemas)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Give surface.loft input and output schemas

Part of #2829. The contract checks each guide rail's shape and leaves
how many rails a loft takes to the handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:20:13 +00:00
0rdnungsamt ceac257649 Agents and scripts: Emboss describes its exact parameters and reply (part of #2829) (#14235)
* claim: solid.emboss schemas (part of #2829)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Give solid.emboss input and output schemas (part of #2829)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* describe_returns_both_schemas takes its unconverted example from unconverted.txt

doc.open has its schemas on main now, so a fixed example goes stale as the list shrinks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:20:11 +00:00
Daniel b55c3c2da8 Tooltips: eleven callers converted, and the container gate warns about egui's own tooltip methods (#12329) (#12331)
* Tooltips: the container gate rejects egui's own tooltip methods, eleven callers converted

cargo xtask ui-containers now reports a raw tooltip call (on_hover_text,
on_hover_ui, on_hover_text_at_pointer, on_hover_ui_at_pointer,
on_disabled_hover_text, on_disabled_hover_ui, show_tooltip_text,
show_tooltip_ui) outside ui_kit/container.rs, as a method call, as a path
call and inside macro bodies, next to the raw hosts it already rejects.
egui::Tooltip itself stays allowed: the kit's widgets and two feature
modules build custom tooltips with it.

The eleven remaining callers use backing_on_hover_text: the Fillet turn
row, the Dimension window's icon buttons and insert hint, the two dimension
step fields in Preferences, Sketch, the two keep-unsaved checkboxes in
Preferences, General, the ground shadow setting in Preferences, Graphics,
the checkbox-with-help control of the preferences macro, the HTTP allow
checkbox in the agent settings and the toolbar button tooltip. Their
tooltips now draw with the themed backing like every other tooltip.

Docs: the UI skill, the container audit and the xtask help line say that
the gate covers tooltips.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Tooltips: the backing text tooltips describe the widget for accessibility, as egui's do

egui's on_hover_text and on_hover_text_at_pointer also hand the tip to the
accessibility tree: a widget that has a node gets the tip as its description,
and as its name when it has none (a label is named by its text, a widget with
a labelled_by relation by that). The backing variants showed the tip and did
nothing for the tree, so a converted caller read less to a screen reader.
backing_on_hover_text and backing_on_hover_text_at_pointer now do the same as
egui, through a helper that mirrors Response::describe_for_accessibility.
on_disabled_hover_text sets no description in egui, so the disabled variant
stays as it is.

Test: two checkboxes and a label with backing tips, read back from the
accesskit tree (red before the helper: the checkbox node had no description).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Tooltip gate: a macro_rules body marked cfg(test) is test-only

The gate skipped test modules and test functions but walked the body of a
macro_rules item carrying #[cfg(test)], so a raw tooltip call in a test
helper macro would fail the gate. Such a macro is skipped like a test module;
the fixture has one (red before the change).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Tooltips: the raw tooltips main gained since the gate was written use the backing form

Twenty-six calls in the render workspace, the panel workspace, the panel
host, the widget gallery and the mesh import options used egui's on_hover_text and
on_disabled_hover_text, which the gate rejects. They now use the
BackingTooltipExt forms, which keep the hover, disabled and accessibility
behaviour. The panel host draws its tab chrome but takes its tooltip from
egui, so it is converted rather than exempted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Format: the dimension window's title tooltip wraps as rustfmt lays it out

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hover text: the new denoise optical-filter checkbox's tooltip goes through the backing tooltip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ui-containers: raw tooltips warn instead of failing, until the queue has none

PRs in the merge queue add raw on_hover_text calls, and each one would fail
the tooltip half of the gate once it lands before this change. cargo xtask
ui-containers now lists raw tooltips as warnings and exits 0 for them; an
outer host that skips ui_kit::Container still fails as before. The fixture
test keeps proving the detector finds every raw form, and the temporary
workspace test checks that a raw tooltip alone does not fail the run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 09:20:08 +00:00
Daniel 7b0ab2f23c Placement handles: each tool declares where its placement is kept (#6818) (#7737)
* Placement handles: a Spec with places, the dialog kept in the app (#6818)

A tool's handles stand at one place (a Rest) or at one per item of its first input (a marker on
each): `Spec::frame` becomes `places`, each with a key, and `move_to` and a new optional `click`
name the place by it. Every tool gates itself through `serves(app, d)`, so a tool can keep its own
preference instead of the shared one. `show` no longer takes the dialog out of the app: the pointer
is picked under with the dialog open, so a drag snaps as a click does, and the dialog is taken
out only around a change. `handle_move` takes those hits instead of picking itself.

`motion::grab` measures the gap from where the button went down, not from the pointer when the
drag starts: a handle that also takes clicks only knows it is dragged once the pointer has moved
a few points, and measured there the gap put every drag one step behind the pointer.

Rest, Boss and Snap Fit adapted; no change in what they do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: the markers are a Spec under place_gizmo (#6818)

Step 2 of #6818. A Single hole's handle is `place_gizmo/hole.rs`: a marker on each placed hole,
drawn and dragged by the shared mechanics, so a hole gets what a Rest has: the marker's press
area, the grab offset that keeps the hole where it was taken instead of jumping under the
pointer, the footprint of its mouth while it drags, the depth arrow starting past the marker and
the value box keeping off it, and the manipulator state while it drags. A click on a marker still
takes the hole out; the markers stay behind Create Hole › Move holes by clicking or dragging, not
the shared Placement handles setting, and holes on sketch points (Multiple) have none.

`hole_place.rs` keeps what is the hole's: its face and rim snaps, the moves of its face places
and the pick that moves a hole. Its handle loop and `place_gizmo::marker` go.

Tests: a press off the centre keeps its gap, one marker per hole and a drag moves only its hole,
a click within the marker's reach takes the hole out, the arrow's clearance follows the setting.
The 18 hole placement tests pass unchanged (`hole:<n>` names, snapping, preferences).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Placement handles, Hole: fixes from the review (#6818)

A hole being edited whose face no longer resolves keeps its marker: `hole::places` falls back to
the `direction` the edit restored, as a Rest's frame does (before, the marker vanished with the
face). A marker drag moves the hole only while the face input is the active one: the hits were
picked by the active input's rules. `place_gizmo::face_pick` is the one face pick for Rest, Boss,
Snap Fit and the hole. After a click took a place out, the markers' states are left alone for
that frame instead of going to the place that moved into the index. `Spec` says where the dialog
is while each callback runs.

Tests: the hole's markers follow Move holes by clicking or dragging, not Placement handles; a
hole whose face is gone keeps its marker through `direction`, and loses it with neither.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: a reference edge holds the hole to its line, and the marker shows how much is left to move (#6818)

With one reference edge picked, the hole's distance drives its place instead of following it: a
drag of the marker, or a pick elsewhere on the face, moves the hole along that edge at its typed
distance (`hole_refs::drag_to`, through `ReferenceFrame::place`), and the distance text, an
expression included, is left alone. With two edges the hole moves anywhere again and a move sets
both distances, as a move did before any edge was picked. Before, a move always measured the
distances again from wherever the hole landed.

The marker says so: a `Spec` tells how freely each place moves (`Freedom`: anywhere, along a
line, not at all), and the marker's arms follow it: the four screen cardinals, two along the edge
as the view shows it, or none, the dot alone stepped back, with no press area, hover or move
cursor. A line seen nearly end-on, or a face seen nearly edge-on where a pick is refused anyway,
counts as held: a drag there would move the hole by centimetres per pixel.

The marker's pick and move go by the place input whichever input is active, so a reference edge
input waiting for its edge no longer leaves the marker lit but dead.

Tests: one edge holds the hole to a line the marker drags along; a typed distance survives the
drag; a pick elsewhere on the face keeps a held hole on its line; two edges free it again and a
drag sets both distances.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: reference edges hold only the hole they place (#6818)

With several holes in one Hole dialog and one reference edge picked, every hole's marker and drag took the first hole's line: a drag of a hole on another face wrote a point on the first hole's line into it, off its own face, and a pick on that face did the same. The edges place the first face pick only (OK refuses them with more than one hole), so freedom and drag_to now go by the item index and hold that hole alone; any other hole moves anywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a marker's press, hover and look go by a stable id, not the place's index (#6818)

The markers' widget and animation ids were built from each place's key, the item's index in the first input. When a click took a hole out, the next hole took its index and with it the hover of the one taken out: egui hit-tests by the last frame's rect for that id, so the surviving marker was hovered on the next frame, drawn hot with the Move cursor, and eased back over 0.22 s. The guard meant to stop that (`settled`) could never be false after a removal.

Each place now has an id by its order, kept while it moves (its key can change as a round face's halves come and go) and renewed for every place when one is gone. The guard is removed. The marker's hot factor is published as `<name>:hot` for the scenario tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the marker tests prove what they claim (#6818)

The click test passed with the old 9 pt reach too: a click 14 pt off the centre that missed the marker went to the canvas pick, which takes out a hole picked within its 5 mm radius. The hole is now 0.5 mm across, so a pick that missed the marker would move it and only the marker takes it out. The grab test's comment said the grab was outside the old handle's reach; it was inside the old 18 pt square, and the test discriminates by the gap itself (about 0.9 mm without it, and also when the gap is measured where the drag starts instead of at the press).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a place held still takes no press, so the view keeps the pointer there (#6818)

A hole held by one reference edge seen nearly end-on (or its face edge-on) is drawn as the dot alone and registers no widget, but it was still listed as a drawn handle: navigation and the depth arrow yielded an 18 pt disc around it in which a drag did nothing. The drawn handles now say whether each takes a press; only those keep the pointer from navigation and the arrow, while the value box still keeps off every drawn dot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: tests for the marker's cursor, Select Other yielding to it and the dragged footprint (#6818)

The behaviour changes the change lists had no test: over a hole marker the cursor is Move (it was Grab), a press held still on it is the marker's and opens no Select Other list (without markers the same hold does), and the outline while a hole drags is its mouth, the counterbore's or countersink's diameter when it has one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a drag along one reference edge keeps the measured distance, not the rounded one in the field (#6818)

drag_to placed the hole at the distance field's text, which shows a measured value rounded to the document's precision, while OK sends the measured value. It now reads each distance as sync does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole's freedom follows a design change in the same frame (#6818)

freedom read the reference frame cached for the edges without its revision, so in the frame after the design changed it could still hold the hole to an edge that was gone. It now finds the frame again when the revision moved on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a pick a held hole's line cannot reach says why instead of doing nothing (#6818)

With one reference edge, a pick elsewhere on the face moves the hole along the edge's line. On a face the line leaves before the pick (an L-shaped face, say), the pick did nothing and said nothing; the dialog now says the line leaves the face there and how to move the hole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole that cannot follow says so on a drag too, until the inputs change (#6818)

The message for a pick the held line cannot reach is now set through the dialog's refusal, so a changed distance or edge clears it; the marker drag gives it as well; it is shown only when the line leaves the face, not when the distance does not evaluate (which has its own error); and it tells where to pick: where the line crosses the face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face keeps its marker, standing on the face's normal where it is (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a tapped hole's dragged outline is its tap drill, not the hidden Diameter field (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: where two markers' reaches overlap, the nearer one takes the press (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the held-line refusal reads as guidance, with no Create Issue (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face takes the face's normal before a stored direction, so Edit Feature does too (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the overlapping markers' test clicks its second hole clear of the first one's depth box (#6818)

egui 0.37 makes the depth box a little taller, so a second hole clicked level with the first
landed on it and was not placed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VYMtcRVatHGG6YWKYjp89v

* Hole: several holes on one face keep their markers through the shared Spec (#6818)

With Several holes on one face on, every hole on a face gets its own
placement marker, as it had its own handle before the markers moved to
place_gizmo. A drag moves that hole only, onto the face the other holes
are on too, and a click on the marker takes that hole out. The marker
names a hole by its item in the face input; hole_place maps it to the
hole's number for several_change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a Spec says where its place is kept (#4384)

A tool's place has one declared source, `Spec.place: PlaceSource`, instead of two functions each
tool wrote itself. `Input(n)` is the common case: the place is the face item of the dialog's input
`n`, read from there and moved by replacing the item, with `direction` and the in-face `along`
carried onto the new face; the marker's pick follows that input's rules whichever input is active.
Rest, Boss and Snap Fit declare `Input(0)` and lose their `places` and `move_to` lines; the frame
and move they shared move from `dialogs_plastic` into `place_gizmo`, where the place lives. `Own`
keeps a tool's own two functions: the hole, with a place per item. Behaviour unchanged, no test
changed.

Refs #4384, groundwork for the primitives (third element).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 09:20:06 +00:00
0rdnungsamt 100a2eb633 Shortcuts: Show/Hide can move off V, and V can go to another command (#13241) (#13389)
* claim: #13241

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Shortcuts: Show/Hide can move off V, and V can go to another command (#13241)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Shortcuts: Show/Hide's old chords keep working, and menus name its key only on its own rows

Shift+V and Alt+V toggle visibility as before while Show/Hide is on V and
nothing else is bound to them. The current key replaces V only on
Show/Hide rows, so a command given V keeps it on its row, and the ui.menu
report names the same key as the open menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Shortcuts: with a menu open, Show/Hide's key runs the menu's Show/Hide row, not a command given V

ui.toggle_visibility pressed the open menu's first row tagged V. A command row bound to V carries that tag too, so with Show/Hide on another key and a command above it on V, Show/Hide's key ran that command. Only Show/Hide rows answer the V tag now; the test binds a command above Show/Hide in the body menu to V.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:20:03 +00:00
dudedagger42 71f1db91ab Body: renaming a body a split cut in two evaluates nothing (#12657) (#13217)
body.rename's fast path declined when a later body was named after the
renamed one (`X (1)`). A split names its other piece that way, but
body.rename stores that name in the split, so the piece keeps it: the
fast path now accepts such a body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:12:16 +00:00
dudedagger42 d7a6aacbb9 Extrude: Through All keeps the side of a negative saved distance (#10415) (#13207)
* Test: Through All keeps the side of a negative saved distance (#10415)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Through All keeps the side of a negative saved distance (#10415)

through_all_distance returns a length, so switching an inward cut to Through
ran to the sign-less positive side. Give the reach the sign of the saved
distance, as an entered distance has.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 09:12:14 +00:00
dudedagger42 41356709bf Extrude with a taper of 0 on a profile with holes is straight (#13188) (#13205)
* Add failing test: extrude with a taper of 0 on a profile with a hole (#13188)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Extrude: a taper of 0 is a straight extrusion, also with holes in the profile (#13188)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 09:12:11 +00:00
dudedagger42 5d7897b22c Hole: stop cutting bodies and walls that stand above the face being drilled (#10695) (#12976)
* Hole: tests for the run-on above the entry face cutting material there (#10695)

A hole's tools start 1 % of the part's size above the entry face; that run-on
cuts a body floating over the face or standing on it, a wall of the part beside
the hole, and the wall of a bore whose floor the hole is drilled from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the run-on above the entry face leaves the material there (#10695)

A hole's tools start above the entry face so that they pass cleanly through
it. That run-on was 1 % of the part's size and cut whatever stood there:
another body floating over the face or standing on it, a wall of the part
beside the hole, the wall of a bore whose floor the hole is drilled from.

The hole now intersects each body that may reach above the face with the
run-on's column (exact, kernel boolean). Material 0.2 mm or more above the
face shortens the run-on to half the gap; nearer material is cut out of
the tools. The drilled body's own surroundings at the entry point (a curved
or slanted face) are drilled as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Test: a counterbore on a round bar drills its rim; the run-on check falls back when the kernel can't answer (#10695)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: make the run-on check best effort, and drill a curved face's own rise (#10695)

A kernel error or no answer for one body leaves that body out (the run-on as
before), and a tool the kernel can't cut keeps its old shape, so a hole that
built before never fails over a neighbour. The entry point of a counterbore on
a round bar lies just inside the bar; the bar's rise over it is the face being
drilled, not material over the face. A body's exact box in the hole's frame
skips the intersect when it lies wholly below the face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 09:12:08 +00:00
ChrisNo ad145c6374 Kernel: a curve's projected maximum is found with the right derivative, and is a maximum (#14327)
* fix: negate a projected maximum's derivative with its equation

CurvePropertyEfo negates the projected stationary equation F for
ProjectedPointMaximize but left F' unchanged, so the local Newton step
t - F/F' divided the negated function by the derivative of the original
one and stepped away from the root.

With the derivative corrected, Newton reaches the nearest stationary
point of the projected distance, a minimum as readily as a maximum, or
runs off where the equation turns back between the guess and its root.
So local_property_analysis accepts a root only where the equation's
derivative is not negative, which is where the distance has a maximum.
Otherwise it samples the equation at 16 steps of the interval, takes the
step where it goes from negative to positive at the largest distance as
a bracket of an interior maximum, and polishes that one with Newton
inside the step, or bisects the sign change to its parameter: a corner
of the distance, such as a polyline vertex, is a maximum without a root.
A distance largest at an end of the interval is no root and stays no
answer. Every caller of the maximize property (the local analysis, the
global curve and curve-pair solvers and the topology solver) goes
through it.

projected_maximum_equation_has_its_actual_derivative fails on main (F'
has the wrong sign at every scale) and passes with the fix.
projected_maximum_is_a_maximum_of_the_projected_distance checks the
acceptance, the fallback and a corner on a parabola, a segment and a
polyline. The C++ has the same evaluator; recorded as WR-768.

Found auditing tangency-labs/solidcore#2840 (closed).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test: bless the projected maximum records

The curve_p1, curve_p4, curve_p5, curve_p7 and topology_solver_p2
records that the corrected projected maximum changes, and the curve_p9
record whose digits move within the comparison tolerance. The pull
request lists every record with its old and new values and the
independent measurement behind each: each curve_p4 change is the exact
negation of the old derivative; every new curve_p1, curve_p5 and
curve_p7 answer re-measures as a maximum of the projected distance; the
lost topology answers were minima on straight silhouettes reported as
maxima.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: ChrisNourse <16234527+ChrisNourse@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 09:05:50 +00:00
bherbruck efc8969f96 Pattern of 512 hole cuts: allow 13x the 128-hole time on a loaded runner (#14515) (#14518)
The test failed merge-queue batches with ratios of 10.7x to 11.1x between 128 and 512 holes against a limit of 8x plus 2 s, while every test binary ran at once. The cost is linear; a quadratic cost would be 16x or more, so the limit for this one test is now 13x. The shared 8x helper is unchanged for the other tests.

Changes a default: no

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:01:45 +00:00
Homero Thompson 881cecb909 Sketch: a face of a two-sided cut keeps its attachment (#12124) (#12212)
The caps of an extrude were named by their height, so a cut with two sides whose distances are
signed alike gave both caps of the tool the same name. Two faces of one body that claim one
name are two pieces of one face, so the history said the same face for both and a sketch on
either of them had no face of its own to keep. A two-sided extrude has no cap on its sketch
plane: its caps close the two ends of the tool, so they are named by the end they close (the
low one "bottom", the high one "top").

Co-authored-by: vdirienzo <vdirienzo@users.noreply.github.com>
2026-11-10 08:56:38 +00:00
Joseph Stewart 42b7892fa6 Construction planes: select points on 3D sketch curves (#11987) (#11990)
* Construction: reference points on drawn 3D sketch curves

* Make 3D point selection opt-in and keep references in construction tools

* Name the pending format change without 'references'; ring only wire nodes

The pending file's name is written into every design's format_pending, which made
a_cylinder_without_references_stays_at_its_base see 'references' in the saved JSON.
The selection ring for 'sketch:point' ids now skips planar points, which already
get their ring, so selected_sketch_point_aliases_* sees 3 rings again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep unsupported 3D points out of Hole picking

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:56:36 +00:00
Brett Lawson bf5cd7a88e Kernel tests: the long-thread cut test takes 6 turns and checks the exact groove volume (945 s on CI) (#14449)
* Claim: right-size the kernel long-thread test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* Kernel tests: the long-thread cut test takes 6 turns and checks its groove volume exactly

thread_tests::a_long_thread_cuts_without_a_deep_tree cut a 48-turn M8 groove
(about 19,000 triangles) through faceted_boolean. It took a median of 945 s on
the 32 vCPU CI runner and ended every full "Native Linux tests" run about ten
minutes after the other tests. Its premise, the BSP of #1250 going as deep as
the facet list, has been gone since faceted_boolean became a sewn planar tool
fed to the exact B-rep boolean (#11351). What was left was a loose volume
window (0.6 to 0.95 of the shaft).

a_long_thread_cuts_to_its_groove_volume cuts the same groove over 6 turns. The
cut must be valid, and the volume removed must lie between two analytic bounds:
the exact helix's (2 pi times the integral of r dA per turn) and that of the
section scaled towards the axis by cos(pi/48), where the 48-step facets lie
between stations. The bounds are 1.8 % apart; the old window was over a
hundred times wider. 25.5 s locally (ci profile, one P-core), against 876 s
before.

The 48-turn case stays as an ignored test (a_bolt_length_thread_...), for work
on the boolean's growth with the number of turns.

Its priority-100 override in .config/nextest.toml goes: the test is no longer
long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* Kernel tests: the ignored 48-turn thread guard names its scaling ticket (#14453)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:56:27 +00:00
Homero Thompson cf9706890f Sketch: a point snaps to the crossing of the grid the viewport draws, not to a finer lattice (#7114) (#9843)
* wip(#7114): the RED test of the snap and the grid helpers

The regression test proves the bug: a point near a crossing of the drawn
grid lands beside it (x=20.5) instead of on it (x=20.0), because the sketch
snaps on a lattice ten times finer than the grid it draws.

The helpers are in place; wiring them into the snap is not done yet.

* fix(#7114): snap a sketch point to the visible grid's crossings

The sketch snapped to a tenth of the drawn grid's spacing, a hidden
lattice between the lines the user can see, so a point placed on a
crossing of the drawn grid landed beside it.

The engine's grid helpers now hold the policy: a point near a crossing
of the drawn grid's lines lands on it, and between the crossings the
finer lattice still holds the point, so a value that is not on a
crossing (an exact inch, say) can still be placed.

The free coordinate of a point that lines up with another one follows
the same rule, with the crossing running through the coordinate it
lines up with: a point that lines up with something off the drawn grid
is on no crossing of it, so there the finer lattice holds it. With Snap
off (Sketch Palette) the grid holds the point as before.

Fixes #7114

* Sketch grid: the crossing takes the pointer that means it (#7114)

The crossing of the drawn grid's lines took the pointer whenever it was
within a quarter of a cell of it, which is wide enough to carry a point
off an exact value of the finer lattice and onto the crossing beside it:
the circle of the scenario s12_pattern_bodies grew from the radius 4 to
the radius 5.

The criterion is now two clauses, and the same for the point and for the
free coordinate of an aligned one:

    the crossing takes the pointer <=> d <= fine
                                  || (l > fine / 4 && d <= minor / 4)

The pointer means the crossing when it is within a fine step of it: that
is the crossing's own place on the finer lattice and the one right beside
it, which is the case the issue is about. Further out the crossing still
takes the pointer, but only when the finer lattice cannot hold it, that
is when the pointer is more than a quarter of a fine step away from any
point of it: a pointer that sits on a point of the finer lattice holds
that exact value, and the drawn grid does not move it.

Fixes #7114

* Sketch grid: the exact value of a lattice point is not carried off (#7114)

The crossing of the drawn grid's lines took the pointer whenever it was
within a fine step of it, and that first clause was looked at before the
finer lattice was asked whether it could hold the pointer. So a pointer
that sat exactly on a point of the finer lattice was carried off to the
crossing beside it: with the drawn step 5 and the fine step 0.5, the
pointer at 10.5 is 0.5 from the crossing 10.0 and the drawn grid took it
there, and the value the user placed was gone.

The criterion is now four rules, in this order, and the same for the point
and for the free coordinate of an aligned one:

    the crossing takes the pointer  <=>  l is not ~0 (the pointer is not
                                          on a point of the fine lattice)
                                   && ( d <= fine
                                      || (l > fine / 4 && d <= minor / 4) )

The first rule is the one that was missing: a pointer on a point of the
finer lattice holds that exact value, and the drawn grid does not move it.
That is what keeps the radius of the circle of the scenario
s12_pattern_bodies at 4: the click at x=14 lands on the lattice's own
point 14, a whole fine step from the crossing 15 beside it.

The numbers of the harness's camera (the half height 80 makes the drawn
step 5 and the fine step 0.5):

    pointer   crossing   d      lattice  l      result
    20.3125   20.0       0.3125 20.5    0.1875 20.0  (the crossing)
    14.0      15.0       1.0    14.0    0.0    14.0  (the lattice)
    10.0      10.0       0.0    10.0    0.0    10.0  (both)
    10.5      10.0       0.5    10.5    0.0    10.5  (the lattice)
    14.5      15.0       0.5    14.5    0.0    14.5  (the lattice)
    9.5       10.0       0.5    9.5     0.0    9.5   (the lattice)

With small cells the finer lattice holds more of the pointer, which is
right: with the drawn step 1 and the fine step 0.1 the pointer at 20.5 is
0.5 from the crossing 21.0, half a cell, and the lattice holds it, while
the pointer at 20.05 is 0.05 from the crossing 20.0, within a fine step
of it, and the crossing takes it.

The pointer comes from the screen, so it is never exactly on a lattice
point: the harness leaves the pointer of s12_pattern_bodies at
14.000001516401388. The tolerance of the first rule is a thousandth of a
fine step, so it swallows that noise and the noise of any other view
(both grow with the view).

Fixes #7114

* The sketch grid test reads Vec2 from solidcore_record, where it lives now

Upstream moved the plain-data Vec2 out of the geometry crate: the geometry
crate now exports the Vec2Geom trait, and the record crate owns the plain
Vec2 the grid works with. The test still imported it from the old place and
did not compile after the rebase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: a point snaps only to a crossing the grid draws

The RED tests of the two findings of the review of #9843, in the area's
existing test file (crates/engine/src/view.rs):

- a point in the cross-fade between the levels 2 and 5 must not snap to a
  crossing of 5 mm: at that zoom the grid draws the lines every 10 mm only;
- the grid's helpers must give the finer lattice point, never the pointer
  itself, when they refuse the crossing;
- the crossing must not take a pointer more than two fine steps away from
  it: with the drawn step 5 and the fine step 0.5, the pointer at 21.2 is
  1.2 mm from the crossing 20.

Fixes #7114

* fix: snap only to the crossings the grid actually draws

The step the sketch snapped to was the step of the level the grid is drawn
at, which is not always the step of the lines that are drawn. The levels 2
and 5 do not nest: each fades its own lines out over its half of the
cross-fade, so at the middle of it only the lines the two share (every
10 mm) are drawn, and a point could snap to a crossing of 5 mm that the
viewport does not draw.

The step is now the one of the lines that are drawn, and the finer lattice
is unchanged: a tenth of the level the grid is drawn at, as before. At the
half height of 50 the point at 5.3125 lands on the lattice's own point 5.5
again, where it landed before the snap to the crossings was added, and the
crossings the user can see are the ones the point can land on.

Fixes #7114

* fix: keep the fine lattice when the snap is refused

The crossing of the drawn grid took the pointer whenever it was within a
quarter of a cell of it, which is wide enough to carry a point more than two
fine steps away from where it was: with the drawn step 5 and the fine step
0.5, the pointer at 21.2 landed on the crossing 20, 1.2 mm away, where it
landed on the lattice's own point 21 before the snap to the crossings was
added.

The crossing now takes the pointer only when it is no farther than two fine
steps, so the point does not move more than that from where the pointer was.
The pointer aimed at a crossing (the case of the issue, a sixteenth of a cell
off it) still lands on the crossing, and a pointer on an exact point of the
finer lattice still keeps that value.

Fixes #7114

* test(engine): a nested cross-fade snaps to the visible crossing (#7114)

* Sketch: the drawn grid's crossings take the pointer (#7114)

* style: the array of the sketch preferences keeps the indentation rustfmt wants

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:38:01 +00:00
Ahmad Khan c3c80adf51 Path-traced renders: less speckle on polished metal (#9815) (#9817)
* claim: #9815

* GPU path render: optional clamp_indirect and a metal-aware diffuse lobe choice

A new GPU path job option, clamp_indirect (off by default), limits speckle on
polished metal: from the first bounce on, each contribution a path adds is
scaled so its largest channel is at most the limit, keeping its hue. What the
camera's first hit adds is never clamped. The option is validated
(0.000001..1000000), reported by preflight, saved with a GPU setup (a pending
design-format change) and kept by the render workspace when a setup is loaded
and saved again. It is documented as biased: it dims real caustics and glints
and also clamps the raw linear EXR master.

The clamp is compiled only into a second pipeline, built once per device by the
first job that asks for it. Jobs without it keep the ordinary pipeline, so their
images are unchanged bit for bit; even an untaken branch at the integrator's
adds moved results by an ulp on Metal.

Continuation sampling now chooses the diffuse lobe with probability
0.5 x (1 - metallic) instead of a fixed 0.5, the same in the shader's sampler,
its density and the f64 oracle (clear_coat::lobe_probabilities). Metallic 0
keeps 0.5 exactly and renders bit for bit as before; a pure metal spends every
base sample on its specular lobe. The expected image is unchanged.

* Path-traced renders: the indirect clamp reaches rough glass, volume and caustic light, and its limit moves to the light-count row's spare lane now that the volume row's carries the glass model flag

* Format

* Path-traced renders: the volume row keeps main's glass model flag; the tests build the studio lighting with its new light lists

* Lobe sampler test draws visible normals, as main's surface density now does

Main moved the base and coat specular lobes to visible-normal GGX sampling.
The sampler/density agreement test now samples them the same way, and the
metal-versus-dielectric density check compares against half the dielectric's
value, which the old even diffuse split would equal.

* Clear coat: the lobe sampler test takes the visible-normal sampler from the viewport crate's surface module, where main moved it

* CPU path renders draw lobes with the same probabilities their density weights

Main's CPU path tracer picked its diffuse lobe for half of every base sample,
while surface_pdf, which it shares, now gives a metal less of the diffuse lobe
(lobe_probabilities). Its sampler now picks lobes with lobe_probabilities, so
sampling and density describe one distribution as on the GPU, and its tests'
oracles use the same split. The render-job test that compares two preflight
replies leaves out the live RAM reading, as main's other preflight
comparisons do.

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-10 08:37:59 +00:00
glitchau a187e8dd58 Assemblies: a joint origin picked on a repeated sub-assembly stays on the copy it was picked on (#11426) (#12922)
* claim: #11426

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Joints: a joint origin picked on a repeated sub-assembly stays on that copy (#11426)

A joint origin picked on a part inside a sub-assembly that is placed more
than once landed on the first copy: the origin stored the part's
occurrence id, which every copy shares, and its frame was worked out
through the first copy. A part mated to it jumped onto the first copy.

The origin is now stored on the copy, with the occurrences inside it down
to the picked part (`inside`, written only when it is needed; one pending
format file). resolve_origin finds the snap on the inner part and carries
the frame up through them, so the solver and the other readers of a side's
occurrence keep working and now hold or move the copy. joint.origin and
joint.create origins take an optional `path` (the placement picked); the
joint dialogs send it, and a pick with no occurrence finds the nearest
placement by exact bounds instead of the display mesh. Paste New, Extract
and deleting follow `inside`; Align keeps a frame picked on another copy
in the part's own coordinates; Motion Trace shares the conversion to a
part's first copy. joint.inspect lists `inside`, and the joint schemas
describe `path` and `inside`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Joints: joint.inspect's inside is checked in the #11426 tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Joints: an origin's path may be null, and a singular placement doesn't stop picks

`"path": null` is left out, as the other optional keys are, and both joint
origin schemas give `path` the 1..64 ids the handler takes (the shared
OccurrencePath). The search for the placement a pick is on skips a placement
with no inverse instead of failing every pick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Joints: a Motion Trace and a Joint pick on a later copy of a sub-assembly work

The Motion Trace dialog sends its pick's placement path with the point it
keeps. The trace converts that point to its part's first placement and
names the copy with its own occurrence path, so the reference's path is
dropped; before, it anchored the reference on the copy a second time and
the trace was refused ("point_ref must belong to the traced occurrence").

The Joint dialog's "bodies of one component" warning compares the
occurrence a joint at each pick would hold (joints::origin_anchor), so the
same part picked in two copies is two sides, not one component.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoD5bGb8KWxkNrvkJujMvE

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:37:20 +00:00
0rdnungsamt a0dbd760b4 Viewport: a construction plane is drawn at least as large as the part, so a midplane stays visible when zoomed in (#13318) (#14469)
* claim: #13318

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Viewport: a construction plane through a part is drawn past the part's edges, so zoomed in the body no longer hides it (#13318)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:28:57 +00:00
Andrzej Błasik f048096459 Speed: a feature's bodies are checked on another core while the next features are evaluated (#14112)
* Speed: SMLib's check of a feature's bodies runs beside the features after it

* Speed: the state a refused check goes back to is saved only when the check runs beside the next features

* Speed: every new body's check runs beside the features after it, on a copy when the step left no result

A body without a step result of its own (a copy, a joined body, most extrusions) was still checked in line. The check now takes the step's result or a copy of the body's SMLib record and runs on its own thread like the others; the results stay the same.
2026-11-10 08:28:55 +00:00
Brett Lawson bcea30a641 solidcore: retire the crossing-rails refusal (WR-460); the band test (WR-542) refuses its cases with a fit (#14047)
* solidcore: claim sc#13834 (retire fillet_refuse_crossing_rails) and re-measure sc#13773

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: retire fillet_refuse_crossing_rails (WR-460); the band test refuses its cases with a fit

The crossing-rails check tested what WR-542's band test
(fillet_refuse_overlapping_bands) tests, but after the fillet's B-rep was
built, and it refused with a bare 1001 naming no size. The band test runs
right after the trace and names the radius at which the bands meet.

- delete session/crossing_rails.rs, its call in finish.rs, the
  UpstreamFixes field, its fixes.json entry, the goldens case flag arm and
  SolidCraft's setting of it;
- issue_1073: with SolidCraft's fix list the post past r 3 is refused
  BandsOverlap, fit 3, and the fit builds a solid;
- wr460_untrimmed_rails, issue_2050: the rounds the check once refused
  wrongly build with the band test, bit for bit as without it;
- fixtures 199 and 871 ask for fillet_refuse_overlapping_bands;
- issue_2652: the twisted disc's top round at 1.9586 (sc#13773's repro,
  877 s and a bare 1001 before sc#13774) builds, check_brep L2 clean;
- WR-460 addendum naming the retirement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: drop the retired crossing-rails check's panic-site row

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

* solidcore: the WR-460 addendum's band test names its fit by default

fillet_gn_section_generator was retired on main (#13945), so WR-542's
refusal names its fit with no flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:28:52 +00:00
bherbruck d4860e0863 Render workspace tests: wait up to three minutes for a render, not thirty seconds (#14503)
progressive_image_controls_route_to_the_registered_host failed with 'render wait timed out' when the whole ui-egui suite ran at once, because a software-GPU render did not finish in 30 seconds on a loaded runner. The wait returns the moment the job reaches a terminal state, so the larger budget costs nothing when the box is quiet.

Changes a default: no

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:28:50 +00:00
bherbruck 9de15ea9bc Fix three more timing-flaky tests that fail merge-queue batches (#14499)
* Make the settings-search shortcut test and the profile import test wait for what they assert

collapsed_shortcut_results_enter_reveals_the_command... ran a fixed four frames before reading the search results and thirty before checking the revealed row, and the profile import test ran six frames before reading the profile names. On a loaded merge-queue runner those frames were not enough and a whole batch failed. Both now poll for the condition they assert.

Changes a default: no

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Make the space-mouse retry test bound its probes by the time that really passed

The test slept 700 ms and then asserted at most four open attempts with a 300 ms wait. On a loaded merge-queue runner the sleep overshoots, more waits elapse and the bound fails. The allowed attempts now grow with the measured elapsed time.

Changes a default: no

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:21:37 +00:00
Mateusz Sych f5263a4853 Joint drive: a mirror inside the part a joint moves stays cached (#14271) (#14295)
* claim: #14271

* Joint drive: a mirror inside the part a joint moves stays cached (#14271)

A mirror of placed bodies keyed its cache on the absolute frames of its own component and of the placements it was picked at, so every new pose of its own part evaluated it, and every feature after it, again. Its result depends on those placements relative to its own frame only, so it now hashes them that way, quantised as the other placement reads are. A plane read from model geometry still counts its own frame.

* Mirror: frames in the mirror's own component through the occurrence path (#14271)

A mirror of placed bodies now finds the copy's frame and the frame its body was picked in relative to its own component by the occurrences the two placements do not share, and keys its cache on exactly those frames. What they share cancels exactly, so a joint that moves the mirror's part with what it mirrors gives the same numbers at every pose: the cached result is the one a fresh evaluation makes, bit for bit.

---------

Co-authored-by: MateuszSychXpl <151755914+MateuszSychXpl@users.noreply.github.com>
2026-11-10 08:20:31 +00:00
0rdnungsamt fbabfca7a4 Export STL and 3MF: a design with one body starts with that body selected (#13098) (#13100)
* claim: #13098

* Export: the mesh export dialog starts with the design's only body selected (#13098)

Export STL, Export 3MF and Send to Slicer opened with an empty Bodies list, so
Save stayed disabled even when the design has a single body. With exactly one
body, that body is now filled in. With more bodies nothing changes, since
nothing says which one to export.

The old behaviour is kept behind the new preference export_selects_only_body
(Preferences > General > Files), on by default. Tests that click a body into
an empty list turn it off; scenario s14 now saves without that click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:29 +00:00
PaddleStroke 967b0d4401 Canvas: straighten the image along a line drawn on it, to horizontal, vertical or an angle (#11989) (#12700)
* claim: #11989

* wip: canvas.straighten turns a canvas so a line drawn on it gets a chosen direction (#11989)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: Straighten card in the canvas menu: pick two points along an edge, choose the direction (#11989)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Canvas Straighten tests: bring Vec2Geom into scope and type the target angle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Canvas Straighten test: a line at -175 degrees turns -5 degrees to lie horizontal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* kernel-cases: canvas.straighten is a reference-image command with no kernel case

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Canvas Straighten: once both points are picked, the hint asks for the direction and the Straighten button

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Canvas Straighten: preserve locked canvases and current UI hints

Preserve current upstream behavior while applying the reviewed correction. Central native builds and strict workspace linting pass; remaining runtime and screenshot checks are recorded in the PR.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:26 +00:00
PeppaWutz ab07e1fd28 Viewport: double-click a face to edit the feature that made it (#10989) (#11401)
* Viewport: double-click a face to edit the feature that made it (#10989)

A double-click on a body face in the 3D view now opens the editor of the
feature that made the face, as a double-click on its Browser or timeline
row does. A fillet or chamfer face puts the arrow by the face clicked.

Components keep their double-click first (edit a linked one in place,
activate another); a face of a component that is not active, a face no
feature made, and double-clicks with a modifier, inside a tool, dialog or
sketch are left as they were. Single click and box selection are
unchanged.

* Viewport: a face of a moved component opens its own feature (#10989)

A double-click's point is in the world, while the history the face is looked up in is in the component's own frame. The point is now taken back through the active placement, as it is shown (a move not captured yet included), so a later feature beside the face is no longer opened instead.
2026-11-10 08:20:24 +00:00
Karl Von Richter 840062c991 Weldments: End Cap closes frame member ends with a plate (#4003) (#8606)
* Weldments: End Cap closes frame member ends with a plate (#4003)

End Cap (WELDMENTS > CREATE, `frame.end_cap`) closes the open ends of
frame members with plates, one body per end named after its member.

- The plate covers the outside of the profile: a closed section's outer
  outline; an open section's outside with its rounds and chamfers, slots
  and the gap between flanges closed along the bounding rectangle.
- Offset (off by default) sets it in from that edge, as a ratio of the
  thickness or a length; Corner Chamfer cuts its outside corners.
- Direction: Outward on top of the end; Inward cuts the member back and
  sets the plate where the end was. Two new original direction icons.
- Refused, leaving the document unchanged: an inset that leaves no
  plate, a chamfer too large for its edges, a face that is not an end of
  a frame member, the same end picked twice (by its exact plane, however
  it was picked), hostile values.
- In assemblies: an inward cap cuts its member where the member is
  placed, even in another component or moved by a body offset; moving the
  member's occurrence rebuilds the cap; a cap copied without its member
  is reported as using what is outside the copy.
- A cap made while another is suppressed never takes that one's name, and
  editing a cap keeps each remaining end's name with that end: a new end
  never takes a kept end's name, and a removed end's name is kept back.
- Caps follow member edits, renames, undo and reopen, and the dialog
  remembers its sizes with "remember dialog values" on. Editing a cap
  whose end can no longer be found starts with no faces picked and names
  the missing end, rather than dropping it unasked.
- One pending format file, input and output schemas, pending locale
  strings in 12 languages and attribution rows. No kernel changes.

Tested in crates/engine/src/cmd/frame_tests.rs (hand-derived volumes),
crates/doc/src/frame_tests.rs and crates/ui-egui/src/dialogs_frame_tests.rs;
frame.end_cap has its tests/kernel-cases/EXEMPT line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ui(test): use shared text lookup in dialog assertions

Use solidcraft_ui_text::tr_label for selection-picker accessibility labels, matching the dialog renderer after the translation API moved out of ui-egui. This fixes the End Cap merge-queue build against current main while preserving both message IDs and legacy English labels.

Signed-off-by: Karl Von Richter<karl@embeint.com>

---------

Signed-off-by: Karl Von Richter<karl@embeint.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:22 +00:00
0rdnungsamt 2e0e4815f1 Make the AI panel's Add agent and Refresh buttons the same size (#14443)
* claim: #14385 (Add agent and Refresh buttons the same size)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Make the AI panel's Add agent and Refresh buttons the same size (#14385)

Add agent… on the panel's Agent row was drawn as a small button next to a
normal Refresh. It now uses the same button style as Refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:19 +00:00
PaddleStroke 4f7ca2c6bf Sketch: show the cursor's coordinates whenever the pointer is over the view (#11070) (#12702)
* claim: #11070

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: sketch cursor coordinates with no tool running (#11070)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: no idle readout in 3D sketches (#11070)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch cursor readout: read the point under the pointer from the drawn sketch (#11070)

The selection hover can be empty under a selection filter and can hold a
dragged point's place from before the drag; look for the nearest shown point
in this frame's sketch instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch coordinates: ignore hidden points and match the picking reach

Preserve current upstream behavior while applying the reviewed correction. Central native builds and strict workspace linting pass; remaining runtime and screenshot checks are recorded in the PR.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 08:20:17 +00:00
dudedagger42 ed1d8a5682 Hole: a countersink's cone stops at the hole's depth (#10697) (#13206)
The countersink tool's cone always ran down to 90 % of the hole radius,
however deep the hole was, so a blind countersunk hole in a thin plate
broke through the bottom and a shallow one cut deeper than its depth.
The cone now stops at the hole's depth when that comes first.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 08:13:14 +00:00
Nik cbb1ab5a42 Hole: a deleted sketch point drops only its own hole (#8087) (#8111)
* claim: #8087

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a deleted sketch point drops only its own hole (#8087)

A Hole drilled at several sketch points drills at the points its sketch
still has and its warning names the ones that are gone; with none left
it fails, naming them. The feature keeps the ids, so undo brings the
hole back. Editing the Hole opens without the gone points, so OK drops
them and clears the warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole dialog: read the world through session_world after main's Result change (#8087)

main's Session::world_state now returns Result, so the kept-points filter
takes the same Arc<ModelState> helper the point lookup above it uses.

* Hole tests: Vec3 comes from solidcore_record on current main (#8087)

* Hole tests: ask classify_point instead of the removed Body::contains (#8087)

* Hole test: fail when classify_point errors instead of reading it as Outside (#8087)

The check that the hole at `a` is drilled defaulted a classification error to
Outside, so it would pass without classifying anything. Both point checks now
expect a classification (CodeRabbit review on #8111).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: name the missing-point list distinctly (#8087)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:47:49 +00:00
Daniel 005bbe6711 Hole: the drag handle behaves like the Rest, Boss and Snap Fit handles (#6818) (#7633)
* Placement handles: a Spec with places, the dialog kept in the app (#6818)

A tool's handles stand at one place (a Rest) or at one per item of its first input (a marker on
each): `Spec::frame` becomes `places`, each with a key, and `move_to` and a new optional `click`
name the place by it. Every tool gates itself through `serves(app, d)`, so a tool can keep its own
preference instead of the shared one. `show` no longer takes the dialog out of the app: the pointer
is picked under with the dialog open, so a drag snaps as a click does, and the dialog is taken
out only around a change. `handle_move` takes those hits instead of picking itself.

`motion::grab` measures the gap from where the button went down, not from the pointer when the
drag starts: a handle that also takes clicks only knows it is dragged once the pointer has moved
a few points, and measured there the gap put every drag one step behind the pointer.

Rest, Boss and Snap Fit adapted; no change in what they do.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: the markers are a Spec under place_gizmo (#6818)

Step 2 of #6818. A Single hole's handle is `place_gizmo/hole.rs`: a marker on each placed hole,
drawn and dragged by the shared mechanics, so a hole gets what a Rest has: the marker's press
area, the grab offset that keeps the hole where it was taken instead of jumping under the
pointer, the footprint of its mouth while it drags, the depth arrow starting past the marker and
the value box keeping off it, and the manipulator state while it drags. A click on a marker still
takes the hole out; the markers stay behind Create Hole › Move holes by clicking or dragging, not
the shared Placement handles setting, and holes on sketch points (Multiple) have none.

`hole_place.rs` keeps what is the hole's: its face and rim snaps, the moves of its face places
and the pick that moves a hole. Its handle loop and `place_gizmo::marker` go.

Tests: a press off the centre keeps its gap, one marker per hole and a drag moves only its hole,
a click within the marker's reach takes the hole out, the arrow's clearance follows the setting.
The 18 hole placement tests pass unchanged (`hole:<n>` names, snapping, preferences).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Placement handles, Hole: fixes from the review (#6818)

A hole being edited whose face no longer resolves keeps its marker: `hole::places` falls back to
the `direction` the edit restored, as a Rest's frame does (before, the marker vanished with the
face). A marker drag moves the hole only while the face input is the active one: the hits were
picked by the active input's rules. `place_gizmo::face_pick` is the one face pick for Rest, Boss,
Snap Fit and the hole. After a click took a place out, the markers' states are left alone for
that frame instead of going to the place that moved into the index. `Spec` says where the dialog
is while each callback runs.

Tests: the hole's markers follow Move holes by clicking or dragging, not Placement handles; a
hole whose face is gone keeps its marker through `direction`, and loses it with neither.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: a reference edge holds the hole to its line, and the marker shows how much is left to move (#6818)

With one reference edge picked, the hole's distance drives its place instead of following it: a
drag of the marker, or a pick elsewhere on the face, moves the hole along that edge at its typed
distance (`hole_refs::drag_to`, through `ReferenceFrame::place`), and the distance text, an
expression included, is left alone. With two edges the hole moves anywhere again and a move sets
both distances, as a move did before any edge was picked. Before, a move always measured the
distances again from wherever the hole landed.

The marker says so: a `Spec` tells how freely each place moves (`Freedom`: anywhere, along a
line, not at all), and the marker's arms follow it: the four screen cardinals, two along the edge
as the view shows it, or none, the dot alone stepped back, with no press area, hover or move
cursor. A line seen nearly end-on, or a face seen nearly edge-on where a pick is refused anyway,
counts as held: a drag there would move the hole by centimetres per pixel.

The marker's pick and move go by the place input whichever input is active, so a reference edge
input waiting for its edge no longer leaves the marker lit but dead.

Tests: one edge holds the hole to a line the marker drags along; a typed distance survives the
drag; a pick elsewhere on the face keeps a held hole on its line; two edges free it again and a
drag sets both distances.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Hole: reference edges hold only the hole they place (#6818)

With several holes in one Hole dialog and one reference edge picked, every hole's marker and drag took the first hole's line: a drag of a hole on another face wrote a point on the first hole's line into it, off its own face, and a pick on that face did the same. The edges place the first face pick only (OK refuses them with more than one hole), so freedom and drag_to now go by the item index and hold that hole alone; any other hole moves anywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a marker's press, hover and look go by a stable id, not the place's index (#6818)

The markers' widget and animation ids were built from each place's key, the item's index in the first input. When a click took a hole out, the next hole took its index and with it the hover of the one taken out: egui hit-tests by the last frame's rect for that id, so the surviving marker was hovered on the next frame, drawn hot with the Move cursor, and eased back over 0.22 s. The guard meant to stop that (`settled`) could never be false after a removal.

Each place now has an id by its order, kept while it moves (its key can change as a round face's halves come and go) and renewed for every place when one is gone. The guard is removed. The marker's hot factor is published as `<name>:hot` for the scenario tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the marker tests prove what they claim (#6818)

The click test passed with the old 9 pt reach too: a click 14 pt off the centre that missed the marker went to the canvas pick, which takes out a hole picked within its 5 mm radius. The hole is now 0.5 mm across, so a pick that missed the marker would move it and only the marker takes it out. The grab test's comment said the grab was outside the old handle's reach; it was inside the old 18 pt square, and the test discriminates by the gap itself (about 0.9 mm without it, and also when the gap is measured where the drag starts instead of at the press).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Placement handles: a place held still takes no press, so the view keeps the pointer there (#6818)

A hole held by one reference edge seen nearly end-on (or its face edge-on) is drawn as the dot alone and registers no widget, but it was still listed as a drawn handle: navigation and the depth arrow yielded an 18 pt disc around it in which a drag did nothing. The drawn handles now say whether each takes a press; only those keep the pointer from navigation and the arrow, while the value box still keeps off every drawn dot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: tests for the marker's cursor, Select Other yielding to it and the dragged footprint (#6818)

The behaviour changes the change lists had no test: over a hole marker the cursor is Move (it was Grab), a press held still on it is the marker's and opens no Select Other list (without markers the same hold does), and the outline while a hole drags is its mouth, the counterbore's or countersink's diameter when it has one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a drag along one reference edge keeps the measured distance, not the rounded one in the field (#6818)

drag_to placed the hole at the distance field's text, which shows a measured value rounded to the document's precision, while OK sends the measured value. It now reads each distance as sync does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole's freedom follows a design change in the same frame (#6818)

freedom read the reference frame cached for the edges without its revision, so in the frame after the design changed it could still hold the hole to an edge that was gone. It now finds the frame again when the revision moved on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a pick a held hole's line cannot reach says why instead of doing nothing (#6818)

With one reference edge, a pick elsewhere on the face moves the hole along the edge's line. On a face the line leaves before the pick (an L-shaped face, say), the pick did nothing and said nothing; the dialog now says the line leaves the face there and how to move the hole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a held hole that cannot follow says so on a drag too, until the inputs change (#6818)

The message for a pick the held line cannot reach is now set through the dialog's refusal, so a changed distance or edge clears it; the marker drag gives it as well; it is shown only when the line leaves the face, not when the distance does not evaluate (which has its own error); and it tells where to pick: where the line crosses the face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face keeps its marker, standing on the face's normal where it is (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a tapped hole's dragged outline is its tap drill, not the hidden Diameter field (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: where two markers' reaches overlap, the nearer one takes the press (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the held-line refusal reads as guidance, with no Create Issue (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: a hole on a curved face takes the face's normal before a stored direction, so Edit Feature does too (#6818)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hole: the overlapping markers' test clicks its second hole clear of the first one's depth box (#6818)

egui 0.37 makes the depth box a little taller, so a second hole clicked level with the first
landed on it and was not placed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VYMtcRVatHGG6YWKYjp89v

* Hole: several holes on one face keep their markers through the shared Spec (#6818)

With Several holes on one face on, every hole on a face gets its own
placement marker, as it had its own handle before the markers moved to
place_gizmo. A drag moves that hole only, onto the face the other holes
are on too, and a click on the marker takes that hole out. The marker
names a hole by its item in the face input; hole_place maps it to the
hole's number for several_change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-10 07:47:47 +00:00
Jackson Oursland 3a4f7a1a1e Render preview: product blocks with stable palette slots (#7468)
The live product preview built every product vertex again whenever the scene
changed, so an appearance edit in the Render workspace rebuilt and re-uploaded
the whole scene. Product triangles are now kept in blocks of 64 bodies, keyed
by their geometry, with each body's and face look's colour in a stable palette
slot (ProductCache, as the model scene keeps its own): a colour or opacity
edit rewrites palette entries and uploads no vertex, an opacity class change
rewrites a block's runs. PBR triangles keep their own stream. gpu_scene keeps
its signature (a fresh cache).

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-10 07:47:40 +00:00
Léon van Velzen 16c720dfbe Scale: stretching a body of flat faces keeps its faces flat (#14422) (#14470)
A non-uniform solid.scale sent every body through SMLib's general
transform, which turned each face into a B-spline surface, planes
included. The kernel now maps the B-rep record itself when the matrix
keeps handedness and the body has only planes, splines, lines and
conics: points, plane axes and control points are mapped, topology,
parameters and pcurves stay as they were, and tolerances grow with the
stretch. A circle or ellipse edge maps its NURBS form exactly and is
labelled as the image ellipse. Reflections and bodies with cylinders,
cones, spheres, tori or revolutions still go through SMLib.

Co-authored-by: Leonvv <lbvanvelzen@gmail.com>
2026-11-10 07:44:08 +00:00
MarkusRe 8e0219403f Kernel: joining or matching two surfaces refuses a control net that was mixed after it was built (follow-up to #14292) (#14482)
* srf_tool::p3: test that join and make_compatible refuse a piece mixed through cpt_mut (#13751)

A non-rational piece with one weighted point, joined with a rational
one, gets weight 1.0 on that point without its coordinates changing.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* srf_tool::p3: join and make_compatible refuse a net mixed after construction (#13751)

Surface::new refuses a net mixing weights with NOW, but cpt_mut (and
set_cpts_and_knots, set_size_indices) can mix one later.
make_rat_compatible judges a surface by Pw[0][0] alone: it would give
the weighted points of a "non-rational" piece weight 1.0, moving them,
or keep NOW as a weight on a "rational" one. Both callers now check
every point in use first, through Surface::refuse_mixed_rationality,
and change nothing on refusal.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-11-10 07:42:24 +00:00
tr1pp4 05e9020413 Dialogs: a right-click in the viewport confirms the current input, and on the last one OK (#6159) (#6160)
* claim: #6159

* Dialogs: with a preference, a right-click in the viewport confirms the current input, and on the last one OK (#6159)

With a feature dialog open and Preferences > General > Dialogs >
"Right-click confirms dialog inputs" on, a short right-click in the
viewport (a click, not a right drag: the gesture and camera checks are
the ones the context menu uses) confirms the dialog's active selection
input:

- it goes on to the next input that is still empty;
- once every input holds something, it runs OK as Enter does (not for
  dialogs Enter doesn't apply, such as Delete's confirmation);
- an empty input the dialog can't make its feature without stays active,
  and the status line says what to pick ("Select Mirror Plane first");
  the hint is cleared once the right-click moves on.

The preference is off by default, so a right-click over a dialog does
nothing unless someone turns it on. Without a dialog a right-click opens
the context menu and inside a sketch tool finishes the tool, as before.
The label, its tooltip and the hint are in a pending locale file.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Tripper <tripper@localhost>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 07:41:41 +00:00
0rdnungsamt 92c2103ffb Patterns: copies of a hole placed by sketch points below the part drill into it (#14050) (#14391)
* claim: #14050

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Patterns: copies of a hole placed by sketch points below the part drill into it (#14050)

Each copy's side is judged at its own spots, as the source's was, instead
of at the source's spots after its bore was already cut. Analysis and test
name by Ehuntabi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:40:56 +00:00
Brazz 170f9e240c fix(blend): name a size that fits only when a blend built at it (#14289)
A blend refused as too large is searched for the largest size that builds
(fillet_max / chamfer_max, bisecting by building candidates), and the refusal names
that size. But a candidate failing any way other than "too large" (its check refusing
the result, say) stopped the search with an error, and when nothing built the
evaluator kept the kernel's first estimate. Either way the message named a size no
blend had built, and it could be one that is itself refused: an estimate that scales
with the request (r cos(theta) where two chains meet across a shallow fold) sends
every retry down by the same fraction and never names a size that builds.

- largest_that_fits: a candidate failing as an operation narrows the search like a
  refusal (a size that does not build is not one that fits); bad input and the
  kernel's own faults are still errors. It returns FitSearch: the largest size built,
  or the smallest size tried and how it failed (fillet_max_why / chamfer_max_why;
  fillet_max / chamfer_max keep their signatures).
- eval's with_largest_fit: names a size only when a candidate built at it. With none,
  the kernel's estimate is removed (without_fit_note) and the message says what the
  smallest candidate met: "no smaller radius builds either (down to X mm: ...)".

Tests: kernel blend tests (a search that builds nothing keeps its smallest refusal; a
candidate failing the check narrows the search; the fit note comes out with its
separator) and doc eval tests (a size nothing built is not named; a search stopped by
another failure says it). The engine's blend_fit tests (verified sizes) are unchanged.


Claude-Session: https://claude.ai/code/session_01JLpvyUWYrVisqsvztWRkGu

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:40:54 +00:00
thocsmith a20d08b753 Show/Hide: V on a selected sketch profile hides its sketch, and a hidden sketch's selected profile is no longer drawn (#13026) (#13035)
* claim: #13026

* Show/Hide: V on a selected profile hides its sketch, and a hidden sketch's selected profile is not drawn (#13026)

V (Show/Hide) ignored a selected sketch profile, so it had nothing to
toggle. It now takes the profile's sketch, as a selected face stands for
its body. The viewport also filled a selected profile whether or not its
sketch was drawn, so hiding the sketch from the Browser left the profile
on screen; it is now only highlighted while view::sketch_shown says the
sketch is drawn, as a selected edge is only drawn while its body is.

Fixes #13026

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: thocsmith <193096300+thocsmith@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:40:51 +00:00
Homero Thompson 6802e2d86a UI: a new fillet opens at the tool's 2 mm, not at 2 inches (#12418) (#12574)
Co-authored-by: vdirienzo <vdirienzo@users.noreply.github.com>
2026-11-10 07:40:49 +00:00
dudedagger42 2b0e51df23 Combine: a tool whose feature is suppressed is left out instead of failing (#13474) (#13892)
* Combine: a tool whose feature is suppressed is left out instead of failing (#13474)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Combine: only a suppressed feature before it excuses a missing tool (#13474)

A suppressed feature after the Combine that would name the missing tool
no longer lets it build without that tool; it is still "unknown body".
Also formats the test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 07:40:44 +00:00
Brett Lawson 255f7ab0af solidcore: retire the sweep flags that change no result (A14) (#14478)
revolve_arc_centre_near_axis_is_sphere, revolve_arc_touching_axis_is_horn_torus and
translation_sweep_regularize are removed: the code each turned on is now the only path,
with the field, preset line, fixes.json entry and the tests' flag-off halves gone.

Part of #14246


Claude-Session: https://claude.ai/code/session_01SdcgEtwSrdwZxqTQp5MfnU

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:40:22 +00:00
Ehuntabi ba61db7c33 Spanish: translate the 265 help texts still in English (#14485)
265 of the 325 help.* messages in es.json were copies of the English text
(fr, de, it, gl and ca have over 300 translated). They are now Spanish, with
the terms the catalog already uses. Placeholders match en.json.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 07:28:40 +00:00
Daniel 6b91257c02 Sketch Intersect: say what was added when Projected Geometries hides it, and add nothing for a repeat pick (#12302) (#12304)
* Sketch Intersect: tests for a result Projected Geometries hides and for a repeat pick

With Projected Geometries off, an Intersect from its dialog adds a point that is not drawn and leaves the status line empty, and the same pick again lays a second link and point on the first. These tests fail on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Intersect: say what was added when Projected Geometries hides it, and add nothing for a repeat pick

After Intersect or Project from its dialog, the status line says what was added and, when the sketch hides linked geometry, that Projected Geometries is off in the sketch palette. Such a result used to show nothing and say nothing.

Intersect now skips what the sketch already holds, as Project does: a reference whose curves and points are all linked into the sketch adds nothing, and a pick of nothing new is refused ("already intersected into this sketch"). For Intersect a point on its own counts as present when a linked point sits there, since cutting a curve or an edge gives points; Project's check is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Intersect: test that a repeat pick's refusal offers no Create Issue

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Project and Intersect: a pick the sketch already holds is guidance, with no Create Issue

The refusal "already intersected into this sketch" (or "already projected") says the pick is in the sketch already, not that the design failed, so the dialog shows it as a hint, as it does for a command that is not available here (#10181).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Intersect: the new status messages in Arabic, Hebrew, Japanese, Vietnamese and Chinese

The complete catalogs must carry every English message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Project and Intersect: the status names a point that stands beside a curve

A Project of an edge and a vertex beside it said only "added 1 curve". A point counts on its own when no curve uses it (a curve's ends and centre are points of its link too), and both are named: "Project added 1 curve and 1 point to the sketch."

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Project and Intersect: count lone points once over the sketch

The status counted the points that stand apart from curves by searching every point and curve for each returned point; it now builds the curves' points and a point index once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Intersect: a cut at a face corner is not "already intersected"

A sketch on a face links the face's border. A cut that landed on a border
corner was taken for a point an earlier Intersect left there, so it was
refused and nothing was added. Only a linked point that no linked curve
uses now counts as an earlier cut; a repeat cut of the same edge is still
refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Intersect: the added-links message takes tr and format from solidcraft_ui_text, where main moved them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:26:32 +00:00
CamWight 075336bfb2 Render: draw an orthographic picture tile by tile (#5624) (#6483)
* Render: pin the product image's output before it is drawn in tiles (#5624, W17b S1)

The decoded rows of five product renders (orthographic on a transparent background, perspective on a
solid one, a PBR surface, two glass layers sorted back to front, triangles crossing every edge of the
picture), taken on this tree. The next change reshapes ImageTask into a prepare stage, tiles and a PNG
sink; they must not move. The PNG bytes are not pinned: their compression depends on the deflate
backend the build unifies (flate2's zlib-rs when the UI crate is built alongside, miniz_oxide
without), not on this code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Geom: the pixel grid of a paper rectangle (#5624, W17b S1)

One rule for where a picture's pixels lie on paper, shared by the picture renderer and the writers
that place it: anchored at the rectangle's lower-left corner, rounded outward (W = ceil(w / p - 1e-9)
with p = 25.4 / dpi), so the overhang is at the top and the right; rows run top-down. At most
65,536 px a side; nothing caps the total, as pictures are drawn in tiles and strips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Render: pictures drawn tile by tile into any pixel window (#5624, W17b S1)

The CPU product renderer, reshaped so drawings can use it: one rasteriser (`Raster`) prepares a
scene once (appearances, projected triangles, glass sorted back to front), then draws each tile of
the picture on a canvas of its own. A sample's position comes from its whole-picture index, so tiles
put side by side are the picture drawn whole, to the byte.

- `ImageTask` (render.image) is that rasteriser over one whole-picture tile from the product camera,
  then its PNG: the same output, pinned by the previous commit's rows.
- `PictureTask` draws a `PictureRequest`: a `Projection` (the product camera, or an `OrthoFrame`,
  W17a's view frame as plain data: a `Plane` basis, a scale and a paper shift, on a
  `geom::pixel_grid::PixelGrid`), any list of `PixelWindow` tiles, `Supersample::One` (pixel centres)
  or `Two` (i + 1/4 and i + 3/4), a `BodyRole` per body (`DepthOnly` hides what lies behind it and
  draws nothing itself) and an optional background (none: transparent). Each tile comes back as
  straight-alpha sRGB RGBA rows, blended in linear light.
- The orthographic map is the frame's paper map, onto the grid, so lines drawn from the same frame
  register with the pixels (to 1e-9 mm in the test).
- Limits: 65,536 px a side, no total cap; each tile under the resolver's `RenderLimits`, as the
  product image is; at most 65,536 tiles; the prepared lists as a product image's; pixel tests up to
  a fixed 400 M a picture (128 M for a product image, as before), counted at admission by the one
  projection the raster uses, as main counts a product image's, and only where a triangle meets the
  tiles asked for. They are counted tile by tile, so overlapping or repeated tiles count each time
  they draw a triangle again. Each tile also looks at every triangle again, so tiles times triangles
  is capped at 2^28 tile visits (1024 tiles at the triangle cap), checked first.

Not here: the drawing light, stored per-tile bins (S2, measured), the paper scene's picture item
(S3), 4x sampling, and `raster::render`, the snapshot rasteriser, which stays as it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:26:29 +00:00
CamWight 70c2312f16 View DXF: its lines come from one module both view commands share (#5866, W07 V1) (#6482)
The view DXF (file.export_view_dxf) finds its lines in four files private to the command: the
export meshes, the projection, the hidden-line scene and the progress stages. Drawing views
(W07's drawing.view) need the same lines, so the four move to engine/src/mesh_lines, with
three changes that let a caller other than the DXF use them:
- prepare takes the bodies to draw from its caller (the DXF passes the shown ones), and
  names the caller's command in its errors;
- the lines are seen from a View (an origin, a right/up/back basis and, for perspective, the
  eye's distance) instead of a viewport Camera; the DXF builds one from its camera, with the
  same arithmetic as before;
- a sketch's polyline (Part) belongs to the module, so the sketch code no longer defines what
  the scene draws.

The DXF writing stays in cmd/view_dxf.rs, with connect (the dashed-line joining), and the stage
names and cancellation text stay the DXF's. Nothing else changes: the module is the DXF's own
code, moved, and the DXF writes the same bytes as before for every case checked (see the PR).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:26:26 +00:00
SS-EN df127b45d5 Browser: hovering a feature or joint row lights it in the viewport (#4417) (#4418)
* claim: #4417

* Browser: hovering a feature or joint row lights it in the viewport (#4417)

A feature row sets the viewport's hover_feature, the same path the timeline's
items use; the browser takes it over only while its row is hovered and clears
only what it set. A joint row lights the joint's glyph in the hover colour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Joint glyphs light with the highlight rim bodies use (#4417)

A hovered joint draws the hovered edge's dark core over its light halo, and a
picked joint the selected edge's core over its rim, at the same widths as
body edges, so joints light like the rest of the model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hover: placement joint rows, timeline takeover and repaint (#4417)

A joint row under a placement's Joints folder lights its glyph as the
root folder's rows do. The timeline's own write of the hovered feature
drops the Browser's claim, so moving straight from a row to its timeline
item keeps the feature lit. Finalizing repaints when the feature or joint
hover changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:26:12 +00:00
jyviko b34a0ad748 UI kit: the shared crate solidcraft-ui-kit (closes #14251) (#14492)
* Theme files: the built-in themes are host data

theme_files reads the built-in themes from a table the host installs
(install_builtin, once per process, like the icon set and the tab table)
instead of including ui-egui's generated table. SolidCraft keeps
generating its table from assets/styles/ui/themes and installs it with
theme::install_builtin_themes() in SolveApp::new, test_support::host_data
and both apps' start. builtin() is empty until then.

Tests that iterate the shipped themes now install the host data first,
so none of them passes on an empty list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Kit tests: the ones that need SolidCraft's data are SolidCraft's

Before the kit moves into a crate of its own, its tests split by what
they need:

- Tests that read SolidCraft's shipped themes, tab table, icon set,
  fonts, view styles, expressions or panel runtime move to ui-egui:
  kit_host_tests.rs (actions, checks, fields, layout, navigation,
  panel), theme_files_tests.rs (26 theme-file tests, with the 1-bit
  checks and the original built-in ids), kit_gallery_tests.rs (the
  visual-style dropdown, now an app specimen) and
  navigation_bar_tests.rs (SolidCraft's slot catalogue), mounted from
  lib.rs. Bodies are unchanged apart from paths.
- The navigation bar component's own tests (plain data) are
  nav_bar_tests.rs beside nav_bar.rs.
- The kit gallery draws on the kit's test context (egui's default faces,
  the kit's catalog); check_elements takes the context, so SolidCraft's
  app specimens still use its fonts. The kit's dropdown_icons specimen
  shows plain options. Ribbon and history bar tests take their accent
  from the theme crate (TabAccent::for_ramp, the same value SolidCraft's
  MODEL and SKETCH tabs give).
- Settings search tests name their own page numbers (the same 2 and 3).
- SolidCraft's two-colour theme ids and the tab fixture are host test
  support (test_support::{is_two_colour, tab_fixture}); theme file
  fixtures shared by both sides are theme_files::fixtures; the raster
  helpers and the host window marker are the kit's test_support.

Items the moved tests reach are pub(crate) (theme_files' parse_color,
resolve_base, slot, ...; fields' literal and scrub helpers; layout's
selection_ink; the feature window's background path), and the gallery
coverage test exempts the parsers and accessor among them.

Path fixes: checks.rs paints through the kit's icons, blur_native names
the viewport GPU crate's Renderer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* UI kit: the shared crate solidcraft-ui-kit (#14251, step 2)

The kit (crates/ui-egui/src/ui_kit/) and its components (ribbon, app bar,
history bar, navigation bar and its drawn bar nav_bar, view compass,
preferences window, start page, window chrome, frame, blur, theme files
and options) move with git mv into crates/ui-kit, a shared crate
(Class::Shared, [lints] workspace, licence, README). The kit's mod.rs is
the crate root; the components are modules beside it.

Dependencies: shared crates only (theme, ui-registry, ui-text, color,
viewport-gpu and viewport-egui for the blur backing), egui, egui-wgpu,
serde, serde_json, log, web-time, tiny-skia, arboard (desktop), muda
(macOS). `cargo xtask shared` builds and tests it on its own (288 tests).

Path fixes only, otherwise:
- In the kit, `crate::ui_kit::` is `crate::`; what was crate-visible is
  the crate's public API (pub(crate) -> pub), since SolidCraft uses it.
- ui-egui mounts the crate where the modules were (`pub use
  solidcraft_ui_kit as ui_kit`, `pub use solidcraft_ui_kit::{ribbon, ...}`),
  so SolidCraft's code and both apps keep their paths. The muda
  dependency moves with window_chrome.
- The kit's test fixtures SolidCraft's tests use (test_support, the
  gallery and its element! macro, theme_files::fixtures, the blur and
  panel fixtures) are behind a `test-support` feature, which ui-egui's
  dev-dependency turns on.
- SolidCraft's source guards (raw widgets, sliders, checkboxes,
  disclosures, colour and font literals, catalog literals, host tab
  names, command ids and message ids) read the kit crate's sources under
  the names they had in ui-egui (test_support::kit_files); a component's
  `crate::` paths are the kit's. They still fail on a SolidCraft tab name
  or message id put back into kit code.
- xtask's layer table and container exemption, docs/architecture.md,
  docs/layers.md, docs/ui-kit.md, the UI skill and the figure generator
  name the new paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* UI kit: the whole-number settings field is public, as the Design page calls it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* UI kit: the whole-number field and the copy cell are public, as SolidCraft calls them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* UI kit: the view compass's tip text is a translated message

The compass built its hover text with a hard-coded English format string,
so it stayed English in every language. It now reads the whole sentence
from the kit's ui. vocabulary (ui.view_compass_tip, and
ui.view_compass_tip_snap with the Shift hint), with the axis as the
{axis} argument, the way the kit formats other text with arguments.

A host test hovers a tip in Japanese and expects the catalog's sentence;
on the old code it read the English text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* Preferences: the colour vision sample is SolidCraft's, with a message id for Bends

The sample (fixed and projected sketch lines, axes, bends, draft and a
failed feature) and its names were in the kit, though only SolidCraft's
Interface page shows it. It moves beside the status palette sample in
prefs::figures; the kit keeps the figure painter, now public as
paint_colour_vision, and the host gallery draws the sample instead of
the kit's.

Its names read "Bends" through tr as if it were an id; it is now
ui.colour_vision_bends, with the catalogs' existing translations. A new
guard rejects a list of message ids that holds an English-label key in
the kit or the host; on the old code it reported ui_kit/preferences.rs:
["Bends"].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

* UI kit: the navigation bar's layout is the kit's nav_bar_layout

measure, editor_layout and BarLayout laid out the kit's bar from kit
types and metrics but lived in ui-egui. They move to the public
nav_bar_layout module beside nav_bar and navigation_bar; the app's
wiring (canvas caps, placement in the shell's free region, slot views,
menus and commands) stays in navigation_bar_view.

The layout takes the slots the canvas shows as a predicate instead of
the app's NavCaps (which gains shows(slot) for the callers), and
reserves a menu value's width for any menu slot whose display is Icon
and value instead of naming visual_style; the catalogue's icon_menus
already keep the View menu icon-only, so the bar is unchanged. The
slot view uses the same rule. The layout tests stay in ui-egui, as
they use SolidCraft's slot catalogue; only their paths and the caps
argument change, no expected value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DtL5M2MmcDrkcWhQeHS2K8

---------

Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:13:05 +00:00
KaworuSF5 a52217f4e0 i18n: complete Portuguese (Brazil) translations (closes #14229) (#14338)
* i18n: complete Portuguese (Brazil) translations for 127 missing keys (closes #14229)

* i18n: adjust Press Pull heading to match command terminology

* i18n: apply Portuguese (Brazil) translation refinements

* i18n: fix placeholder in hole_folder.applies_to (refs #14229)

---------

Co-authored-by: SolidCraft Agent <agent@solidcraft.local>
2026-11-10 07:12:51 +00:00
Andrzej Błasik e8e73e11ab Polish translation: one word for each CAD term, counts that read right, and button names that fit the sentence (#14175)
* Polish translation: one word for each CAD term, counts that read right, and button names that fit the sentence

A timeline feature is an operacja everywhere (it was a funkcja, and sometimes an element). Messages
that put an inflected noun after a number now put the count after a label. Button and command names
inside sentences get a word that carries the grammar, common nouns lose stray capitals, the informal
you is lower case, masculine-only forms are rephrased, and a few calques and stale translations are
rewritten. docs/localization.md gains the Polish terminology paragraph the other languages have.

* Polish translation: keep the suggested name of a saved copy as it was
2026-11-10 07:12:46 +00:00
FinnDaCaptain 64614d7071 Viewport: the picture follows the mouse one frame sooner when orbiting, panning and dragging (#13993)
Claude-Session: https://claude.ai/code/session_01VTLw4zU71LyMwTq6zdP73b

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:12:44 +00:00
Dahak Builds 0c0ac5faca Add keyboard navigation keys for viewport orbit/pan/zoom (#717) (#6816)
* claim: #717

* Keyboard zoom keys: PageUp/PageDown and +/− zoom the view (#717)

* chore: re-trigger checks (defaults line present in PR body)

---------

Co-authored-by: Dahak Builds <dahakbuilds@users.noreply.github.com>
2026-11-10 07:12:41 +00:00
dudedagger42 68a4399ad9 Look At on a construction plane turns the camera to it (#13111) (#13150)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-10 07:12:09 +00:00
PaddleStroke 3de9bfefc3 Sketch: the first dimension scales a shape about its own centre, not the sketch origin (#11043) (#12704)
* claim: #11043

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: first dimension scales a free shape about its own centre (#11043)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: Sketch preference keeps the first dimension scaling about the origin (#11043)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* wip: fmt (#11043)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch dimensions: describe the scale origin in the typed contract

Preserve current upstream behavior while applying the reviewed correction. Central native builds and strict workspace linting pass; remaining runtime and screenshot checks are recorded in the PR.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:12:06 +00:00
1407 changed files with 66891 additions and 29023 deletions
+8 -8
View File
@@ -48,13 +48,6 @@ filter = "binary(action_matrix) & test(=action_matrix_sample)"
threads-required = 12
priority = 100
# The longest test by far (a median of 950 s on the 32 vCPU runner, #14362) starts at once, beside
# the action matrix sample. In the list below it would wait behind the tests that sort before it,
# and the run ends when it does.
[[profile.ci.overrides]]
filter = "package(solidcraft-kernel) & test(=thread_tests::a_long_thread_cuts_without_a_deep_tree)"
priority = 100
# The slowest tests start first, so a shard does not end with one of them running alone on a
# core while the others sit idle. Medians from the CI test timings (the junit artifacts), slowest
# first; a test over ~100 s belongs here (the medians of 24 full runs added the last ones, #14362).
@@ -154,5 +147,12 @@ max-threads = 1
[[profile.local-ci.overrides]]
platform = "cfg(windows)"
filter = "package(solidcraft-gpu) | package(solidcraft) | (package(solidcraft-ui-egui) & test(/(offscreen|gpu)/))"
# Viewport tests also open real devices when their names do not contain "gpu".
filter = """
package(solidcraft-gpu) | package(solidcraft) | (package(solidcraft-ui-egui) & (
test(/(offscreen|gpu)/)
| test(/^viewport::tests::/)
| test(=render_workspace::tests::progressive_image_controls_route_to_the_registered_host)
))
"""
test-group = "windows-gpu"
+1 -1
View File
@@ -1,6 +1,6 @@
# Preserve canonical source receipts and the runtime icon-discovery snapshot.
.gitattributes text eol=lf
/assets/icons/ui/design/requested_icons.txt text eol=lf
/crates/look/icons/design/requested_icons.txt text eol=lf
# Shaders reach the code through include_str!, and tests match multi-line WGSL excerpts
# written as Rust strings (always LF), so a CRLF checkout must not change them (#13138).
*.wgsl text eol=lf
-2
View File
@@ -30,7 +30,6 @@ on:
- "crates/kernel/**"
- "crates/geom/**"
- "crates/smlib/**"
- "crates/step/**"
- "crates/io/src/**"
- "crates/doc/src/**"
- "crates/engine/src/**"
@@ -51,7 +50,6 @@ on:
- "crates/kernel/**"
- "crates/geom/**"
- "crates/smlib/**"
- "crates/step/**"
- "crates/io/src/**"
- "crates/doc/src/**"
- "crates/engine/src/**"
+455 -452
View File
@@ -42,13 +42,13 @@ Editable drawing code, native projects and shipped exports are collected under `
| examples/render-path-studio.json | SolidCraft contributors | original procedural opaque enclosure, teal insert and metal fasteners for progressive rendering; no imported models | MIT OR Apache-2.0 |
| crates/gpu/src/path/path.wgsl | SolidCraft contributors | original software BVH traversal and path integration using the existing SolidCraft surface/studio equations; no external shader source | MIT OR Apache-2.0 |
| crates/gpu/src/pbr.rs | SolidCraft contributors | original WGSL translation of SolidCraft's opaque surface and fixed studio reference, embedded as Rust source; no external shader code | MIT OR Apache-2.0 |
| assets/icons/app/macos/source/SolidCraft.icon/icon.json | SolidCraft contributors | approved Icon Composer composition and appearance settings for the original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/02-grid.svg | SolidCraft contributors | original perspective grid with elliptical radial alpha, exported from VectorCraft | MIT OR Apache-2.0 |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/02-grid-dark.svg | SolidCraft contributors | original blue perspective grid with elliptical radial alpha, exported from VectorCraft for the Dark appearance | MIT OR Apache-2.0 |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg | SolidCraft contributors | original saturated blue CAD solid with transparent topology cutouts, edited and exported with VectorCraft | MIT OR Apache-2.0 |
| assets/icons/app/macos/exports/Assets.car | SolidCraft contributors | Apple actool compilation of assets/icons/app/macos/source/SolidCraft.icon for macOS; contains original artwork only | MIT OR Apache-2.0 |
| assets/icons/app/macos/source/SolidCraft.icon/icon.json | SolidCraft contributors | approved Icon Composer composition and appearance settings for the original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/02-grid.svg | SolidCraft contributors | original perspective grid with elliptical radial alpha, exported from VectorCraft | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/02-grid-dark.svg | SolidCraft contributors | original blue perspective grid with elliptical radial alpha, exported from VectorCraft for the Dark appearance | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg | SolidCraft contributors | original saturated blue CAD solid with transparent topology cutouts, edited and exported with VectorCraft | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/macos/exports/Assets.car | SolidCraft contributors | Apple actool compilation of assets/icons/app/macos/source/SolidCraft.icon for macOS; contains original artwork only | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/archive/icons/macos-v1/source/icon.vectorcraft | SolidCraft contributors | retained editable historical VectorCraft source, with named face and background layers; redundant exports retired | MIT OR Apache-2.0 |
| assets/icons/app/macos/exports/icon.icns | SolidCraft contributors | macOS fallback compiled by Apple's actool from the approved assets/icons/app/macos/source/SolidCraft.icon composition | MIT OR Apache-2.0 |
| assets/icons/app/macos/exports/icon.icns | SolidCraft contributors | macOS fallback compiled by Apple's actool from the approved assets/icons/app/macos/source/SolidCraft.icon composition | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/models/test_boat.bin | 3DBenchy.com | 3DBenchy.com | Public Domain |
| assets/models/make_test_boat.py | SolidCraft contributors | original script that packs a model into the compact file above | MIT OR Apache-2.0 |
| docs/screenshots/class-a-blend.png | SolidCraft contributors | screenshot of SolidCraft itself: a 24 mm and a 10 mm box bridged by a `surface.blend` sheet (G1 at both edges), rendered by the app's `ui.render` in the dark theme with examples/demo/class_a_shots.py | MIT OR Apache-2.0 |
@@ -73,14 +73,14 @@ Editable drawing code, native projects and shipped exports are collected under `
| docs/design/ux-redesign/start-page.png | SolidCraft contributors | original UX mockup (start page (File view)) rendered from an HTML mockup that uses the original Technical Accent icon set; no third-party artwork, and not a screenshot of any other CAD product | MIT OR Apache-2.0 |
| docs/design/ux-redesign/workspaces.png | SolidCraft contributors | original UX mockup (workspace switcher) rendered from an HTML mockup that uses the original Technical Accent icon set; no third-party artwork, and not a screenshot of any other CAD product | MIT OR Apache-2.0 |
| docs/design/ux-redesign/command-map.png | SolidCraft contributors | original UX mockup (ribbon command map) rendered from an HTML mockup that uses the original Technical Accent icon set; no third-party artwork, and not a screenshot of any other CAD product | MIT OR Apache-2.0 |
| assets/branding/web/source/og.png | SolidCraft contributors | original 1280 × 640 social preview card (the SolidCraft mark, name and tagline), served by the docs site for link previews | MIT OR Apache-2.0 |
| assets/branding/web/source/og.png | SolidCraft contributors | original 1280 × 640 social preview card (the SolidCraft mark, name and tagline), served by the docs site for link previews | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/book/src/generated/sample-plate.png | SolidCraft contributors | copy of docs/screenshots/sample-plate.png made by `cargo xtask book` (gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/bracket.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot examples/bracket.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/enclosure.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/enclosure.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/revolve.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/revolve.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/sheet-metal.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/sheet-metal.json`; gitignored) | MIT OR Apache-2.0 |
| assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.ttf | IBM Corp. (IBM Plex Mono) | https://github.com/IBM/plex (via google/fonts), unmodified; licence text in assets/fonts/ibm-plex-mono/OFL.txt; the interface monospace font | SIL OFL 1.1 |
| assets/fonts/ibm-plex-sans/IBMPlexSans-Variable.ttf | IBM Corp. (IBM Plex Sans, variable wdth and wght) | https://github.com/IBM/plex (via google/fonts), unmodified; licence text in assets/fonts/ibm-plex-sans/OFL.txt; the default interface font | SIL OFL 1.1 |
| crates/look/fonts/ibm-plex-mono/IBMPlexMono-Regular.ttf | IBM Corp. (IBM Plex Mono) | https://github.com/IBM/plex (via google/fonts), unmodified; licence text in crates/look/fonts/ibm-plex-mono/OFL.txt; the interface monospace font | SIL OFL 1.1 |
| crates/look/fonts/ibm-plex-sans/IBMPlexSans-Variable.ttf | IBM Corp. (IBM Plex Sans, variable wdth and wght) | https://github.com/IBM/plex (via google/fonts), unmodified; licence text in crates/look/fonts/ibm-plex-sans/OFL.txt; the default interface font | SIL OFL 1.1 |
| docs/book/src/generated/tool-preview.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/tool-preview.json`; gitignored) | MIT OR Apache-2.0 |
| assets/fonts/biz-udp-gothic/BIZUDPGothic-Regular.ttf | The BIZ UDGothic Project Authors | https://github.com/googlefonts/morisawa-biz-ud-gothic (Google Fonts), unmodified; licence text in assets/fonts/biz-udp-gothic/OFL.txt; used for web UI Japanese font | SIL OFL 1.1 |
| assets/fonts/craft-ui-sc/CraftUI-SC.otf | Adobe / Google Inc. (Noto Sans SC); SolidCraft subset | https://github.com/notofonts/noto-cjk Sans/SubsetOTF/SC Regular, glyph-subset for assets/locales/zh.json and renamed Craft UI SC (OFL reserved-name); licence text in assets/fonts/craft-ui-sc/OFL.txt; web UI Simplified Chinese | SIL OFL 1.1 |
@@ -144,24 +144,25 @@ Editable drawing code, native projects and shipped exports are collected under `
| assets/fonts/biz-udp-gothic/OFL.txt | The BIZ UDGothic Project Authors | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/fonts/craft-ui-sc/OFL.txt | Adobe / Google Inc. (Noto CJK); SolidCraft header | Accompanying OFL for CraftUI-SC.otf | SIL OFL 1.1 |
| assets/fonts/craft-ui-tc/OFL.txt | Adobe / Google Inc. (Noto CJK); SolidCraft header | Accompanying OFL for CraftUI-TC.otf | SIL OFL 1.1 |
| assets/fonts/ibm-plex-mono/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/fonts/ibm-plex-sans/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/icons/app/linux/exports/hicolor/128x128/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/16x16/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/24x24/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/256x256/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/32x32/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/48x48/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/512x512/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/linux/exports/hicolor/64x64/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/shared/source/app_icon.rs | SolidCraft contributors | Original SolidCraft drawing code: the borderless mark, drawn from the faces and gradients of assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg | MIT OR Apache-2.0 |
| assets/icons/app/shared/source/windows_ico.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/icons/app/windows/exports/solidcraft-executable.ico | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/app/windows/exports/solidcraft.ico | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | MIT OR Apache-2.0 |
| assets/icons/ui/source/glyphs.rs | SolidCraft / VectorCraft contributors | Original glyphs; caption geometry adapted from VectorCraft titlebar.rs (https://github.com/storytold/vectorcraft) | MIT OR Apache-2.0 |
| assets/icons/ui/source/markers.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/icons/ui/source/navigation.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/icons/ui/source/pointer.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| crates/look/fonts/ibm-plex-mono/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
| crates/look/fonts/ibm-plex-sans/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/icons/app/linux/exports/hicolor/128x128/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/16x16/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/24x24/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/256x256/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/32x32/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/48x48/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/512x512/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/linux/exports/hicolor/64x64/apps/io.tangencylabs.solidcraft.png | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/shared/source/app_icon.rs | SolidCraft contributors | Original SolidCraft drawing code: the borderless mark, drawn from the faces and gradients of assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/shared/source/windows_ico.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/windows/exports/solidcraft-executable.ico | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/icons/app/windows/exports/solidcraft.ico | SolidCraft contributors | Generated from assets/icons/app/shared/source/app_icon.rs with the original CLI/ICO encoders | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/src/glyphs.rs | SolidCraft / VectorCraft contributors | Original glyphs; caption geometry adapted from VectorCraft titlebar.rs (https://github.com/storytold/vectorcraft) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/ui-egui/src/icons/markers.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| crates/ui-egui/src/icons/navigation.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| crates/look/src/compass.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/src/pointer.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/locales/cs.json | potuzai | Czech translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
| assets/locales/da.json | SolidCraft contributors | Original Danish translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/locales/de.json | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
@@ -201,122 +202,122 @@ Editable drawing code, native projects and shipped exports are collected under `
| assets/platforms/windows/solidcraft.en-us.wxl | PhotoCraft / SolidCraft contributors | PhotoCraft packaging templates (https://github.com/storytold/photocraft), adapted for SolidCraft | Apache-2.0 |
| assets/platforms/windows/solidcraft.wxs | PhotoCraft / SolidCraft contributors | PhotoCraft packaging templates (https://github.com/storytold/photocraft), adapted for SolidCraft | Apache-2.0 |
| crates/viewport-gpu/shaders/viewport.wgsl | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/styles/ui/themes/gruvbox-dark.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/gruvbox-light.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/solidcraft-95.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/platinum-9.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/cupertino.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/green-phosphor.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/amber-phosphor.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/blueprint.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/one-dark.json | SolidCraft contributors | original SolidCraft theme file with colours adapted from the One Dark palette (Atom One Dark by GitHub Atom, https://github.com/atom/atom, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/tokyo-night.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Tokyo Night by enkia, https://github.com/enkia/tokyo-night-vscode-theme, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/solarized-light.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Solarized by Ethan Schoonover, https://github.com/altercation/solarized, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/solarized-dark.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Solarized by Ethan Schoonover, https://github.com/altercation/solarized, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/nord.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Nord by Sven Greb and the Nord contributors, https://github.com/nordtheme/nord, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/high-contrast.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/graphite.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/nosferatu.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Dracula by Zeno Rocha and the Dracula Theme contributors, https://github.com/dracula/dracula-theme, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/catppuccin-mocha.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Catppuccin by the Catppuccin organisation, https://github.com/catppuccin/catppuccin, MIT) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/okibi.json | SolidCraft contributors (Kai Evans) | original SolidCraft theme file mapping SolidCraft's UI colours to the Okibi palette (dark) of the Okibi design system by Kai Evans (https://kaievns.github.io/okibi-akiri-design-system-spec/) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/akari.json | SolidCraft contributors (Kai Evans) | original SolidCraft theme file mapping SolidCraft's UI colours to the Akari palette (light) of the Okibi design system by Kai Evans (https://kaievns.github.io/okibi-akiri-design-system-spec/) | MIT OR Apache-2.0 |
| crates/look/themes/gruvbox-dark.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/gruvbox-light.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/solidcraft-95.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/platinum-9.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/cupertino.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/green-phosphor.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/amber-phosphor.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/blueprint.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/one-dark.json | SolidCraft contributors | original SolidCraft theme file with colours adapted from the One Dark palette (Atom One Dark by GitHub Atom, https://github.com/atom/atom, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/tokyo-night.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Tokyo Night by enkia, https://github.com/enkia/tokyo-night-vscode-theme, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/solarized-light.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Solarized by Ethan Schoonover, https://github.com/altercation/solarized, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/solarized-dark.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Solarized by Ethan Schoonover, https://github.com/altercation/solarized, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/nord.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Nord by Sven Greb and the Nord contributors, https://github.com/nordtheme/nord, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/high-contrast.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/graphite.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/nosferatu.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Dracula by Zeno Rocha and the Dracula Theme contributors, https://github.com/dracula/dracula-theme, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/catppuccin-mocha.json | SolidCraft contributors | original SolidCraft theme file adapting the colours of a published palette (Catppuccin by the Catppuccin organisation, https://github.com/catppuccin/catppuccin, MIT) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/okibi.json | SolidCraft contributors (Kai Evans) | original SolidCraft theme file mapping SolidCraft's UI colours to the Okibi palette (dark) of the Okibi design system by Kai Evans (https://kaievns.github.io/okibi-akiri-design-system-spec/) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/akari.json | SolidCraft contributors (Kai Evans) | original SolidCraft theme file mapping SolidCraft's UI colours to the Akari palette (light) of the Okibi design system by Kai Evans (https://kaievns.github.io/okibi-akiri-design-system-spec/) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/styles/web/loading-logo.svg | SolidCraft contributors | Animation of the SolidCraft mark, built from the paths and gradients of assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg; original animation | MIT OR Apache-2.0 |
| assets/styles/web/loading.css | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| crates/io/src/native_cad/fixtures/block.FCStd | SolidCraft contributors | original 10 × 20 × 30 mm test box saved by FreeCAD 1.1.4 run as an external program (`make_block_fcstd.py` beside it); no third-party geometry | MIT OR Apache-2.0 |
| crates/io/src/native_cad/fixtures/block.3dm | SolidCraft contributors | original 10 × 20 × 30 mm test box written with McNeel's MIT-licensed rhino3dm Python package (`make_block_3dm.py` beside it); no third-party geometry | MIT OR Apache-2.0 |
| assets/icons/ui/design/aliases.toml | SolidCraft contributors | icon ids that share a master, original SolidCraft data | MIT OR Apache-2.0 |
| assets/icons/ui/design/palette.toml | SolidCraft contributors | icon colour roles (light and dark) and accents, original SolidCraft data | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/bug_report.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/chevron.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/chevron_right.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/close.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/disclosure_closed.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/disclosure_open.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/fit.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/folder.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/help.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/home.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/lookat.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/moon.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/nav_settings.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/orbit.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/plus.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/pan.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/perspective.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_appearance.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_assistant.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_design.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_general.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_graphics.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_layout.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_mouse3d.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_navigation.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_plugins.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_shortcuts.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_sketch.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/prefs_tools.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/redo.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/save.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_keyboard.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_monitor.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_mouse.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_palette.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_plug.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/spin.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/style.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/undo.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/zoom.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/accessibility.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/activate.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/align.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/appearance.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/arc3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/arc_center.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/arc_slot.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/arc_tangent.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/as_built.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/auto_constrain.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/bendtable.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/blend.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/blend_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/boss.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/boundary.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/boundary_fill.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/box.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/break.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_coincident.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_collinear.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_concentric.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_equal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_fix.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_hv.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_midpoint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_parallel.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_perpendicular.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_polygon.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_smooth.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_symmetry.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/c_tangent.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/camera.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/canvas.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/capture.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/center_of_mass.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/centerline.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/chain.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/chamfer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/checkpoint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/circle.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/circle2.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/circle3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/circle_tt.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/circle_ttt.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/coil.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/colored_components.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/combine.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/component.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| crates/look/icons/design/aliases.toml | SolidCraft contributors | icon ids that share a master, original SolidCraft data | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/palette.toml | SolidCraft contributors | icon colour roles (light and dark) and accents, original SolidCraft data | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/bug_report.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/chevron.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/chevron_right.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/close.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/disclosure_closed.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/disclosure_open.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/fit.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/folder.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/help.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/home.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/lookat.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/moon.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/nav_settings.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/orbit.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/plus.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/pan.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/perspective.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_appearance.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_assistant.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_design.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_general.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_graphics.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_layout.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_mouse3d.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_navigation.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_plugins.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_shortcuts.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_sketch.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/prefs_tools.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/redo.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/save.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings_keyboard.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings_monitor.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings_mouse.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings_palette.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/settings_plug.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/spin.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/style.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/undo.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/zoom.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/accessibility.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/activate.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/align.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/appearance.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/arc3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/arc_center.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/arc_slot.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/arc_tangent.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/as_built.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/auto_constrain.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/bendtable.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/blend.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/blend_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/boss.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/boundary.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/boundary_fill.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/box.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/break.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_coincident.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_collinear.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_concentric.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_equal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_fix.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_hv.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_midpoint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_parallel.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_perpendicular.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_polygon.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_smooth.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_symmetry.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/c_tangent.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/camera.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/canvas.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/capture.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/center_of_mass.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/centerline.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/chain.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/chamfer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/checkpoint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/circle.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/circle2.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/circle3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/circle_tt.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/circle_ttt.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/coil.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/colored_components.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/combine.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/component.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
### Render workspace icon drafts
@@ -324,328 +325,328 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| File | Author | Source | Licence |
|---|---|---|---|
| assets/icons/ui/design/svg/model/render_all_shots.svg | SolidCraft contributors | original Camera icon master (64 grid): stacked camera bodies with a lower-right play badge | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_appearance.svg | SolidCraft contributors | original Looks icon master (64 grid): shaded look sphere on the top corner of an accent-shaded cube | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_aspect_frame.svg | SolidCraft contributors | original Camera icon master (64 grid): wide rounded frame with two opposite corner brackets | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_backdrop.svg | SolidCraft contributors | original Studio icon master (64 grid): grey cube in front of a tall upright accent panel | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_cancel.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round stop badge | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_check.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round check badge | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_compare.svg | SolidCraft contributors | original Output icon master (64 grid): two grey pictures split by a vertical slider with opposed arrows | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_copy_look.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere in a square frame offset from a second frame outline | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_execute.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round play badge | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_export_image.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a large outward diagonal arrow at the upper right | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_exposure.svg | SolidCraft contributors | original Camera icon master (64 grid): split light and accent disc with plus and minus marks | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_fit_product.svg | SolidCraft contributors | original Camera icon master (64 grid): grey cube inside four corner brackets | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_frame_guides.svg | SolidCraft contributors | original Camera icon master (64 grid): rounded frame with a rule-of-thirds grid and four accent nodes | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_from_material.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere struck through above a plain grey slab | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_ground.svg | SolidCraft contributors | original Studio icon master (64 grid): grey cube on a slab with an accent contact patch | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_lens.svg | SolidCraft contributors | original Camera icon master (64 grid): concentric lens rings around an accent centre | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_library.svg | SolidCraft contributors | original Studio icon master (64 grid): row of three look spheres, middle one accent, on a shelf bar | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_light_area.svg | SolidCraft contributors | original Lights icon master (64 grid): slanted flat panel above a dotted accent stem | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_light_by_highlight.svg | SolidCraft contributors | original Lights icon master (64 grid): shaded sphere with a ringed highlight target and dotted stem arriving from above | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_light_point.svg | SolidCraft contributors | original Lights icon master (64 grid): round source disc with centre dot above a dotted accent stem | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_light_spot.svg | SolidCraft contributors | original Lights icon master (64 grid): cone source with curved rim above a dotted accent stem | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_lighting_presets.svg | SolidCraft contributors | original Studio icon master (64 grid): two stacked cards, the front one holding a light bulb | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_output_size.svg | SolidCraft contributors | original Output icon master (64 grid): picture frame with a diagonal double-headed dimension arrow | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_paint.svg | SolidCraft contributors | original Looks icon master (64 grid): flat brush with an accent tip, light ferrule and slate handle | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_pick_up.svg | SolidCraft contributors | original Looks icon master (64 grid): eyedropper with a grey bulb, slate crossbar and accent sampling tip | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_quality.svg | SolidCraft contributors | original Output icon master (64 grid): three rising bars, the tallest in accent | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_replace_all.svg | SolidCraft contributors | original Looks icon master (64 grid): grey sample sphere with an arrow to an accent sphere beside a second one | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_results.svg | SolidCraft contributors | original Output icon master (64 grid): stack of two pictures, the front one showing a landscape | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_same_look.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere and three cubes, the two matching cubes ringed | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_shot.svg | SolidCraft contributors | original Camera icon master (64 grid): camera body with a lower-right plus badge | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_shots_strip.svg | SolidCraft contributors | original Camera icon master (64 grid): strip of three small frames, the middle one in accent | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_solo_light.svg | SolidCraft contributors | original Lights icon master (64 grid): point source and dotted stem inside four corner focus brackets | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_sun.svg | SolidCraft contributors | original Lights icon master (64 grid): source disc with eight short radial rays | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_transparent_background.svg | SolidCraft contributors | original Output icon master (64 grid): grey cube on a checker tile | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_update_shot.svg | SolidCraft contributors | original Camera icon master (64 grid): camera body with a lower-right refresh badge | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/render_all_shots.svg | SolidCraft contributors | original Camera icon master (64 grid): stacked camera bodies with a lower-right play badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_appearance.svg | SolidCraft contributors | original Looks icon master (64 grid): shaded look sphere on the top corner of an accent-shaded cube | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_aspect_frame.svg | SolidCraft contributors | original Camera icon master (64 grid): wide rounded frame with two opposite corner brackets | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_backdrop.svg | SolidCraft contributors | original Studio icon master (64 grid): grey cube in front of a tall upright accent panel | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_cancel.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round stop badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_check.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round check badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_compare.svg | SolidCraft contributors | original Output icon master (64 grid): two grey pictures split by a vertical slider with opposed arrows | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_copy_look.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere in a square frame offset from a second frame outline | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_execute.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a lower-right round play badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_export_image.svg | SolidCraft contributors | original Output icon master (64 grid): picture with a large outward diagonal arrow at the upper right | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_exposure.svg | SolidCraft contributors | original Camera icon master (64 grid): split light and accent disc with plus and minus marks | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_fit_product.svg | SolidCraft contributors | original Camera icon master (64 grid): grey cube inside four corner brackets | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_frame_guides.svg | SolidCraft contributors | original Camera icon master (64 grid): rounded frame with a rule-of-thirds grid and four accent nodes | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_from_material.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere struck through above a plain grey slab | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_ground.svg | SolidCraft contributors | original Studio icon master (64 grid): grey cube on a slab with an accent contact patch | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_lens.svg | SolidCraft contributors | original Camera icon master (64 grid): concentric lens rings around an accent centre | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_library.svg | SolidCraft contributors | original Studio icon master (64 grid): row of three look spheres, middle one accent, on a shelf bar | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_light_area.svg | SolidCraft contributors | original Lights icon master (64 grid): slanted flat panel above a dotted accent stem | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_light_by_highlight.svg | SolidCraft contributors | original Lights icon master (64 grid): shaded sphere with a ringed highlight target and dotted stem arriving from above | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_light_point.svg | SolidCraft contributors | original Lights icon master (64 grid): round source disc with centre dot above a dotted accent stem | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_light_spot.svg | SolidCraft contributors | original Lights icon master (64 grid): cone source with curved rim above a dotted accent stem | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_lighting_presets.svg | SolidCraft contributors | original Studio icon master (64 grid): two stacked cards, the front one holding a light bulb | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_output_size.svg | SolidCraft contributors | original Output icon master (64 grid): picture frame with a diagonal double-headed dimension arrow | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_paint.svg | SolidCraft contributors | original Looks icon master (64 grid): flat brush with an accent tip, light ferrule and slate handle | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_pick_up.svg | SolidCraft contributors | original Looks icon master (64 grid): eyedropper with a grey bulb, slate crossbar and accent sampling tip | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_quality.svg | SolidCraft contributors | original Output icon master (64 grid): three rising bars, the tallest in accent | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_replace_all.svg | SolidCraft contributors | original Looks icon master (64 grid): grey sample sphere with an arrow to an accent sphere beside a second one | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_results.svg | SolidCraft contributors | original Output icon master (64 grid): stack of two pictures, the front one showing a landscape | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_same_look.svg | SolidCraft contributors | original Looks icon master (64 grid): look sphere and three cubes, the two matching cubes ringed | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_shot.svg | SolidCraft contributors | original Camera icon master (64 grid): camera body with a lower-right plus badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_shots_strip.svg | SolidCraft contributors | original Camera icon master (64 grid): strip of three small frames, the middle one in accent | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_solo_light.svg | SolidCraft contributors | original Lights icon master (64 grid): point source and dotted stem inside four corner focus brackets | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_sun.svg | SolidCraft contributors | original Lights icon master (64 grid): source disc with eight short radial rays | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_transparent_background.svg | SolidCraft contributors | original Output icon master (64 grid): grey cube on a checker tile | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_update_shot.svg | SolidCraft contributors | original Camera icon master (64 grid): camera body with a lower-right refresh badge | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
### UI icon masters (continued)
| File | Author | Source | Licence |
|---|---|---|---|
| assets/icons/ui/design/svg/model/compute.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/configuration_table.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/conic.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/constrainer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/convert_sheet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/copy.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/curvature_comb.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/curvature_map.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/cylinder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/decal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/delete.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/dimension.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/dots.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/draft.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/draft_analysis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/drive.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/dxf.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/edge_continuity.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/edit.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/ellipse.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/emboss.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/environment_map.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/explode.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/export.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/extend.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/extrude.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/eye.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/fastener.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/fillet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/filter.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/finish.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/fit_section.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/flange.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/flat.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/fold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/folder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/graph.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/hem.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/hole.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/import.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/include.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/inspect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/interference.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/intersect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/intersection_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/iso_analysis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/iso_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/joint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/joint_origin.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/library.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/line.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/line_mid.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/lip.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/list.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/loft.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/material.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/measure.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/min_radius.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/mirror.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/motion_link.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/move.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/new.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/offset.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/offset_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/offset_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/open.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/origin.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/params.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/paste.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/patch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern_circ.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern_path.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern_rect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/perforate.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pipe.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/silhouette.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/assistant.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/agent_link.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/offset_two_sides.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/offset_symmetric.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/import_tray.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/export_tray.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/send.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/stop.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/shield.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/status_recovery.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/frame_member.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_environment.svg | SolidCraft contributors | original Studio icon master (64 grid): dome with a grey cube inside | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/style_shaded.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/style_wireframe.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/style_hidden_edges.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/style_translucent.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_faces_edges.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_bodies.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_features.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_parts.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_components.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/select_sketch.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/display.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/grid.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/ground_shadow.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/ambient_occlusion.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/placeholder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_angle.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plastic_assign.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plastic_rule.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/play.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/polygon.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/presspull.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/project.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/project_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rect3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rect_center.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rect_rounded.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/refold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rename.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_image.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/render_scene.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/reorder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rest.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/restore.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/reverse_normal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/revert.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/revolve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rib.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rigid_group.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rollback.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/ruled.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/scale.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/section.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/select.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sheet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sheet_rules.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/shell.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch_chamfer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch_fillet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch_mirror.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/slot.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/snap.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sphere.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/spline.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/spline_cv.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/split_body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/split_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/spun.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/star.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/status_error.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/status_warning.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/stitch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/suppress.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/svg.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sweep.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/text.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/thicken.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/thread.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/torus.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/trim.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/unfold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/unstitch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/untrim.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/update.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/zebra.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/as_built.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/component.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/curvature_comb.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/interference.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/iso_analysis.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/joint.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/pattern.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/small/section.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/workspace/ws_animate.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/polygon_circumscribed.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/polygon_edge.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/slot_overall.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/slot_center.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/arc_slot_center.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch_chamfer_angle.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/sketch_chamfer_two_distances.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/gear.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/rack_pinion.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/screw.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/cam.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/trace.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/agent_chat.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/normal.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/infinite.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern_flip.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/pattern_center.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/reach.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/cut.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/compare.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/web.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/replace_face.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/bounding_solid.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/delete_face.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/snap_fit.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/contact_sets.svg | SolidCraft contributors | original contact icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/contact_all.svg | SolidCraft contributors | original contact icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/contact_off.svg | SolidCraft contributors | original contact icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/contact_new.svg | SolidCraft contributors | original contact icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis_through_cylinder.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis_normal_to_face.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis_two_planes.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis_two_points.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/axis_edge.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_vertex.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_two_edges.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_three_planes.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_center.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_edge_plane.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/point_along_path.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_midplane.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_two_edges.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_three_points.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_tangent.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_along_path.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_perpendicular.svg | SolidCraft contributors | original construction icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/workspace/ws_design.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/workspace/ws_drawing.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/workspace/ws_render.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/references.toml | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/author/bases.py | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/author/new_icon.py | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/review/index.html | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/review/guide.html | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/review/review.css | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/review/review.js | SolidCraft contributors | original icon authoring or review tool resource | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/icon_palette.py | SolidCraft contributors | Original shared semantic icon palette resolver for repository tools | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/icon_status.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/lint_icons.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/preview.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/review_state.py | SolidCraft contributors | icon review state helper (standard-library Python), original SolidCraft code | MIT OR Apache-2.0 |
| assets/icons/ui/design/requested_icons.txt | SolidCraft contributors | Runtime icon requests collected by the headless menu audit, original SolidCraft data | MIT OR Apache-2.0 |
| assets/icons/ui/design/review.json | SolidCraft contributors | icon review state (accepted icons and notes), original SolidCraft data | MIT OR Apache-2.0 |
| assets/icons/ui/design/tools/author/lib.py | SolidCraft contributors | icon authoring script (standard-library Python), original SolidCraft code | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/compute.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/configuration_table.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/conic.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/constrainer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/convert_sheet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/copy.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/curvature_comb.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/curvature_map.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/cylinder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/decal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/delete.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/dimension.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/dots.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/draft.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/draft_analysis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/drive.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/dxf.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/edge_continuity.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/edit.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/ellipse.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/emboss.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/environment_map.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/explode.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/export.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/extend.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/extrude.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/eye.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/fastener.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/fillet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/filter.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/finish.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/fit_section.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/flange.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/flat.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/fold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/folder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/graph.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/hem.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/hole.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/import.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/include.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/inspect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/interference.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/intersect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/intersection_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/iso_analysis.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/iso_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/joint.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/joint_origin.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/library.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/line.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/line_mid.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/lip.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/list.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/loft.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/material.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/measure.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/min_radius.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/mirror.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/motion_link.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/move.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/new.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/offset.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/offset_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/offset_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/open.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/origin.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/params.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/paste.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/patch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern_circ.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern_path.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern_rect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/perforate.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pipe.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/silhouette.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/assistant.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/agent_link.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/offset_two_sides.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/offset_symmetric.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/import_tray.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/export_tray.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/send.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/stop.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/shield.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/status_recovery.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/frame_member.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_environment.svg | SolidCraft contributors | original Studio icon master (64 grid): dome with a grey cube inside | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/style_shaded.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/style_wireframe.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/style_hidden_edges.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/style_translucent.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_faces_edges.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_bodies.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_features.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_parts.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_components.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/select_sketch.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/display.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/grid.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/ground_shadow.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/ambient_occlusion.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/placeholder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_angle.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plastic_assign.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plastic_rule.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/play.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/polygon.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/presspull.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/project.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/project_surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rect.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rect3.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rect_center.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rect_rounded.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/refold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rename.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_image.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/render_scene.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/reorder.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rest.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/restore.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/reverse_normal.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/revert.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/revolve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rib.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rigid_group.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rollback.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/ruled.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/scale.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/section.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/select.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sheet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sheet_rules.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/shell.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch_chamfer.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch_fillet.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch_mirror.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/slot.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/snap.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sphere.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/spline.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/spline_cv.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/split_body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/split_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/spun.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/star.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/status_error.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/status_warning.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/stitch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/suppress.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/surface.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/svg.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sweep.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/text.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/thicken.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/thread.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/torus.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/trim.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/unfold.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/unstitch.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/untrim.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/update.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/zebra.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/as_built.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/component.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/curvature_comb.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/interference.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/iso_analysis.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/joint.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/pattern.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/small/section.svg | SolidCraft contributors | small-slot icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/workspace/ws_animate.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/polygon_circumscribed.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/polygon_edge.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/slot_overall.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/slot_center.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/arc_slot_center.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch_chamfer_angle.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/sketch_chamfer_two_distances.svg | SolidCraft contributors | original sketch variant icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/gear.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/rack_pinion.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/screw.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/cam.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/trace.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/agent_chat.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/normal.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/infinite.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern_flip.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/pattern_center.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/reach.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/cut.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/compare.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/web.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/replace_face.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/bounding_solid.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/delete_face.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/snap_fit.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/contact_sets.svg | SolidCraft contributors | original contact icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/contact_all.svg | SolidCraft contributors | original contact icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/contact_off.svg | SolidCraft contributors | original contact icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/contact_new.svg | SolidCraft contributors | original contact icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis_through_cylinder.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis_normal_to_face.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis_two_planes.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis_two_points.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/axis_edge.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_vertex.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_two_edges.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_three_planes.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_center.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_edge_plane.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/point_along_path.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_midplane.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_two_edges.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_three_points.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_tangent.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_along_path.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/plane_perpendicular.svg | SolidCraft contributors | original construction icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/workspace/ws_design.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/workspace/ws_drawing.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/workspace/ws_render.svg | SolidCraft contributors | workspace icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/references.toml | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/author/bases.py | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/author/new_icon.py | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/review/index.html | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/review/guide.html | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/review/review.css | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/review/review.js | SolidCraft contributors | original icon authoring or review tool resource | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/icon_palette.py | SolidCraft contributors | Original shared semantic icon palette resolver for repository tools | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/icon_status.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/lint_icons.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/preview.py | SolidCraft contributors | icon lint, status page or preview tool (standard-library Python), original SolidCraft code | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/review_state.py | SolidCraft contributors | icon review state helper (standard-library Python), original SolidCraft code | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/requested_icons.txt | SolidCraft contributors | Runtime icon requests collected by the headless menu audit, original SolidCraft data | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/review.json | SolidCraft contributors | icon review state (accepted icons and notes), original SolidCraft data | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/tools/author/lib.py | SolidCraft contributors | icon authoring script (standard-library Python), original SolidCraft code | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/book/src/og.png | SolidCraft contributors | copy of assets/branding/web/source/og.png staged by cargo xtask book (gitignored) | MIT OR Apache-2.0 |
| docs/sponsors/blacksmith-ci-powered.png | Blacksmith (blacksmith.sh) | "CI powered by Blacksmith" sponsor banner supplied by Blacksmith for the sponsorship credit; used only to credit the sponsor, not part of the application | © Blacksmith, used with permission |
| assets/icons/ui/design/svg/model/path_flange.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/path_flange.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/book/src/generated/hem.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/hem.json`; gitignored), original sheet metal demonstration | MIT OR Apache-2.0 |
| docs/book/scripts/hem.json | SolidCraft contributors | original parametric recipe for an 80 × 50 mm sheet with an 8 mm returned edge, authored for the command guide | MIT OR Apache-2.0 |
| assets/styles/ui/themes/clay.json | SolidCraft contributors | original SolidCraft theme file (Clay, light): warm paper palette chosen for SolidCraft | MIT OR Apache-2.0 |
| assets/styles/ui/themes/clay-dark.json | SolidCraft contributors | original SolidCraft theme file (Clay Dark): warm charcoal palette chosen for SolidCraft | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/cone.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| crates/look/themes/clay.json | SolidCraft contributors | original SolidCraft theme file (Clay, light): warm paper palette chosen for SolidCraft | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/clay-dark.json | SolidCraft contributors | original SolidCraft theme file (Clay Dark): warm charcoal palette chosen for SolidCraft | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/cone.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/locales/ar.json | Abdullah (A-AL-ANAZI) | Original Arabic translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/locales/he.json | SolidCraft contributors | Original Hebrew translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/styles/ui/themes/cga.json | SolidCraft contributors | original SolidCraft theme file using the 16 colours of the IBM Color Graphics Adapter (black, cyan, magenta, and white of its high-intensity palette 1 for the interface) | MIT OR Apache-2.0 |
| assets/styles/ui/themes/1-bit.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| assets/styles/ui/themes/1-bit-dark.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
| crates/look/themes/cga.json | SolidCraft contributors | original SolidCraft theme file using the 16 colours of the IBM Color Graphics Adapter (black, cyan, magenta, and white of its high-intensity palette 1 for the interface) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/1-bit.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/1-bit-dark.json | SolidCraft contributors | original SolidCraft theme file | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| `assets/locales/pending/navbar-customisation.json` | SolidCraft contributors | Original navigation bar editor translations | MIT OR Apache-2.0 |
| `assets/locales/pending/navbar-slots.json` | SolidCraft contributors | Original navigation slot translations | MIT OR Apache-2.0 |
| assets/locales/bs.json | Tarik Sijercic (tsijercic1) | Original Bosnian translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/locales/hr.json | Tarik Sijercic (tsijercic1) | Original Croatian translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/locales/sr.json | Tarik Sijercic (tsijercic1) | Original Serbian (ekavian, Cyrillic) translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/finish_edit.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/finish_edit.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| `assets/locales/pending/sketch-tracking-guides.json` | SolidCraft contributors | Original alignment-guide preference labels and help text | MIT OR Apache-2.0 |
| assets/locales/pending/point-clouds.json | SolidCraft contributors | Original point-cloud UI strings and translations | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/feature_group.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/mesh_body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/timeline_play.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/timeline_stop.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/status_pin.svg | SolidCraft contributors | Original analytic pin icon for persistent viewport results | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/feature_group.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/mesh_body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/timeline_play.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/timeline_stop.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/flat/status_pin.svg | SolidCraft contributors | Original analytic pin icon for persistent viewport results | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/locales/pending/render-wear.json | SolidCraft contributors | Original UI labels and translations | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/equation_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/equation_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/locales/pending/sketch-recent-snap.json | SolidCraft contributors | Original preference messages for the recent centre and midpoint snap | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_horizontal.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_vertical.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_angle.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_parallel.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_perpendicular.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_tangent_external.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_tangent_at.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_tangent_two.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/construction_line_bisector.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/construction_line.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_horizontal.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_vertical.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_angle.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_parallel.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_perpendicular.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_tangent_external.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_tangent_at.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_tangent_two.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/construction_line_bisector.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/book/src/generated/equation-circle.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-circle.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/equation-flower.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-flower.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/equation-involute.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-involute.json`; gitignored) | MIT OR Apache-2.0 |
@@ -653,9 +654,9 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| docs/book/src/generated/equation-parabola.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-parabola.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/equation-spiral.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-spiral.json`; gitignored) | MIT OR Apache-2.0 |
| docs/book/src/generated/equation-wave.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-wave.json`; gitignored) | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/print_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/print_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/locales/fi.json | SolidCraft contributors | Original Finnish translation of SolidCraft's English catalog, AI-assisted (Claude Code) clean-room from the English and not yet reviewed line by line by a native speaker; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/model/plane_axis_point.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/model/plane_axis_point.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/design/preferences/figures/aa-2x.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/aa-2x.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/aa-4x.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
@@ -706,6 +707,8 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| docs/design/preferences/figures/mouse-mapping.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-axes.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-axes.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-cube.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/navigator-cube.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-centre.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-centre.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/orbit-cursor.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
@@ -777,20 +780,20 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| docs/design/preferences/figures/view-shadow.dark.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| docs/design/preferences/figures/view-shadow.light.svg | SolidCraft contributors | original SolidCraft artwork drawn for the Preferences redesign (tracker #9863), extracted from the design board as a standalone SVG | MIT OR Apache-2.0 |
| `assets/locales/pending/sketch-offset-instances.json` | SolidCraft contributors | Original offset instance-count label and translations | MIT OR Apache-2.0 |
| assets/icons/ui/design/svg/flat/settings_profile.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original analytic head and shoulder geometry for settings profiles | MIT OR Apache-2.0 |
| crates/look/icons/design/svg/flat/settings_profile.svg | SolidCraft contributors | single-colour application/navigation icon master (64 grid), original analytic head and shoulder geometry for settings profiles | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| tests/kernel-cases/import/4561-convert-box-mesh-with-a-zero-area-triangle/box-degenerate.stl | SolidCraft contributors | synthetic ASCII STL written by hand: a box with one zero-area triangle, for the kernel regression case of tangency-labs/solidcraft#4561 | MIT OR Apache-2.0 |
| assets/locales/pending/theme-blur-ui.json | SolidCraft contributors | Original blur controls, notices and translations | MIT OR Apache-2.0 |
| crates/ui-egui/tests/fixtures/theme-blur.json | SolidCraft contributors | Original theme for blur option scenarios and manager review | MIT OR Apache-2.0 |
| assets/locales/ka.json | David Machakhelidze (devius) | Original Georgian translation of SolidCraft's English catalog, written with Claude Code from the meaning of each English string; terminology and doubtful strings decided by a native Georgian speaker; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark.svg | SolidCraft contributors | static SolidCraft mark: the five faces and gradients of assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg (the final frame of assets/styles/web/loading-logo.svg), cropped to the mark's bounds; original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark-mono-black.svg | SolidCraft contributors | one-colour (black) version of assets/branding/logo/solidcraft-mark.svg, same paths; original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark-mono-white.svg | SolidCraft contributors | one-colour (white) version of assets/branding/logo/solidcraft-mark.svg, same paths; original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark-512.png | SolidCraft contributors | transparent 512 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark-1024.png | SolidCraft contributors | transparent 1024 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark-2048.png | SolidCraft contributors | transparent 2048 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-wordmark.svg | SolidCraft contributors | the name SolidCraft set like the loading logo's wordmark (bold, +0.02 em tracking, #15499e) in IBM Plex Sans Bold from assets/fonts/ibm-plex-sans (SIL OFL 1.1, IBM Corp.), outlined to paths; no font file is embedded | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-lockup-horizontal.svg | SolidCraft contributors | assets/branding/logo/solidcraft-mark.svg beside assets/branding/logo/solidcraft-wordmark.svg, in the proportions of assets/branding/web/source/og.png; original artwork | MIT OR Apache-2.0 |
| assets/styles/ui/themes/onyx.json | SolidCraft contributors | original Onyx stone-grey palette, option overlays and semantic icon-role mapping; existing SolidCraft artwork is unchanged | MIT OR Apache-2.0 |
| assets/branding/logo/solidcraft-mark.svg | SolidCraft contributors | static SolidCraft mark: the five faces and gradients of assets/icons/app/macos/source/SolidCraft.icon/Assets/03-solid-blue-cutout.svg (the final frame of assets/styles/web/loading-logo.svg), cropped to the mark's bounds; original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-mark-mono-black.svg | SolidCraft contributors | one-colour (black) version of assets/branding/logo/solidcraft-mark.svg, same paths; original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-mark-mono-white.svg | SolidCraft contributors | one-colour (white) version of assets/branding/logo/solidcraft-mark.svg, same paths; original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-mark-512.png | SolidCraft contributors | transparent 512 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-mark-1024.png | SolidCraft contributors | transparent 1024 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-mark-2048.png | SolidCraft contributors | transparent 2048 px render of assets/branding/logo/solidcraft-mark.svg (cairosvg); original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-wordmark.svg | SolidCraft contributors | the name SolidCraft set like the loading logo's wordmark (bold, +0.02 em tracking, #15499e) in IBM Plex Sans Bold from crates/look/fonts/ibm-plex-sans (SIL OFL 1.1, IBM Corp.), outlined to paths; no font file is embedded | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| assets/branding/logo/solidcraft-lockup-horizontal.svg | SolidCraft contributors | assets/branding/logo/solidcraft-mark.svg beside assets/branding/logo/solidcraft-wordmark.svg, in the proportions of assets/branding/web/source/og.png; original artwork | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/themes/onyx.json | SolidCraft contributors | original Onyx stone-grey palette, option overlays and semantic icon-role mapping; existing SolidCraft artwork is unchanged | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| docs/book/src/media/ui-tour/window.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (`solidcraft --sample`, default dark theme, software renderer, 1280x800) with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py | MIT OR Apache-2.0 |
| docs/book/src/media/ui-tour/navigate.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (`--sample`, default dark theme, software renderer) orbiting, panning and zooming, with the original drawn pointer of examples/demo/overlay.py and labels set in DejaVu Sans Bold, captured with examples/demo/doc_shots.py | MIT OR Apache-2.0 |
| assets/locales/pending/sketch-tool-hints.json | carlymx | Original sketch tool hints and engine error translations | MIT OR Apache-2.0 |
+8 -4
View File
@@ -321,7 +321,7 @@ and a fresh CI run:
- **Growing Rust lists**: use slices (`const ITEMS: &[Item] = &[...];`) without a written
length. `cargo xtask lists` rejects non-test const/static arrays with more than ten lines
of entries, except fixed standard or algorithm tables listed with reasons in `xtask/src/lists.rs`.
Built-in themes need only a JSON file in `assets/styles/ui/themes/`, with a unique nonnegative
Built-in themes need only a JSON file in `crates/look/themes/`, with a unique nonnegative
integer `order` (the picker order) and its own `provenance` line; keep existing order values.
- **Message catalogs** (`assets/locales/*.json`): one message per line, sorted by id. Add your
message anywhere and run `cargo xtask lists --fix`; `cargo xtask lists` (in `cargo xtask ci`
@@ -509,11 +509,15 @@ The user guide's screenshots and short clips (`docs/book/src/media/`) are captur
app by `examples/demo/doc_shots.py`, one function per figure. Each run starts a fresh app with its
own settings, so your preferences never show. When a change makes a figure out of date, run
`python3 examples/demo/doc_shots.py <page or shot>` (it needs Xvfb, ffmpeg, Pillow and a release
build) and commit the new file. A new figure is a new function there, an ATTRIBUTION row in
`attribution/pending/`, and a `<video>` (clips) or image link on the page. Keep a still under
build) and commit the new file. Stills come in both themes: `--light` makes `<name>.light.png`,
and the page shows the one that matches the book's theme (an `<img class="dark-ui">` and an
`<img class="light-ui">`). A new figure is a new function there, an ATTRIBUTION row in
`attribution/pending/`, and a `<video>` (clips) or the image pair on the page. Keep a still under
about 250 KB and a clip under about 1 MB.
## Licence
By contributing you agree that your contribution is licensed as MIT OR Apache-2.0, like the rest
of SolidCraft. SolidCraft isn't affiliated with any CAD vendor; product names are trademarks of their owners (see NOTICE).
of SolidCraft. A contribution to the brand and interface (`crates/ui-kit`, `crates/look`,
`crates/theme`, `assets/branding`, `assets/icons/app`) is licensed under
[LICENSE-BRAND](LICENSE-BRAND), which lets the maintainers also license it as MIT OR Apache-2.0. SolidCraft isn't affiliated with any CAD vendor; product names are trademarks of their owners (see NOTICE).
Generated
+50 -13
View File
@@ -4234,6 +4234,16 @@ dependencies = [
"thiserror 2.0.21",
]
[[package]]
name = "solidcore-step"
version = "0.1.0"
dependencies = [
"solidcore",
"solidcore-convert",
"solidcore-ops",
"solidcore-record",
]
[[package]]
name = "solidcore-tess"
version = "0.1.0"
@@ -4275,6 +4285,7 @@ dependencies = [
"solidcraft-control",
"solidcraft-engine",
"solidcraft-gpu",
"solidcraft-look",
"solidcraft-space-mouse",
"solidcraft-theme",
"solidcraft-ui-egui",
@@ -4477,16 +4488,28 @@ dependencies = [
"serde_json",
"solidcore-ops",
"solidcore-record",
"solidcore-step",
"solidcore-tess",
"solidcraft-geom",
"solidcraft-profile",
"solidcraft-smlib",
"solidcraft-step",
"spade",
"thiserror 2.0.21",
"web-time",
]
[[package]]
name = "solidcraft-look"
version = "0.40.0-rc.3"
dependencies = [
"egui",
"log",
"solidcraft-theme",
"solidcraft-ui-kit",
"tiny-skia",
"toml",
]
[[package]]
name = "solidcraft-mcp"
version = "0.40.0-rc.3"
@@ -4574,16 +4597,6 @@ dependencies = [
"serde",
]
[[package]]
name = "solidcraft-step"
version = "0.40.0-rc.3"
dependencies = [
"solidcore-ops",
"solidcore-record",
"solidcraft-geom",
"solidcraft-profile",
]
[[package]]
name = "solidcraft-testkit"
version = "0.40.0-rc.3"
@@ -4609,7 +4622,6 @@ dependencies = [
"log",
"lopdf",
"minisign-verify",
"muda",
"nix 0.31.3",
"pollster 0.4.0",
"proc-macro2",
@@ -4624,8 +4636,10 @@ dependencies = [
"solidcraft-control-egui",
"solidcraft-engine",
"solidcraft-gpu",
"solidcraft-look",
"solidcraft-space-mouse",
"solidcraft-theme",
"solidcraft-ui-kit",
"solidcraft-ui-registry",
"solidcraft-ui-text",
"solidcraft-viewport",
@@ -4633,13 +4647,35 @@ dependencies = [
"solidcraft-viewport-gpu",
"syn 2.0.119",
"tiny-skia",
"toml",
"ttf-parser",
"web-time",
"winreg",
"zip",
]
[[package]]
name = "solidcraft-ui-kit"
version = "0.40.0-rc.3"
dependencies = [
"arboard",
"egui",
"egui-wgpu",
"image",
"log",
"muda",
"serde",
"serde_json",
"solidcraft-color",
"solidcraft-theme",
"solidcraft-ui-registry",
"solidcraft-ui-text",
"solidcraft-viewport-egui",
"solidcraft-viewport-gpu",
"syn 2.0.119",
"tiny-skia",
"web-time",
]
[[package]]
name = "solidcraft-ui-registry"
version = "0.40.0-rc.3"
@@ -4708,6 +4744,7 @@ dependencies = [
"serde_json",
"solidcraft-control",
"solidcraft-engine",
"solidcraft-look",
"solidcraft-ui-egui",
"solidcraft-ui-text",
"url",
+4 -1
View File
@@ -21,7 +21,6 @@ solidcraft-profile = { path = "crates/profile" }
solidcraft-sketch = { path = "crates/sketch" }
solidcraft-kernel = { path = "crates/kernel" }
solidcraft-smlib = { path = "crates/smlib" }
solidcraft-step = { path = "crates/step" }
solidcraft-render = { path = "crates/render" }
solidcraft-dynamics = { path = "crates/dynamics" }
solidcraft-gpu = { path = "crates/gpu" }
@@ -29,6 +28,8 @@ solidcraft-doc = { path = "crates/doc" }
solidcraft-io = { path = "crates/io" }
solidcraft-engine = { path = "crates/engine" }
solidcraft-ui-egui = { path = "crates/ui-egui" }
solidcraft-ui-kit = { path = "crates/ui-kit" }
solidcraft-look = { path = "crates/look" }
solidcraft-ui-registry = { path = "crates/ui-registry" }
solidcraft-color = { path = "crates/color" }
solidcraft-ui-text = { path = "crates/ui-text" }
@@ -53,6 +54,8 @@ solidcore-record = { path = "solidcore/crates/solidcore-record" }
# The modelling layer (solidcore's layers §1, "Ops"): the record-level calls SolidCraft makes into the
# kernel, converting through solidcore-convert.
solidcore-ops = { path = "solidcore/crates/solidcore-ops" }
# STEP import and export (vendored with solidcore): the Part 21 parser is solidcore-record's.
solidcore-step = { path = "solidcore/crates/solidcore-step" }
# Geometry made drawable (solidcore's layers §3): the one mesher, SolidCraft's, moved into the
# subtree (RFC 0003, item 1.1), with the display mesh and its levels of detail, the types
# SolidCraft's meshes are. Vendored with solidcore, in the same subtree.
+62
View File
@@ -0,0 +1,62 @@
SolidCraft Brand and Interface Licence
Copyright (c) 2026 the SolidCraft maintainers.
SolidCraft's code that models, imports, exports and computes geometry is open source under the MIT
License or the Apache License 2.0 (LICENSE-MIT, LICENSE-APACHE). This licence covers something
different: how SolidCraft looks and feels. That is its brand. A CAD program can be built from
SolidCraft's open code; it should not look like SolidCraft unless the maintainers have agreed.
1. What this licence covers ("the Brand Material")
a. The UI kit, `crates/ui-kit` (solidcraft-ui-kit): the code and the design of SolidCraft's
controls, panels, menus, ribbon, app bar, history bar, navigation bar, view compass,
Preferences window, start page and window chrome.
b. The look, `crates/look` (solidcraft-look): the interface icon masters and their artwork,
the code-drawn glyphs, and the built-in themes.
c. The theme, `crates/theme` (solidcraft-theme): the design tokens, colour palettes, accent
ramps, sizes and spacing that give SolidCraft its appearance.
d. The SolidCraft name, logo, app icon and brand kit (`assets/branding`, `assets/icons/app`).
Third-party material inside these folders keeps its own licence, listed in ATTRIBUTION.md.
In particular the IBM Plex fonts are under the SIL Open Font License 1.1, and nothing here
limits what that licence allows.
2. What you may do without asking
a. Read, build, run and modify the Brand Material as part of SolidCraft itself, including
your own builds and forks of SolidCraft used for development, testing, learning or
contributing back.
b. Contribute changes to the Brand Material through the SolidCraft repository.
c. Show SolidCraft, with its look, in reviews, tutorials, articles, videos and teaching.
3. What needs the maintainers' written permission first
a. Using any Brand Material in another program, product, service or library, including
linking to the UI kit, the look or the theme from software that is not SolidCraft.
b. Distributing the Brand Material, or a modified version of it, other than as part of
SolidCraft.
c. Distributing a fork or modified build of SolidCraft to others under the SolidCraft name,
logo or app icon, or with a look that could be taken for SolidCraft's.
d. Using the SolidCraft name, logo or app icon to name, promote or endorse anything else.
To ask, open an issue at https://github.com/tangency-labs/solidcraft or contact the
maintainers there. Permission is given in writing and may come with conditions.
4. Contributions
By contributing to the Brand Material you agree that the maintainers may license your
contribution under this licence, and under the MIT License or the Apache License 2.0, at
their choice.
5. Earlier versions
Versions of SolidCraft published before this licence took effect stay under the licences
they were published with.
6. No warranty
The Brand Material is provided "as is", without warranty of any kind, express or implied,
including the warranties of merchantability, fitness for a particular purpose and
non-infringement. In no event shall the maintainers or contributors be liable for any
claim, damages or other liability arising from the Brand Material or its use.
+9
View File
@@ -3,6 +3,15 @@ Copyright (c) 2026 SolidCraft contributors.
Licensed under the MIT License or the Apache License, Version 2.0, at your option
(LICENSE-MIT, LICENSE-APACHE).
Brand and interface
SolidCraft's brand and interface are not under MIT OR Apache-2.0. The UI kit (crates/ui-kit), the
look (crates/look: the interface icons, glyphs and built-in themes), the theme (crates/theme: the
design tokens and palettes), and the SolidCraft name, logo, app icon and brand kit are under the
SolidCraft Brand and Interface Licence (LICENSE-BRAND). They may be used, changed and contributed
to as part of SolidCraft; using them in anything else needs the maintainers' written permission.
Third-party fonts in those folders keep their own licences.
Third-party material
Software dependencies are listed in Cargo.lock; their licences are in THIRD-PARTY-LICENSES.txt
+6
View File
@@ -133,6 +133,12 @@ MIT OR Apache-2.0, at your option. Developed under the
[clean-room contribution rules](AGENTS.md); third-party code and assets retain their
documented licences and attribution.
SolidCraft's brand and interface are licensed separately, under
[LICENSE-BRAND](LICENSE-BRAND): the UI kit, the look (interface icons, glyphs, built-in themes),
the theme's design tokens and palettes, and the SolidCraft name, logo and app icon. Use them freely
as part of SolidCraft. Using them in another program or product needs the maintainers' written
permission first.
SolidCraft is independent. Behaviour is designed from public documentation, general CAD
conventions and user feedback. Reference tests use analytic values and open-source tools.
SolidCraft is not affiliated with, sponsored by or endorsed by Autodesk, Dassault Systèmes, PTC,
+2
View File
@@ -24,6 +24,8 @@ profile = ["solidcraft-engine/profile"]
solidcraft-engine = { workspace = true }
solidcraft-control = { workspace = true }
solidcraft-ui-egui = { workspace = true }
# SolidCraft's look (icons, glyphs, built-in themes), installed at startup.
solidcraft-look = { workspace = true }
solidcraft-ui-text = { workspace = true }
egui = { workspace = true }
log = { workspace = true }
+1 -1
View File
@@ -1246,7 +1246,7 @@ mod web {
pub fn start() {
eframe::WebLogger::init(log::LevelFilter::Info).ok();
solidcraft_ui_egui::i18n::install();
solidcraft_ui_egui::icon_svg::install();
solidcraft_look::install_tables();
solidcraft_ui_egui::workspace::install_tabs();
solidcraft_ui_egui::navigation_slots::install();
wasm_bindgen_futures::spawn_local(async {
+19 -5
View File
@@ -44,8 +44,10 @@ const UPDATE_TIMEOUT_MS = 20000;
const COMPLETE = "build-complete";
/** The entry that marks a build replaced by a newer worker. */
const RETIRED = "build-retired";
/** A page remembered this recently may still be loading (not yet listed among the clients). */
const PAGE_LOADING_MS = 30 * 1000;
/** A page remembered this recently may still be loading (not yet listed among the clients). A slow
* device can take minutes between the launch's answer and the page appearing; a live page's record is
* kept for as long as it is listed. */
const PAGE_LOADING_MS = 10 * 60 * 1000;
const url = (file) => new URL(file, self.registration.scope).href;
const has = (name, entry) => caches.match(url(entry), { cacheName: name }).then(Boolean);
@@ -102,10 +104,13 @@ async function started(id, build) {
await (await caches.open(PAGES)).put(pageEntry(id), new Response(record));
}
/** The build a page started; a page started before it was remembered gets this worker's. */
/**
* The build a page started, or null when it was not remembered. Never this worker's build instead:
* after an update that is another build than the page's, and its files would be mixed into the page.
*/
async function startedBy(id) {
const response = id ? await caches.match(pageEntry(id), { cacheName: PAGES }) : null;
return response ? (await response.json()).build : CACHE;
return response ? (await response.json()).build : null;
}
/** The builds open pages use (pages closed since are forgotten). */
@@ -148,6 +153,10 @@ self.addEventListener("activate", (event) => {
}
await sweep();
await self.clients.claim();
// Pages open when the worker first takes over came from the network, and get their files from it.
for (const client of await self.clients.matchAll({ includeUncontrolled: true })) {
if (!(await startedBy(client.id).catch(() => null))) await started(client.id, NETWORK).catch(() => {});
}
})(),
);
});
@@ -221,7 +230,12 @@ async function launchOrKept(event) {
/** A page's files come from the build it started, else the network. */
async function asset(event) {
const build = await startedBy(event.clientId).catch(() => CACHE);
const build = await startedBy(event.clientId).catch(() => null);
// A page whose build is not known, or whose build's copy is gone, would get another build's files
// (a mixed page that never starts). It fails visibly instead: reloading starts a whole build.
if (!build || (build !== NETWORK && !(await caches.has(build)))) {
return new Response("This page's version of the app is no longer kept. Reload the page.", { status: 503, headers: { "Content-Type": "text/plain" } });
}
const kept = build === NETWORK ? null : await caches.match(event.request, { cacheName: build, ignoreSearch: true });
return kept || fetch(event.request);
}
+2
View File
@@ -37,6 +37,8 @@ solidcraft-control = { workspace = true }
# The D3D12 shader compiler the window starts with (#6756).
solidcraft-gpu = { workspace = true }
solidcraft-ui-egui = { workspace = true }
# SolidCraft's look (icons, glyphs, built-in themes), installed at startup.
solidcraft-look = { workspace = true }
solidcraft-ui-text = { workspace = true }
solidcraft-theme = { workspace = true }
solidcraft-space-mouse = { workspace = true }
+63 -35
View File
@@ -3,7 +3,7 @@
//! with what SolidCraft's requests mean ([`SolidCraft`]).
use std::net::TcpListener;
use std::sync::mpsc::{Receiver, Sender, channel};
use std::sync::mpsc::{Sender, channel};
use std::sync::{Arc, OnceLock};
use serde_json::{Value, json};
@@ -12,6 +12,7 @@ use solidcraft_control::{ControlRequest, auth};
use solidcraft_engine::MAX_LINE;
use solidcraft_engine::control_auth::APP;
use solidcraft_engine::control_pending;
use solidcraft_ui_egui::control_switch;
/// The token files this launch wrote (its control port, the agent chat's endpoint) and the
/// token in each, removed when the app ends unless another launch has written the file since.
@@ -85,40 +86,60 @@ pub fn remove_token_file() {
/// The port the app's own channel listens on and its token, for removing the discovery file at exit.
static APP_PORT: std::sync::Mutex<Option<(u16, String)>> = std::sync::Mutex::new(None);
pub fn start(listen_on: auth::Listen, ctx: egui::Context) -> Receiver<ControlRequest> {
/// Open the app's control channel (at launch, or turned on in the settings): its listener, its
/// token file and the discovery file. Stopping it removes both files again.
pub fn start(listen_on: auth::Listen, ctx: egui::Context) -> Result<control_switch::Started, control_switch::StartError> {
use control_switch::StartError;
let (tx, rx) = channel::<ControlRequest>();
// Every connection must show the token before anything runs (docs/control-protocol.md).
match APP.env_token().or_else(server::new_token) {
Some(token) => {
let listener = match listen_on {
auth::Listen::Exact(port) => TcpListener::bind(("127.0.0.1", port)),
auth::Listen::Default => auth::bind_with_fallback(APP.default_port, auth::PORT_TRIES),
};
match listener {
Ok(l) => {
if let Some(port) = listen_on_listener(l, token.clone(), tx, ctx, false) {
if matches!(listen_on, auth::Listen::Default) {
solidcraft_engine::note!(
"solidcraft: control channel on the default port 127.0.0.1:{port} (Preferences > Assistant turns it off)"
);
}
// The discovery file: where `solidcraft-cli mcp` finds this app with no arguments.
match APP.write_current_port(port) {
Ok(_) => {
if let Ok(mut p) = APP_PORT.lock() {
*p = Some((port, token));
}
}
Err(e) => solidcraft_engine::note!("solidcraft: could not write the control discovery file ({e})"),
}
}
}
Err(e) => solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}"),
let Some(token) = APP.env_token().or_else(server::new_token) else {
solidcraft_engine::note!("solidcraft: control server not started: no random token available");
return Err(StartError::Failed("no random token available".into()));
};
let listener = match listen_on {
auth::Listen::Exact(port) => TcpListener::bind(("127.0.0.1", port)),
auth::Listen::Default => auth::bind_with_fallback(APP.default_port, auth::PORT_TRIES),
};
let listener = listener.map_err(|e| {
solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}");
match (listen_on, e.kind()) {
// In use; Windows reports a port another program holds exclusively as denied.
(auth::Listen::Exact(port), std::io::ErrorKind::AddrInUse | std::io::ErrorKind::PermissionDenied) => StartError::PortTaken(port),
(auth::Listen::Default, std::io::ErrorKind::AddrInUse | std::io::ErrorKind::PermissionDenied) => StartError::PortTaken(APP.default_port),
_ => StartError::Failed(e.to_string()),
}
})?;
let (port, stop) =
listen_on_listener(listener, token.clone(), tx, ctx, false).ok_or_else(|| StartError::Failed("the listener did not start".into()))?;
if matches!(listen_on, auth::Listen::Default) {
solidcraft_engine::note!("solidcraft: control channel on the default port 127.0.0.1:{port} (Preferences > Assistant turns it off)");
}
// The discovery file: where `solidcraft-cli mcp` finds this app with no arguments.
match APP.write_current_port(port) {
Ok(_) => {
if let Ok(mut p) = APP_PORT.lock() {
*p = Some((port, token.clone()));
}
}
None => solidcraft_engine::note!("solidcraft: control server not started: no random token available"),
Err(e) => solidcraft_engine::note!("solidcraft: could not write the control discovery file ({e})"),
}
rx
let stop = Box::new(move || {
stop.stop();
if let Ok(mut p) = APP_PORT.lock()
&& p.as_ref().is_some_and(|(held, _)| *held == port)
{
*p = None;
}
APP.remove_current_port(port, &token);
if let Some(path) = APP.token_path(port) {
auth::remove_token_file(&path, &token);
if let Ok(mut files) = TOKEN_FILES.lock() {
files.retain(|(p, _)| *p != path);
}
}
solidcraft_engine::note!("solidcraft: control channel on 127.0.0.1:{port} closed");
});
Ok(control_switch::Started { port, requests: rx, stop })
}
/// The agent chat's own endpoint for its agent's MCP server (docs/agent-chat.md): a free loopback
@@ -137,12 +158,19 @@ pub fn listen_agent(tx: Sender<ControlRequest>, ctx: egui::Context) -> Option<u1
return None;
}
};
listen_on_listener(listener, token, tx, ctx, true)
// The chat's endpoint lives as long as the app.
listen_on_listener(listener, token, tx, ctx, true).map(|(port, _)| port)
}
/// Serve `listener` (loopback) with `token`; the port it listens on.
/// Serve `listener` (loopback) with `token`; the port it listens on and how to stop it.
/// `patient`: every request may wait as long as a batch (a person decides on it).
fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRequest>, ctx: egui::Context, patient: bool) -> Option<u16> {
fn listen_on_listener(
listener: TcpListener,
token: String,
tx: Sender<ControlRequest>,
ctx: egui::Context,
patient: bool,
) -> Option<(u16, server::Stop)> {
let port = listener.local_addr().ok()?.port();
match APP.token_path(port) {
Some(path) => match APP.write_token_file(&path, &token) {
@@ -164,8 +192,8 @@ fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRe
)
}
}
match hub(ctx).listen(listener, token, tx, patient) {
Ok(()) => Some(port),
match hub(ctx).listen_stoppable(listener, token, tx, patient) {
Ok(stop) => Some((port, stop)),
Err(e) => {
solidcraft_engine::note!("solidcraft: control server not started: {e}");
None
+162 -23
View File
@@ -87,6 +87,8 @@ struct App {
solve: SolveApp,
/// The settings folder whose start marker the first frame clears (`startup::started`).
starting: Option<std::path::PathBuf>,
/// A newly selected API is confirmed only once the first frame has been presented.
backend_attempt: Option<(std::path::PathBuf, startup::BackendAttempt)>,
/// Frames begun; the second one means the first was drawn (startup is over).
frames: u32,
/// Started over the control channel: the window doesn't ask for the foreground.
@@ -215,6 +217,12 @@ impl eframe::App for App {
solidcraft_ui_egui::ai_connect::begin(&mut self.solve);
solidcraft_ui_egui::agent_chat::begin(&mut self.solve);
}
if let Some((path, attempt)) = self.backend_attempt.take()
&& let Err(reason) = startup::confirm_backend_start(&path, &attempt)
{
log::warn!("graphics: could not confirm the startup choice: {reason}");
self.solve.set_status(reason, true);
}
if let Some(dir) = self.starting.take() {
startup::started(&dir);
}
@@ -341,10 +349,17 @@ impl Drop for App {
// never return (#9044).
device_lost::end();
}
// An update asked to restart into the new version or to run its installer.
// Restart only after eframe has flushed settings. Graphics restarts also reopen
// the saved designs collected by the normal quit flow.
let graphics_restart = solidcraft_ui_egui::update::take_graphics_restart(&mut self.solve);
if let Some((program, args)) = solidcraft_ui_egui::update::take_launch(&mut self.solve) {
let mut command = std::process::Command::new(&program);
command.args(&args);
let mut command = if graphics_restart {
graphics_restart_command(&program, &args, &self.solve.preferences.open_designs)
} else {
let mut command = std::process::Command::new(&program);
command.args(&args);
command
};
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
@@ -360,6 +375,62 @@ impl Drop for App {
}
}
/// A UI restart applies the saved API instead of inheriting this session's recovery
/// overrides. Explicit developer overrides remain authoritative.
fn graphics_restart_command(program: &std::path::Path, args: &[String], designs: &[String]) -> std::process::Command {
let mut command = std::process::Command::new(program);
command.args(args).args(designs);
for variable in [
startup::RETRY_BACKEND_ENV,
startup::FALLBACK_NOTE_ENV,
startup::RENDERER_ENV,
startup::SAFE_MODE_ENV,
device_lost::LOST_ENV,
device_lost::REASON_ENV,
] {
command.env_remove(variable);
}
command
}
/// Re-enter an AppImage through its outer executable only when this process actually lives
/// in that image's mount. An inherited APPIMAGE from another application is not our launcher.
fn graphics_restart_program(
exe: Option<&std::path::Path>,
appimage: Option<&std::ffi::OsStr>,
appdir: Option<&std::ffi::OsStr>,
is_file: impl Fn(&std::path::Path) -> bool,
) -> Option<std::path::PathBuf> {
let exe = exe?;
if let (Some(image), Some(directory)) = (appimage, appdir) {
let image = std::path::Path::new(image);
let directory = std::path::Path::new(directory);
if image.is_absolute() && directory.is_absolute() && exe.starts_with(directory) && is_file(image) {
return Some(image.to_path_buf());
}
}
Some(exe.to_path_buf())
}
/// Keep launch-scoped settings through a UI restart. Safe mode and the sample are one-shot;
/// original file arguments are replaced by the current saved tabs at shutdown.
fn graphics_restart_args(args: impl IntoIterator<Item = String>) -> Vec<String> {
let mut retained = Vec::new();
let mut args = args.into_iter();
while let Some(argument) = args.next() {
match argument.as_str() {
"--control" | "--theme-file" | "--max-file-size" => {
if let Some(value) = args.next() {
retained.extend([argument, value]);
}
}
value if value.starts_with("--max-file-size=") => retained.push(argument),
_ => {}
}
}
retained
}
/// The window's graphics device, watched for its loss.
struct LostWatch {
lost: eframe::egui_wgpu::DeviceLost,
@@ -569,6 +640,15 @@ fn services(cc: &eframe::CreationContext<'_>, folder: &DialogFolder) -> Services
Box::pin(async move { folder.answer(future.await) })
})),
graphics_adapters: Vec::new(),
graphics_backend: None,
graphics_backend_override: std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty()),
graphics_restart: graphics_restart_program(
std::env::current_exe().ok().as_deref(),
std::env::var_os("APPIMAGE").as_deref(),
std::env::var_os("APPDIR").as_deref(),
std::path::Path::is_file,
)
.map(|program| (program, graphics_restart_args(std::env::args().skip(1)))),
graphics_path: graphics_path().map(|p| p.to_string_lossy().to_string()),
window_system: window_system_now(),
// Linux: the desktop's dark or light setting, which the window is not told on every
@@ -832,6 +912,12 @@ fn restore_preferences(app: &mut SolveApp, stored_ui: Option<&str>, saved_graphi
/// Restore startup choices after loading the separately saved UI preferences.
fn restore_graphics_preferences(app: &mut SolveApp, saved: Option<&serde_json::Value>) {
// Preserve legacy comma lists until the user explicitly selects a different API.
app.preferences.graphics_backend = saved
.and_then(|v| v.get("backend").and_then(serde_json::Value::as_str))
.filter(|choice| !choice.trim().is_empty())
.unwrap_or("auto")
.to_string();
app.preferences.graphics_adapter = saved.and_then(|v| v.get("adapter").and_then(serde_json::Value::as_str)).unwrap_or_default().to_string();
// graphics.json chooses the window before app.ron is loaded. Reflect that saved choice,
// not the current session's window system (which an environment override may change).
@@ -843,11 +929,6 @@ fn restore_graphics_preferences(app: &mut SolveApp, saved: Option<&serde_json::V
.to_string();
}
/// The graphics backend preference (`graphics.json`'s `backend`: `auto`, `dx12`, `vulkan`, `gl`).
fn backend_preference() -> Option<String> {
graphics().and_then(|v| v.get("backend").and_then(serde_json::Value::as_str).map(str::to_string))
}
/// The viewport scene's sample count, by the rule the web app shares
/// (`solidcraft_ui_egui::gpu::scene_samples`).
fn scene_samples(backend: eframe::wgpu::Backend, samples: u32, supported: &[u32]) -> u32 {
@@ -934,7 +1015,7 @@ fn main() -> eframe::Result {
objc2_foundation::NSProcessInfo::processInfo().setProcessName(objc2_foundation::ns_string!("SolidCraft"));
mark("main");
solidcraft_ui_egui::i18n::install();
solidcraft_ui_egui::icon_svg::install();
solidcraft_look::install_tables();
solidcraft_ui_egui::workspace::install_tabs();
solidcraft_ui_egui::navigation_slots::install();
// On OCLP-patched Macs, wgpu picks a Metal Shading Language standard that the system's
@@ -1016,7 +1097,27 @@ fn main() -> eframe::Result {
safe_mode = true;
notes.push(format!("The last {failed_starts} launches stopped before the window opened, so this one is in safe mode."));
}
let cpu_renderer = safe_mode || startup::cpu_renderer_env(std::env::var(startup::RENDERER_ENV).ok().as_deref());
let mut cpu_renderer = safe_mode || startup::cpu_renderer_env(std::env::var(startup::RENDERER_ENV).ok().as_deref());
// Persist the one-start guard before any adapter, device or depth-format probe.
// Recovery launches and explicit overrides must not consume a pending UI choice.
let backend_override = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
let retry_backend = std::env::var(startup::RETRY_BACKEND_ENV).ok();
let backend_path = settings.as_ref().map(|dir| dir.join("graphics.json"));
let backend_launch = match backend_path
.as_ref()
.map(|path| startup::prepare_backend_start(path, !cpu_renderer && !backend_override && retry_backend.is_none()))
.transpose()
{
Ok(launch) => launch.unwrap_or_default(),
Err(reason) => {
// A choice that could not be guarded must not load the requested driver.
cpu_renderer = true;
notes.push(reason);
startup::BackendLaunch::default()
}
};
let backend_attempt = backend_path.zip(backend_launch.attempt);
let backend_note = backend_launch.note;
// The launch before this one closed because its graphics device was lost (`App::watch_device`).
let after_loss = device_lost::recent(std::env::var(device_lost::LOST_ENV).ok().as_deref(), device_lost::now_secs());
if after_loss {
@@ -1029,14 +1130,14 @@ fn main() -> eframe::Result {
if safe_mode {
notes.push("Safe mode: default settings (yours are kept for the next normal start), no recovery offer, software rendering.".into());
}
let fallback_note = std::env::var(startup::FALLBACK_NOTE_ENV).ok().map(|s| s.chars().take(4096).collect::<String>());
let fallback_note = std::env::var(startup::FALLBACK_NOTE_ENV).ok().map(|s| s.chars().take(4096).collect::<String>()).or(backend_note);
if let Some(note) = &fallback_note {
log::warn!("{note}");
solidcraft_engine::note!("SolidCraft: {note}");
notes.push(note.clone());
}
let saved_samples = if safe_mode { None } else { msaa() };
let wgpu_options = wgpu_options(cpu_renderer, if safe_mode { None } else { backend_preference() }.as_deref());
let wgpu_options = wgpu_options(cpu_renderer, if safe_mode { None } else { backend_launch.backend.as_deref() });
let depth_bits = if !safe_mode && startup::float_depth_everywhere(&wgpu_options) { FLOAT_DEPTH_BITS } else { DEPTH_BITS };
// Crashes leave a report in the crash folder (solidcraft_engine::crash, docs/crash-reports.md).
let crashed = solidcraft_engine::crash::default_dir()
@@ -1117,6 +1218,7 @@ fn main() -> eframe::Result {
let created = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let created_in_app = created.clone();
let starting = settings.clone();
let attempt_in_app = backend_attempt.clone();
// A panic on the window's thread ends the app without `on_exit`; this disconnects from the
// 3D mouse driver then too.
#[cfg(target_os = "macos")]
@@ -1181,6 +1283,13 @@ fn main() -> eframe::Result {
})
.collect();
let info = rs.adapter.get_info();
app.services.graphics_backend = match info.backend {
eframe::wgpu::Backend::Vulkan => Some("vulkan"),
eframe::wgpu::Backend::Dx12 => Some("dx12"),
eframe::wgpu::Backend::Gl => Some("gl"),
eframe::wgpu::Backend::Metal => Some("metal"),
_ => None,
};
if !app.preferences.graphics_adapter.is_empty() && !info.name.eq_ignore_ascii_case(app.preferences.graphics_adapter.as_str()) {
solidcraft_engine::note!(
"SolidCraft graphics: preferred adapter {:?} was not used; using {:?} instead",
@@ -1211,12 +1320,11 @@ fn main() -> eframe::Result {
));
}
mark("viewport pipelines");
// `--control`/the environment name a port; otherwise the preference (on by default)
// opens the default one (docs/control-protocol.md).
if let Some(listen_on) = solidcraft_control::auth::plan(control_port, app.preferences.agent_control) {
let rx = control_server::start(listen_on, cc.egui_ctx.clone());
app = app.with_control(rx);
}
// `--control`/the environment name a port for this run; otherwise the preference (off
// by default) opens its port, and turning it off or on later takes effect at once
// (docs/control-protocol.md).
let ctx = cc.egui_ctx.clone();
solidcraft_ui_egui::control_switch::launch(&mut app, Box::new(move |listen| control_server::start(listen, ctx.clone())), control_port);
// The agent chat's MCP bridge reaches the app through an endpoint of its own, started
// on a free port the first time the chat connects (docs/agent-chat.md).
let ctx = cc.egui_ctx.clone();
@@ -1313,6 +1421,7 @@ fn main() -> eframe::Result {
prefs_writer: PrefsWriter::read(app.prefs()),
solve: app,
starting,
backend_attempt: attempt_in_app,
frames: 0,
take_focus_unwanted: control_port.is_some(),
come_forward: come_forward::ComeForward::default(),
@@ -1328,7 +1437,9 @@ fn main() -> eframe::Result {
);
control_server::remove_token_file();
match result {
Err(e) if !created.load(std::sync::atomic::Ordering::SeqCst) => no_window(e, cpu_renderer, started, settings.as_deref()),
Err(e) if !created.load(std::sync::atomic::Ordering::SeqCst) => {
no_window(e, cpu_renderer, started, settings.as_deref(), backend_attempt.as_ref())
}
r => r,
}
}
@@ -1347,7 +1458,10 @@ fn startup_step(step: &'static str, detail: &str) {
/// backends come from `startup::choose_backends` (on Windows D3D12 first, and only the backend
/// in use is started); `preference` is `graphics.json`'s `backend`.
fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuConfiguration {
let mut options = eframe::egui_wgpu::WgpuConfiguration::default();
// One frame in flight, as eframe's own default (`NativeOptions::default`): egui-wgpu's
// `WgpuConfiguration::default()` is HIGH_THROUGHPUT (two frames queued), which added a frame
// of input-to-display latency to every pan, orbit and drag.
let mut options = eframe::egui_wgpu::WgpuConfiguration::default().with_surface_config(eframe::egui_wgpu::SurfaceConfig::LOW_LATENCY);
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut options.wgpu_setup {
let env_set = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
// A retry applies only to this launch. WGPU_BACKEND always has priority.
@@ -1378,7 +1492,13 @@ fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuC
/// A failed renderer returns here before app creation. A fresh process avoids reusing winit's
/// event loop or a failed device; each retry advances through the APIs, then software once.
fn no_window(error: eframe::Error, tried_cpu: bool, failed: eframe::wgpu::Backends, settings: Option<&std::path::Path>) -> eframe::Result {
fn no_window(
error: eframe::Error,
tried_cpu: bool,
failed: eframe::wgpu::Backends,
settings: Option<&std::path::Path>,
backend_attempt: Option<&(std::path::PathBuf, startup::BackendAttempt)>,
) -> eframe::Result {
log::error!("the window could not open: {error}");
solidcraft_engine::note!("SolidCraft: the window could not open: {error}");
// This failure was handled, so neither the marker nor the journal should call it a crash.
@@ -1386,6 +1506,25 @@ fn no_window(error: eframe::Error, tried_cpu: bool, failed: eframe::wgpu::Backen
startup::started(dir);
}
solidcraft_engine::crash::end_session();
// A rejected UI choice goes back to its previous API before ordinary fallback.
// This is separate from startup::started: a handled failure is not confirmation.
if let Some((path, attempt)) = backend_attempt {
match startup::rollback_backend_start(path, attempt) {
Ok(()) => {
if let Ok(exe) = std::env::current_exe() {
let note = startup::backend_reverted_note(&attempt.requested, &attempt.previous);
let mut command = std::process::Command::new(exe);
command.args(std::env::args_os().skip(1)).env_remove(startup::RETRY_BACKEND_ENV).env(startup::FALLBACK_NOTE_ENV, note);
match command.status() {
Ok(status) if status.success() => return Ok(()),
Ok(_) => return Err(error),
Err(reason) => log::error!("could not restart with the previous graphics API: {reason}"),
}
}
}
Err(reason) => log::warn!("could not restore the previous graphics API: {reason}"),
}
}
let explicit = std::env::var(startup::WGPU_BACKEND_ENV).is_ok_and(|v| !v.trim().is_empty());
if let Some(next) = startup::fallback_backend(cfg!(target_os = "windows"), explicit, tried_cpu, failed)
&& let Ok(exe) = std::env::current_exe()
@@ -1631,7 +1770,7 @@ mod prefs_writer_tests {
let now = Instant::now();
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
assert_eq!(disk.flushes, 0, "the settings read at start are not written again");
app.preferences.navigator_style = NavigatorStyle::Custom;
app.preferences.navigator_style = NavigatorStyle::Cube;
app.preferences.display_quality = "fine".into();
assert!(writer.due(true, now), "a frame with input is checked");
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
@@ -1643,7 +1782,7 @@ mod prefs_writer_tests {
let mut next = new_app();
let stored = solidcraft_ui_egui::prefs::stored(|k| disk.flushed.get(k).cloned()).expect("settings on disk");
next.load_prefs(&stored);
assert_eq!(next.preferences.navigator_style, NavigatorStyle::Custom);
assert_eq!(next.preferences.navigator_style, NavigatorStyle::Cube);
assert_eq!(next.preferences.display_quality, "fine");
assert!(disk.flushed.contains_key(STORAGE_KEY));
}
+5 -1
View File
@@ -2592,11 +2592,15 @@ mod tests {
let reader = Running::start(driver, fake.clone());
reader.reads("spacenavd");
// Still not readable, over two waits: the daemon read goes on, one connection, a few probes.
let slept = std::time::Instant::now();
std::thread::sleep(Duration::from_millis(700));
let waited = slept.elapsed();
assert_eq!(reader.key().as_deref(), Some("spacenavd"), "{driver:?}");
assert_eq!(fake.world().connects, 1, "{driver:?}: the daemon read was not restarted for a device that still cannot be read");
let opens = fake.world().opens;
assert!(opens <= 4, "{driver:?}: {opens} tries in 700 ms with a 300 ms wait");
// A loaded machine can sleep far past 700 ms: bound the tries by the time that really passed.
let allowed = 4 + (waited.as_millis().saturating_sub(700) / 300) as u32;
assert!(opens <= allowed, "{driver:?}: {opens} tries in {waited:?} with a 300 ms wait");
// The permission is fixed.
fake.world().openable = true;
reader.reads(&Source::Hid(Some(IDS)).key());
+430
View File
@@ -114,6 +114,158 @@ pub fn started(dir: &Path) {
let _ = std::fs::remove_file(dir.join(MARKER));
}
/// A saved backend change that this launch is trying. Keep this value until the first
/// frame is presented, so only this launch's matching attempt can be confirmed or reverted.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BackendAttempt {
pub requested: String,
pub previous: String,
}
/// The backend to use before creating any graphics device, with any pending recovery notice.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct BackendLaunch {
pub backend: Option<String>,
pub attempt: Option<BackendAttempt>,
pub note: Option<String>,
}
type GraphicsSettings = serde_json::Map<String, serde_json::Value>;
const BACKEND_TRIAL: &str = "backend_trial";
const MAX_BACKEND_PREFERENCE_BYTES: usize = 256;
/// Read only object-shaped settings. A missing or empty file means defaults; other failures
/// are reported so the caller can use its safe renderer without overwriting unreadable data.
fn read_backend_settings(path: &Path) -> Result<GraphicsSettings, String> {
let text = match std::fs::read_to_string(path) {
Ok(text) => text,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(GraphicsSettings::new()),
Err(error) => return Err(format!("could not read graphics settings: {error}")),
};
if text.trim().is_empty() {
return Ok(GraphicsSettings::new());
}
serde_json::from_str(&text).map_err(|error| format!("could not read graphics settings: {error}"))
}
/// The attempt marker and backend are written together: a crash must leave a whole old or
/// new record, never a selected API whose recovery data was only partly written.
fn write_backend_settings(path: &Path, graphics: &GraphicsSettings) -> Result<(), String> {
let bytes = serde_json::to_vec(graphics).map_err(|error| format!("could not encode graphics settings: {error}"))?;
solidcraft_engine::io::safe_write::write_atomic(path, &bytes, false).map_err(|error| format!("could not save graphics settings: {error}"))
}
/// UI choices are single API names. The previous value remains verbatim, including legacy
/// comma lists and blanks, because startup already knows how to interpret those preferences.
fn backend_trial(graphics: &GraphicsSettings) -> Option<(BackendAttempt, bool)> {
let trial = graphics.get(BACKEND_TRIAL)?.as_object()?;
let requested = trial.get("requested")?.as_str()?;
if !matches!(requested, "auto" | "dx12" | "vulkan" | "gl" | "metal") {
return None;
}
let previous = trial.get("previous")?.as_str()?;
if previous.len() > MAX_BACKEND_PREFERENCE_BYTES {
return None;
}
let started = trial.get("started")?.as_bool()?;
Some((BackendAttempt { requested: requested.into(), previous: previous.into() }, started))
}
/// Describe a restored choice using the same catalog as the Graphics preferences page.
pub(super) fn backend_reverted_note(requested: &str, previous: &str) -> String {
let requested = solidcraft_ui_egui::prefs::graphics_backend_label(requested);
let previous = solidcraft_ui_egui::prefs::graphics_backend_label(previous);
solidcraft_ui_text::format("prefs.graphics_api_start_reverted", &[("requested", &requested), ("previous", &previous)])
}
/// Prepare a UI-selected API before any adapter is opened. Safe mode, an explicit environment
/// override and process-local fallback launches pass `false` and leave the attempt untouched.
/// An interrupted attempt restores its previous API. A new attempt is returned only after its
/// started marker reaches disk; any I/O error must make the caller avoid the requested API.
pub fn prepare_backend_start(path: &Path, allow_trial: bool) -> Result<BackendLaunch, String> {
prepare_backend_launch(read_backend_settings(path)?, allow_trial, |graphics| write_backend_settings(path, graphics))
}
/// Separate the state transition from persistence so a refused marker write is testable
/// without depending on the test user's filesystem permissions.
fn prepare_backend_launch(
mut graphics: GraphicsSettings,
allow_trial: bool,
save: impl FnOnce(&GraphicsSettings) -> Result<(), String>,
) -> Result<BackendLaunch, String> {
let backend = graphics.get("backend").and_then(serde_json::Value::as_str).map(str::to_string);
let mut launch = BackendLaunch { backend, ..Default::default() };
if !allow_trial || !graphics.contains_key(BACKEND_TRIAL) {
return Ok(launch);
}
let parsed = backend_trial(&graphics);
let requested = graphics.get(BACKEND_TRIAL).and_then(|trial| trial.get("requested")).and_then(serde_json::Value::as_str);
if requested.is_some() && requested != launch.backend.as_deref() {
// Another edit replaced the selected API; stale recovery data cannot undo that edit.
graphics.remove(BACKEND_TRIAL);
} else if let Some((attempt, started)) = parsed {
if attempt.requested == attempt.previous {
graphics.remove(BACKEND_TRIAL);
} else if started {
graphics.insert("backend".into(), serde_json::Value::String(attempt.previous.clone()));
graphics.remove(BACKEND_TRIAL);
launch.backend = Some(attempt.previous.clone());
launch.note = Some(backend_reverted_note(&attempt.requested, &attempt.previous));
} else {
let trial = graphics
.get_mut(BACKEND_TRIAL)
.and_then(serde_json::Value::as_object_mut)
.ok_or_else(|| "graphics backend attempt changed before it could start".to_string())?;
trial.insert("started".into(), serde_json::Value::Bool(true));
launch.attempt = Some(attempt);
}
} else {
// A damaged guard must not turn a protected API into an unguarded attempt. Prefer its
// intact previous value; otherwise use Automatic, preserving the other graphics keys.
let previous = graphics
.get(BACKEND_TRIAL)
.and_then(|trial| trial.get("previous"))
.and_then(serde_json::Value::as_str)
.filter(|value| value.len() <= MAX_BACKEND_PREFERENCE_BYTES)
.unwrap_or("auto")
.to_string();
launch.note = Some(backend_reverted_note(launch.backend.as_deref().unwrap_or("auto"), &previous));
graphics.insert("backend".into(), serde_json::Value::String(previous.clone()));
graphics.remove(BACKEND_TRIAL);
launch.backend = Some(previous);
}
save(&graphics)?;
Ok(launch)
}
/// Only a matching, started attempt still owning the saved backend may change recovery state.
/// A newer preference edit is left alone, including a newly pending attempt at the same API.
fn finish_backend_start(path: &Path, attempt: &BackendAttempt, revert: bool) -> Result<(), String> {
let mut graphics = read_backend_settings(path)?;
let matches = backend_trial(&graphics).is_some_and(|(saved, started)| started && saved == *attempt)
&& graphics.get("backend").and_then(serde_json::Value::as_str) == Some(attempt.requested.as_str());
if !matches {
return Ok(());
}
graphics.remove(BACKEND_TRIAL);
if revert {
graphics.insert("backend".into(), serde_json::Value::String(attempt.previous.clone()));
}
write_backend_settings(path, &graphics)
}
/// Keep a backend only after the window has presented its first frame. Handled startup
/// failures must call `rollback_backend_start` instead, even if the ordinary crash marker clears.
pub fn confirm_backend_start(path: &Path, attempt: &BackendAttempt) -> Result<(), String> {
finish_backend_start(path, attempt, false)
}
/// A handled window-start failure restores the previous backend before the host retries.
/// Reading fresh settings and matching the attempt avoids erasing a later preference edit.
pub fn rollback_backend_start(path: &Path, attempt: &BackendAttempt) -> Result<(), String> {
finish_backend_start(path, attempt, true)
}
/// The software adapter among `adapters` (WARP on Windows, lavapipe or llvmpipe elsewhere), else
/// the first one that can draw to `surface`.
pub fn pick_cpu_adapter(adapters: &[eframe::wgpu::Adapter], surface: Option<&eframe::wgpu::Surface<'_>>) -> Result<eframe::wgpu::Adapter, String> {
@@ -486,6 +638,284 @@ mod tests {
assert!(settings_directory(Some(file.as_os_str()), Some(default)).is_err());
}
// These restart contracts apply to Windows and macOS as well as Linux.
#[test]
fn graphics_restart_applies_saved_choices_and_reopens_saved_designs() {
use std::ffi::OsStr;
let program = std::env::current_exe().unwrap();
let designs = vec!["/saved/first design.sc".to_string(), "/saved/second.sc".to_string()];
let command = crate::graphics_restart_command(&program, &[], &designs);
assert_eq!(command.get_program(), program.as_os_str());
assert_eq!(command.get_args().collect::<Vec<_>>(), designs.iter().map(OsStr::new).collect::<Vec<_>>());
let changes: std::collections::BTreeMap<_, _> = command.get_envs().collect();
for variable in [
crate::startup::RETRY_BACKEND_ENV,
crate::startup::FALLBACK_NOTE_ENV,
crate::startup::RENDERER_ENV,
crate::startup::SAFE_MODE_ENV,
crate::device_lost::LOST_ENV,
crate::device_lost::REASON_ENV,
] {
assert_eq!(changes.get(OsStr::new(variable)), Some(&None), "{variable}");
}
assert!(!changes.contains_key(OsStr::new(crate::startup::WGPU_BACKEND_ENV)));
assert!(!changes.contains_key(OsStr::new("SOLIDCRAFT_SETTINGS_DIR")));
assert!(!changes.contains_key(OsStr::new("WGPU_ADAPTER_NAME")));
}
#[test]
fn graphics_restart_uses_an_appimage_only_from_its_own_existing_mount() {
use crate::graphics_restart_program;
use std::ffi::OsStr;
let root = std::env::temp_dir().join("solidcraft-graphics-restart-fixture");
let appdir = root.join("mount");
let mounted = appdir.join("usr").join("bin").join("solidcraft");
let image = root.join("SolidCraft.AppImage");
let outside = root.join("source").join("solidcraft");
let looks_similar = root.join("mount-other").join("solidcraft");
let exists = |path: &std::path::Path| path == image;
assert_eq!(graphics_restart_program(Some(&mounted), Some(image.as_os_str()), Some(appdir.as_os_str()), exists), Some(image.clone()));
for executable in [&outside, &looks_similar] {
assert_eq!(
graphics_restart_program(Some(executable), Some(image.as_os_str()), Some(appdir.as_os_str()), exists),
Some(executable.to_path_buf()),
"a launcher inherited from another process is ignored"
);
}
for (appimage, directory) in [
(None, Some(appdir.as_os_str())),
(Some(image.as_os_str()), None),
(Some(OsStr::new("")), Some(appdir.as_os_str())),
(Some(image.as_os_str()), Some(OsStr::new(""))),
(Some(OsStr::new("relative.AppImage")), Some(appdir.as_os_str())),
] {
assert_eq!(graphics_restart_program(Some(&mounted), appimage, directory, exists), Some(mounted.clone()));
}
assert_eq!(
graphics_restart_program(Some(&mounted), Some(image.as_os_str()), Some(appdir.as_os_str()), |_| false),
Some(mounted.clone()),
"a missing outer image cannot replace the running executable"
);
assert_eq!(graphics_restart_program(None, Some(image.as_os_str()), Some(appdir.as_os_str()), exists), None);
}
#[test]
fn graphics_restart_keeps_launch_options_and_uses_the_current_saved_tabs() {
let original = [
"--safe-mode",
"--control",
"7878",
"original design.sc",
"--theme-file",
"a theme.json",
"--sample",
"--max-file-size",
"2GB",
"other-original.sc",
"--max-file-size=3GB",
];
let args = crate::graphics_restart_args(original.into_iter().map(str::to_string));
assert_eq!(args, ["--control", "7878", "--theme-file", "a theme.json", "--max-file-size", "2GB", "--max-file-size=3GB"]);
let program = std::env::current_exe().unwrap();
let designs = ["current saved.sc".to_string()];
let command = crate::graphics_restart_command(&program, &args, &designs);
assert_eq!(
command.get_args().map(|value| value.to_string_lossy().into_owned()).collect::<Vec<_>>(),
["--control", "7878", "--theme-file", "a theme.json", "--max-file-size", "2GB", "--max-file-size=3GB", "current saved.sc"]
);
for missing_value in ["--control", "--theme-file", "--max-file-size"] {
assert!(crate::graphics_restart_args([missing_value.to_string()]).is_empty());
}
}
#[test]
fn startup_graphics_api_is_authoritative_over_stale_ui_preferences() {
use serde_json::json;
for choice in ["auto", "vulkan", "dx12", "metal", "gl", "dx12,vulkan"] {
for safe in [false, true] {
let mut app = crate::SolveApp::new(crate::Session::default(), crate::Services::default());
let stored = json!({"preferences":{"graphics_backend":"gl"}}).to_string();
let saved = json!({"backend":choice});
crate::restore_preferences(&mut app, Some(&stored), Some(&saved), safe);
assert_eq!(app.preferences.graphics_backend, choice);
}
}
let mut app = crate::SolveApp::new(crate::Session::default(), crate::Services::default());
app.preferences.graphics_backend = "vulkan".into();
crate::restore_graphics_preferences(&mut app, None);
assert_eq!(app.preferences.graphics_backend, "auto");
}
fn backend_settings(path: &Path) -> serde_json::Value {
serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()
}
fn pending_backend(previous: &str) -> serde_json::Value {
serde_json::json!({
"backend": "vulkan",
"backend_trial": {"requested": "vulkan", "previous": previous, "started": false},
"msaa": 8,
"adapter": "Saved GPU",
"window_system": "x11",
"future_setting": {"enabled": true}
})
}
#[test]
fn backend_start_marks_the_attempt_before_selection_and_keeps_it_after_a_presented_frame() {
let dir = scratch("backend-confirm");
let path = dir.join("graphics.json");
let original = pending_backend("auto");
std::fs::write(&path, original.to_string()).unwrap();
let launch = prepare_backend_start(&path, true).unwrap();
assert_eq!(launch.backend.as_deref(), Some("vulkan"));
assert!(launch.note.is_none());
let attempt = launch.attempt.unwrap();
assert_eq!(attempt, BackendAttempt { requested: "vulkan".into(), previous: "auto".into() });
let mut started = original.clone();
started["backend_trial"]["started"] = serde_json::json!(true);
assert_eq!(backend_settings(&path), started, "selection is returned only after the started marker is durable");
confirm_backend_start(&path, &attempt).unwrap();
let mut kept = original;
kept.as_object_mut().unwrap().remove(BACKEND_TRIAL);
assert_eq!(backend_settings(&path), kept, "confirmation changes no other graphics preferences");
let next = prepare_backend_start(&path, true).unwrap();
assert_eq!(next.backend.as_deref(), Some("vulkan"));
assert!(next.attempt.is_none() && next.note.is_none());
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn interrupted_backend_start_restores_the_exact_previous_choice_once() {
solidcraft_ui_egui::i18n::install();
let _language = solidcraft_ui_text::scope("en");
let dir = scratch("backend-interrupted");
let path = dir.join("graphics.json");
for (previous, label) in [("auto", "Automatic"), (" dx12, vulkan ", " dx12, vulkan "), ("", "Automatic")] {
let mut expected = pending_backend(previous);
std::fs::write(&path, expected.to_string()).unwrap();
assert!(prepare_backend_start(&path, true).unwrap().attempt.is_some());
// A process crash leaves the started marker; the next normal launch rolls back.
let recovered = prepare_backend_start(&path, true).unwrap();
assert_eq!(recovered.backend.as_deref(), Some(previous));
assert!(recovered.attempt.is_none());
assert_eq!(
recovered.note,
Some(format!("The previous start with Vulkan did not open the window. SolidCraft restored {label}.")),
"recovery describes both APIs using their displayed names"
);
expected["backend"] = serde_json::json!(previous);
expected.as_object_mut().unwrap().remove(BACKEND_TRIAL);
assert_eq!(backend_settings(&path), expected, "only the attempted API is reverted");
assert!(prepare_backend_start(&path, true).unwrap().note.is_none(), "the notice is not repeated");
}
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn safe_override_and_fallback_launches_leave_backend_attempts_untouched() {
let dir = scratch("backend-bypass");
let path = dir.join("graphics.json");
assert_eq!(prepare_backend_start(&path, true).unwrap(), BackendLaunch::default());
assert!(!path.exists(), "default startup does not create a settings file");
for started in [false, true] {
let mut saved = pending_backend("dx12");
saved["backend_trial"]["started"] = serde_json::json!(started);
let bytes = serde_json::to_vec_pretty(&saved).unwrap();
std::fs::write(&path, &bytes).unwrap();
let launch = prepare_backend_start(&path, false).unwrap();
assert_eq!(launch.backend.as_deref(), Some("vulkan"));
assert!(launch.attempt.is_none() && launch.note.is_none());
assert_eq!(std::fs::read(&path).unwrap(), bytes, "even an interrupted attempt waits for a normal launch");
}
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn backend_start_rollback_and_confirmation_cannot_overwrite_a_newer_choice() {
let dir = scratch("backend-ownership");
let path = dir.join("graphics.json");
let saved = pending_backend("dx12");
std::fs::write(&path, saved.to_string()).unwrap();
let attempt = prepare_backend_start(&path, true).unwrap().attempt.unwrap();
rollback_backend_start(&path, &attempt).unwrap();
let mut reverted = saved.clone();
reverted["backend"] = serde_json::json!("dx12");
reverted.as_object_mut().unwrap().remove(BACKEND_TRIAL);
assert_eq!(backend_settings(&path), reverted, "handled failure restores the last working preference");
for newer in [
serde_json::json!({"backend": "gl"}),
serde_json::json!({"backend": "vulkan", "backend_trial": {"previous": "dx12", "requested": "vulkan", "started": false}}),
serde_json::json!({"backend": "vulkan", "backend_trial": {"previous": "auto", "requested": "vulkan", "started": true}}),
serde_json::json!({"backend": "gl", "backend_trial": {"previous": "dx12", "requested": "vulkan", "started": true}}),
] {
let bytes = serde_json::to_vec_pretty(&newer).unwrap();
std::fs::write(&path, &bytes).unwrap();
confirm_backend_start(&path, &attempt).unwrap();
rollback_backend_start(&path, &attempt).unwrap();
assert_eq!(std::fs::read(&path).unwrap(), bytes, "stale launch state cannot consume another preference");
}
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn malformed_backend_guards_use_the_previous_api_or_automatic_without_touching_other_settings() {
let dir = scratch("backend-malformed");
let path = dir.join("graphics.json");
for (trial, expected_backend) in [
(serde_json::json!(null), "auto"),
(serde_json::json!(42), "auto"),
(serde_json::json!({}), "auto"),
(serde_json::json!({"requested": "vulkan", "previous": "dx12"}), "dx12"),
(serde_json::json!({"requested": "vulkan", "previous": "dx12", "started": "yes"}), "dx12"),
(serde_json::json!({"requested": "vulkan", "previous": "x".repeat(257), "started": false}), "auto"),
] {
let mut saved = pending_backend("auto");
saved["backend_trial"] = trial;
std::fs::write(&path, saved.to_string()).unwrap();
let launch = prepare_backend_start(&path, true).unwrap();
assert_eq!(launch.backend.as_deref(), Some(expected_backend));
assert!(launch.attempt.is_none());
saved["backend"] = serde_json::json!(expected_backend);
saved.as_object_mut().unwrap().remove(BACKEND_TRIAL);
assert_eq!(backend_settings(&path), saved);
}
let mut saved = pending_backend("auto");
saved["backend"] = serde_json::json!("gl");
std::fs::write(&path, saved.to_string()).unwrap();
let launch = prepare_backend_start(&path, true).unwrap();
assert_eq!(launch.backend.as_deref(), Some("gl"), "a stale marker cannot replace a newer API");
assert!(launch.attempt.is_none() && launch.note.is_none());
saved.as_object_mut().unwrap().remove(BACKEND_TRIAL);
assert_eq!(backend_settings(&path), saved);
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn a_backend_attempt_is_never_returned_when_its_marker_cannot_be_saved() {
for started in [false, true] {
let mut saved = pending_backend("dx12");
saved["backend_trial"]["started"] = serde_json::json!(started);
let graphics = saved.as_object().unwrap().clone();
let error = prepare_backend_launch(graphics, true, |_| Err("fixture: write refused".into())).unwrap_err();
assert_eq!(error, "fixture: write refused", "no selected backend escapes a failed transition");
}
let dir = scratch("backend-unreadable");
let path = dir.join("graphics.json");
for damaged in ["{", "[]", "null"] {
std::fs::write(&path, damaged).unwrap();
assert!(prepare_backend_start(&path, true).is_err());
assert_eq!(std::fs::read_to_string(&path).unwrap(), damaged, "unreadable settings are never overwritten");
}
assert!(prepare_backend_start(&dir, true).is_err(), "a filesystem read failure is reported");
let _ = std::fs::remove_dir_all(dir);
}
#[test]
fn intel_macs_start_without_indirect_call_validation() {
use eframe::wgpu::InstanceFlags as F;
+1 -1
View File
@@ -2,7 +2,7 @@
Read `assets/README.md` before changing media, fonts, artwork or their consumers.
For **any UI icon, icon assignment or review-tool change**, also read
`assets/icons/ui/AGENTS.md` and `assets/icons/ui/STYLE_GUIDE.md` before editing.
`crates/look/icons/AGENTS.md` and `crates/look/icons/STYLE_GUIDE.md` before editing.
These files are the specification; chat history and old previews are not required.
- Keep one editable authority per resource. UI SVGs are masters, not exports of a
+7 -1
View File
@@ -70,4 +70,10 @@ meetup. If you publish a fork or a modified build, give it its own name and logo
don't mistake it for SolidCraft.
The wordmark is set in IBM Plex Sans Bold (SIL Open Font License 1.1, the interface font in
`assets/fonts/ibm-plex-sans/`) and outlined, so you don't need the font to print it.
`crates/look/fonts/ibm-plex-sans/`) and outlined, so you don't need the font to print it.
## Licence
The SolidCraft name, logo and brand kit are under the SolidCraft Brand and Interface Licence
([LICENSE-BRAND](../../LICENSE-BRAND)). Using them for anything other than SolidCraft needs the
maintainers' written permission first.
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "إنشاء بلاغ…",
"Cross curves": "المنحنيات العرضية",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter يتابع في GitHub.",
"Cube": "مكعب",
"Current orthographic view (1:1 mm)": "العرض المتعامد الحالي (1:1 mm)",
"Current perspective view": "العرض المنظوري الحالي",
"Current plane": "المستوى الحالي",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "شكل SolidCraft وأماكن أجزائه.",
"prefs.interval_minutes": "{n} دقيقة",
"prefs.invert_curved_roll_arrows": "عكس سهمي التدوير المنحنيين",
"prefs.invert_curved_roll_arrows_note": "سهما التدوير المنحنيان عند زاوية أداة التنقل يدوران العرض داخل مستوى الشاشة. عند التشغيل: سهم التدوير مع عقارب الساعة يدور عكسها، وسهم العكس يدور معها. عند الإيقاف: يدور كل سهم بالعرض حسب انحنائه.",
"prefs.invert_navigator_arrows": "عكس أسهم تدوير أداة التنقل",
"prefs.invert_navigator_arrows_note": "تدوّر الأسهم المحيطة بأداة التنقل الكاميرا في الاتجاه الذي تشير إليه، كما في Fusion وInventor: السهم الموجود على اليسار يشير إلى اليمين ويدوّر الكاميرا إلى اليمين. عند الإيقاف: يدوّر السهم العرض نحو الجهة التي يقع فيها، فيدوّر السهم الأيسر الكاميرا إلى اليسار. لا يتأثر سهما الدوران المنحنيان.",
"prefs.invert_curved_roll_arrows_note": "سهما التدوير المنحنيان عند زاوية المكعب يدوران العرض داخل مستوى الشاشة. عند التشغيل: سهم التدوير مع عقارب الساعة يدور عكسها، وسهم العكس يدور معها. عند الإيقاف: يدور كل سهم بالعرض حسب انحنائه.",
"prefs.invert_navigator_arrows": "عكس أسهم تدوير مكعب العرض",
"prefs.invert_navigator_arrows_note": "تدوّر الأسهم المحيطة بالمكعب الكاميرا في الاتجاه الذي تشير إليه، كما في Fusion وInventor: السهم الموجود على اليسار يشير إلى اليمين ويدوّر الكاميرا إلى اليمين. عند الإيقاف: يدوّر السهم المكعب نحو الجهة التي يقع فيها، فيدوّر السهم الأيسر الكاميرا إلى اليسار. لا يتأثر سهما الدوران المنحنيان.",
"prefs.keep_unsaved_also_asks": "السؤال أيضًا عند إغلاق علامة التبويب",
"prefs.keep_unsaved_also_asks_tip": "عند إيقاف هذا الخيار، تُغلق علامة التبويب دون مربع حوار المتصفح بعد تحديث نسخة كل تصميم غير محفوظ.",
"prefs.keep_unsaved_in_browser": "الاحتفاظ بالعمل غير المحفوظ في هذا المتصفح",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "عند الإيقاف: لا يُميَّز أي شيء تحت المؤشر أثناء سحب مكوّن بأسهم أداة التحريك، فتبقى التجميعات الكبيرة سلسة. مع عرض مقطع أو تحليل يبقى التمييز كما هو، ولا يُميَّز شيء أبدًا عند سحب جزء على امتداد وصلاته.",
"prefs.navigation": "التنقل",
"prefs.navigation.axes_signed": "المحاور",
"prefs.navigation.cube_compact": "المكعب",
"prefs.navigation.device": "الجهاز",
"prefs.navigation.free": "حر",
"prefs.navigation.orbit_style": "نمط التدوير",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "طاولة دوارة",
"prefs.navigation_note": "كيف تحرك الفأرة ولوحة اللمس والفأرة ثلاثية الأبعاد العرض.",
"prefs.navigator_fit": "ملاءمة النموذج بعد تغيير العرض من متصفح العرض",
"prefs.navigator_fit_note": "النقر على وجه أو ركن أو سهم في أداة التنقل، أو على محور في أداة المحاور، يوجّه العرض أيضًا نحو منتصف النموذج من المسافة الواحدة التي تُظهره كاملًا من كل جهة (كرته المحيطة). يستخدم العرض الرئيسي التكبير والمركز ذاتهما ما دام هذا مفعّلًا، فلا تغيّر العروض المختارة بعده سوى الاتجاه. عند الإيقاف: يدور العرض في مكانه محتفظًا بالهدف والتكبير.",
"prefs.navigator_fit_note": "النقر على وجه أو ركن أو سهم في المكعب، أو على محور في أداة المحاور، يوجّه العرض أيضًا نحو منتصف النموذج من المسافة الواحدة التي تُظهره كاملًا من كل جهة (كرته المحيطة). يستخدم العرض الرئيسي التكبير والمركز ذاتهما ما دام هذا مفعّلًا، فلا تغيّر العروض المختارة بعده سوى الاتجاه. عند الإيقاف: يدور العرض في مكانه محتفظًا بالهدف والتكبير.",
"prefs.network_host_remove": "إزالة",
"prefs.network_locations": "السماح بمواقع الشبكة في التصاميم",
"prefs.network_locations_note": "للمؤسسات التي تحفظ التصاميم على خوادم الملفات. عند الإيقاف: الخوادم التي تسمح بها فقط.",
+1
View File
@@ -144,6 +144,7 @@
"Create Issue…": "Create Issue…",
"Cross curves": "Cross curves",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continues on GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Current orthographic view (1:1 mm)",
"Current perspective view": "Current perspective view",
"Current plane": "Current plane",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Prijavi problem…",
"Cross curves": "Presječne krive",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter nastavlja na GitHubu.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Trenutni ortografski prikaz (1:1 mm)",
"Current perspective view": "Trenutni perspektivni prikaz",
"Current plane": "Trenutna ravan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Kako SolidCraft izgleda i gdje su njegovi dijelovi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrni zakrivljene strelice za valjanje",
"prefs.invert_curved_roll_arrows_note": "Dvije zakrivljene strelice u uglu kocke valjaju prikaz unutar ravni ekrana. Uključeno: strelica u smjeru kazaljke na satu valja prikaz suprotno od smjera kazaljke na satu, a strelica suprotno od smjera kazaljke na satu valja ga u smjeru kazaljke na satu. Isključeno: svaka strelica valja prikaz onako kako je zakrivljena.",
"prefs.invert_navigator_arrows": "Obrni strelice za rotaciju kocke prikaza",
"prefs.invert_navigator_arrows_note": "Strelice oko kocke orbitiraju kameru u smjeru u kojem pokazuju, kao u programima Fusion i Inventor: strelica s lijeve strane pokazuje udesno i zakreće kameru udesno. Isključeno: strelica okreće kocku prema strani na kojoj se nalazi, pa lijeva strelica zakreće kameru ulijevo. Postavka ne utiče na zakrivljene strelice za valjanje.",
"prefs.keep_work_on_tab_switch": "Zadrži dijaloge i alate otvorenima pri prebacivanju između dizajna",
"prefs.keep_work_on_tab_switch_note": "Svaka kartica dizajna zadržava svoj otvoreni dijalog ili alat, s onim što ste u njemu izabrali i upisali, te svoju karticu trake s alatima. Kada se vratite na dizajn, ponovo su tu. Isključeno: prebacivanje između dizajna otkazuje ih i prikazuje karticu Model.",
"prefs.labels": "Oznake",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigacija",
"prefs.navigation_note": "Kako miš, trackpad i 3D miš pomjeraju prikaz.",
"prefs.navigator_fit": "Uklopi model nakon promjene prikaza u navigatoru",
"prefs.navigator_fit_note": "Lice, ugao ili strelica kocke prikaza, odnosno osa alata za orijentaciju, također usmjerava pogled na sredinu modela s jedne udaljenosti na kojoj se uklapa iz svakog smjera (njegova granična sfera). Početni prikaz koristi isti zum i centar dok je ova opcija uključena, pa se prikazi koje izaberete poslije njega samo okreću. Isključeno: prikaz se okreće na mjestu i zadržava svoj cilj i zum.",
"prefs.network_host_remove": "Ukloni",
"prefs.network_locations": "Dozvoli mrežne lokacije u dizajnima",
"prefs.network_locations_note": "Isključeno: povezane datoteke dizajna na drugom računaru (\\\\server\\share) otvaraju se samo sa servera navedenih ovdje ili nakon što ga dozvolite kada se to zatraži.",
+135 -1
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crear una incidència…",
"Cross curves": "Corbes transversals",
"Ctrl+Enter continues on GitHub.": "Ctrl+Retorn continua a GitHub.",
"Cube": "Cub",
"Current orthographic view (1:1 mm)": "Vista ortogràfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Pla actual",
@@ -264,6 +265,7 @@
"Edge": "Aresta",
"Edges": "Arestes",
"Edit": "Editar",
"Edit Holes": "Editar forats",
"Edit Profile Sketch": "Editar el bocet del perfil",
"Edit shortcuts": "Editar les dreceres",
"Enable rule": "Activar la regla",
@@ -975,6 +977,7 @@
"browser.calibrate_click_a": "Feu clic a la imatge per al punt A, o escriviu-ne les coordenades.",
"browser.calibrate_click_b": "Feu clic a la imatge per al punt B, o escriviu-ne les coordenades.",
"browser.calibrate_title": "Calibrar: {name}",
"browser.canvas_locked": "El llenç està bloquejat. Desbloquegeu-lo primer.",
"browser.capture_many": "S'han mogut {count} components, però no s'han capturat les seves posicions.",
"browser.capture_note": "Capturar la posició conserva la posició nova; Revertir la posició restaura l'anterior.",
"browser.capture_one": "S'ha mogut un component, però no s'ha capturat la seva posició.",
@@ -1204,6 +1207,7 @@
"cmd.material_properties_directional": "Mòdul elàstic direccional",
"cmd.material_properties_validate": "Validar les dades del material físic",
"cmd.mesh_convert": "Convertir la malla",
"cmd.model_body_features": "Llistar les operacions del cos",
"cmd.model_edges": "Llistar les arestes",
"cmd.model_faces": "Llistar les cares",
"cmd.model_threads": "Llistar les roscas",
@@ -1232,8 +1236,11 @@
"cmd.panel.dismiss": "Descartar la vista prèvia del panell",
"cmd.panel.float": "Panell flotant",
"cmd.panel.focus": "Enfocar el panell",
"cmd.panel.focus.next": "Enfocar el panell següent",
"cmd.panel.focus.previous": "Enfocar el panell anterior",
"cmd.panel.list": "Llistar els panells",
"cmd.panel.move": "Moure el panell",
"cmd.panel.move.next_zone": "Moure el panell a la zona següent",
"cmd.panel.native_close": "Tornar a acoblar la secció de panell nativa",
"cmd.panel.open": "Obrir el panell",
"cmd.panel.peek": "Vista prèvia d'un panell contret",
@@ -1241,6 +1248,12 @@
"cmd.panel.reset_pair": "Restablir el divisor del panell",
"cmd.panel.resize": "Redimensionar la secció del panell",
"cmd.panel.resize_pair": "Redimensionar el divisor del panell",
"cmd.panel.sash.down": "Redimensionar el divisor del panell cap avall",
"cmd.panel.sash.left": "Redimensionar el divisor del panell cap a l'esquerra",
"cmd.panel.sash.reset": "Restablir el divisor del panell enfocat",
"cmd.panel.sash.right": "Redimensionar el divisor del panell cap a la dreta",
"cmd.panel.sash.up": "Redimensionar el divisor del panell cap amunt",
"cmd.panel.toggle": "Alternar el panell enfocat",
"cmd.parameters_add": "Afegir un paràmetre d'usuari",
"cmd.parameters_change": "Canviar paràmetres",
"cmd.parameters_comment": "Comentar el paràmetre",
@@ -1364,6 +1377,7 @@
"cmd.sketch.construction_line.tangent_external": "Tangent per un punt exterior",
"cmd.sketch.construction_line.tangent_two": "Tangent comuna",
"cmd.sketch.construction_line.vertical": "Línia de construcció vertical",
"cmd.sketch.replace": "Substituir el bocet",
"cmd.sketch_arc3d": "Arc 3D",
"cmd.sketch_arc_center_point": "Arc de centre i punt",
"cmd.sketch_arc_tangent": "Arc tangent",
@@ -1495,6 +1509,7 @@
"cmd.timeline_stop": "Aturar l'historial",
"cmd.timeline_suppress": "Suprimir l'operació",
"cmd.ui.assistant": "Alternar l'Assistent",
"cmd.ui.palette": "Cercar ordres",
"cmd.view.navigator": "Navegador de vistes personalitzat",
"cmd.view.render_browser": "Explorador de render",
"cmd.view.render_dock": "Moure l'acoblament del render",
@@ -2014,6 +2029,7 @@
"help.view.visual_style": "Canvia com es dibuixa el model: sombrejat amb o sense arestes, filferro, o amb arestes ocultes. Feu servir filferro per veure-hi a dins, i sombrejat per a un aspecte net.",
"history.sketch_under_constrained": "Restricció insuficient ({count} graus de llibertat)",
"history.sketch_under_constrained_one": "Restricció insuficient ({count} grau de llibertat)",
"hole_folder.applies_to": "Els canvis s'apliquen als {count} forats de {folder}; cadascun conserva la seva posició.",
"hole_presets.confirm_delete": "Confirmar l'eliminació",
"hole_presets.delete": "Eliminar",
"hole_presets.delete_prompt": "Voleu eliminar aquest preajust personal? Els forats existents no canvien.",
@@ -2416,6 +2432,7 @@
"parts.dimension.width": "Amplada",
"parts.family.bearing": "Rodament rígid de boles (envolupant)",
"parts.family.button_head_cap_screw": "Cargol de cap botó",
"parts.family.countersunk_socket_screw": "Cargol avellanat amb hexàgon interior",
"parts.family.dowel_pin": "Passador cilíndric",
"parts.family.hex_bolt": "Cargol de cap hexagonal",
"parts.family.hex_cap_screw_inch": "Cargol de cap hexagonal (polzades)",
@@ -2514,6 +2531,8 @@
"prefs.bottom_centre": "Baix al centre",
"prefs.bottom_right": "Baix a la dreta",
"prefs.browser": "Explorador",
"prefs.browser_body_features": "Operacions sota els cossos",
"prefs.browser_body_features_note": "Cada cos de l'explorador es desplega sobre les operacions de la línia de temps que el van construir, en l'ordre de la línia de temps.",
"prefs.browser_components_open": "Els components comencen oberts",
"prefs.browser_components_open_note": "Cada component de l'explorador comença obert, com abans, en lloc de tancat fins que l'obriu.",
"prefs.browser_eye_left": "Ull al costat de la fletxa de plegat",
@@ -2554,7 +2573,11 @@
"prefs.design_tools.degrees": "Graus",
"prefs.design_tools.double_click_help": "O per editar-ne un de vinculat al seu lloc.",
"prefs.design_tools.ghost": "Mostrar com un fantasma la posició anterior de les peces mogudes",
"prefs.design_tools.hole_group": "Agrupar els forats creats junts",
"prefs.design_tools.hole_group_help": "Els forats creats alhora comparteixen una carpeta a l'historial, tancada al principi; obriu-la per editar un forat per separat.",
"prefs.design_tools.hole_moves_help": "Tornar a triar la cara mou el forat en lloc d'eliminar-lo.",
"prefs.design_tools.hole_several": "Diversos forats en una cara",
"prefs.design_tools.hole_several_help": "Fer clic en un altre punt d'una cara afegeix un altre forat; fer clic en un forat el treu.",
"prefs.design_tools.hole_snaps_help": "El centre d'una cara i els centres de les seves arestes rodones.",
"prefs.design_tools.imported_files": "Fitxers importats",
"prefs.design_tools.note": "Nota",
@@ -2636,6 +2659,8 @@
"prefs.history": "Historial",
"prefs.history_bar_groups": "Plegar la barra Historial en grups",
"prefs.history_bar_groups_note": "En un historial llarg, una sèrie d'operacions d'un mateix component es plega en una fitxa, i les carpetes d'operacions comencen plegades. Un ensamblatge STEP inserit va a una carpeta Grup. Desactivat, es mostra cada operació, les carpetes comencen obertes i no es crea cap carpeta.",
"prefs.history_folder_kind_icon": "Icona de carpeta segons les seves operacions",
"prefs.history_folder_kind_icon_note": "Una carpeta de l'historial les operacions de la qual són totes del mateix tipus mostra la seva icona.",
"prefs.history_group_joints": "Agrupar les unions a l'historial",
"prefs.history_group_joints_note": "Dues o més unions es mostren com un botó amb el seu nombre, i en fer clic es mostra cadascuna. Desactivat, es mostra cada unió.",
"prefs.history_origin_bodies": "Mostrar l'origen i els cossos a dalt",
@@ -2658,6 +2683,9 @@
"prefs.interface_note": "Com es veu SolidCraft i on se situen les seves parts.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertir les fletxes de gir corbes",
"prefs.invert_curved_roll_arrows_note": "Les dues fletxes corbes a la cantonada del cub giren la vista dins del pla de la pantalla. Activades: la fletxa horària gira en sentit antihorari i l'antihorària gira en sentit horari. Desactivades: cada fletxa gira la vista cap on es corba.",
"prefs.invert_navigator_arrows": "Invertir les fletxes de rotació del cub de vista",
"prefs.invert_navigator_arrows_note": "Les fletxes al voltant del cub orbiten la càmera cap on apunten, com a Fusion i Inventor: la fletxa de l'esquerra apunta a la dreta i gira la càmera a la dreta. Desactivades: una fletxa gira el cub cap al costat on és, així la fletxa de l'esquerra gira la càmera a l'esquerra. Les fletxes de gir corbes no en queden afectades.",
"prefs.keep_unsaved_also_asks": "Continuar preguntant quan es tanca la pestanya",
"prefs.keep_unsaved_also_asks_tip": "Amb això desactivat, la pestanya es tanca sense la finestra del navegador un cop la còpia de cada disseny sense desar està al dia.",
"prefs.keep_unsaved_in_browser": "Conservar la feina sense desar en aquest navegador",
@@ -2717,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Desactivat: mentre les fletxes de Moure arrosseguen un component, no es ressalta res del que hi ha sota el punter, cosa que manté àgils els ensamblatges grans. Amb una secció o una anàlisi mostrades, es ressalta igualment, i una peça arrossegada al llarg de les seves unions no ho ressalta mai.",
"prefs.navigation": "Navegació",
"prefs.navigation.axes_signed": "Eixos",
"prefs.navigation.cube_compact": "Cub",
"prefs.navigation.device": "Dispositiu",
"prefs.navigation.free": "Lliure",
"prefs.navigation.orbit_style": "Estil d'òrbita",
@@ -2724,6 +2753,7 @@
"prefs.navigation.turntable": "Plat giratori",
"prefs.navigation_note": "Com mouen la vista el ratolí, el panel tàctil i el ratolí 3D.",
"prefs.navigator_fit": "Ajustar el model després d'un canvi de vista del navegador",
"prefs.navigator_fit_note": "Una cara, cantonada o fletxa del cub de vista, o un eix del gizmo, també miren el centre del model des de la distància que l'ajusta des de tots els costats (la seva esfera envolupant). Inici fa servir el mateix zoom i centre mentre això està activat, així les vistes triades després només giren. Desactivat: la vista gira al seu lloc, mantenint el seu objectiu i zoom.",
"prefs.network_host_remove": "Eliminar",
"prefs.network_locations": "Permetre ubicacions de xarxa als dissenys",
"prefs.network_locations_note": "Per a organitzacions que desen dissenys en servidors de fitxers. Desactivat: només els servidors que permeteu.",
@@ -2736,6 +2766,7 @@
"prefs.origin_plane_names": "Noms dels plans d'origen",
"prefs.origin_plane_names_note": "Noms que es mostren a l'explorador, als diàlegs i a les llistes. {top} és XY, {front} és XZ i {right} és YZ, amb Z cap amunt. Les ordres, els scripts i els dissenys desats mantenen XY, XZ i YZ.",
"prefs.overall_speed": "Velocitat general",
"prefs.panel_layout.recovery": "No s'han pogut restaurar les disposicions de panells desades. Les dades desades es conserven; Clàssic continua disponible.",
"prefs.parameter_list_rows": "Files de la llista de paràmetres",
"prefs.parameter_list_rows_tip": "El nombre de paràmetres que la fletxa avall llista en un quadre d'expressió buit.",
"prefs.persistent_ribbon_pressed": "Ressaltar les ordres actives de la cinta",
@@ -2797,6 +2828,8 @@
"prefs.remember_dialog_values.help": "Desactivat de manera predeterminada. Si s'activa, quan una ordre acaba correctament, els seus valors i opcions segurs es reutilitzen la propera vegada que obriu la mateixa ordre, fins que es tanqui SolidCraft.",
"prefs.render_legacy_image_defaults": "Fer servir els valors d'imatge anteriors de Render",
"prefs.render_legacy_image_defaults_help": "Manté el flux manual anterior: les configuracions noves fan servir el rasteritzat de CPU, el ray tracing de CPU conserva el mostreig fix i els resultats renderitzats s'obren a mà. En entrar a Render es reenquadra, es canvien les preses sense restaurar-ne les càmeres i es fa servir l'enquadrament i la navegació anteriors. Es desactiva la vista prèvia automàtica de la imatge en directe. Les configuracions desades no canvien.",
"prefs.render_legacy_memory_admission": "Fer servir les comprovacions de memòria de renderitzat anteriors",
"prefs.render_legacy_memory_admission_help": "Permet els renderitzats natius dins dels pressupostos fixos de memòria compartida i de l'amfitrió encara que la seva estimació superi la RAM disponible. Els límits del dispositiu i les comprovacions d'assignació es continuen aplicant.",
"prefs.render_previous_geometry_budget": "Fer servir el pressupost de geometria anterior de la previsualització del renderitzat",
"prefs.render_previous_geometry_budget_help": "Restaura el límit fix anterior (512 MiB a l'escriptori de 64 bits, 128 MiB a la resta) en lloc del pressupost basat en el dispositiu.",
"prefs.reports_saved": "{n} desats",
@@ -2823,6 +2856,8 @@
"prefs.select_other_hidden": "Seleccionar geometria oculta amb Seleccionar-ne un altre",
"prefs.select_other_hidden_help": "Activat: inclou cossos, bocets i arestes ocults o ocluïts a prop del punter. Desactivat: usa la llista original de geometria visible sota el punter.",
"prefs.selecting": "Selecció",
"prefs.shared_panel_layout": "Fer servir la disposició de panells compartida",
"prefs.shared_panel_layout_help": "Mostra l'explorador, l'historial i l'assistent existents en panells movibles. El canvi s'aplica en aplicar les preferències.",
"prefs.shift": "Majúscules",
"prefs.shift_add_ctrl_toggle": "El Majúscules només afegeix; Ctrl/Cmd alterna",
"prefs.shift_add_note": "Activat: el Majúscules afegeix i Ctrl/Cmd alterna. Desactivat (predeterminat): tots dos alternen.",
@@ -2845,6 +2880,8 @@
"prefs.sketch.drawing": "Dibuix",
"prefs.sketch.ellipse_axes": "Dibuixar les el·lipses amb els seus eixos",
"prefs.sketch.ellipse_axes_note": "Els eixos major i menor com a línies de construcció, per poder acotar els semieixos i els eixos. Desactivat: només l'el·lipse, i D a sobre seu dóna el radi menor allà on es tiri el valor, dibuixat i etiquetat R com abans.",
"prefs.sketch.escape_twice_finishes": "Doble Esc acaba el bocet",
"prefs.sketch.escape_twice_finishes_note": "Dues pulsacions ràpides d'Esc acaben el bocet. Desactivat: Esc només cancel·la l'eina o la selecció, i el bocet només s'acaba amb Acabar el bocet.",
"prefs.sketch.exit_keep": "Mantenir",
"prefs.sketch.exit_previous": "Tornar a la vista anterior",
"prefs.sketch.exit_unless_rotated": "Tret que s'hagi girat",
@@ -3187,8 +3224,10 @@
"render.category_paint": "Pintura",
"render.category_plastic": "Plàstic",
"render.category_wood": "Fusta",
"render.caustics_area_lights": "Càustiques de llums d'àrea",
"render.caustics_depth": "Profunditat del camí de càustiques",
"render.caustics_enable": "Càustiques de vidre amb llums puntuals i direccionals",
"render.caustics_environment": "Càustiques de l'entorn",
"render.caustics_help": "El nombre de fotons controla el soroll i la feina. El radi de captació canvia detall nítid per una estimació més suau. La CPU necessita il·luminació indirecta.",
"render.caustics_path_required": "Les càustiques de CPU necessiten il·luminació indirecta.",
"render.caustics_photons": "Fotons",
@@ -3365,7 +3404,7 @@
"render.cpu_opaque_required": "El ray tracing de CPU necessita un fons opac. Desactiveu Fons transparent per continuar.",
"render.cpu_options_pending": "Aquest panell de CPU encara no pot editar l'emissió, els efectes de superfície, el vidre ni l'anisotropia. Esborreu aquestes opcions de l'API abans de fer-lo servir.",
"render.cpu_path_depth": "Profunditat del camí",
"render.cpu_path_help": "Afegeix rebots de llum entre superfícies opaques i a través de formes de vidre admeses. Requereix renderitzat progressiu i ombres traçades. La profunditat del camí compta superfícies ombrejades, límits de vidre i esdeveniments de dispersió, començant pel primer impacte (1–16). La profunditat 1 dona il·luminació directa sobre superfícies opaques; els valors més alts permeten més rebots o creuaments de vidre i poden trigar més. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
"render.cpu_path_help": "Afegeix rebots de llum entre superfícies opaques i a través de formes de vidre admeses. Requereix renderitzat progressiu i ombres traçades. La profunditat del camí compta superfícies ombrejades, límits de vidre i esdeveniments de dispersió, començant pel primer impacte (1–64). La profunditat 1 dona il·luminació directa sobre superfícies opaques; els valors més alts permeten més rebots o creuaments de vidre i poden trigar més. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
"render.cpu_path_lighting": "Il·luminació indirecta",
"render.cpu_path_optics_reason": "Es conserven els vostres ajustos. Desactiveu la il·luminació indirecta per fer servir reflexos personalitzats o anisotropia.",
"render.cpu_point": "Llum puntual",
@@ -3405,6 +3444,12 @@
"render.cpu_subsurface_denoise_reason": "La dispersió subsuperficial de CPU necessita la reducció de soroll desactivada. Es conserven els vostres ajustos.",
"render.cpu_subsurface_help": "La dispersió redirigeix la llum dins del vidre tancat. Les taxes positives necessiten il·luminació indirecta amb la reducció de soroll desactivada. La taxa és de col·lisions per mm; 0 no afegeix dispersió. Un biaix de fase positiu afavoreix les direccions cap endavant; un de negatiu, les cap enrere.",
"render.cpu_summary": "Ray tracing de CPU · reflexos · HDR · llums direccionals i puntuals",
"render.cpu_threads": "Processos de CPU",
"render.cpu_threads_auto": "Automàtic",
"render.cpu_threads_custom": "Personalitzat",
"render.cpu_threads_help": "Automàtic fa servir els processos de CPU disponibles. Un procés s'executa en sèrie. Més processos poden necessitar més memòria.",
"render.cpu_threads_single": "Un",
"render.cpu_threads_web": "El renderitzat al navegador fa servir un procés cooperatiu. Es conserva l'elecció de processos desada per a l'escriptori.",
"render.cpu_transparent_help": "El PNG transparent treu el fons i conserva la cobertura de les vores. L'opacitat del cos i de la cara ha de mantenir-se al 100 %.",
"render.cpu_volume_enable_path": "Activar la il·luminació indirecta",
"render.cpu_volume_enable_path_plan": "Ray tracing de CPU · profunditat {depth} · {spp} mostres/píxel · llavor {seed} · ombres traçades. Conserva l'atmosfera definida i el pressupost d'imatge.",
@@ -3413,6 +3458,40 @@
"render.cpu_volume_method_incompatible": "Aquests ajustos de llum, mostreig o atmosfera no es poden transferir a aquest mètode. Es conserven els vostres ajustos.",
"render.cpu_volume_path_required": "Activeu la il·luminació indirecta per fer servir l'atmosfera de CPU.",
"render.cpu_warm_cool": "Càlid i fred",
"render.denoise_class_background": "Omès: fons",
"render.denoise_class_coverage": "Omès: cobertura parcial",
"render.denoise_class_degenerate": "Omès: camí degenerat",
"render.denoise_class_depth": "Omès: límit de profunditat del camí",
"render.denoise_class_emitter": "Omès: emissor de llum",
"render.denoise_class_exit": "Omès: sortida incompatible",
"render.denoise_class_identity": "Omès: límit d'identitat de guia",
"render.denoise_class_lens": "Omès: profunditat de camp",
"render.denoise_class_material": "Omès: material no admès",
"render.denoise_class_nested": "Omès: medi imbricat",
"render.denoise_class_optical": "Elegible: superfície refractada",
"render.denoise_class_reflection": "Omès: punt final reflectant",
"render.denoise_class_surface": "Elegible: superfície",
"render.denoise_class_tir": "Omès: reflexió total interna",
"render.denoise_class_transmission": "Omès: transmissió addicional",
"render.denoise_class_unavailable": "Omès: sense guia",
"render.denoise_class_volume": "Omès: dispersió de volum",
"render.denoise_diagnostics_counts": "Elegibles: {eligible} · Omessos: {skipped}",
"render.denoise_diagnostics_enable": "Recollir el diagnòstic de reducció de soroll",
"render.denoise_diagnostics_grid": "Recomptes de píxels amb la mida interna {width} × {height}.",
"render.denoise_diagnostics_help": "Recull els recomptes de píxels elegibles i omesos fins i tot amb la reducció de soroll desactivada. Els recomptes fan servir la mida interna de renderitzat; la màscara fa servir la mida de sortida.",
"render.denoise_diagnostics_title": "Diagnòstic de reducció de soroll",
"render.denoise_export_mask": "Exportar la màscara PNG",
"render.denoise_firefly": "Suprimir els píxels brillants aïllats",
"render.denoise_format_mask": "Màscara PNG",
"render.denoise_mask_copy_help": "Exporteu la màscara de reducció de soroll com a PNG o torneu a la imatge renderitzada per copiar-la.",
"render.denoise_mask_unavailable": "Activeu el diagnòstic de reducció de soroll i renderitzeu una imatge per inspeccionar-ne la màscara.",
"render.denoise_optical_filter": "Filtrar miralls i vidre",
"render.denoise_optical_filter_help": "Filtra la llum reflectida i transmesa elegible. Desactiveu-ho per reduir el soroll només a les superfícies opaques.",
"render.denoise_passes": "Passades del filtre",
"render.denoise_settings_help": "Més passades suavitzen una àrea més gran. La intensitat controla quant filtra cada passada. Els camins òptics no admesos no es filtren.",
"render.denoise_strength": "Intensitat de la reducció de soroll",
"render.denoise_view_image": "Imatge renderitzada",
"render.denoise_view_mask": "Màscara de reducció de soroll",
"render.diag_bodies": "Cossos visibles",
"render.diag_job_details": "Detalls del treball capturat",
"render.diag_last_check": "Última comprovació prèvia",
@@ -3967,6 +4046,8 @@
"render.material_transient": "Sobreescriptures òptiques temporals d'aquesta pestanya del document. No es desen al disseny, a la configuració de renderitzat ni a la biblioteca de materials.",
"render.material_v_up": "La coordenada V apunta cap amunt a la imatge",
"render.material_weight": "Pes del recobriment (0–1)",
"render.metal_energy_compensation": "Recuperar la reflectància del metall rugós",
"render.metal_energy_compensation_help": "Compensa la llum perduda entre les microfacetes del metall rugós. El renderitzat per CPU necessita il·luminació indirecta.",
"render.method_cpu": "Ray tracing de CPU",
"render.method_gpu": "Path tracing de GPU",
"render.method_limit_raster": "El raster fa servir la vista prèvia d'estudi opaca fixa. Trieu un mètode de ray tracing explícit per als controls òptics compatibles.",
@@ -4095,6 +4176,8 @@
"render.quality_denoise_on": "Reducció de soroll: Activada",
"render.quality_draft": "Esborrany",
"render.quality_high": "Alt",
"render.quality_legacy_samples": "Valor desat: {samples} spp. Les seleccions noves es limiten a {maximum} spp.",
"render.quality_preset_limit": "Aquest preajust supera el límit de selecció de 16384 spp. Trieu un nombre de mostres de fins a 16384.",
"render.quality_projection_help": "Aquesta revisió només canvia la resolució, el pressupost de mostres, la profunditat del camí, la llavor i la reducció de soroll. Els altres ajustos es conserven; el pressupost no certifica la convergència.",
"render.quality_review": "Revisar el pressupost de mostres",
"render.quality_summary": "{width} × {height} · {samples} mostres · profunditat {depth} · llavor {seed} · {denoise}",
@@ -4242,6 +4325,7 @@
"render.show_shots_label": "Mostrar la tira de preses",
"render.size_4k": "4K",
"render.size_4k_uhd": "4K UHD",
"render.size_8k_uhd": "8K UHD",
"render.size_custom": "Personalitzat…",
"render.size_full_hd": "Full HD",
"render.size_hd": "HD",
@@ -4404,6 +4488,11 @@
"render.subsurface_enable": "Recorregut aleatori de dispersió interior",
"render.subsurface_help": "Només dielèctrics tancats. La dispersió i l'absorció RGB són coeficients separats per mm. Els camins es dispersen dins de la geometria real i després es refracten o reflecteixen a la frontera. Desactiveu la transmissió recta d'ombres, la reducció de soroll de superfície i el volum exterior; feu servir un estrat de Fresnel. No és un shader de difusió, una graella de densitat ni un material mesurat. Els medis densos poden necessitar més mostres i profunditat de camí.",
"render.subsurface_rate": "Taxa de col·lisions de dispersió",
"render.supersampling": "Supermostreig",
"render.supersampling_dimensions": "Renderitza {width} × {height} i redueix a {output_width} × {output_height}. Fa servir el quàdruple de píxels.",
"render.supersampling_help": "Renderitzeu al doble d'amplada i alçada i després reduïu-ho en llum lineal. La mida de sortida no canvia.",
"render.supersampling_off": "Desactivat",
"render.supersampling_x2": "2×",
"render.surface_import.author": "Autor",
"render.surface_import.busy": "S'està important la imatge…",
"render.surface_import.complete": "Trieu una imatge i introduïu-ne l'autor, la font i la llicència.",
@@ -4417,6 +4506,8 @@
"render.surface_import.saved_cpu": "Deseu els mapes per fer-los servir amb el renderitzat de CPU.",
"render.surface_import.source": "Font",
"render.surface_import.title": "Importar una imatge",
"render.texture_filtering": "Filtrar el detall de les textures",
"render.texture_filtering_help": "Fa servir nivells mip i filtratge anisotròpic per reduir l'aliasing de les textures en reduir-les. Consumeix més memòria; desactivat manté el filtratge anterior.",
"render.tone_aces_fitted": "ACES ajustat",
"render.tone_reinhard": "Reinhard",
"render.transmission_scope": "El vidre de GPU admet medis disjunts certificats. No s'ofereixen medis imbricats sense restriccions ni un estimador de transmissió sense soroll.",
@@ -5511,6 +5602,7 @@
"ui.heading_plastic": "PLÀSTIC",
"ui.heading_position": "POSICIÓ",
"ui.heading_prepare": "PREPARAR",
"ui.heading_press_pull": "PRÉMER I ESTIRAR",
"ui.heading_rectangular_pattern": "PATRÓ RECTANGULAR",
"ui.heading_revolve": "REVOLUCIÓ",
"ui.heading_right": "DRETA",
@@ -5647,6 +5739,8 @@
"ui.mesh_format_3mf": "3MF",
"ui.mesh_format_3mf_tagged": "3MF amb etiquetes de cara",
"ui.mesh_format_stl": "STL",
"ui.mesh_import_origin": "Moure a l'origen",
"ui.mesh_import_origin_tip": "Centra la malla en X i Y amb la base a Z = 0. Si està desactivat, la malla conserva les coordenades desades al fitxer.",
"ui.minor_radius": "Radi menor",
"ui.mirror": "Simetria",
"ui.mirror_line": "Línia de simetria",
@@ -5751,6 +5845,42 @@
"ui.panel_host.surface": "Panell",
"ui.panel_host.tab": "Pestanya del panell",
"ui.panel_host.tabs": "Totes les pestanyes",
"ui.panel_layout.applied": "S'ha aplicat {name} a {workspace}",
"ui.panel_layout.cancel": "Cancel·lar",
"ui.panel_layout.confirm_replace": "Voleu substituir «{name}»?",
"ui.panel_layout.copy": "Copiar",
"ui.panel_layout.current": "Disposició actual",
"ui.panel_layout.custom": "Personalitzada",
"ui.panel_layout.custom_hint": "S'han mogut panells des de {name}.",
"ui.panel_layout.details": "Detalls",
"ui.panel_layout.layout_workspace": "Espai de treball de disposició",
"ui.panel_layout.page_defaults_hint": "Restableix els ajustos d'aquesta pàgina. L'organització dels panells i les disposicions desades es conserven.",
"ui.panel_layout.panel_layout": "Disposició de panells",
"ui.panel_layout.panel_style": "Estil de panells",
"ui.panel_layout.replace": "Substituir la disposició",
"ui.panel_layout.replace_current": "Substituir per l'actual",
"ui.panel_layout.replace_short": "Substituir",
"ui.panel_layout.reset": "Restablir l'espai de treball",
"ui.panel_layout.reset_hint": "Restableix {workspace} a la seva disposició predeterminada. Les disposicions desades es conserven.",
"ui.panel_layout.reset_short": "Restablir",
"ui.panel_layout.restore_failed": "No s'ha pogut restaurar la vostra disposició",
"ui.panel_layout.save": "Desar la disposició",
"ui.panel_layout.save_as": "Desar com a",
"ui.panel_layout.save_as_tile": "Desar com a…",
"ui.panel_layout.selected": "seleccionada",
"ui.panel_layout.suggested_name": "Disposició {n}",
"ui.panel_layout.try_again": "Torneu-ho a provar",
"ui.panel_layout.validation.builtin": "Les disposicions integrades no es poden canviar",
"ui.panel_layout.validation.duplicate": "Ja teniu aquest nom",
"ui.panel_layout.validation.empty": "Introduïu un nom",
"ui.panel_layout.validation.full": "64 de 64 desades. Trieu-ne una per substituir-la.",
"ui.panel_layout.validation.invalid": "Feu servir d'1 a 64 caràcters, sense caràcters de control",
"ui.panel_layout.workspace.classic": "Clàssic",
"ui.panel_layout.workspace.modelling": "Modelatge",
"ui.panel_layout.workspace.render": "Renderitzat",
"ui.panel_layout.workspace.review": "Revisió",
"ui.panel_layout.workspace.sketch": "Bocet",
"ui.panel_layout.your_layout": "la vostra disposició",
"ui.parallel": "Paral·lel",
"ui.parameters": "Paràmetres",
"ui.part_size_needs_a_part": "Seleccioneu una peça normalitzada inserida (un cargol, una femella, una volandera o un passador) per canviar-ne la mida. Per fer un cos més gran o més petit, feu servir Escala.",
@@ -5816,6 +5946,8 @@
"ui.profiles": "Perfils",
"ui.project": "Projectar",
"ui.project_face_edges_sketch": "Projectar arestes de cares als bocets nous",
"ui.project_references_construction": "Projectar les referències com a geometria de construcció",
"ui.project_references_construction_note": "Projectar, Intersecar, Incloure geometria 3D i les arestes de cara d'un bocet nou sobre una cara creen geometria de construcció: referències sobre les quals dibuixar, excloses dels perfils. Continuen vinculades al model.",
"ui.properties": "Propietats",
"ui.properties.copy_matrix": "Copiar la matriu",
"ui.properties.first_moments": "Primers moments",
@@ -5859,6 +5991,8 @@
"ui.renderer": "Motor de renderitzat",
"ui.repeat": "Repetir",
"ui.repeat_nothing": "Encara no hi ha res a repetir: inicieu una eina o un diàleg primer.",
"ui.replace_sketch.from_file": "Des d'un fitxer de disseny…",
"ui.replace_sketch.no_sketches": "Aquest disseny no té cap bocet per reutilitzar",
"ui.replace_with_link_done": "Les còpies ja són col·locacions del disseny vinculat.",
"ui.report_a_bug": "Notificar un error",
"ui.report_characters_left_one": "Queda {count} caràcter",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Vytvořit hlášení…",
"Cross curves": "Příčné křivky",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter pokračuje na GitHubu.",
"Cube": "Krychle",
"Current orthographic view (1:1 mm)": "Aktuální pravoúhlý pohled (1:1 mm)",
"Current perspective view": "Aktuální perspektivní pohled",
"Current plane": "Aktuální rovina",
@@ -2658,6 +2659,9 @@
"prefs.interface_note": "Vzhled aplikace SolidCraft a rozmístění jejích částí.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrátit zakřivené šipky natočení",
"prefs.invert_curved_roll_arrows_note": "Dvě zakřivené šipky v rohu krychle natáčejí pohled v rovině obrazovky. Zapnuto: šipka po směru hodinových ručiček natáčí pohled proti směru hodinových ručiček a šipka proti směru hodinových ručiček ho natáčí po směru. Vypnuto: každá šipka natáčí pohled tak, jak je zakřivená.",
"prefs.invert_navigator_arrows": "Obrátit šipky otáčení krychle pohledu",
"prefs.invert_navigator_arrows_note": "Šipky kolem krychle otáčejí kameru tím směrem, kam míří, jako ve Fusion a Inventor: šipka vlevo míří doprava a stáčí kameru doprava. Vypnuto: šipka otáčí krychli na stranu, na které leží, takže šipka vlevo stáčí kameru doleva. Zakřivené šipky natočení tím nejsou dotčeny.",
"prefs.keep_unsaved_also_asks": "Přesto se ptát při zavření karty",
"prefs.keep_unsaved_also_asks_tip": "Když je vypnuto, karta se zavře bez dotazu prohlížeče, jakmile je kopie každého neuloženého návrhu aktuální.",
"prefs.keep_unsaved_in_browser": "Uchovávat neuloženou práci v tomto prohlížeči",
@@ -2717,6 +2721,7 @@
"prefs.move_drag_highlights_tip": "Vypnuto: když šipky Přesunout táhnou komponentu, nic pod ukazatelem se nezvýrazní, takže velké sestavy zůstanou plynulé. Při zobrazeném řezu nebo analýze se zvýrazňuje i tak a díl tažený po svých spojích nezvýrazňuje nikdy.",
"prefs.navigation": "Navigace",
"prefs.navigation.axes_signed": "Osy",
"prefs.navigation.cube_compact": "Krychle",
"prefs.navigation.device": "Zařízení",
"prefs.navigation.free": "Volné",
"prefs.navigation.orbit_style": "Styl otáčení",
@@ -2724,6 +2729,7 @@
"prefs.navigation.turntable": "Otočný stůl",
"prefs.navigation_note": "Jak myš, trackpad a 3D myš pohybují pohledem.",
"prefs.navigator_fit": "Přizpůsobit model po změně pohledu v navigátoru",
"prefs.navigator_fit_note": "Plocha, roh nebo šipka krychle pohledu, případně osa orientačního ovladače, také zaměří pohled na střed modelu z jediné vzdálenosti, ze které je celý vidět ze všech stran (jeho ohraničující koule). Domů při zapnutí používá stejné přiblížení a střed, takže pohledy zvolené po něm se jen otáčejí. Vypnuto: pohled se otáčí na místě a zachovává svůj cíl a přiblížení.",
"prefs.network_host_remove": "Odebrat",
"prefs.network_locations": "Povolit síťová umístění v návrzích",
"prefs.network_locations_note": "Vypnuto: propojené soubory návrhu na jiném počítači (\\\\server\\share) se otevírají jen ze zde uvedených serverů nebo poté, co jeden povolíte na výzvu.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Opret fejlrapport…",
"Cross curves": "Tværkurver",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsætter på GitHub.",
"Cube": "Terning",
"Current orthographic view (1:1 mm)": "Aktuel visning uden perspektiv (1:1 mm)",
"Current perspective view": "Aktuel perspektivvisning",
"Current plane": "Aktuelt plan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "SolidCrafts udseende og placeringen af dets dele.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Vend de buede rulningspile om",
"prefs.invert_curved_roll_arrows_note": "De to buede pile i kubens hjørne ruller visningen i skærmplanet. Slået til: Pilen med uret ruller mod uret, og pilen mod uret ruller med uret. Slået fra: Hver pil ruller visningen den vej, den krummer.",
"prefs.invert_navigator_arrows": "Vend visningskubens rotationspile om",
"prefs.invert_navigator_arrows_note": "Pilene rundt om kuben roterer kameraet i den retning, de peger, som i Fusion og Inventor: Pilen til venstre peger mod højre og svinger kameraet til højre. Slået fra: En pil drejer kuben mod den side, den sidder på, så venstre pil svinger kameraet til venstre. De buede rulningspile påvirkes ikke.",
"prefs.keep_work_on_tab_switch": "Behold dialoger og værktøjer åbne, når du skifter design",
"prefs.keep_work_on_tab_switch_note": "Hver designfane beholder sin åbne dialog eller sit åbne værktøj med det, du har valgt og skrevet i den, og sin fane på båndet. De er der igen, når du vender tilbage til designet. Slået fra: Skift af design annullerer dem og viser fanen Model.",
"prefs.labels": "Etiketter",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigation",
"prefs.navigation_note": "Hvordan musen, pegefeltet og 3D-musen styrer visningen.",
"prefs.navigator_fit": "Tilpas modellen efter et skift af visning i navigatoren",
"prefs.navigator_fit_note": "En flade, et hjørne eller en pil på visningskuben eller en akse på orienteringsgizmoen ser også mod modellens midte fra den ene afstand, der får den til at passe fra alle sider (dens omsluttende kugle). Hjem bruger samme zoom og centrum, mens dette er slået til, så visninger, der vælges bagefter, kun drejer. Slået fra: Visningen drejer på stedet og beholder sit mål og sin zoom.",
"prefs.network_host_remove": "Fjern",
"prefs.network_locations": "Tillad netværksplaceringer i designs",
"prefs.network_locations_note": "Slået fra: Et designs linkede filer på en anden computer (\\\\server\\share) åbnes kun fra de servere, der er angivet her, eller efter at du har tilladt en, når du bliver spurgt.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Issue erstellen…",
"Cross curves": "Querkurven",
"Ctrl+Enter continues on GitHub.": "Strg+Enter geht weiter zu GitHub.",
"Cube": "Würfel",
"Current orthographic view (1:1 mm)": "Aktuelle orthogonale Ansicht (1:1 mm)",
"Current perspective view": "Aktuelle perspektivische Ansicht",
"Current plane": "Aktuelle Ebene",
@@ -2468,6 +2469,8 @@
"prefs.interface_language": "Oberflächensprache",
"prefs.interface_note": "Legt das Erscheinungsbild von SolidCraft und die Anordnung seiner Bereiche fest.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_navigator_arrows": "Drehpfeile des Ansichtswürfels umkehren",
"prefs.invert_navigator_arrows_note": "Die Pfeile um den Würfel drehen die Kamera in die Richtung, in die sie zeigen, wie in Fusion und Inventor: Der linke Pfeil zeigt nach rechts und schwenkt die Kamera nach rechts. Aus: Ein Pfeil dreht den Würfel zu der Seite hin, an der er sitzt, sodass der linke Pfeil die Kamera nach links schwenkt. Die gebogenen Rollpfeile sind davon nicht betroffen.",
"prefs.keep_work_on_tab_switch": "Dialoge und Werkzeuge beim Wechsel zwischen Konstruktionen offen lassen",
"prefs.keep_work_on_tab_switch_note": "Jeder Konstruktions-Tab behält seinen offenen Dialog oder sein Werkzeug mit allem, was darin ausgewählt und eingegeben wurde, sowie seinen Werkzeugleisten-Tab. Beim Zurückkehren zur Konstruktion ist alles wieder da. Aus: Ein Wechsel bricht sie ab und zeigt den Tab Modell.",
"prefs.labels": "Beschriftungen",
@@ -2523,6 +2526,7 @@
"prefs.move_drag_highlights_tip": "Aus: Solange die Pfeile von Verschieben eine Komponente ziehen, wird nichts unter dem Zeiger hervorgehoben; so bleiben große Baugruppen flüssig. Mit einem Schnitt oder einer Analyse wird es trotzdem hervorgehoben, und ein entlang seiner Gelenke gezogenes Teil hebt nie etwas hervor.",
"prefs.navigation": "Navigation",
"prefs.navigation.axes_signed": "Achsen",
"prefs.navigation.cube_compact": "Würfel",
"prefs.navigation.device": "Gerät",
"prefs.navigation.free": "Frei",
"prefs.navigation.orbit_style": "Drehstil",
@@ -2530,6 +2534,7 @@
"prefs.navigation.turntable": "Drehteller",
"prefs.navigation_note": "Legt fest, wie Maus, Trackpad und 3D-Maus die Ansicht steuern.",
"prefs.navigator_fit": "Modell nach einem Ansichtswechsel am Navigator einpassen",
"prefs.navigator_fit_note": "Eine Fläche, Ecke oder ein Pfeil des Würfels oder eine Achse des Gizmos blickt auch auf die Mitte des Modells, aus dem einen Abstand, der es von jeder Seite einpasst (seine Hüllkugel). Home nutzt denselben Zoom und dieselbe Mitte, solange dies an ist, sodass danach gewählte Ansichten sich nur drehen. Aus: Die Ansicht dreht sich an Ort und Stelle und behält Ziel und Zoom.",
"prefs.network_host_remove": "Entfernen",
"prefs.network_locations": "Netzwerkspeicherorte in Designs zulassen",
"prefs.network_locations_note": "Für Organisationen, die Entwürfe auf Dateiservern speichern. Aus: nur erlaubte Server.",
+8 -6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Create Issue…",
"Cross curves": "Cross curves",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continues on GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Current orthographic view (1:1 mm)",
"Current perspective view": "Current perspective view",
"Current plane": "Current plane",
@@ -930,7 +931,7 @@
"ai.http.confirm": "Allow for this endpoint",
"ai.http.warning": "The API key and conversation will be sent unencrypted. Anyone with access to the network may read or change them. Use this only on a network you trust.",
"ai.prefs.allow_control": "Let AI agents connect",
"ai.prefs.allow_control_note": "A local channel (MCP). Nothing leaves this computer.\n\nOpens a control channel on this computer only (127.0.0.1, port 27878 or the next free one). A program that connects must also show a secret token that only your user account can read, made fresh at every start. Takes effect the next time SolidCraft starts. Off: nothing listens unless you start SolidCraft with --control.",
"ai.prefs.allow_control_note": "A local channel (MCP). Nothing leaves this computer.\n\nOpens a control channel on this computer only (127.0.0.1, on the port below; 27878 takes the next free one when it is in use). A program that connects must also show a secret token that only your user account can read, made fresh at every start. Takes effect at once. Off: nothing listens unless you start SolidCraft with --control.",
"ai.prefs.availability": "Availability",
"ai.prefs.background_commands": "Run slow commands in the background",
"ai.prefs.connect_apps": "Add SolidCraft to AI apps",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "How SolidCraft looks and where its parts sit.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invert the curved roll arrows",
"prefs.invert_curved_roll_arrows_note": "The two curved arrows at the navigator's corner roll the view within the screen plane. On: the clockwise arrow rolls counterclockwise and the counterclockwise arrow rolls clockwise. Off: each arrow rolls the view the way it curls.",
"prefs.invert_navigator_arrows": "Invert the navigator rotation arrows",
"prefs.invert_navigator_arrows_note": "The arrows around the navigator orbit the camera the way they point, as in Fusion and Inventor: the arrow on the left points right and swings the camera right. Off: an arrow rotates the view toward the side it sits on, so the left arrow swings the camera left. The curved roll arrows are not affected.",
"prefs.invert_curved_roll_arrows_note": "The two curved arrows at the cube's corner roll the view within the screen plane. On: the clockwise arrow rolls counterclockwise and the counterclockwise arrow rolls clockwise. Off: each arrow rolls the view the way it curls.",
"prefs.invert_navigator_arrows": "Invert the view cube rotation arrows",
"prefs.invert_navigator_arrows_note": "The arrows around the cube orbit the camera the way they point, as in Fusion and Inventor: the arrow on the left points right and swings the camera right. Off: an arrow rotates the cube toward the side it sits on, so the left arrow swings the camera left. The curved roll arrows are not affected.",
"prefs.keep_unsaved_also_asks": "Still ask when the tab closes",
"prefs.keep_unsaved_also_asks_tip": "With this off, the tab closes without the browser's box once every unsaved design's copy is current.",
"prefs.keep_unsaved_in_browser": "Keep unsaved work in this browser",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Off: while Move's arrows drag a component, nothing under the pointer is highlighted, which keeps large assemblies smooth. With a section or an analysis shown it is highlighted all the same, and a part dragged along its joints never highlights it.",
"prefs.navigation": "Navigation",
"prefs.navigation.axes_signed": "Axes",
"prefs.navigation.cube_compact": "Cube",
"prefs.navigation.device": "Device",
"prefs.navigation.free": "Free",
"prefs.navigation.orbit_style": "Orbit style",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "Turntable",
"prefs.navigation_note": "How the mouse, trackpad and 3D mouse move the view.",
"prefs.navigator_fit": "Fit the model after a navigator view change",
"prefs.navigator_fit_note": "A face, corner or arrow of a navigator, or an axis of the gizmo, also looks at the middle of the model from the one distance that fits it from every side (its bounding sphere). Home uses the same zoom and centre while this is on, so views chosen after it only turn. Off: the view turns in place, keeping its target and zoom.",
"prefs.navigator_fit_note": "A face, corner or arrow of the view cube, or an axis of the gizmo, also looks at the middle of the model from the one distance that fits it from every side (its bounding sphere). Home uses the same zoom and centre while this is on, so views chosen after it only turn. Off: the view turns in place, keeping its target and zoom.",
"prefs.network_host_remove": "Remove",
"prefs.network_locations": "Allow network locations in designs",
"prefs.network_locations_note": "For organizations that keep designs on file servers. Off: only servers you allow.",
@@ -5039,7 +5041,7 @@
"ui.agent_chat_permission": "The agent asks to run: {title}",
"ui.agent_chat_pick": "Agent",
"ui.agent_chat_pick_context": "Pick context",
"ui.agent_chat_pick_context_tip": "Choose faces, edges, features and bodies in the model for the agent to look at, then press OK",
"ui.agent_chat_pick_context_tip": "Choose faces, edges, features and bodies in the model, then press OK: they are put into the message as a pill where the cursor is (typing @ does the same)",
"ui.agent_chat_placeholder": "Ask the agent to change the design…",
"ui.agent_chat_placeholder_busy": "Queue a message for when the agent is done (Ctrl+Enter: send now)",
"ui.agent_chat_pop_out": "Open in its own window, which you can move to another screen",
+271 -265
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crear incidencia…",
"Cross curves": "Curvas transversales",
"Ctrl+Enter continues on GitHub.": "Ctrl+Intro continúa en GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Plano actual",
@@ -1703,189 +1704,189 @@
"from the rule": "de la regla",
"help.apache": "Licencia Apache 2.0",
"help.appearance.assign": "Da a los cuerpos, caras o componentes seleccionados un color o un aspecto de material, con",
"help.assembly.bom": "Lists the parts of the design or a component with their counts, by part number, and can save the list as CSV or JSON. Use it as the parts list for ordering and assembly.",
"help.assembly.bom": "Lista las piezas del diseño o de un componente con sus cantidades, por número de pieza, y puede guardar la lista como CSV o JSON. Úsalo como lista de piezas para pedidos y ensamblaje.",
"help.attributions": "Atribuciones (ATTRIBUTION.md)",
"help.build": "Versión {version} · commit {commit} · compilada el {date}",
"help.canvas.decal": "Places an image on a planar face of the model, like a sticker. Use it to show a label, logo or printed pattern on a part.",
"help.canvas.edit": "Changes a canvas: its position, size, angle, opacity, mirroring, visibility or name. Use it to line up a reference image with the sketch you trace over it.",
"help.canvas.insert": "Places a PNG or JPEG image on a plane or face as a see-through reference. Use it to trace a photo or drawing in a sketch, with the image scaled to a known size.",
"help.component.break_link": "Cuts a linked component loose from its design file, keeping its bodies as they are. Use it when the part should no longer follow changes to the original file.",
"help.component.capture_position": "Keeps the positions of parts you moved by hand, so they become where those parts are. Use it after dragging parts into place that no joint holds.",
"help.component.create": "Adds a new, empty component to the design, inside the active component unless you choose another parent. Use it to give a new part of an assembly its own place for bodies and sketches.",
"help.canvas.decal": "Coloca una imagen sobre una cara plana del modelo, como una pegatina. Úsalo para mostrar una etiqueta, un logotipo o un dibujo impreso en una pieza.",
"help.canvas.edit": "Cambia un lienzo: su posición, tamaño, ángulo, opacidad, simetría, visibilidad o nombre. Úsalo para alinear una imagen de referencia con el boceto que dibujas sobre ella.",
"help.canvas.insert": "Coloca una imagen PNG o JPEG en un plano o una cara como referencia translúcida. Úsalo para calcar una foto o un dibujo en un boceto, con la imagen escalada a un tamaño conocido.",
"help.component.break_link": "Desvincula un componente enlazado de su archivo de diseño y conserva sus cuerpos tal como están. Úsalo cuando la pieza ya no deba seguir los cambios del archivo original.",
"help.component.capture_position": "Conserva las posiciones de las piezas que moviste a mano, de modo que pasan a ser donde están ahora. Úsalo tras arrastrar a su sitio piezas que ninguna unión sujeta.",
"help.component.create": "Añade un componente nuevo y vacío al diseño, dentro del componente activo salvo que elijas otro padre. Úsalo para dar a una pieza nueva de un ensamblaje su propio lugar para cuerpos y bocetos.",
"help.component.finish_edit": "Guarda la pieza que estás editando en contexto, vuelve a su ensamblaje y actualiza el",
"help.component.from_bodies": "Turns each selected body into a component of its own, named after the body. Use it when a design built as loose bodies should become an assembly whose parts can be joined and moved.",
"help.component.insert_design": "Inserts another saved design as a component linked to its file, with its solid bodies placed as they are there. Use it to reuse a part in an assembly and pick up later changes with Update Links.",
"help.component.properties": "Shows the volume, mass, centre of mass and moments of inertia of a component, using its bodies' materials. Use it to check weight and balance of an assembly.",
"help.component.revert_position": "Puts parts you moved by hand back where they were, dropping moves that were not captured. Use it to undo trial moves in an assembly.",
"help.component.update_links": "Reads the linked design files again and replaces bodies where they changed. Use it after editing a part that this assembly uses.",
"help.config.configure": "Adds parameters, features, materials or appearances as columns of the configuration table. Use it to build variants of one design, such as sizes of a part.",
"help.config.preview": "Checks that a row of the configuration table rebuilds, without changing the design or its history. Use it before switching to a variant you are not sure of.",
"help.config.rules": "Shows the rules of the configuration table, its rows and which row is active. Use it to see how the variants of a design are set up.",
"help.config.table": "Shows the configuration table: one row per variant, one column per parameter or feature, and whether the design still matches the active row. Use it to review the variants of a design.",
"help.component.from_bodies": "Convierte cada cuerpo seleccionado en un componente propio, con el nombre del cuerpo. Úsalo cuando un diseño hecho con cuerpos sueltos deba pasar a ser un ensamblaje cuyas piezas se puedan unir y mover.",
"help.component.insert_design": "Inserta otro diseño guardado como componente vinculado a su archivo, con sus cuerpos sólidos colocados como están allí. Úsalo para reutilizar una pieza en un ensamblaje y recoger los cambios posteriores con Actualizar vínculos.",
"help.component.properties": "Muestra el volumen, la masa, el centro de masa y los momentos de inercia de un componente, según los materiales de sus cuerpos. Úsalo para comprobar el peso y el equilibrio de un ensamblaje.",
"help.component.revert_position": "Devuelve a su sitio las piezas que moviste a mano y descarta los movimientos que no se capturaron. Úsalo para deshacer movimientos de prueba en un ensamblaje.",
"help.component.update_links": "Vuelve a leer los archivos de diseño vinculados y reemplaza los cuerpos que cambiaron. Úsalo después de editar una pieza que usa este ensamblaje.",
"help.config.configure": "Añade parámetros, operaciones, materiales o aspectos como columnas de la tabla de configuración. Úsalo para crear variantes de un diseño, como tamaños de una pieza.",
"help.config.preview": "Comprueba que una fila de la tabla de configuración se reconstruye, sin cambiar el diseño ni su historial. Úsalo antes de cambiar a una variante de la que no estés seguro.",
"help.config.rules": "Muestra las reglas de la tabla de configuración, sus filas y cuál está activa. Úsalo para ver cómo están definidas las variantes de un diseño.",
"help.config.table": "Muestra la tabla de configuración: una fila por variante, una columna por parámetro u operación, y si el diseño sigue coincidiendo con la fila activa. Úsalo para revisar las variantes de un diseño.",
"help.connect_note": "Reinicia cada asistente para que cargue el servidor de SolidCraft. Cada archivo se guardó como .bak antes de modificarlo.",
"help.connect_title": "Conectar asistentes de IA",
"help.construct.axis.edge": "Creates a construction axis along a straight edge or sketch line. Use it as the axis for a revolve, a circular pattern or a joint.",
"help.construct.axis.normal_to_face": "Creates a construction axis through a point, square to a face. Use it as an axis that stands straight out of a surface.",
"help.construct.axis.through_cylinder": "Creates a construction axis through the centre of a cylinder, cone or torus face, or a circular edge. Use it to turn or pattern features around a round part.",
"help.construct.axis.two_planes": "Creates a construction axis where two planes or flat faces meet. Use it when the axis you need is the line between two faces.",
"help.construct.axis.two_points": "Creates a construction axis through two points, vertices or sketch points. Use it for an axis that runs between two known positions.",
"help.construct.plane.along_path": "Creates a construction plane square to an edge or curve, at a position along it. Use it to sketch a profile for a sweep or a section of a path.",
"help.construct.axis.edge": "Crea un eje de construcción a lo largo de una arista recta o de una línea de boceto. Úsalo como eje de una revolución, un patrón circular o una unión.",
"help.construct.axis.normal_to_face": "Crea un eje de construcción que pasa por un punto, perpendicular a una cara. Úsalo como un eje que sale recto de una superficie.",
"help.construct.axis.through_cylinder": "Crea un eje de construcción por el centro de una cara cilíndrica, cónica o toroidal, o de una arista circular. Úsalo para girar o repetir operaciones alrededor de una pieza redonda.",
"help.construct.axis.two_planes": "Crea un eje de construcción donde se cortan dos planos o caras planas. Úsalo cuando el eje que necesitas sea la línea entre dos caras.",
"help.construct.axis.two_points": "Crea un eje de construcción por dos puntos, vértices o puntos de boceto. Úsalo para un eje que va entre dos posiciones conocidas.",
"help.construct.plane.along_path": "Crea un plano de construcción perpendicular a una arista o curva, en una posición a lo largo de ella. Úsalo para dibujar el perfil de un barrido o una sección de una trayectoria.",
"help.construct.plane.at_angle": "Crea un plano de construcción girado un ángulo respecto a un plano o cara, alrededor de un eje o arista. Activa «Usar solo la dirección del eje» para proyectar el eje sobre la base y pivotar alrededor de un punto de ese plano (el origen de la base cuando no se elige ninguno). Úsalo para bocetos inclinados, como un soporte angular.",
"help.construct.plane.axis_point": "Creates a construction plane containing an axis and a point off that axis. Pick an origin or construction axis, a straight edge or sketch line, then a vertex, sketch point or construction point. A point on the axis cannot define a unique plane.",
"help.construct.plane.midplane": "Creates a construction plane halfway between two planes or flat faces, or bisecting them where they meet at an angle. Use it as a symmetry plane for mirroring.",
"help.construct.plane.offset": "Creates a construction plane parallel to a plane or flat face, at a distance or through a point. Use it to sketch at a set height above a face.",
"help.construct.plane.perpendicular": "Creates a construction plane that holds a line or edge and stands square to a plane or face. Use it to sketch upright on a model along an edge.",
"help.construct.plane.tangent": "Creates a construction plane that touches a cylinder, cone, sphere or torus at a point. Use it to sketch on the side of a round part.",
"help.construct.plane.three_points": "Creates a construction plane through three points. Use it for a plane set by positions on the model, such as three corners.",
"help.construct.plane.two_edges": "Creates a construction plane through two straight edges or lines that lie in one plane. Use it for a plane across a part, such as through two opposite edges.",
"help.construct.point.along_path": "Creates a construction point at a position along an edge or curve. Use it as a reference partway along a path.",
"help.construct.point.center": "Creates a construction point at the centre of a circular edge, sketch circle or arc, sphere or torus. Use it as a reference for holes, axes and joints.",
"help.construct.point.edge_plane": "Creates a construction point where an edge or line passes through a plane or flat face. Use it to mark where a path crosses a plane.",
"help.construct.point.three_planes": "Creates a construction point where three planes or flat faces meet. Use it as a corner reference, even where the model has no vertex.",
"help.construct.point.two_edges": "Creates a construction point where two edges or lines meet, or come closest. Use it as a reference at a virtual corner.",
"help.construct.point.vertex": "Creates a construction point on a vertex or sketch point. Use it as a reference that stays when the sketch or body around it is hidden.",
"help.contact.check": "Lists the pairs of parts in contact sets that pass through each other in their current position. Use it to find collisions before you drive joints or run a motion study.",
"help.contact.create": "Groups two or more parts into a contact set, whose bodies are kept from passing through each other while joints move. Use it for parts that should stop when they touch, such as a lever against its stop.",
"help.contact.disable_all": "Turns contact off, so driven joints and motion studies no longer stop where parts touch. Use it to move parts freely again, or to keep a large assembly responsive.",
"help.contact.edit": "Changes a contact set: the parts it holds, its name, or whether it is suppressed; it can also delete the set. Use it to adjust which parts are kept from passing through each other.",
"help.contact.enable_all": "Puts every part of the assembly into one contact set, so no two parts can pass through each other while joints move. Use it for a quick check of a whole mechanism.",
"help.contact.enable_sets": "Turns contact on for the contact sets you defined, so driven joints and motion studies stop where their parts would pass through each other. Use it to bring your sets back after turning contact off.",
"help.contact.list": "Lists the contact sets of the design, the parts in each one and whether contact is on. Use it to check how contact is set up before you drive the assembly.",
"help.document.inspect": "Shows an overview of the design: its components, bodies, sketches, features and parameters. Use it to get your bearings in a design you did not build yourself.",
"help.document.units": "Changes the units the design shows lengths in, such as mm or inches. The geometry keeps its size; only the display and plain numbers follow.",
"help.edit.checkpoint": "Remembers the design, the active sketch and the undo history as they are now. Use it before trying something risky that you may want to go back from.",
"help.edit.restore_checkpoint": "Goes back to a checkpoint, undo history included. Use it to drop everything done since the checkpoint in one step.",
"help.explode.create": "Creates an exploded view that pushes the parts away from the assembly's centre, or by the moves you set. Use it to show how an assembly goes together, for instructions or presentations.",
"help.construct.plane.axis_point": "Crea un plano de construcción que contiene un eje y un punto fuera de ese eje. Elige un origen o un eje de construcción, una arista recta o una línea de boceto, y después un vértice, un punto de boceto o un punto de construcción. Un punto del eje no define un plano único.",
"help.construct.plane.midplane": "Crea un plano de construcción a medio camino entre dos planos o caras planas, o que los biseca donde se encuentran en ángulo. Úsalo como plano de simetría para un espejo.",
"help.construct.plane.offset": "Crea un plano de construcción paralelo a un plano o una cara plana, a una distancia o por un punto. Úsalo para dibujar a una altura fija sobre una cara.",
"help.construct.plane.perpendicular": "Crea un plano de construcción que contiene una línea o arista y es perpendicular a un plano o una cara. Úsalo para dibujar en vertical sobre un modelo a lo largo de una arista.",
"help.construct.plane.tangent": "Crea un plano de construcción que toca un cilindro, cono, esfera o toro en un punto. Úsalo para dibujar en el lado de una pieza redonda.",
"help.construct.plane.three_points": "Crea un plano de construcción por tres puntos. Úsalo para un plano definido por posiciones del modelo, como tres esquinas.",
"help.construct.plane.two_edges": "Crea un plano de construcción por dos aristas rectas o líneas que están en un mismo plano. Úsalo para un plano que cruza una pieza, por ejemplo por dos aristas opuestas.",
"help.construct.point.along_path": "Crea un punto de construcción en una posición a lo largo de una arista o curva. Úsalo como referencia a mitad de una trayectoria.",
"help.construct.point.center": "Crea un punto de construcción en el centro de una arista circular, un círculo o arco de boceto, una esfera o un toro. Úsalo como referencia para agujeros, ejes y uniones.",
"help.construct.point.edge_plane": "Crea un punto de construcción donde una arista o línea atraviesa un plano o una cara plana. Úsalo para marcar dónde una trayectoria cruza un plano.",
"help.construct.point.three_planes": "Crea un punto de construcción donde se encuentran tres planos o caras planas. Úsalo como referencia de esquina, incluso donde el modelo no tiene vértice.",
"help.construct.point.two_edges": "Crea un punto de construcción donde se cortan dos aristas o líneas, o donde están más cerca. Úsalo como referencia en una esquina virtual.",
"help.construct.point.vertex": "Crea un punto de construcción sobre un vértice o un punto de boceto. Úsalo como referencia que permanece cuando se oculta el boceto o el cuerpo que lo rodea.",
"help.contact.check": "Lista los pares de piezas de los conjuntos de contacto que se atraviesan en su posición actual. Úsalo para encontrar colisiones antes de accionar uniones o ejecutar un estudio de movimiento.",
"help.contact.create": "Agrupa dos o más piezas en un conjunto de contacto, cuyos cuerpos no pueden atravesarse mientras las uniones se mueven. Úsalo para piezas que deben detenerse al tocarse, como una palanca contra su tope.",
"help.contact.disable_all": "Desactiva el contacto, de modo que las uniones accionadas y los estudios de movimiento ya no se detienen donde las piezas se tocan. Úsalo para mover las piezas con libertad o para mantener ágil un ensamblaje grande.",
"help.contact.edit": "Cambia un conjunto de contacto: las piezas que contiene, su nombre o si está desactivado; también puede eliminar el conjunto. Úsalo para ajustar qué piezas no pueden atravesarse.",
"help.contact.enable_all": "Pone todas las piezas del ensamblaje en un único conjunto de contacto, de modo que ningún par de piezas se atraviese mientras las uniones se mueven. Úsalo para una comprobación rápida de todo un mecanismo.",
"help.contact.enable_sets": "Activa el contacto de los conjuntos de contacto que definiste, de modo que las uniones accionadas y los estudios de movimiento se detienen donde sus piezas se atravesarían. Úsalo para recuperar tus conjuntos tras desactivar el contacto.",
"help.contact.list": "Lista los conjuntos de contacto del diseño, las piezas de cada uno y si el contacto está activado. Úsalo para comprobar cómo está configurado el contacto antes de accionar el ensamblaje.",
"help.document.inspect": "Muestra un resumen del diseño: sus componentes, cuerpos, bocetos, operaciones y parámetros. Úsalo para orientarte en un diseño que no construiste tú.",
"help.document.units": "Cambia las unidades en que el diseño muestra las longitudes, como mm o pulgadas. La geometría mantiene su tamaño; solo cambian la visualización y los números sin unidad.",
"help.edit.checkpoint": "Recuerda el diseño, el boceto activo y el historial de deshacer tal como están ahora. Úsalo antes de probar algo arriesgado de lo que quizá quieras volver.",
"help.edit.restore_checkpoint": "Vuelve a un punto de control, historial de deshacer incluido. Úsalo para descartar de una vez todo lo hecho desde el punto de control.",
"help.explode.create": "Crea una vista explosionada que aleja las piezas del centro del ensamblaje, o según los movimientos que indiques. Úsalo para mostrar cómo se monta un ensamblaje, en instrucciones o presentaciones.",
"help.face.delete": "Elimina las caras seleccionadas y deja que las caras vecinas cierren el hueco, o deja",
"help.file.insert_mesh": "Adds a 3MF, STL, OBJ, PLY or glTF file to the design as mesh bodies in a new component. Use it to place a downloaded or scanned model beside your design as a reference.",
"help.file.insert_step": "Adds a STEP, IGES, FreeCAD or Rhino file to the design as solid bodies in a new component; an assembly's parts become nested components. Use it to bring in models from suppliers or other CAD programs.",
"help.file.save_mesh": "Saves bodies as an STL, 3MF or OBJ mesh, with the smoothness of curved faces you choose. Use it to prepare parts for 3D printing or for programs that read meshes.",
"help.file.send_to_slicer": "Saves the selected bodies as a 3MF file and opens it in the slicer you choose. Use it to go from the model to printing in one step.",
"help.file.insert_mesh": "Añade un archivo 3MF, STL, OBJ, PLY o glTF al diseño como cuerpos de malla en un componente nuevo. Úsalo para colocar un modelo descargado o escaneado junto a tu diseño como referencia.",
"help.file.insert_step": "Añade un archivo STEP, IGES, FreeCAD o Rhino al diseño como cuerpos sólidos en un componente nuevo; las piezas de un ensamblaje pasan a ser componentes anidados. Úsalo para traer modelos de proveedores o de otros programas de CAD.",
"help.file.save_mesh": "Guarda cuerpos como una malla STL, 3MF u OBJ, con la suavidad de las caras curvas que elijas. Úsalo para preparar piezas para la impresión 3D o para programas que leen mallas.",
"help.file.send_to_slicer": "Guarda los cuerpos seleccionados como un archivo 3MF y lo abre en el laminador que elijas. Úsalo para pasar del modelo a la impresión en un solo paso.",
"help.font_details": "La interfaz utiliza las fuentes integradas de egui (Ubuntu Light y Hack, bajo las licencias Ubuntu Font Licence y MIT/Bitstream Vera; Noto Emoji y la fuente de iconos emoji, bajo OFL y MIT). El texto de los bocetos utiliza Liberation Sans (SIL OFL 1.1). El paquete opcional de fuentes de The Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), no se incluye en las compilaciones de SolidCraft.",
"help.fonts": "Fuentes",
"help.frame.member": "Places a profile, such as a tube or an aluminium extrusion, along the lines of a frame sketch, one member per line. Use it to build frames, racks and welded structures.",
"help.inspect.accessibility": "Colours the faces a tool can reach from one direction, and those it cannot. Use it to check a part for machining or moulding from that side.",
"help.inspect.center_of_mass": "Shows the centre of mass of bodies, each on its own and all together, at uniform density. Use it to check balance and where a part will tip.",
"help.inspect.colored_components": "Gives each component its own temporary colour, without changing appearances. Use it to tell the parts of an assembly apart at a glance.",
"help.inspect.compare": "Compares two bodies and shows where one has material the other does not, with volume and deviation. Use it to check a changed or imported part against the original.",
"help.inspect.continuity": "Checks how smoothly faces meet along their edges: gaps, kinks or curvature jumps, and shades the seams. Use it to find where surfaces do not join cleanly.",
"help.inspect.curvature_comb": "Draws combs along curves, edges or faces whose teeth show how strongly they bend. Use it to spot flat spots, kinks and uneven curvature.",
"help.inspect.curvature_map": "Colours faces by how strongly they curve, red where the radius is small. Use it to find tight spots and to judge how smooth a surface is.",
"help.inspect.draft": "Colours faces by their draft angle to a pull direction, marking those with too little. Use it to check a part before moulding or casting.",
"help.inspect.environment_map": "Shows the model with a reflective, mirror-like finish. Use it to judge the flow of surfaces by the way reflections run across them.",
"help.inspect.interference": "Finds bodies that overlap and shows each overlap with its volume. Use it to check an assembly for parts that collide.",
"help.inspect.isocurve": "Draws the isoparametric curves of faces, the grid the surface is built on. Use it to see how a surface flows and where it bunches up.",
"help.inspect.measure": "Measures lengths, distances, angles, areas and radii between what you pick, or the volume and mass of bodies. Use it to check sizes and clearances.",
"help.inspect.minimum_radius": "Finds the smallest radius of curvature of curves, edges or faces, and where it is. Use it to check that a tool or nozzle can follow the shape.",
"help.inspect.section": "Cuts the view open along a plane and hatches the cut faces, without changing the model. Use it to look inside parts and assemblies.",
"help.inspect.zebra": "Shows black and white stripes reflected on the model's faces. Use it to judge smoothness: stripes that break or kink at an edge show a poor transition.",
"help.joint.as_built": "Joins two parts where they already are, without moving either one, and sets how they may still move. Use it for parts you have already placed in their final position.",
"help.joint.cam": "Links a turning cam to a follower, so the follower slides or swings as the cam's outline passes under it. Use it for cams, eccentrics and valve drives.",
"help.joint.create": "Joins two parts at the joint origins you pick and moves the second part into place; the joint type sets how they may still move. Use it to build an assembly whose parts move like the real mechanism.",
"help.joint.drive": "Sets a joint's angle or distance and moves the parts with it, within its limits; linked joints and closed loops follow. Use it to check that a mechanism moves as intended.",
"help.joint.gear": "Links two turning joints with a gear ratio, so driving one turns the other. Use it for spur and ring gears, with the ratio from pitch radii or tooth counts.",
"help.joint.limits": "Sets how far a joint may turn or slide, as a minimum and a maximum, or clears those limits. Use it to keep a hinge, slider or lever within its real range of travel.",
"help.joint.motion_link": "Couples two joints with a ratio and an offset, so driving one moves the other. Use it for a fixed relation between joints that Gear, Rack and Pinion or Screw do not cover.",
"help.joint.origin": "Places a named joint origin on a part: at the centre of a face or round end, the middle of an edge, a corner or a point. Use it to prepare where joints attach; one picked on a face follows it when the part changes size.",
"help.joint.rack_pinion": "Links a turning pinion to a sliding rack, so the rack moves by the length of pitch circle the pinion rolls through. Use it for rack drives, steering and linear stages.",
"help.joint.reach": "Moves a point on a part toward a target by changing the joints on its chain, within their limits. Use it to pose a mechanism by where its end should be, such as the tip of a robot arm.",
"help.joint.rigid_group": "Locks the selected parts together as they are, so they move as one. Use it for parts that belong together and have no motion between them.",
"help.joint.screw": "Links turning and sliding by a pitch, so each turn advances by that distance. Use it for lead screws, bolts and threaded spindles.",
"help.layout.apply": "Apply a saved layout to the current workspace. Retained editors keep their drafts.",
"help.layout.get": "Read the committed layout and discover registered workspaces.",
"help.layout.reset": "Restore the current workspace's registered default layout. User presets remain available.",
"help.layout.save": "Save the complete layout under a name. Replacing a user preset requires explicit overwrite permission.",
"help.layout.workspace.select": "Select a registered layout workspace and remember the outgoing layout.",
"help.library.apply": "Applies a material or appearance from a local library file to bodies, faces or components. Use it to reuse materials you saved from another design.",
"help.library.export": "Saves the design's materials and appearances to a library file. Use it to share them or reuse them in other designs.",
"help.library.inspect": "Checks a library file and lists its materials and appearances, without changing the design. Use it to see what a library holds before applying it.",
"help.frame.member": "Coloca un perfil, como un tubo o un perfil de aluminio extruido, a lo largo de las líneas de un boceto de estructura, un miembro por línea. Úsalo para construir bastidores, estanterías y estructuras soldadas.",
"help.inspect.accessibility": "Colorea las caras a las que una herramienta puede llegar desde una dirección y las que no. Úsalo para comprobar una pieza para mecanizado o moldeo desde ese lado.",
"help.inspect.center_of_mass": "Muestra el centro de masa de los cuerpos, cada uno por separado y todos juntos, con densidad uniforme. Úsalo para comprobar el equilibrio y dónde volcará una pieza.",
"help.inspect.colored_components": "Da a cada componente su propio color temporal, sin cambiar los aspectos. Úsalo para distinguir de un vistazo las piezas de un ensamblaje.",
"help.inspect.compare": "Compara dos cuerpos y muestra dónde uno tiene material que el otro no, con volumen y desviación. Úsalo para comprobar una pieza modificada o importada con el original.",
"help.inspect.continuity": "Comprueba con qué suavidad se encuentran las caras a lo largo de sus aristas: huecos, quiebros o saltos de curvatura, y sombrea las uniones. Úsalo para encontrar dónde las superficies no se unen limpiamente.",
"help.inspect.curvature_comb": "Dibuja peines a lo largo de curvas, aristas o caras, cuyos dientes muestran cuánto se curvan. Úsalo para detectar zonas planas, quiebros y curvatura irregular.",
"help.inspect.curvature_map": "Colorea las caras según cuánto se curvan, en rojo donde el radio es pequeño. Úsalo para encontrar zonas cerradas y para juzgar lo suave que es una superficie.",
"help.inspect.draft": "Colorea las caras según su ángulo de desmoldeo respecto a una dirección de extracción, y marca las que tienen muy poco. Úsalo para comprobar una pieza antes del moldeo o la fundición.",
"help.inspect.environment_map": "Muestra el modelo con un acabado reflectante, como un espejo. Úsalo para juzgar el fluir de las superficies por cómo corren los reflejos sobre ellas.",
"help.inspect.interference": "Encuentra cuerpos que se solapan y muestra cada solapamiento con su volumen. Úsalo para comprobar si un ensamblaje tiene piezas que chocan.",
"help.inspect.isocurve": "Dibuja las curvas isoparamétricas de las caras, la malla sobre la que se construye la superficie. Úsalo para ver cómo fluye una superficie y dónde se amontona.",
"help.inspect.measure": "Mide longitudes, distancias, ángulos, áreas y radios entre lo que elijas, o el volumen y la masa de los cuerpos. Úsalo para comprobar tamaños y holguras.",
"help.inspect.minimum_radius": "Encuentra el menor radio de curvatura de curvas, aristas o caras, y dónde está. Úsalo para comprobar que una herramienta o una boquilla puede seguir la forma.",
"help.inspect.section": "Corta la vista a lo largo de un plano y raya las caras cortadas, sin cambiar el modelo. Úsalo para mirar dentro de piezas y ensamblajes.",
"help.inspect.zebra": "Muestra rayas blancas y negras reflejadas en las caras del modelo. Úsalo para juzgar la suavidad: las rayas que se rompen o se doblan en una arista indican una mala transición.",
"help.joint.as_built": "Une dos piezas donde ya están, sin mover ninguna, y define cómo pueden seguir moviéndose. Úsalo para piezas que ya colocaste en su posición final.",
"help.joint.cam": "Enlaza una leva giratoria con un seguidor, de modo que el seguidor se desliza o oscila cuando el contorno de la leva pasa por debajo. Úsalo para levas, excéntricas y accionamientos de válvulas.",
"help.joint.create": "Une dos piezas en los orígenes de unión que elijas y mueve la segunda pieza a su sitio; el tipo de unión define cómo pueden seguir moviéndose. Úsalo para construir un ensamblaje cuyas piezas se muevan como el mecanismo real.",
"help.joint.drive": "Fija el ángulo o la distancia de una unión y mueve las piezas con ella, dentro de sus límites; las uniones enlazadas y los lazos cerrados la siguen. Úsalo para comprobar que un mecanismo se mueve como se pretende.",
"help.joint.gear": "Enlaza dos uniones giratorias con una relación de engranaje, de modo que mover una hace girar la otra. Úsalo para engranajes rectos y de corona, con la relación a partir de los radios primitivos o del número de dientes.",
"help.joint.limits": "Fija hasta dónde puede girar o deslizarse una unión, con un mínimo y un máximo, o quita esos límites. Úsalo para mantener una bisagra, una guía o una palanca dentro de su recorrido real.",
"help.joint.motion_link": "Acopla dos uniones con una relación y un desfase, de modo que mover una mueve la otra. Úsalo para una relación fija entre uniones que Engranaje, Cremallera y piñón o Tornillo no cubren.",
"help.joint.origin": "Coloca un origen de unión con nombre en una pieza: en el centro de una cara o de un extremo redondo, en el medio de una arista, en una esquina o en un punto. Úsalo para preparar dónde se acoplan las uniones; el elegido en una cara la sigue cuando la pieza cambia de tamaño.",
"help.joint.rack_pinion": "Enlaza un piñón giratorio con una cremallera deslizante, de modo que la cremallera se mueve la longitud del círculo primitivo que recorre el piñón. Úsalo para accionamientos de cremallera, dirección y mesas lineales.",
"help.joint.reach": "Mueve un punto de una pieza hacia un objetivo cambiando las uniones de su cadena, dentro de sus límites. Úsalo para posicionar un mecanismo según dónde deba estar su extremo, como la punta de un brazo robótico.",
"help.joint.rigid_group": "Bloquea las piezas seleccionadas tal como están, de modo que se muevan como una sola. Úsalo para piezas que van juntas y no tienen movimiento entre ellas.",
"help.joint.screw": "Enlaza giro y deslizamiento mediante un paso, de modo que cada vuelta avanza esa distancia. Úsalo para husillos, tornillos y ejes roscados.",
"help.layout.apply": "Aplica una disposición guardada al espacio de trabajo actual. Los editores retenidos conservan sus borradores.",
"help.layout.get": "Lee la disposición confirmada y descubre los espacios de trabajo registrados.",
"help.layout.reset": "Restaura la disposición predeterminada registrada del espacio de trabajo actual. Los ajustes del usuario siguen disponibles.",
"help.layout.save": "Guarda la disposición completa con un nombre. Reemplazar un ajuste del usuario exige permiso explícito de sobrescritura.",
"help.layout.workspace.select": "Selecciona un espacio de trabajo de disposición registrado y recuerda la disposición que se abandona.",
"help.library.apply": "Aplica un material o un aspecto de un archivo de biblioteca local a cuerpos, caras o componentes. Úsalo para reutilizar materiales que guardaste desde otro diseño.",
"help.library.export": "Guarda los materiales y aspectos del diseño en un archivo de biblioteca. Úsalo para compartirlos o reutilizarlos en otros diseños.",
"help.library.inspect": "Comprueba un archivo de biblioteca y lista sus materiales y aspectos, sin cambiar el diseño. Úsalo para ver qué contiene una biblioteca antes de aplicarla.",
"help.licences": "Licencias",
"help.material.assign": "Define de qué están hechos los cuerpos seleccionados, como acero, aluminio o ABS. Usa",
"help.material.properties.validate": "Checks a material data card for consistent numbers and missing values. Use it before relying on the data for mass or stiffness.",
"help.mesh.convert": "Rebuilds a mesh body, such as an STL, as an editable solid with flat and cylindrical faces. Use it to modify imported mechanical parts like a modelled body.",
"help.material.properties.validate": "Comprueba que una ficha de datos de material tiene números coherentes y no le faltan valores. Úsalo antes de fiarte de los datos para la masa o la rigidez.",
"help.mesh.convert": "Reconstruye un cuerpo de malla, como un STL, en un sólido editable con caras planas y cilíndricas. Úsalo para modificar piezas mecánicas importadas como un cuerpo modelado.",
"help.mit": "Licencia MIT",
"help.motion.study": "Sets joint values at steps along a timeline and plays them back as an animation. Use it to watch a mechanism move through a sequence and check clearances along the way.",
"help.motion.trace": "Traces the path a point on a part follows while a motion study plays or a joint is driven, and keeps it as a 3D sketch curve when you confirm. Use it to see where a mechanism reaches, or to build on its path.",
"help.motion.study": "Fija valores de unión en pasos a lo largo de una línea de tiempo y los reproduce como una animación. Úsalo para ver cómo se mueve un mecanismo en una secuencia y comprobar las holguras por el camino.",
"help.motion.trace": "Traza el camino que sigue un punto de una pieza mientras se reproduce un estudio de movimiento o se acciona una unión, y lo conserva como una curva de boceto 3D al confirmar. Úsalo para ver hasta dónde llega un mecanismo o para construir sobre su trayectoria.",
"help.notice": "AVISO",
"help.occurrence.ground": "Fixes a part in place, or frees it again, so that joints move the other parts around it. Use it for the frame or base that the rest of the assembly is built on.",
"help.occurrence.ground": "Fija una pieza en su sitio, o la libera de nuevo, para que las uniones muevan las demás piezas a su alrededor. Úsalo para el bastidor o la base sobre la que se construye el resto del ensamblaje.",
"help.occurrence.move": "Mueve una pieza de ensamblaje solo por las libertades permitidas por sus uniones. Selecciona una pieza",
"help.panel.activate": "Select an open panel tab without requesting keyboard focus.",
"help.panel.close": "Close a panel through its content lifecycle guard. Its placement is remembered.",
"help.panel.collapse": "Collapse or expand a panel section while retaining its requested dimensions.",
"help.panel.dismiss": "Dismiss the temporary view of a collapsed panel.",
"help.panel.float": "Move a panel into an explicitly positioned floating section.",
"help.panel.focus": "Focus a panel, reopening its retained state and expanding its section when needed.",
"help.panel.list": "Read registered panel kinds, committed instances, active tabs, availability and host capabilities.",
"help.panel.move": "Move a panel into a new section or join an existing tab group.",
"help.panel.native_close": "Return a native panel section to its remembered dock without cancelling its content.",
"help.panel.open": "Open a panel kind with an explicit instance identity and placement for a new instance.",
"help.panel.peek": "Temporarily show a collapsed panel without changing its saved size or collapse state.",
"help.panel.popout": "Move a panel to a native host when supported. Browser hosts use a floating section.",
"help.panel.reset_pair": "Restore an adjacent dock pair's default size ratio within its shared bounds.",
"help.panel.resize": "Set a panel section's outer width and height within every tab's bounds.",
"help.panel.resize_pair": "Resize adjacent dock sections together while conserving their shared extent.",
"help.panel.activate": "Selecciona una pestaña de panel abierta sin pedir el foco del teclado.",
"help.panel.close": "Cierra un panel mediante la protección del ciclo de vida de su contenido. Se recuerda su ubicación.",
"help.panel.collapse": "Contrae o expande una sección de panel conservando las dimensiones solicitadas.",
"help.panel.dismiss": "Descarta la vista temporal de un panel contraído.",
"help.panel.float": "Mueve un panel a una sección flotante con posición explícita.",
"help.panel.focus": "Da el foco a un panel, reabre su estado retenido y expande su sección cuando hace falta.",
"help.panel.list": "Lee los tipos de panel registrados, las instancias confirmadas, las pestañas activas, la disponibilidad y las capacidades del anfitrión.",
"help.panel.move": "Mueve un panel a una sección nueva o lo une a un grupo de pestañas existente.",
"help.panel.native_close": "Devuelve una sección de panel nativa a su acoplamiento recordado sin cancelar su contenido.",
"help.panel.open": "Abre un tipo de panel con una identidad de instancia explícita y una ubicación para una instancia nueva.",
"help.panel.peek": "Muestra temporalmente un panel contraído sin cambiar su tamaño guardado ni su estado de contracción.",
"help.panel.popout": "Mueve un panel a un anfitrión nativo cuando se admite. Los anfitriones de navegador usan una sección flotante.",
"help.panel.reset_pair": "Restaura la proporción de tamaño predeterminada de un par de acoplamientos adyacentes dentro de sus límites compartidos.",
"help.panel.resize": "Fija el ancho y el alto exteriores de una sección de panel dentro de los límites de cada pestaña.",
"help.panel.resize_pair": "Redimensiona juntas secciones de acoplamiento adyacentes conservando su extensión compartida.",
"help.parameters.change": "Abre la tabla de valores y expresiones con nombre que controlan las dimensiones del",
"help.parameters.export": "Saves the design's parameters as CSV or JSON. Use it to edit them in a spreadsheet or move them to another design.",
"help.parameters.graph": "Shows which parameters and features use which others, and any loops or errors among them. Use it to see what a change to a parameter will affect.",
"help.parameters.import": "Reads parameters from CSV or JSON into the design, all or none of them. Use it to bring in values from a spreadsheet or another design.",
"help.parameters.move": "Moves a user parameter before or after another in the list. Use it to keep related parameters together.",
"help.parts.fastener": "Adds a standard screw, bolt, nut, washer, pin or bearing in the size you pick. Placed on a hole, it seats in the hole with a joint, so you need not model fasteners yourself.",
"help.parts.insert": "Inserts a standard part in the family, size and length you pick. Placed on the rim or wall of a hole, it seats on the hole with a rigid joint.",
"help.parts.library": "Opens the standard parts: screws, bolts, nuts, washers, set screws, dowel pins and bearings in standard sizes. Use it to add a standard part instead of modelling it yourself.",
"help.parts.resize": "Changes the size or length of an inserted standard part and rebuilds it; its joints keep it seated. Use it when a screw turns out too long or a hole needs another size.",
"help.plastic.assign_rule": "Assigns a plastic rule to bodies, so their plastic features take its draft and clearance as defaults. Use it to set up a moulded part once for all its features.",
"help.plastic.boss": "Adds a screw boss on a face: a post with an optional hole, draft, root fillet and supporting ribs. Use it for screw points in moulded or printed housings.",
"help.parameters.export": "Guarda los parámetros del diseño como CSV o JSON. Úsalo para editarlos en una hoja de cálculo o pasarlos a otro diseño.",
"help.parameters.graph": "Muestra qué parámetros y operaciones usan a cuáles otros, y los lazos o errores que haya entre ellos. Úsalo para ver qué afectará un cambio en un parámetro.",
"help.parameters.import": "Lee parámetros de un CSV o JSON al diseño, todos o ninguno. Úsalo para traer valores de una hoja de cálculo o de otro diseño.",
"help.parameters.move": "Mueve un parámetro de usuario antes o después de otro en la lista. Úsalo para mantener juntos los parámetros relacionados.",
"help.parts.fastener": "Añade un tornillo, perno, tuerca, arandela, pasador o rodamiento estándar del tamaño que elijas. Colocado sobre un agujero, se asienta en él con una unión, así que no necesitas modelar los elementos de fijación.",
"help.parts.insert": "Inserta una pieza estándar de la familia, el tamaño y la longitud que elijas. Colocada en el borde o la pared de un agujero, se asienta en él con una unión rígida.",
"help.parts.library": "Abre las piezas estándar: tornillos, pernos, tuercas, arandelas, tornillos sin cabeza, pasadores cilíndricos y rodamientos en tamaños estándar. Úsalo para añadir una pieza estándar en lugar de modelarla tú.",
"help.parts.resize": "Cambia el tamaño o la longitud de una pieza estándar insertada y la reconstruye; sus uniones la mantienen asentada. Úsalo cuando un tornillo resulta demasiado largo o un agujero necesita otro tamaño.",
"help.plastic.assign_rule": "Asigna una regla de plástico a cuerpos, de modo que sus operaciones de plástico toman su desmoldeo y holgura como valores por defecto. Úsalo para configurar una pieza moldeada una sola vez para todas sus operaciones.",
"help.plastic.boss": "Añade una torreta para tornillo en una cara: un poste con agujero opcional, desmoldeo, redondeo en la base y nervios de apoyo. Úsalo para los puntos de tornillo en carcasas moldeadas o impresas.",
"help.plastic.lip": "Adds a lip or a matching groove along the rim of a shelled body. Use it so that two housing halves locate on each other and close tightly.",
"help.plastic.manage_rules": "Creates and edits plastic rules: material, wall thickness, radii, clearance and draft. Use them to keep the features of a moulded part consistent.",
"help.plastic.rest": "Adds a rest on a face: a round or rectangular pad, solid or hollow, with draft. Use it as a support or standoff in a moulded housing.",
"help.plastic.snap_fit": "Adds a snap-fit hook on a face, with its length, thickness and catch. Use it to clip parts together without screws.",
"help.plastic.manage_rules": "Crea y edita reglas de plástico: material, espesor de pared, radios, holgura y desmoldeo. Úsalas para mantener coherentes las operaciones de una pieza moldeada.",
"help.plastic.rest": "Añade un apoyo en una cara: un taco redondo o rectangular, macizo o hueco, con desmoldeo. Úsalo como soporte o separador en una carcasa moldeada.",
"help.plastic.snap_fit": "Añade un gancho de encaje a presión en una cara, con su longitud, espesor y resalte. Úsalo para unir piezas sin tornillos.",
"help.pointcloud.insert": "Inserta un escaneo PLY, XYZ o PTS como nube de puntos junto al modelo. Úsala como",
"help.sheet.convert": "Turns a plate or shelled body of even thickness into a sheet metal body, with bends at the edges you pick. Use it to make an existing part unfoldable.",
"help.sheet.export_bend_table": "Saves the bend table of a sheet metal body as CSV or JSON: angles, radii and bend positions in the flat. Use it for the press brake or the workshop.",
"help.sheet.export_dxf": "Saves the flat pattern as a DXF, with outlines, bend lines and optional bend notes. Use it for laser, plasma or waterjet cutting.",
"help.sheet.flange": "Adds a flange: a base plate from a sketch, a wall along an open sketch contour, or a bent wall on sheet edges. Use it to build up sheet metal parts.",
"help.sheet.flat_pattern": "Creates the flat pattern of a sheet metal body, with its size, cut-outs and bend lines. Use it to check the blank before you cut it.",
"help.sheet.fold": "Bends a sheet along a sketch line by an angle and radius. Use it to fold a flat sheet after cutting features into it.",
"help.sheet.hem": "Folds a sheet edge back on itself. Use it for safe, stiff edges without sharp burrs.",
"help.sheet.manage_rules": "Creates and edits sheet metal rules: thickness, bend radius, K-factor, reliefs and gaps. Use them to match the material and tools of your workshop.",
"help.sheet.path_flange": "Adds a chain of flanges along a sheet edge, following an open chain of sketch lines. Use it for profiles such as a U or Z shape in one step.",
"help.sheet.perforate": "Adds a field of holes over the whole flat sheet, in a staggered or square pattern. Use it for vents, grilles and lighter panels.",
"help.sheet.refold": "Folds an unfolded sheet metal body back up. Use it after adding features to the flat sheet.",
"help.sheet.unfold": "Unfolds all bends of a sheet metal body. Use it to add holes or cuts that have to cross a bend, then refold.",
"help.sketch.arc.center_point": "Draws a circular arc around a centre point, from a start point to an end point. Use it when the arc's centre is known, such as a radius around a hole or a pivot.",
"help.sketch.arc.tangent": "Draws an arc that starts at the end of a line or arc and continues tangent to it. Use it to carry on a chain with a smooth bend instead of a corner.",
"help.sketch.arc.three_point": "Draws an arc from a start point to an end point through a third point. Use it when the arc has to pass through given points rather than around a known centre.",
"help.sketch.arc3d": "Draws an exact circular arc in space through three points, with 3D Sketch on. Use it for bends in paths and guide rails that leave the sketch plane.",
"help.sketch.auto_constrain": "Adds the constraints the sketch nearly has already, such as horizontal, parallel or coincident, then dimensions it until it is fully defined. Use it to lock a roughly drawn sketch in one step.",
"help.sketch.auto_constrain_from_datum": "Works like AutoConstrain, but measures the positions from a datum point you pick instead of the origin. Use it when the part is laid out from one reference point, such as a corner or a hole.",
"help.sketch.blend_curve": "Joins the ends of two curves with a smooth spline that is tangent to both, or also curvature continuous if you choose. Use it to bridge a gap between curves without a kink.",
"help.sketch.break": "Splits a curve into pieces where other curves cross it, or at points you place on it. Use it when part of a curve needs its own constraint or should be deleted on its own.",
"help.sketch.cancel": "Leaves the sketch and discards everything changed since it was created or opened for editing. Undo brings the changes back.",
"help.sketch.centerline": "Switches lines between normal lines and centerlines, axes that profiles leave out. Use a centerline as the axis for a revolve, a mirror or a symmetry constraint.",
"help.sketch.chamfer.distance_angle": "Bevels the corner between two lines, set by a distance along the first line and an angle. Use it when a drawing gives the chamfer as a length and an angle, such as 2 mm × 30°.",
"help.sketch.chamfer.equal_distance": "Bevels the corner between two lines the same distance back along both. Use it for the usual 45° chamfer on an outline.",
"help.sketch.chamfer.two_distance": "Bevels the corner between two lines, set by a separate distance along each line. Use it for chamfers that are not 45°, given as two lengths.",
"help.sketch.circle.center": "Draws a circle from its centre and its diameter. Use it for holes, bosses and other round features whose centre is known.",
"help.sketch.circle.three_point": "Draws a circle through three points. Use it when the circle has to pass through given points, for example of existing geometry.",
"help.sketch.circle.three_tangent": "Draws a circle that touches three lines, circles or arcs. Use it to fit a circle into the space between three curves, such as the inscribed circle of a triangle.",
"help.sketch.circle.two_point": "Draws a circle from the two ends of its diameter. Use it when the circle's edge points are known rather than its centre.",
"help.sketch.circle.two_tangent": "Draws a circle of a given size that touches two lines, circles or arcs. Use it for a rounding of fixed radius between two curves.",
"help.sketch.conic": "Draws a conic curve between two end points, shaped by an apex point and a rho value. Use it for smooth transitions whose fullness you want to tune, from flat to nearly a sharp corner.",
"help.sketch.constrainer": "Applies the constraint that one or two picked curves nearly have already, such as horizontal, parallel, tangent or equal. Use it to tidy a hand-drawn sketch one relation at a time.",
"help.sketch.constraint.coincident": "Makes a point lie on another point, a curve or a sketch axis. Use it to close gaps in a profile or to put a point on a line.",
"help.sketch.constraint.collinear": "Makes two lines lie on one straight line. Use it to line up interrupted edges, such as both sides of a notch.",
"help.sketch.constraint.concentric": "Gives two circles or arcs the same centre, or centres a circle or arc on a sketch point, including the origin. Pick either pair in either order.",
"help.sketch.constraint.curvature": "Makes two curves that meet at an end point continue with the same curvature (G2). Use it where a tangent join is not smooth enough, for example on visible surfaces.",
"help.sketch.constraint.equal": "Makes lines the same length, or circles and arcs the same radius. Use it so that one dimension drives several matching features.",
"help.sketch.constraint.fix": "Fixes points or curves where they are, or frees them again. Use it for geometry that must not move when you drag or solve the sketch.",
"help.sketch.constraint.horizontal_vertical": "Makes a line, or the line between two points, horizontal or vertical, whichever is closer. Use it to square an outline up to the sketch axes.",
"help.sketch.constraint.midpoint": "Puts a point on the middle of a line, or makes the midpoints of two lines meet. Use it to centre geometry on an edge.",
"help.sketch.constraint.parallel": "Makes two lines parallel. Use it for sides that must stay parallel when other dimensions change.",
"help.sketch.constraint.perpendicular": "Makes two lines meet at a right angle. Use it for square corners between lines that are not on the sketch axes.",
"help.sketch.constraint.polygon": "Makes a closed chain of lines a regular polygon: equal sides, with every corner on one circle. Use it to make a hand-drawn polygon regular and keep it so.",
"help.sketch.constraint.symmetry": "Makes two points or curves mirror each other across a line or about a point. Use it to keep a profile symmetric when you change one side.",
"help.sketch.constraint.tangent": "Makes two curves touch tangentially, such as a line and an arc. Use it for smooth joins without a kink.",
"help.sketch.construction": "Switches curves between normal geometry and construction geometry, which profiles leave out. Use construction curves as helpers for layout, references and dimensions.",
"help.sheet.convert": "Convierte una placa o un cuerpo vaciado de espesor uniforme en un cuerpo de chapa metálica, con pliegues en las aristas que elijas. Úsalo para hacer desplegable una pieza existente.",
"help.sheet.export_bend_table": "Guarda la tabla de plegado de un cuerpo de chapa metálica como CSV o JSON: ángulos, radios y posiciones de los pliegues en el desarrollo. Úsalo para la plegadora o el taller.",
"help.sheet.export_dxf": "Guarda el desarrollo plano como DXF, con contornos, líneas de plegado y notas de plegado opcionales. Úsalo para corte por láser, plasma o chorro de agua.",
"help.sheet.flange": "Añade una pestaña: una placa base a partir de un boceto, una pared a lo largo de un contorno abierto de boceto, o una pared plegada en aristas de chapa. Úsalo para construir piezas de chapa metálica.",
"help.sheet.flat_pattern": "Crea el desarrollo plano de un cuerpo de chapa metálica, con su tamaño, recortes y líneas de plegado. Úsalo para comprobar la pieza en bruto antes de cortarla.",
"help.sheet.fold": "Pliega una chapa a lo largo de una línea de boceto con un ángulo y un radio. Úsalo para plegar una chapa plana tras practicarle operaciones de corte.",
"help.sheet.hem": "Dobla el borde de una chapa sobre sí mismo. Úsalo para bordes seguros y rígidos, sin rebabas cortantes.",
"help.sheet.manage_rules": "Crea y edita reglas de chapa metálica: espesor, radio de plegado, factor K, alivios y holguras. Úsalas para ajustarte al material y a las herramientas de tu taller.",
"help.sheet.path_flange": "Añade una cadena de pestañas a lo largo del borde de una chapa, siguiendo una cadena abierta de líneas de boceto. Úsalo para perfiles como una U o una Z en un solo paso.",
"help.sheet.perforate": "Añade un campo de agujeros sobre toda la chapa plana, en patrón al tresbolillo o cuadrado. Úsalo para rejillas, ventilaciones y paneles más ligeros.",
"help.sheet.refold": "Vuelve a plegar un cuerpo de chapa metálica desplegado. Úsalo tras añadir operaciones a la chapa plana.",
"help.sheet.unfold": "Despliega todos los pliegues de un cuerpo de chapa metálica. Úsalo para añadir agujeros o cortes que deban cruzar un pliegue, y luego vuelve a plegar.",
"help.sketch.arc.center_point": "Dibuja un arco circular alrededor de un punto central, de un punto inicial a un punto final. Úsalo cuando se conoce el centro del arco, como un radio alrededor de un agujero o de un pivote.",
"help.sketch.arc.tangent": "Dibuja un arco que empieza en el extremo de una línea o arco y continúa tangente a él. Úsalo para seguir una cadena con una curva suave en lugar de una esquina.",
"help.sketch.arc.three_point": "Dibuja un arco de un punto inicial a un punto final pasando por un tercer punto. Úsalo cuando el arco deba pasar por puntos dados y no alrededor de un centro conocido.",
"help.sketch.arc3d": "Dibuja un arco circular exacto en el espacio por tres puntos, con el Boceto 3D activado. Úsalo para curvas en trayectorias y guías que salen del plano del boceto.",
"help.sketch.auto_constrain": "Añade las restricciones que el boceto ya casi cumple, como horizontal, paralela o coincidente, y luego lo acota hasta definirlo por completo. Úsalo para fijar de un paso un boceto dibujado a mano alzada.",
"help.sketch.auto_constrain_from_datum": "Funciona como Restricción automática, pero mide las posiciones desde un punto de referencia que eliges en lugar del origen. Úsalo cuando la pieza se organiza a partir de un punto de referencia, como una esquina o un agujero.",
"help.sketch.blend_curve": "Une los extremos de dos curvas con una spline suave tangente a ambas, o también de curvatura continua si lo eliges. Úsalo para salvar un hueco entre curvas sin quiebros.",
"help.sketch.break": "Divide una curva en trozos donde otras curvas la cruzan, o en puntos que colocas sobre ella. Úsalo cuando una parte de una curva necesite su propia restricción o deba borrarse por separado.",
"help.sketch.cancel": "Sale del boceto y descarta todo lo cambiado desde que se creó o se abrió para editarlo. Deshacer recupera los cambios.",
"help.sketch.centerline": "Cambia las líneas entre líneas normales y líneas de eje, ejes que los perfiles dejan fuera. Usa una línea de eje como eje de una revolución, un espejo o una restricción de simetría.",
"help.sketch.chamfer.distance_angle": "Bisela la esquina entre dos líneas, definido por una distancia a lo largo de la primera línea y un ángulo. Úsalo cuando un plano da el chaflán como una longitud y un ángulo, como 2 mm × 30°.",
"help.sketch.chamfer.equal_distance": "Bisela la esquina entre dos líneas la misma distancia hacia atrás en ambas. Úsalo para el chaflán habitual de 45° en un contorno.",
"help.sketch.chamfer.two_distance": "Bisela la esquina entre dos líneas, definido por una distancia distinta a lo largo de cada línea. Úsalo para chaflanes que no son de 45°, dados como dos longitudes.",
"help.sketch.circle.center": "Dibuja un círculo a partir de su centro y su diámetro. Úsalo para agujeros, salientes y otras formas redondas cuyo centro se conoce.",
"help.sketch.circle.three_point": "Dibuja un círculo por tres puntos. Úsalo cuando el círculo deba pasar por puntos dados, por ejemplo de geometría existente.",
"help.sketch.circle.three_tangent": "Dibuja un círculo que toca tres líneas, círculos o arcos. Úsalo para ajustar un círculo en el espacio entre tres curvas, como el círculo inscrito de un triángulo.",
"help.sketch.circle.two_point": "Dibuja un círculo a partir de los dos extremos de su diámetro. Úsalo cuando se conocen los puntos del borde del círculo y no su centro.",
"help.sketch.circle.two_tangent": "Dibuja un círculo de un tamaño dado que toca dos líneas, círculos o arcos. Úsalo para un redondeo de radio fijo entre dos curvas.",
"help.sketch.conic": "Dibuja una curva cónica entre dos puntos finales, definida por un punto de vértice y un valor rho. Úsalo para transiciones suaves cuya plenitud quieras ajustar, de plana a casi una esquina viva.",
"help.sketch.constrainer": "Aplica la restricción que una o dos curvas elegidas ya casi cumplen, como horizontal, paralela, tangente o igual. Úsalo para ordenar un boceto dibujado a mano, una relación cada vez.",
"help.sketch.constraint.coincident": "Hace que un punto quede sobre otro punto, una curva o un eje del boceto. Úsalo para cerrar huecos en un perfil o para poner un punto sobre una línea.",
"help.sketch.constraint.collinear": "Hace que dos líneas queden sobre una misma recta. Úsalo para alinear aristas interrumpidas, como los dos lados de una muesca.",
"help.sketch.constraint.concentric": "Da a dos círculos o arcos el mismo centro, o centra un círculo o arco en un punto de boceto, incluido el origen. Elige cualquiera de los dos pares en cualquier orden.",
"help.sketch.constraint.curvature": "Hace que dos curvas que se encuentran en un punto final continúen con la misma curvatura (G2). Úsalo donde una unión tangente no es lo bastante suave, por ejemplo en superficies visibles.",
"help.sketch.constraint.equal": "Hace que las líneas tengan la misma longitud, o los círculos y arcos el mismo radio. Úsalo para que una sola cota controle varias formas iguales.",
"help.sketch.constraint.fix": "Fija puntos o curvas donde están, o los libera de nuevo. Úsalo para geometría que no debe moverse al arrastrar o resolver el boceto.",
"help.sketch.constraint.horizontal_vertical": "Hace que una línea, o la línea entre dos puntos, sea horizontal o vertical, la más cercana. Úsalo para ajustar un contorno a los ejes del boceto.",
"help.sketch.constraint.midpoint": "Pone un punto en el medio de una línea, o hace que se encuentren los puntos medios de dos líneas. Úsalo para centrar geometría sobre una arista.",
"help.sketch.constraint.parallel": "Hace paralelas dos líneas. Úsalo para lados que deben seguir paralelos cuando cambian otras cotas.",
"help.sketch.constraint.perpendicular": "Hace que dos líneas se encuentren en ángulo recto. Úsalo para esquinas en escuadra entre líneas que no están sobre los ejes del boceto.",
"help.sketch.constraint.polygon": "Convierte una cadena cerrada de líneas en un polígono regular: lados iguales, con todas las esquinas en un mismo círculo. Úsalo para hacer regular un polígono dibujado a mano y mantenerlo así.",
"help.sketch.constraint.symmetry": "Hace que dos puntos o curvas sean reflejo uno de otro respecto a una línea o a un punto. Úsalo para mantener simétrico un perfil cuando cambias un lado.",
"help.sketch.constraint.tangent": "Hace que dos curvas se toquen tangencialmente, como una línea y un arco. Úsalo para uniones suaves sin quiebros.",
"help.sketch.construction": "Cambia las curvas entre geometría normal y geometría de construcción, que los perfiles dejan fuera. Usa las curvas de construcción como ayuda para la disposición, las referencias y las cotas.",
"help.sketch.construction_line": "Crea una línea de construcción infinita a través de dos puntos. Úsala para organizar un boceto.",
"help.sketch.construction_line.angle": "Crea una línea de construcción infinita en un ángulo desde el eje X del boceto. Elige el punto a",
"help.sketch.construction_line.bisector": "Elige dos líneas rectas de boceto que se intersecten, luego elige una de las dos bisectrices del ángulo.",
@@ -1896,72 +1897,72 @@
"help.sketch.construction_line.tangent_external": "Elige un círculo o arco circular, luego un punto externo y una solución de tangente. Th",
"help.sketch.construction_line.tangent_two": "Elige dos círculos o arcos circulares, luego elige una tangente común en la previsualización.",
"help.sketch.construction_line.vertical": "Crea una línea de construcción vertical infinita a través de un punto. Su dirección vertical",
"help.sketch.copy": "Copies the selected sketch curves and points, together with the constraints and dimensions among them. Paste them into this sketch or another one.",
"help.sketch.create": "Starts a new 2D sketch on a plane or on a flat face of the model. Every extrude, revolve and sweep begins with a sketch.",
"help.sketch.cut": "Copies the selected sketch geometry and deletes it from the sketch, in one undo step. Paste it elsewhere in this sketch or into another one.",
"help.sketch.dimension": "Adds a driving dimension: a length, distance, angle, radius or diameter, depending on what you pick. Type a value or a parameter name, and the sketch follows it.",
"help.sketch.edit": "Opens an existing sketch for editing. The features built on it update when you finish the sketch.",
"help.sketch.ellipse": "Draws an ellipse from its centre, the end of its major axis and a point on its minor side. Use it for oval openings, cams and other elongated round shapes.",
"help.sketch.copy": "Copia las curvas y puntos de boceto seleccionados, junto con las restricciones y cotas entre ellos. Pégalos en este boceto o en otro.",
"help.sketch.create": "Empieza un nuevo boceto 2D en un plano o en una cara plana del modelo. Toda extrusión, revolución y barrido empieza con un boceto.",
"help.sketch.cut": "Copia la geometría de boceto seleccionada y la borra del boceto, en un solo paso de deshacer. Pégala en otro lugar de este boceto o en otro.",
"help.sketch.dimension": "Añade una cota conductora: una longitud, distancia, ángulo, radio o diámetro, según lo que elijas. Escribe un valor o el nombre de un parámetro y el boceto lo sigue.",
"help.sketch.edit": "Abre un boceto existente para editarlo. Las operaciones construidas sobre él se actualizan al terminar el boceto.",
"help.sketch.ellipse": "Dibuja una elipse a partir de su centro, el extremo de su eje mayor y un punto de su lado menor. Úsalo para aberturas ovaladas, levas y otras formas redondas alargadas.",
"help.sketch.equation_curve": "Dibuja una curva a partir de fórmulas: x(t) e y(t), o y = f(x), sobre un rango. La fórmula",
"help.sketch.extend": "Lengthens a line or arc up to the nearest curve in its way, or grows two curves until they meet. Use it to close gaps in a profile after trimming or editing.",
"help.sketch.fillet": "Rounds the corner where two lines or arcs meet with an arc of a given radius. Several corners rounded together share one radius.",
"help.sketch.finish": "Leaves the sketch and returns to the model. Its closed profiles are then ready for Extrude, Revolve and other features.",
"help.sketch.finish_auto_constrain": "Runs AutoConstrain on the sketch, then finishes it. Use it to leave a sketch fully defined in one step.",
"help.sketch.fit_curves_to_section": "Cuts a mesh or solid body with the sketch plane and fits lines and arcs to the section. Use it to rebuild a scanned or imported part as an editable sketch.",
"help.sketch.include_3d": "Brings model edges, vertices and curves of other sketches into this sketch as linked references, flattening those off its plane onto it. Use it to build on geometry that does not lie in the sketch plane.",
"help.sketch.infinite": "Switches lines between normal lines and infinite construction lines that run across the whole view. Use them as layout references that never end too short.",
"help.sketch.insert_dxf": "Reads the curves of a DXF drawing into a sketch, scaled, turned and placed where you set. Use it to build on a 2D drawing from another program, such as a laser-cut outline.",
"help.sketch.insert_svg": "Reads the paths of an SVG drawing into a sketch, scaled, turned and placed where you set. Use it to turn a logo or vector outline into curves you can extrude.",
"help.sketch.extend": "Alarga una línea o un arco hasta la curva más cercana que encuentre, o hace crecer dos curvas hasta que se encuentran. Úsalo para cerrar huecos de un perfil tras recortar o editar.",
"help.sketch.fillet": "Redondea la esquina donde se encuentran dos líneas o arcos con un arco de un radio dado. Varias esquinas redondeadas a la vez comparten un radio.",
"help.sketch.finish": "Sale del boceto y vuelve al modelo. Sus perfiles cerrados quedan listos para Extrusión, Revolución y otras operaciones.",
"help.sketch.finish_auto_constrain": "Ejecuta Restricción automática en el boceto y luego lo finaliza. Úsalo para dejar un boceto totalmente definido de un paso.",
"help.sketch.fit_curves_to_section": "Corta un cuerpo de malla o sólido con el plano del boceto y ajusta líneas y arcos a la sección. Úsalo para reconstruir como boceto editable una pieza escaneada o importada.",
"help.sketch.include_3d": "Trae aristas del modelo, vértices y curvas de otros bocetos a este boceto como referencias vinculadas, aplanando sobre él las que no están en su plano. Úsalo para construir sobre geometría que no está en el plano del boceto.",
"help.sketch.infinite": "Cambia las líneas entre líneas normales y líneas de construcción infinitas que cruzan toda la vista. Úsalas como referencias de disposición que nunca se quedan cortas.",
"help.sketch.insert_dxf": "Lee las curvas de un dibujo DXF en un boceto, escaladas, giradas y colocadas donde indiques. Úsalo para construir sobre un dibujo 2D de otro programa, como un contorno para corte láser.",
"help.sketch.insert_svg": "Lee los trazados de un dibujo SVG en un boceto, escalados, girados y colocados donde indiques. Úsalo para convertir un logotipo o un contorno vectorial en curvas que puedas extruir.",
"help.sketch.inspect": "Abre un informe sobre el boceto abierto: cuántos grados de libertad quedan y qué",
"help.sketch.intersect": "Adds the curves or points where bodies, faces, edges or other sketches cross the sketch plane. They stay linked and follow the model when it changes.",
"help.sketch.intersect": "Añade las curvas o puntos donde cuerpos, caras, aristas u otros bocetos cruzan el plano del boceto. Quedan vinculados y siguen al modelo cuando cambia.",
"help.sketch.intersection_curve": "Crea curvas 3D donde se encuentran dos cuerpos, caras o curvas de otros bocetos, vinculadas a ellos. Úsalas como trayectorias o líneas guía que siguen el modelo.",
"help.sketch.isoparametric_curve": "Creates a 3D curve along a face's U or V direction through a point you pick, linked to the face. Use it as a path or split line that follows the surface.",
"help.sketch.line": "Draws connected lines point by point, as an open chain or a closed outline. It is the basic tool for most profiles.",
"help.sketch.line.midpoint": "Draws a line from its midpoint out to one end, with the other end mirrored. Use it for lines centred on a point, such as a symmetric edge.",
"help.sketch.line3d": "Draws connected straight lines between points in space, with 3D Sketch on. Use it for paths and frames that leave the sketch plane.",
"help.sketch.mirror": "Mirrors sketch curves and points across a line or axis and adds symmetry constraints. Use it to draw half of a symmetric profile and complete it.",
"help.sketch.move": "Moves or rotates sketch curves and points, or a copy of them. Use it to reposition geometry while keeping its shape and constraints.",
"help.sketch.offset": "Creates a copy of a chain of curves at a set distance, on one side or both. Use it for walls, outlines and clearances; the distance stays an editable dimension.",
"help.sketch.paste": "Pastes sketch geometry you copied or cut into the active sketch. Place it at a point or shift it by an offset.",
"help.sketch.pattern.circular": "Copies sketch geometry around a centre point, over a full circle or a set angle. Use it for bolt circles, spokes and teeth.",
"help.sketch.pattern.rectangular": "Copies sketch geometry in rows and columns at set spacings. Use it for grids of holes, slots or vents.",
"help.sketch.point": "Places a sketch point. Use it as a reference for dimensions, constraints, hole centres or later features.",
"help.sketch.isoparametric_curve": "Crea una curva 3D en la dirección U o V de una cara, por un punto que eliges, vinculada a la cara. Úsala como trayectoria o línea de división que sigue la superficie.",
"help.sketch.line": "Dibuja líneas conectadas punto por punto, como cadena abierta o contorno cerrado. Es la herramienta básica de la mayoría de los perfiles.",
"help.sketch.line.midpoint": "Dibuja una línea desde su punto medio hasta un extremo, con el otro extremo reflejado. Úsalo para líneas centradas en un punto, como una arista simétrica.",
"help.sketch.line3d": "Dibuja líneas rectas conectadas entre puntos del espacio, con el Boceto 3D activado. Úsalo para trayectorias y estructuras que salen del plano del boceto.",
"help.sketch.mirror": "Refleja curvas y puntos de boceto respecto a una línea o un eje y añade restricciones de simetría. Úsalo para dibujar la mitad de un perfil simétrico y completarlo.",
"help.sketch.move": "Mueve o gira curvas y puntos de boceto, o una copia de ellos. Úsalo para recolocar geometría conservando su forma y sus restricciones.",
"help.sketch.offset": "Crea una copia de una cadena de curvas a una distancia fijada, por un lado o por ambos. Úsalo para paredes, contornos y holguras; la distancia sigue siendo una cota editable.",
"help.sketch.paste": "Pega en el boceto activo la geometría de boceto que copiaste o cortaste. Colócala en un punto o desplázala un desfase.",
"help.sketch.pattern.circular": "Copia la geometría de boceto alrededor de un punto central, en un círculo completo o un ángulo fijado. Úsalo para círculos de pernos, radios y dientes.",
"help.sketch.pattern.rectangular": "Copia la geometría de boceto en filas y columnas con separaciones fijadas. Úsalo para cuadrículas de agujeros, ranuras o ventilaciones.",
"help.sketch.point": "Coloca un punto de boceto. Úsalo como referencia para cotas, restricciones, centros de agujeros u operaciones posteriores.",
"help.sketch.point.divide": "Coloca puntos que dividen las curvas elegidas en longitudes iguales. Los puntos permanecen en cada curva y mantienen su separación cuando esta cambia.",
"help.sketch.point3d": "Places a point in space, with 3D Sketch on. Use it as a reference for 3D curves and paths.",
"help.sketch.polygon.circumscribed": "Draws a regular polygon around a circle, sized from its centre to the middle of a side. Use it when the width across flats is known, as for a hex nut.",
"help.sketch.polygon.edge": "Draws a regular polygon from the two ends of one side. Use it when the length and position of a side are known.",
"help.sketch.polygon.inscribed": "Draws a regular polygon inside a circle, sized from its centre to a corner. Use it when the size across corners is known.",
"help.sketch.project": "Brings model edges, faces, vertices and curves of other sketches into this sketch, projected onto its plane. They stay linked and follow the model when it changes.",
"help.sketch.project_to_surface": "Projects curves of other sketches along this sketch's normal onto a face, as linked 3D curves. Use it to put a logo, split line or path onto a curved surface.",
"help.sketch.rectangle.center": "Draws a rectangle from its centre and one corner. Use it for outlines centred on a point, such as the origin.",
"help.sketch.rectangle.rounded": "Draws a rectangle with all four corners rounded to one radius. Use it for plates, lids and openings with rounded corners.",
"help.sketch.rectangle.three_point": "Draws a rectangle from one edge and a point on the opposite side. Use it for rectangles at an angle to the sketch axes.",
"help.sketch.rectangle.two_point": "Draws a rectangle from two opposite corners. Use it for the outlines of plates, blocks and pockets.",
"help.sketch.scale": "Scales sketch curves and points by a factor about a base point. Use it to resize part of a sketch without drawing it again.",
"help.sketch.slot.arc_center": "Draws a curved slot of a given width along an arc set by its centre, start and end. Use it for adjustment slots around a pivot.",
"help.sketch.slot.arc_three_point": "Draws a curved slot of a given width along an arc through three points. Use it when the slot's path has to pass through given points.",
"help.sketch.slot.center_point": "Draws a straight slot of a given width from its centre to the centre of one end arc. Use it for slots centred on a point.",
"help.sketch.slot.center_to_center": "Draws a straight slot of a given width between the centres of its two end arcs. Use it for slots dimensioned centre to centre, such as adjustment slots for screws.",
"help.sketch.slot.overall": "Draws a straight slot of a given width from one outer end to the other. Use it when the slot's overall length is what matters.",
"help.sketch.spline.control_point": "Draws a cubic spline shaped by control points that it does not pass through. Use it for smooth, flowing curves that you shape by moving the points.",
"help.sketch.spline.control_point_5": "Draws a degree 5 spline shaped by control points. Use it where curves have to join with smoother curvature, for example on visible styled surfaces.",
"help.sketch.spline.fit_point": "Draws a smooth spline that passes through every point you place, open or closed. Use it to trace a shape through known points.",
"help.sketch.spline3d": "Draws a smooth curve in space through points, with 3D Sketch on. Use it for sweep paths and cable runs that leave the sketch plane.",
"help.sketch.spun_profile": "Creates in the sketch plane the outline a body sweeps when it turns about an axis. Use it to get the silhouette of a turned part for a revolve or a drawing.",
"help.sketch.text": "Writes text in the sketch in a chosen font, height and angle; its words can follow parameters. Extrude or emboss it for labels and lettering.",
"help.sketch.transform": "Scales, turns and moves sketch geometry about a centre point in one step. Use it to reposition and resize a selection at once.",
"help.sketch.trim": "Removes the piece of a curve between the nearest crossings around where you click. Use it to clean up overlapping lines into a closed profile.",
"help.sketch.point3d": "Coloca un punto en el espacio, con el Boceto 3D activado. Úsalo como referencia para curvas y trayectorias 3D.",
"help.sketch.polygon.circumscribed": "Dibuja un polígono regular alrededor de un círculo, dimensionado desde su centro hasta el medio de un lado. Úsalo cuando se conoce la anchura entre caras, como en una tuerca hexagonal.",
"help.sketch.polygon.edge": "Dibuja un polígono regular a partir de los dos extremos de un lado. Úsalo cuando se conocen la longitud y la posición de un lado.",
"help.sketch.polygon.inscribed": "Dibuja un polígono regular dentro de un círculo, dimensionado desde su centro hasta una esquina. Úsalo cuando se conoce la medida entre esquinas.",
"help.sketch.project": "Trae aristas del modelo, caras, vértices y curvas de otros bocetos a este boceto, proyectados sobre su plano. Quedan vinculados y siguen al modelo cuando cambia.",
"help.sketch.project_to_surface": "Proyecta curvas de otros bocetos a lo largo de la normal de este boceto sobre una cara, como curvas 3D vinculadas. Úsalo para poner un logotipo, una línea de división o una trayectoria sobre una superficie curva.",
"help.sketch.rectangle.center": "Dibuja un rectángulo a partir de su centro y una esquina. Úsalo para contornos centrados en un punto, como el origen.",
"help.sketch.rectangle.rounded": "Dibuja un rectángulo con las cuatro esquinas redondeadas con un mismo radio. Úsalo para placas, tapas y aberturas con esquinas redondeadas.",
"help.sketch.rectangle.three_point": "Dibuja un rectángulo a partir de un borde y un punto del lado opuesto. Úsalo para rectángulos inclinados respecto a los ejes del boceto.",
"help.sketch.rectangle.two_point": "Dibuja un rectángulo a partir de dos esquinas opuestas. Úsalo para los contornos de placas, bloques y vaciados.",
"help.sketch.scale": "Escala curvas y puntos de boceto por un factor respecto a un punto base. Úsalo para cambiar el tamaño de parte de un boceto sin volver a dibujarla.",
"help.sketch.slot.arc_center": "Dibuja una ranura curva de una anchura dada a lo largo de un arco definido por su centro, inicio y fin. Úsalo para ranuras de ajuste alrededor de un pivote.",
"help.sketch.slot.arc_three_point": "Dibuja una ranura curva de una anchura dada a lo largo de un arco por tres puntos. Úsalo cuando la trayectoria de la ranura deba pasar por puntos dados.",
"help.sketch.slot.center_point": "Dibuja una ranura recta de una anchura dada desde su centro hasta el centro de un arco de extremo. Úsalo para ranuras centradas en un punto.",
"help.sketch.slot.center_to_center": "Dibuja una ranura recta de una anchura dada entre los centros de sus dos arcos de extremo. Úsalo para ranuras acotadas de centro a centro, como las ranuras de ajuste de tornillos.",
"help.sketch.slot.overall": "Dibuja una ranura recta de una anchura dada de un extremo exterior al otro. Úsalo cuando lo que importa es la longitud total de la ranura.",
"help.sketch.spline.control_point": "Dibuja una spline cúbica definida por puntos de control por los que no pasa. Úsalo para curvas suaves y fluidas que moldeas moviendo los puntos.",
"help.sketch.spline.control_point_5": "Dibuja una spline de grado 5 definida por puntos de control. Úsalo donde las curvas deban unirse con una curvatura más suave, por ejemplo en superficies de diseño visibles.",
"help.sketch.spline.fit_point": "Dibuja una spline suave que pasa por cada punto que colocas, abierta o cerrada. Úsalo para trazar una forma por puntos conocidos.",
"help.sketch.spline3d": "Dibuja una curva suave en el espacio por puntos, con el Boceto 3D activado. Úsalo para trayectorias de barrido y recorridos de cable que salen del plano del boceto.",
"help.sketch.spun_profile": "Crea en el plano del boceto el contorno que barre un cuerpo al girar sobre un eje. Úsalo para obtener la silueta de una pieza torneada para una revolución o un plano.",
"help.sketch.text": "Escribe texto en el boceto con una fuente, altura y ángulo elegidos; sus palabras pueden seguir parámetros. Extrúyelo o grábalo para etiquetas y rótulos.",
"help.sketch.transform": "Escala, gira y mueve la geometría del boceto respecto a un punto central en un solo paso. Úsalo para recolocar y cambiar de tamaño una selección a la vez.",
"help.sketch.trim": "Elimina el trozo de una curva entre los cruces más cercanos alrededor de donde haces clic. Úsalo para limpiar líneas solapadas y obtener un perfil cerrado.",
"help.solid.align": "Mueve los cuerpos seleccionados para que un punto, cara o plano de ellos coincida con un punto,",
"help.solid.boundary_fill": "Makes solids from the regions enclosed by overlapping tool bodies, filling only the regions you pick. Use it to build a shape from the space that several bodies bound together.",
"help.solid.bounding_solid": "Creates a box that encloses the selected bodies, with an optional margin. Use it to see a part's overall size, or as the stock it is machined from.",
"help.solid.box": "Creates a box from a length, width and height, from a corner point or centred on a point. Use it for a quick block, a placeholder or a body to cut features into.",
"help.solid.boundary_fill": "Crea sólidos a partir de las regiones encerradas por cuerpos herramienta que se solapan, rellenando solo las regiones que elijas. Úsalo para construir una forma a partir del espacio que delimitan varios cuerpos juntos.",
"help.solid.bounding_solid": "Crea una caja que envuelve los cuerpos seleccionados, con un margen opcional. Úsalo para ver el tamaño total de una pieza, o como material en bruto del que se mecaniza.",
"help.solid.box": "Crea una caja a partir de largo, ancho y alto, desde un punto de esquina o centrada en un punto. Úsalo para un bloque rápido, un marcador de posición o un cuerpo en el que practicar operaciones de corte.",
"help.solid.chamfer": "Corta las aristas seleccionadas con un chaflán plano de la distancia que indiques. Úsalo para romper aristas vivas o para facilitar la entrada de un pasador o un tornillo.",
"help.solid.coil": "Creates a helical body, such as a spring, from a diameter, turns, height or pitch and a round or square section. Use it for springs, coils and helical ridges.",
"help.solid.coil": "Crea un cuerpo helicoidal, como un muelle, a partir de un diámetro, vueltas, altura o paso y una sección redonda o cuadrada. Úsalo para muelles, bobinas y resaltes helicoidales.",
"help.solid.combine": "Combina cuerpos: los une, los recorta de un cuerpo de destino o conserva solo el volumen que comparten, y puede mantener los cuerpos de herramienta. Úsalo para fusionar piezas, recortar una forma con otra o encontrar dónde se solapan dos cuerpos.",
"help.solid.cone": "Creates a cone from a base circle and a height, or a truncated cone when the top has a radius too. Use it for tapers, funnels, countersinks and points.",
"help.solid.cylinder": "Creates a cylinder from a radius or diameter and a height, standing on a point along an axis. Use it for shafts, pins, bosses and round blanks.",
"help.solid.cone": "Crea un cono a partir de un círculo base y una altura, o un cono truncado cuando la parte superior también tiene radio. Úsalo para conicidades, embudos, avellanados y puntas.",
"help.solid.cylinder": "Crea un cilindro a partir de un radio o diámetro y una altura, apoyado en un punto a lo largo de un eje. Úsalo para ejes, pasadores, salientes y piezas en bruto redondas.",
"help.solid.draft": "Inclina las caras seleccionadas según el ángulo que indiques, medido desde un plano neutro. Usa",
"help.solid.emboss": "Raises sketch profiles, such as text or a logo, out of a face, or sinks them into it. Use it for lettering, labels and markings on flat or round faces.",
"help.solid.emboss": "Eleva perfiles de boceto, como texto o un logotipo, sobre una cara, o los hunde en ella. Úsalo para rótulos, etiquetas y marcas en caras planas o redondas.",
"help.solid.extrude": "Empuja un perfil de boceto hacia el 3D a lo largo de una distancia, añadiendo o quitando material. Úsalo para convertir un contorno plano en un bloque, un saliente o una cavidad.",
"help.solid.fillet": "Redondea las aristas seleccionadas con una transición circular suave del radio que indiques. Úsalo para suavizar aristas vivas por resistencia, comodidad o aspecto.",
"help.solid.hole": "Perfora un agujero redondo del diámetro que indiques en un punto elegido de una cara. Úsalo para holguras de tornillos, pasadores y otras aberturas redondas sencillas.",
@@ -1970,62 +1971,62 @@
"help.solid.move": "Mueve o rota los cuerpos seleccionados, o una copia de ellos, por la distancia y el ángulo",
"help.solid.offset_face": "Empuja las caras seleccionadas hacia dentro o fuera por la distancia que indiques, y las caras de alrededor",
"help.solid.pattern.circular": "Repite los objetos seleccionados alrededor de un eje, con el recuento y el ángulo total que indiques. Úsalo para círculos de tornillos, radios, aletas y dientes.",
"help.solid.pattern.path": "Copies features or bodies along a sketch path, by count and spacing. Use it for holes along a curved edge or parts along a rail.",
"help.solid.pattern.path": "Copia operaciones o cuerpos a lo largo de una trayectoria de boceto, por número y separación. Úsalo para agujeros a lo largo de una arista curva o piezas a lo largo de un carril.",
"help.solid.pattern.rectangular": "Repite los objetos seleccionados en una o dos direcciones con el recuento y el espaciado que indiques. Úsalo para filas y cuadrículas de agujeros, nervios, pasadores o patas.",
"help.solid.pipe": "Creates a round tube along a path of sketch curves, solid or hollow with a wall thickness. Use it for tubes, wires, cables and rails.",
"help.solid.pipe": "Crea un tubo redondo a lo largo de una trayectoria de curvas de boceto, macizo o hueco con un espesor de pared. Úsalo para tubos, cables y carriles.",
"help.solid.press_pull": "Añade o quita material al arrastrar una cara, o redondea aristas al arrastrarlas. Usa",
"help.solid.remove": "Saca los cuerpos seleccionados del diseño desde este punto de la línea de tiempo en adelante;",
"help.solid.replace_face": "Mueve las caras planas seleccionadas sobre un plano o sobre una cara paralela, y el cuerpo",
"help.solid.revolve": "Gira un perfil de boceto alrededor de un eje para crear un sólido de revolución. Úsalo para ejes, pomos, cuencos y cualquier otra pieza de revolución.",
"help.solid.rib": "Adds a thin wall along an open sketch curve, filled out to the next faces of the body. Use it to stiffen walls and corners, for example in moulded or printed parts.",
"help.solid.rib": "Añade una pared fina a lo largo de una curva de boceto abierta, extendida hasta las siguientes caras del cuerpo. Úsalo para reforzar paredes y esquinas, por ejemplo en piezas moldeadas o impresas.",
"help.solid.scale": "Hace los cuerpos seleccionados más grandes o más pequeños por un factor, el mismo en todas las direcciones",
"help.solid.shell": "Vacía un sólido y deja paredes del grosor que indiques; además, puede abrir las caras que elijas. Úsalo para cajas, tapas y otras piezas de paredes finas.",
"help.solid.sphere": "Creates a sphere from a radius or diameter around a centre point. Use it for balls, knobs and rounded ends.",
"help.solid.sphere": "Crea una esfera a partir de un radio o diámetro alrededor de un punto central. Úsalo para bolas, pomos y extremos redondeados.",
"help.solid.split_body": "Corta un cuerpo en cuerpos separados con un plano, la cara de otro cuerpo o un boceto",
"help.solid.split_face": "Divide las caras seleccionadas a lo largo de un plano, la cara de otro cuerpo o una curva de boceto",
"help.solid.sweep": "Arrastra un perfil de boceto a lo largo de una trayectoria para crear un sólido. Úsalo para tubos, raíles, asas y cualquier pieza de sección constante que siga una curva.",
"help.solid.thread": "Adds an ISO metric thread to a cylindrical face, either as a cosmetic thread or cut into the body. Use it for bolts, threaded holes and printed screw parts.",
"help.solid.torus": "Creates a ring from a major radius around its axis and a minor radius for its round section. Use it for O-rings, handles and round beads.",
"help.solid.web": "Adds a thin wall along each open sketch curve, each filled out to the next faces of the body. Use it for a grid of supporting walls inside housings and trays.",
"help.surface.blend": "Creates a surface that bridges the edges of two bodies, tangent or curvature continuous to both. Use it to join two surfaces smoothly across a gap.",
"help.surface.boundary": "Creates a surface filling a loop of two to four sketch curves, or a network of curves. Use it for free-form panels defined by their edges.",
"help.surface.extend": "Lengthens a surface past its edges, by a distance or up to a plane or face. Use it so that surfaces overlap before you trim or stitch them.",
"help.surface.extrude": "Pushes sketch curves or profiles along a distance into a surface, walls only, without caps. Use it for thin walls and for cutting or splitting tools.",
"help.surface.fair": "Smooths the inside of free-form faces while their edges stay put. Use it to even out bumps and wavy reflections in a surface.",
"help.surface.loft": "Creates a surface that passes through two or more sections in order, without caps. Use it for shells and transitions between different shapes.",
"help.surface.match": "Rebuilds the edge of a surface so it meets another body's edge, with matching tangent or curvature. Use it to close a seam smoothly between two surfaces.",
"help.surface.offset": "Creates a copy of faces at a distance along their normals, as a new surface body. Use it for skins, clearances or the other side of a wall.",
"help.surface.patch": "Fills a sketch region or a closed loop of edges with a face, flat or smoothly curved. Use it to close holes in a surface body.",
"help.surface.reverse_normal": "Turns faces of a surface body over, so their outside faces the other way. Use it before thickening or stitching when the faces point inward.",
"help.surface.revolve": "Turns sketch curves or profiles about an axis into a surface, without caps. Use it for round shells such as lampshades, bowls and nozzles.",
"help.surface.ruled": "Creates a strip of straight lines out from a chain of edges, along the face's normal, tangent or at an angle. Use it for draft walls, run-offs and parting surfaces.",
"help.surface.stitch": "Sews surface bodies together along their shared edges, into a solid when they close. Use it to turn a set of surfaces into one body.",
"help.surface.sweep": "Moves sketch curves or profiles along a path into a surface, without caps. Use it for gutters, trims and other thin shapes that follow a path.",
"help.surface.thicken": "Gives a surface body a thickness, turning it into a solid. Use it to make printable or machinable parts from surfaces.",
"help.surface.trim": "Cuts a surface with a plane, another surface or sketch curves, and keeps the side you pick. Use it to cut surfaces to shape before stitching.",
"help.surface.unstitch": "Separates faces of a body into surface bodies of their own; a solid comes apart into surfaces. Use it to rework single faces of a body.",
"help.surface.untrim": "Removes holes from a face, or restores its outer boundary to the surface's natural bounds. Use it to get back the full surface after a trim.",
"help.solid.thread": "Añade una rosca métrica ISO a una cara cilíndrica, como rosca cosmética o tallada en el cuerpo. Úsalo para pernos, agujeros roscados y piezas impresas con rosca.",
"help.solid.torus": "Crea un anillo a partir de un radio mayor alrededor de su eje y un radio menor para su sección redonda. Úsalo para juntas tóricas, asas y cuentas redondas.",
"help.solid.web": "Añade una pared fina a lo largo de cada curva de boceto abierta, cada una extendida hasta las siguientes caras del cuerpo. Úsalo para una rejilla de paredes de apoyo dentro de carcasas y bandejas.",
"help.surface.blend": "Crea una superficie que une las aristas de dos cuerpos, tangente o de curvatura continua con ambos. Úsalo para unir suavemente dos superficies a través de un hueco.",
"help.surface.boundary": "Crea una superficie que rellena un lazo de dos a cuatro curvas de boceto, o una red de curvas. Úsalo para paneles de forma libre definidos por sus bordes.",
"help.surface.extend": "Alarga una superficie más allá de sus bordes, una distancia o hasta un plano o una cara. Úsalo para que las superficies se solapen antes de recortarlas o coserlas.",
"help.surface.extrude": "Empuja curvas o perfiles de boceto una distancia para crear una superficie, solo paredes, sin tapas. Úsalo para paredes finas y para herramientas de corte o división.",
"help.surface.fair": "Suaviza el interior de caras de forma libre mientras sus bordes se quedan donde están. Úsalo para igualar bultos y reflejos ondulados en una superficie.",
"help.surface.loft": "Crea una superficie que pasa por dos o más secciones en orden, sin tapas. Úsalo para cascarones y transiciones entre formas distintas.",
"help.surface.match": "Reconstruye el borde de una superficie para que encuentre el borde de otro cuerpo, con tangencia o curvatura coincidentes. Úsalo para cerrar suavemente una unión entre dos superficies.",
"help.surface.offset": "Crea una copia de caras a una distancia a lo largo de sus normales, como un nuevo cuerpo de superficie. Úsalo para pieles, holguras o el otro lado de una pared.",
"help.surface.patch": "Rellena una región de boceto o un lazo cerrado de aristas con una cara, plana o suavemente curva. Úsalo para cerrar agujeros en un cuerpo de superficie.",
"help.surface.reverse_normal": "Da la vuelta a caras de un cuerpo de superficie, de modo que su exterior mire al otro lado. Úsalo antes de engrosar o coser cuando las caras apuntan hacia dentro.",
"help.surface.revolve": "Gira curvas o perfiles de boceto alrededor de un eje para crear una superficie, sin tapas. Úsalo para cascarones redondos como pantallas de lámpara, cuencos y toberas.",
"help.surface.ruled": "Crea una tira de líneas rectas a partir de una cadena de aristas, a lo largo de la normal de la cara, tangente o en ángulo. Úsalo para paredes con desmoldeo, salidas y superficies de partición.",
"help.surface.stitch": "Cose cuerpos de superficie a lo largo de sus aristas compartidas, en un sólido cuando se cierran. Úsalo para convertir un conjunto de superficies en un solo cuerpo.",
"help.surface.sweep": "Mueve curvas o perfiles de boceto a lo largo de una trayectoria para crear una superficie, sin tapas. Úsalo para canalones, molduras y otras formas finas que siguen una trayectoria.",
"help.surface.thicken": "Da espesor a un cuerpo de superficie y lo convierte en sólido. Úsalo para obtener piezas imprimibles o mecanizables a partir de superficies.",
"help.surface.trim": "Corta una superficie con un plano, otra superficie o curvas de boceto, y conserva el lado que elijas. Úsalo para dar forma a las superficies antes de coserlas.",
"help.surface.unstitch": "Separa caras de un cuerpo en cuerpos de superficie propios; un sólido se descompone en superficies. Úsalo para retocar caras sueltas de un cuerpo.",
"help.surface.untrim": "Quita agujeros de una cara, o restaura su contorno exterior a los límites naturales de la superficie. Úsalo para recuperar la superficie completa tras un recorte.",
"help.third_party": "Licencias de terceros",
"help.timeline.compute_all": "Reconstruye cada operación de la línea de tiempo desde el inicio. Úsalo para refrescar el modelo",
"help.timeline.delete": "Elimina las operaciones seleccionadas de la línea de tiempo; borrar un boceto también elimina",
"help.timeline.dependents": "Lists the features that would be deleted with a feature, and those that would fail without it. Use it before deleting or changing a feature.",
"help.timeline.dependents": "Lista las operaciones que se borrarían junto con una operación, y las que fallarían sin ella. Úsalo antes de borrar o cambiar una operación.",
"help.timeline.play": "Reproduce las operaciones restantes una a una, con una pausa de medio segundo tras cada una",
"help.version": "Version {version}",
"help.view.apply": "Turns the view to a standard direction such as front, top or iso, or to a saved named view. Use it to look at the model from a fixed angle.",
"help.view.delete": "Deletes a saved named view. The model is not changed.",
"help.view.fit": "Zooms and pans so the whole model, or the selection, fills the view. Use it when the model has gone out of sight.",
"help.view.grid": "Shows or hides the grid in the viewport. Use it as a size and orientation guide while modelling.",
"help.view.ground_shadow": "Shows or hides the model's shadow on the ground. Use it to judge height and position more easily.",
"help.view.home": "Turns the view back to the home direction and fits the model. Use it to get back to a known view quickly.",
"help.view.list": "Lists the named views saved in the design. Use it to find a view you saved earlier.",
"help.view.navigate": "Turns, pans or zooms the view by steps, such as a quarter turn left. Use it to move the camera precisely instead of dragging.",
"help.view.navigation_bar": "Shows or hides the navigation bar at the bottom of the viewport. Hide it for more room, show it to reach the view tools by mouse.",
"help.view.rename": "Gives a saved named view a new name. The view itself stays the same.",
"help.version": "Versión {version}",
"help.view.apply": "Gira la vista a una dirección estándar como frontal, superior o isométrica, o a una vista con nombre guardada. Úsalo para mirar el modelo desde un ángulo fijo.",
"help.view.delete": "Borra una vista con nombre guardada. El modelo no cambia.",
"help.view.fit": "Acerca y desplaza para que todo el modelo, o la selección, llene la vista. Úsalo cuando el modelo se ha salido de la vista.",
"help.view.grid": "Muestra u oculta la cuadrícula en la vista. Úsala como guía de tamaño y orientación al modelar.",
"help.view.ground_shadow": "Muestra u oculta la sombra del modelo en el suelo. Úsalo para juzgar con más facilidad la altura y la posición.",
"help.view.home": "Devuelve la vista a la dirección de inicio y encuadra el modelo. Úsalo para volver rápido a una vista conocida.",
"help.view.list": "Lista las vistas con nombre guardadas en el diseño. Úsalo para encontrar una vista que guardaste antes.",
"help.view.navigate": "Gira, desplaza o acerca la vista por pasos, como un cuarto de vuelta a la izquierda. Úsalo para mover la cámara con precisión en lugar de arrastrar.",
"help.view.navigation_bar": "Muestra u oculta la barra de navegación en la parte inferior de la vista. Ocúltala para tener más espacio, muéstrala para llegar a las herramientas de vista con el ratón.",
"help.view.rename": "Da un nombre nuevo a una vista con nombre guardada. La vista en sí no cambia.",
"help.view.ribbon_tabs_only": "Pliega la cinta hasta su fila de pestañas para que la vista recupere el espacio de los paneles. Haz clic en una pestaña para mostrar sus paneles sobre la vista; vuelve a elegir esta opción para mantener toda la cinta visible.",
"help.view.save": "Saves the current camera position as a named view in the design. Use it to come back to the same angle later, for example for screenshots.",
"help.view.spin": "Orbits the view around the model continuously until the next click or key. Use it to present a model from all sides.",
"help.view.tool": "Latches a camera tool, orbit, pan or zoom, so that dragging with the left mouse button moves the view until you switch it off. Use it on a trackpad or without a middle mouse button.",
"help.view.visual_style": "Switches how the model is drawn: shaded with or without edges, wireframe, or with hidden edges. Use wireframe to see inside, shaded for a clean look.",
"help.view.save": "Guarda la posición actual de la cámara como una vista con nombre en el diseño. Úsalo para volver al mismo ángulo más tarde, por ejemplo para capturas de pantalla.",
"help.view.spin": "Hace orbitar la vista alrededor del modelo de forma continua hasta el siguiente clic o tecla. Úsalo para presentar un modelo por todos sus lados.",
"help.view.tool": "Fija una herramienta de cámara, órbita, desplazamiento o zoom, de modo que arrastrar con el botón izquierdo del ratón mueva la vista hasta que la desactives. Úsalo en un trackpad o sin botón central del ratón.",
"help.view.visual_style": "Cambia cómo se dibuja el modelo: sombreado con o sin aristas, estructura alámbrica o con aristas ocultas. Usa la estructura alámbrica para ver el interior y el sombreado para un aspecto limpio.",
"history.sketch_under_constrained": "Bajo restricción ({count} grados de libertad)",
"history.sketch_under_constrained_one": "Bajo restricción ({count} grado de libertad)",
"hole_folder.applies_to": "Los cambios se aplican a los {count} agujeros de {folder}; cada uno conserva su posición.",
@@ -2682,6 +2683,9 @@
"prefs.interface_note": "Cómo se ve SolidCraft y dónde se sitúan sus partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertir las flechas de giro curvo",
"prefs.invert_curved_roll_arrows_note": "Las dos flechas curvas en la esquina del cubo giran la vista en el plano de la pantalla. Activado: la flecha horaria gira antihoraria y la antihoraria gira horaria. Desactivado: cada flecha gira la vista hacia donde se curva.",
"prefs.invert_navigator_arrows": "Invertir las flechas de rotación del cubo de vista",
"prefs.invert_navigator_arrows_note": "Las flechas alrededor del cubo orbitan la cámara hacia donde apuntan, como en Fusion e Inventor: la flecha de la izquierda apunta a la derecha y gira la cámara a la derecha. Desactivado: una flecha rota el cubo hacia el lado en que está, así la flecha izquierda gira la cámara a la izquierda. Las flechas de giro curvo no se ven afectadas.",
"prefs.keep_unsaved_also_asks": "Preguntar igualmente al cerrar la pestaña",
"prefs.keep_unsaved_also_asks_tip": "Con esto desactivado, la pestaña se cierra sin el cuadro del navegador en cuanto la copia de cada diseño sin guardar está al día.",
"prefs.keep_unsaved_in_browser": "Conservar el trabajo sin guardar en este navegador",
@@ -2741,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Desactivado: mientras las flechas de Mover arrastran un componente no se resalta nada bajo el puntero, y los ensamblajes grandes se mueven con fluidez. Con un corte o un análisis visible se resalta igualmente, y una pieza arrastrada a lo largo de sus uniones nunca lo resalta.",
"prefs.navigation": "Navegación",
"prefs.navigation.axes_signed": "Ejes",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Libre",
"prefs.navigation.orbit_style": "Estilo de órbita",
@@ -2748,6 +2753,7 @@
"prefs.navigation.turntable": "Plato giratorio",
"prefs.navigation_note": "Cómo mueven la vista el ratón, el panel táctil y el ratón 3D.",
"prefs.navigator_fit": "Ajustar el modelo tras un cambio de vista del navegador",
"prefs.navigator_fit_note": "Una cara, esquina o flecha del cubo de vista, o un eje del gizmo, también mira el centro del modelo desde la única distancia que lo encaja desde todos los lados (su esfera envolvente). Inicio usa el mismo zoom y centro mientras esto está activado, así que las vistas elegidas después solo giran. Desactivado: la vista gira en su lugar, manteniendo su objetivo y zoom.",
"prefs.network_host_remove": "Eliminar",
"prefs.network_locations": "Permitir ubicaciones de red en diseños",
"prefs.network_locations_note": "Desactivado: los archivos vinculados de un diseño en otro equipo (\\\\servidor\\\\carpeta) solo se abren desde los servidores listados aquí, o tras permitir uno cuando se pregunte.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Luo ilmoitus…",
"Cross curves": "Poikkikäyrät",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter jatkaa GitHubissa.",
"Cube": "Kuutio",
"Current orthographic view (1:1 mm)": "Nykyinen ortografinen näkymä (1:1 mm)",
"Current perspective view": "Nykyinen perspektiivinäkymä",
"Current plane": "Nykyinen taso",
@@ -2680,6 +2681,9 @@
"prefs.interface_note": "Miltä SolidCraft näyttää ja missä sen osat sijaitsevat.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Käännä kaarevat kallistusnuolet",
"prefs.invert_curved_roll_arrows_note": "Kuution kulman kaksi kaarevaa nuolta kallistavat näkymää näytön tasossa. Päällä: myötäpäivään osoittava nuoli kallistaa vastapäivään ja vastapäivään osoittava myötäpäivään. Pois: kumpikin nuoli kallistaa näkymää kaartumissuuntaansa.",
"prefs.invert_navigator_arrows": "Käännä näkymäkuution kiertonuolet",
"prefs.invert_navigator_arrows_note": "Kuution ympärillä olevat nuolet kiertävät kameraa osoittamaansa suuntaan kuten Fusionissa ja Inventorissa: vasemmalla oleva nuoli osoittaa oikealle ja kääntää kameraa oikealle. Pois: nuoli kiertää kuutiota omaa puoltaan kohti, joten vasen nuoli kääntää kameraa vasemmalle. Kaarevat kallistusnuolet eivät muutu.",
"prefs.keep_unsaved_also_asks": "Kysy silti, kun välilehti suljetaan",
"prefs.keep_unsaved_also_asks_tip": "Kun tämä on pois päältä, välilehti sulkeutuu ilman selaimen kyselyikkunaa, kun jokaisen tallentamattoman mallin kopio on ajan tasalla.",
"prefs.keep_unsaved_in_browser": "Säilytä tallentamaton työ tässä selaimessa",
@@ -2739,6 +2743,7 @@
"prefs.move_drag_highlights_tip": "Pois: kun Siirrä-toiminnon nuolilla vedetään komponenttia, osoittimen alla olevaa kohdetta ei korosteta, mikä pitää suuret kokoonpanot sulavina. Kun leikkaus tai analyysi on näkyvissä, kohde korostetaan silti, eikä niveliään pitkin vedetty osa koskaan korosta sitä.",
"prefs.navigation": "Navigointi",
"prefs.navigation.axes_signed": "Akselit",
"prefs.navigation.cube_compact": "Kuutio",
"prefs.navigation.device": "Laite",
"prefs.navigation.free": "Vapaa",
"prefs.navigation.orbit_style": "Kiertotapa",
@@ -2746,6 +2751,7 @@
"prefs.navigation.turntable": "Pyörivä alusta",
"prefs.navigation_note": "Miten hiiri, kosketuslevy ja 3D-hiiri liikuttavat näkymää.",
"prefs.navigator_fit": "Sovita malli navigaattorin näkymänvaihdon jälkeen",
"prefs.navigator_fit_note": "Näkymäkuution pinta, kulma tai nuoli tai gizmon akseli katsoo myös mallin keskikohtaa siltä yhdeltä etäisyydeltä, joka sovittaa sen joka suunnasta (sen rajaava pallo). Aloitusnäkymä käyttää samaa zoomausta ja keskipistettä, kun tämä on päällä, joten sen jälkeen valitut näkymät vain kääntyvät. Pois: näkymä kääntyy paikallaan säilyttäen kohteensa ja zoomauksensa.",
"prefs.network_host_remove": "Poista",
"prefs.network_locations": "Salli verkkosijainnit malleissa",
"prefs.network_locations_note": "Pois: mallin linkitetyt tiedostot toisella tietokoneella (\\\\server\\share) avataan vain tässä luetelluilta palvelimilta tai sen jälkeen, kun sallit palvelimen kysyttäessä.",
+375 -66
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Créer un ticket…",
"Cross curves": "Courbes transversales",
"Ctrl+Enter continues on GitHub.": "Ctrl+Entrée continue sur GitHub.",
"Cube": "Cube",
"Current orthographic view (1:1 mm)": "Vue orthographique actuelle (1:1 mm)",
"Current perspective view": "Vue en perspective actuelle",
"Current plane": "Plan actuel",
@@ -476,6 +477,7 @@
"Rectangular": "Rectangulaire",
"Rectangular Tube": "Tube rectangulaire",
"Reference face": "Face de référence",
"Reference plane": "Plan de référence",
"Relief Depth": "Profondeur de dégagement",
"Relief Width": "Largeur de dégagement",
"Remove Tools": "Retirer les outils",
@@ -494,6 +496,7 @@
"Render Stage": "Plateau de rendu",
"Reopen designs": "Rouvrir les conceptions",
"Reopen the designs that were open when SolidCraft was last closed": "Rouvrir les conceptions ouvertes lors de la dernière fermeture de SolidCraft",
"Repair Part": "Réparer la pièce",
"Replace existing library file": "Remplacer le fichier de bibliothèque existant",
"Report a bug — review a screenshot and open a GitHub draft": "Signaler un bug — relire une capture d'écran et ouvrir un brouillon GitHub",
"Report copied. Keep this text to submit on GitHub when you are online.": "Rapport copié. Conservez ce texte pour le soumettre sur GitHub une fois en ligne.",
@@ -789,18 +792,19 @@
"browser.edit_canvas_title": "Modifier la toile : {name}",
"browser.edit_point_cloud_title": "Modifier le nuage de points : {name}",
"browser.move_title": "Déplacer : {name}",
"browser.needs_repair": "{name} : nécessite une réparation",
"browser.parameters": "Paramètres ({count})",
"browser.precision": "Précision : {precision}",
"browser.sketch_attachment_lost": "{name} (attache perdue)",
"browser.sketch_editing": "{name} (en cours de modification)",
"browser.sketch_name": "Esquisse{number}",
"browser.sketches_to_parts_already_in_part": "déjà dans leur pièce",
"browser.sketches_to_parts_design_body": "sur un corps de la conception elle-même",
"browser.sketches_to_parts_moved": "{moved} esquisses déplacées vers la pièce sur laquelle elles se trouvent",
"browser.sketches_to_parts_no_exact_attachment": "sur une face sans rattachement exact",
"browser.sketches_to_parts_not_on_face": "pas sur la face d'une pièce",
"browser.sketches_to_parts_design_body": "sur un corps appartenant directement à la conception",
"browser.sketches_to_parts_moved": "{moved} esquisses déplacées dans la pièce à laquelle elles appartiennent",
"browser.sketches_to_parts_no_exact_attachment": "sur une face sans liaison exacte",
"browser.sketches_to_parts_not_on_face": "pas sur une face de pièce",
"browser.sketches_to_parts_part_missing": "leur pièce n'existe plus",
"browser.sketches_to_parts_result": "{moved} esquisses déplacées vers la pièce sur laquelle elles se trouvent ; {stayed} sont restées en place : {why}",
"browser.sketches_to_parts_result": "{moved} esquisses déplacées dans leur pièce ; {stayed} conservées à leur emplacement : {why}",
"browser.units": "Unités : {units}",
"cam.flat": "Plateau",
"cam.follower": "Suiveur",
@@ -833,6 +837,7 @@
"cmd.assembly_mass_properties": "Propriétés de masse",
"cmd.body.print_face": "Face d’impression",
"cmd.body_rename": "Renommer le corps",
"cmd.body_repair": "Réparer la pièce",
"cmd.browser_collapse_all": "Tout réduire",
"cmd.browser_expand_all": "Tout développer",
"cmd.browser_group": "Nouveau groupe",
@@ -869,7 +874,7 @@
"cmd.component_move_bodies": "Déplacer les corps vers le composant",
"cmd.component_move_features": "Déplacer les fonctions vers le composant",
"cmd.component_move_sketches": "Déplacer les esquisses vers le composant",
"cmd.component_move_sketches_to_parts": "Déplacer les esquisses vers leurs pièces",
"cmd.component_move_sketches_to_parts": "Déplacer les esquisses dans leurs pièces",
"cmd.component_paste_from_design": "Coller depuis une autre conception",
"cmd.component_paste_new": "Coller comme nouveau",
"cmd.component_properties": "Propriétés physiques du composant",
@@ -917,6 +922,8 @@
"cmd.diagnostics_crash_reports": "Rapports de plantage",
"cmd.diagnostics_crash_reports_clear": "Supprimer les rapports de plantage",
"cmd.diagnostics_crash_test": "Test de plantage",
"cmd.diagnostics_profile": "Profil",
"cmd.diagnostics_validation": "Validation",
"cmd.doc_recover": "Récupérer la conception",
"cmd.doc_recovery_discard": "Abandonner la conception récupérée",
"cmd.doc_recovery_list": "Conceptions récupérables",
@@ -937,11 +944,11 @@
"cmd.explode_show": "Afficher la vue éclatée",
"cmd.expr_evaluate": "Évaluer une expression",
"cmd.face_delete": "Supprimer la face",
"cmd.file.export_3mf": "Exporter en 3MF",
"cmd.file.export_obj": "Exporter en OBJ",
"cmd.file.export_step": "Exporter en STEP",
"cmd.file.export_stl": "Exporter en STL",
"cmd.file.export_urdf": "Exporter en URDF",
"cmd.file.export_3mf": "Exporter au format 3MF",
"cmd.file.export_obj": "Exporter au format OBJ",
"cmd.file.export_step": "Exporter au format STEP",
"cmd.file.export_stl": "Exporter au format STL",
"cmd.file.export_urdf": "Exporter au format URDF",
"cmd.file_export": "Exporter",
"cmd.file_insert_mesh": "Insérer un maillage",
"cmd.file_insert_step": "Insérer un STEP",
@@ -954,6 +961,7 @@
"cmd.frame_profile_list": "Bibliothèque de profilés",
"cmd.frame_profile_properties": "Propriétés du profilé",
"cmd.inspect_accessibility": "Analyse d'accessibilité",
"cmd.inspect_analysis": "Afficher l'analyse",
"cmd.inspect_center_of_mass": "Centre de gravité",
"cmd.inspect_clearance": "Jeu",
"cmd.inspect_compare": "Comparer les corps",
@@ -975,6 +983,7 @@
"cmd.joint_delete": "Supprimer la liaison",
"cmd.joint_drive": "Piloter les liaisons",
"cmd.joint_edit": "Modifier la liaison",
"cmd.joint_find_limits": "Rechercher les limites de la liaison",
"cmd.joint_gear": "Engrenage",
"cmd.joint_inspect": "Inspecter la liaison",
"cmd.joint_limits": "Limites de liaison",
@@ -987,6 +996,11 @@
"cmd.joint_screw": "Vis",
"cmd.joint_solve": "Résoudre les liaisons",
"cmd.joint_sweep": "Balayer une liaison",
"cmd.layout.apply": "Appliquer la disposition",
"cmd.layout.get": "Inspecter la disposition",
"cmd.layout.reset": "Réinitialiser la disposition",
"cmd.layout.save": "Enregistrer la disposition",
"cmd.layout.workspace.select": "Sélectionner l'espace de travail de la disposition",
"cmd.library_apply": "Appliquer une entrée de la bibliothèque locale",
"cmd.library_export": "Exporter la bibliothèque de la conception",
"cmd.library_inspect": "Inspecter la bibliothèque locale",
@@ -1021,6 +1035,21 @@
"cmd.occurrence_move": "Déplacer l'occurrence",
"cmd.occurrence_properties": "Propriétés physiques de l'occurrence",
"cmd.occurrence_reparent": "Déplacer vers le composant",
"cmd.panel.activate": "Activer l'onglet de panneau",
"cmd.panel.close": "Fermer le panneau",
"cmd.panel.collapse": "Réduire la section de panneau",
"cmd.panel.dismiss": "Fermer l'aperçu du panneau",
"cmd.panel.float": "Rendre le panneau flottant",
"cmd.panel.focus": "Mettre le panneau au premier plan",
"cmd.panel.list": "Lister les panneaux",
"cmd.panel.move": "Déplacer le panneau",
"cmd.panel.native_close": "Réancrer la section de panneau natif",
"cmd.panel.open": "Ouvrir le panneau",
"cmd.panel.peek": "Aperçu d'un panneau réduit",
"cmd.panel.popout": "Détacher le panneau",
"cmd.panel.reset_pair": "Réinitialiser le séparateur de panneaux",
"cmd.panel.resize": "Redimensionner la section de panneau",
"cmd.panel.resize_pair": "Redimensionner le séparateur de panneaux",
"cmd.parameters_add": "Ajouter un paramètre utilisateur",
"cmd.parameters_change": "Modifier les paramètres",
"cmd.parameters_comment": "Commenter le paramètre",
@@ -1051,8 +1080,8 @@
"cmd.pointcloud_list": "Nuages de points",
"cmd.pointcloud_reload": "Recharger le nuage de points",
"cmd.render.compare.divider": "Déplacer le séparateur de comparaison des rendus",
"cmd.render.result.discard": "Écarter le résultat de rendu",
"cmd.render.result.select": "Sélectionner le résultat de rendu",
"cmd.render.result.discard": "Ignorer le résultat du rendu",
"cmd.render.result.select": "Sélectionner le résultat du rendu",
"cmd.render_aging_describe": "Vieillissement de surface en couches",
"cmd.render_backends": "Moteurs de rendu",
"cmd.render_batch": "Rendre toutes les prises de vue",
@@ -1269,7 +1298,7 @@
"cmd.timeline_rollback": "Déplacer le marqueur de chronologie",
"cmd.timeline_stop": "Arrêter l'historique",
"cmd.timeline_suppress": "Désactiver la fonction",
"cmd.ui.assistant": "Afficher/masquer l'assistant",
"cmd.ui.assistant": "Afficher ou masquer l'assistant",
"cmd.view.render_browser": "Navigateur de rendu",
"cmd.view.render_dock": "Déplacer le panneau de rendu",
"cmd.view.render_focus": "Vue de rendu ciblée",
@@ -1324,8 +1353,8 @@
"color.step_up": "Augmenter d'un pas",
"color.value": "Valeur, la luminosité (pour cent)",
"config.column_filter_empty": "Aucune colonne correspondante",
"config.rule_parameter_columns": "Seuls les paramètres ayant une colonne dans la table sont listés. Ajouter une colonne avec Ajouter une colonne (+) pour l'utiliser ici.",
"config.rule_suppression_columns": "Seules les fonctions ayant une colonne Désactiver dans la table sont listées. Ajouter une colonne avec Ajouter une colonne (+) pour la piloter ici.",
"config.rule_parameter_columns": "Seuls les paramètres disposant d'une colonne dans le tableau sont répertoriés. Ajoutez une colonne avec Ajouter une colonne (+) pour utiliser un paramètre ici.",
"config.rule_suppression_columns": "Seules les fonctions disposant d'une colonne Supprimer dans le tableau sont répertoriées. Ajoutez une colonne avec Ajouter une colonne (+) pour les piloter ici.",
"contact.components_count": "{count} composants",
"contact.enabled_label": "activé",
"coupling.gear_1": "Engrenage 1",
@@ -1360,6 +1389,7 @@
"crash.unclean_explanation": "Détecté lors d’un lancement ultérieur ; l’heure exacte de la sortie n’a pas été enregistrée. Un arrêt du système ou une interruption forcée peut aussi provoquer une sortie anormale.",
"delete.and_more": "… et {count} de plus",
"diagnostic.empty_boolean_component": "il n'y a aucun corps à couper ou à intersecter dans le composant « {component} » ; l'outil chevauche peut-être « {body} » dans le composant « {other} » : activez ce composant ou choisissez ce corps comme cible",
"diagnostic.reselect_reference": "{feature} : la référence `{reference}` n'existe plus à l'emplacement où elle avait été sélectionnée ; sélectionnez-la à nouveau",
"dialog.bodies_count": "{count} corps",
"dialog.clearance_invalid": "le jeu doit être une longueur positive ou nulle",
"dialog.compute": "Calculer",
@@ -1380,7 +1410,7 @@
"dialog.selection_constraint": "Contrainte {id}",
"dialog.selection_external_curve": "{sketch} · courbe {id}",
"dialog.selection_guidance": "Sélectionner une entrée pour la modifier. Cliquer sur un objet sélectionné pour le retirer ; Ctrl/Cmd-clic le bascule aussi. Vérifier l'aperçu, puis appuyer sur OK.",
"dialog.selection_midpoint": "Point milieu · {id}",
"dialog.selection_midpoint": "Milieu · {id}",
"dialog.selection_profile": "{sketch} · profil {number}",
"dialog.selection_step": "{step} sur {total} : sélectionner {input}",
"dialog.step": "Étape",
@@ -1430,6 +1460,14 @@
"file_load.rebuilding": "Reconstruction de l’entité {done} sur {total}",
"file_load.recovering": "Récupération de la conception",
"file_load.reloading_cloud": "Rechargement du nuage de points",
"file_load.step_build": "Construction du modèle",
"file_load.step_feature": "Fonction {done} sur {total}",
"file_load.step_part": "Pièce {done} sur {total}",
"file_load.step_percent": "{percent} %",
"file_load.step_read": "Lecture du fichier",
"file_load.step_rebuild": "Reconstruction des fonctions",
"file_load.step_repair": "Vérification et réparation des pièces",
"file_load.step_show": "Préparation de la vue",
"file_load.stopping": "Attente de l’arrêt de l’opération précédente...",
"file_load.updating_links": "Mise à jour des liens",
"file_load.waiting": "En attente d’une opération sur fichier",
@@ -1466,7 +1504,7 @@
"help.construct.axis.two_points": "Crée un axe de construction passant par deux points, sommets ou points d'esquisse. À utiliser pour un axe qui relie deux positions connues.",
"help.construct.plane.along_path": "Crée un plan de construction perpendiculaire à une arête ou une courbe, à une position choisie le long de celle-ci. À utiliser pour esquisser le profil d'un balayage ou une coupe d'une trajectoire.",
"help.construct.plane.at_angle": "Crée un plan de construction tourné d'un angle par rapport à un plan ou une face, autour d'un axe ou d'une arête. À utiliser pour des esquisses inclinées, par exemple une équerre à angle.",
"help.construct.plane.axis_point": "Crée un plan de construction contenant un axe et un point situé hors de cet axe. Sélectionner une origine ou un axe de construction, une arête rectiligne ou une ligne d'esquisse, puis un sommet, un point d'esquisse ou un point de construction. Un point situé sur l'axe ne définit pas un plan unique.",
"help.construct.plane.axis_point": "Crée un plan de construction contenant un axe et un point situé hors de cet axe. Sélectionnez une origine ou un axe de construction, une arête droite ou une ligne d'esquisse, puis un sommet, un point d'esquisse ou un point de construction. Un point situé sur l'axe ne permet pas de définir un plan unique.",
"help.construct.plane.midplane": "Crée un plan de construction à mi-distance entre deux plans ou faces planes, ou bissecteur lorsqu'ils se rencontrent en formant un angle. À utiliser comme plan de symétrie.",
"help.construct.plane.offset": "Crée un plan de construction parallèle à un plan ou une face plane, à une distance donnée ou passant par un point. À utiliser pour esquisser à une hauteur précise au-dessus d'une face.",
"help.construct.plane.perpendicular": "Crée un plan de construction qui contient une droite ou une arête et qui est perpendiculaire à un plan ou une face. À utiliser pour esquisser à la verticale sur un modèle, le long d'une arête.",
@@ -1526,6 +1564,11 @@
"help.joint.reach": "Déplace un point d'une pièce vers une cible en modifiant les liaisons de sa chaîne, dans leurs limites. À utiliser pour positionner un mécanisme selon l'endroit où doit se trouver son extrémité, comme le bout d'un bras de robot.",
"help.joint.rigid_group": "Verrouille ensemble les pièces sélectionnées telles qu'elles sont, pour qu'elles se déplacent d'un seul bloc. À utiliser pour des pièces qui vont ensemble et qui n'ont aucun mouvement entre elles.",
"help.joint.screw": "Couple rotation et translation par un pas, de sorte que chaque tour avance de cette distance. À utiliser pour des vis mères, des boulons et des broches filetées.",
"help.layout.apply": "Applique une disposition enregistrée à l'espace de travail actuel. Les éditeurs conservés gardent leurs brouillons.",
"help.layout.get": "Lit la disposition validée et recense les espaces de travail enregistrés.",
"help.layout.reset": "Rétablit la disposition par défaut enregistrée pour l'espace de travail actuel. Les préréglages de l'utilisateur restent disponibles.",
"help.layout.save": "Enregistre la disposition complète sous un nom. Remplacer un préréglage de l'utilisateur nécessite une autorisation explicite d'écrasement.",
"help.layout.workspace.select": "Sélectionne un espace de travail de disposition enregistré et mémorise la disposition quittée.",
"help.library.apply": "Applique un matériau ou une apparence d'un fichier de bibliothèque local à des corps, des faces ou des composants. À utiliser pour réutiliser des matériaux enregistrés depuis une autre conception.",
"help.library.export": "Enregistre les matériaux et apparences de la conception dans un fichier de bibliothèque. À utiliser pour les partager ou les réutiliser dans d'autres conceptions.",
"help.library.inspect": "Vérifie un fichier de bibliothèque et liste ses matériaux et apparences, sans modifier la conception. À utiliser pour voir ce que contient une bibliothèque avant de l'appliquer.",
@@ -1539,6 +1582,21 @@
"help.notice": "NOTICE",
"help.occurrence.ground": "Fixe une pièce en place, ou la libère, de sorte que les liaisons déplacent les autres pièces autour d'elle. À utiliser pour le châssis ou la base sur laquelle le reste de l'assemblage est construit.",
"help.occurrence.move": "Déplace une pièce d’assemblage selon les seules libertés permises par ses liaisons. Sélectionnez une face de la pièce, puis faites glisser une flèche ou un arc disponible.",
"help.panel.activate": "Sélectionne un onglet de panneau ouvert sans demander le focus clavier.",
"help.panel.close": "Ferme un panneau via la protection du cycle de vie de son contenu. Son emplacement est mémorisé.",
"help.panel.collapse": "Réduit ou développe une section de panneau en conservant les dimensions demandées.",
"help.panel.dismiss": "Ferme l'affichage temporaire d'un panneau réduit.",
"help.panel.float": "Déplace un panneau dans une section flottante positionnée explicitement.",
"help.panel.focus": "Donne le focus à un panneau, en rouvrant son état conservé et en développant sa section si nécessaire.",
"help.panel.list": "Lit les types de panneaux enregistrés, les instances validées, les onglets actifs, la disponibilité et les capacités de l'hôte.",
"help.panel.move": "Déplace un panneau dans une nouvelle section ou le rattache à un groupe d'onglets existant.",
"help.panel.native_close": "Replace une section de panneau natif dans son ancrage mémorisé sans annuler son contenu.",
"help.panel.open": "Ouvre un type de panneau avec une identité d'instance explicite et un emplacement pour une nouvelle instance.",
"help.panel.peek": "Affiche temporairement un panneau réduit sans modifier sa taille enregistrée ni son état réduit.",
"help.panel.popout": "Déplace un panneau vers un hôte natif lorsque c'est pris en charge. Les hôtes de navigateur utilisent une section flottante.",
"help.panel.reset_pair": "Rétablit le rapport de taille par défaut d'une paire de panneaux ancrés adjacents dans leurs limites communes.",
"help.panel.resize": "Définit la largeur et la hauteur extérieures d'une section de panneau dans les limites de chaque onglet.",
"help.panel.resize_pair": "Redimensionne ensemble des sections ancrées adjacentes en conservant leur étendue commune.",
"help.parameters.change": "Ouvre le tableau des valeurs nommées et des expressions qui pilotent les cotes de la conception. À utiliser pour changer une dimension à un seul endroit et faire suivre toutes les fonctions qui l'utilisent.",
"help.parameters.export": "Enregistre les paramètres de la conception en CSV ou JSON. À utiliser pour les modifier dans un tableur ou les transférer vers une autre conception.",
"help.parameters.graph": "Montre quels paramètres et fonctions en utilisent quels autres, ainsi que les boucles ou erreurs entre eux. À utiliser pour voir ce que la modification d'un paramètre va affecter.",
@@ -1725,6 +1783,7 @@
"help.timeline.delete": "Supprime les fonctions sélectionnées de la chronologie ; supprimer une esquisse supprime aussi les fonctions construites à partir d'elle. À utiliser pour retirer une étape devenue inutile.",
"help.timeline.dependents": "Liste les fonctions qui seraient supprimées avec une fonction, et celles qui échoueraient sans elle. À utiliser avant de supprimer ou de modifier une fonction.",
"help.timeline.play": "Rejoue les fonctions restantes une par une, avec une pause d'une demi-seconde après chaque reconstruction. Relancez cette commande ou appuyez sur Échap pour arrêter ; Aller à la fin saute immédiatement.",
"help.version": "Version {version}",
"help.view.apply": "Oriente la vue selon une direction standard comme face, dessus ou iso, ou selon une vue nommée enregistrée. À utiliser pour regarder le modèle sous un angle fixe.",
"help.view.delete": "Supprime une vue nommée enregistrée. Le modèle n'est pas modifié.",
"help.view.fit": "Zoome et déplace la vue pour que tout le modèle, ou la sélection, remplisse la vue. À utiliser lorsque le modèle est sorti du champ.",
@@ -1812,6 +1871,27 @@
"home.start_hint": "Créez une conception, ouvrez un fichier récent ou explorez un exemple.",
"home.whats_new": "Nouveautés",
"home.yesterday": "Hier",
"import_report.details": "Détails :",
"import_report.file_one": "Un autre problème a été détecté dans le fichier.",
"import_report.file_other": "{count} autres problèmes ont été détectés dans le fichier.",
"import_report.hint": "Réexporter ces pièces depuis le logiciel d'origine peut résoudre le problème. La commande Copier le message d'avertissement fournit les détails.",
"import_report.left_out_one": "Une face n'a pas pu être réparée et est manquante.",
"import_report.left_out_other": "{count} faces n'ont pas pu être réparées et sont manquantes.",
"import_report.needs_repair_one": "Une pièce doit être réparée avant de pouvoir servir à la création de nouvelles fonctions.",
"import_report.needs_repair_other": "{count} pièces doivent être réparées avant de pouvoir servir à la création de nouvelles fonctions.",
"import_report.not_imported_one": "Une pièce n'a pas pu être importée.",
"import_report.not_imported_other": "{count} pièces n'ont pas pu être importées.",
"import_report.not_shown_one": "Une face n'a pas pu être affichée et est masquée.",
"import_report.not_shown_other": "{count} faces n'ont pas pu être affichées et sont masquées.",
"import_report.open_one": "Une pièce présente des espaces entre ses faces et a été importée sous forme de corps ouvert.",
"import_report.open_other": "{count} pièces présentent des espaces entre leurs faces et ont été importées sous forme de corps ouverts.",
"import_report.refused_one": "Une pièce n'a pas pu être convertie en solide et n'a pas été importée.",
"import_report.refused_other": "{count} pièces n'ont pas pu être converties en solides et n'ont pas été importées.",
"import_report.repaired_one": "De petits défauts ont été réparés sur une pièce.",
"import_report.repaired_other": "De petits défauts ont été réparés sur {count} pièces.",
"import_report.solids": "{solids} pièces sur {parts} ont été importées sous forme de solides.",
"import_report.surfaces_one": "Une pièce n'a pas pu être convertie en solide et a été importée sous forme de surfaces.",
"import_report.surfaces_other": "{count} pièces n'ont pas pu être converties en solides et ont été importées sous forme de surfaces.",
"install.button_tip": "Installer SolidCraft comme une app : il s'ouvre dans sa propre fenêtre et fonctionne hors ligne",
"install.dock_1": "Choisissez Fichier › Ajouter au Dock.",
"install.dock_2": "Cliquez sur Ajouter.",
@@ -1836,7 +1916,18 @@
"issue.note_save_failed": "Impossible d’enregistrer la capture d’écran : {error}",
"issue.note_saved": "Capture d’écran enregistrée. Joignez le PNG dans le brouillon GitHub.",
"issue.save_screenshot": "Enregistrer la capture d’écran…",
"joint.find_limits": "Rechercher les limites",
"joint.find_limits_failed": "La recherche des limites s'est interrompue à la suite d'une erreur.",
"joint.find_limits_hint": "Définissez les limites à partir des positions où les pièces déplacées par cette liaison entrent en contact avec une autre pièce pour la première fois, en tournant ou en faisant coulisser chaque pièce dans les deux sens depuis sa position actuelle. L'opération s'effectue sur une copie : rien ne change avant de cliquer sur OK.",
"joint.find_limits_stale": "La liaison ou la conception a changé depuis le calcul de ces limites. Recherchez-les à nouveau.",
"joint.finding_limits": "Recherche des limites…",
"joint.from_bodies_hint": "Chaque corps sélectionné passe dans un nouveau composant à lui et reste où il est.",
"joint.limit_contact": "{side} {value} : {a} entre en contact avec {b}",
"joint.limit_limit": "{side} {value} : limite imposée par une autre valeur ou une autre liaison",
"joint.limit_loop": "{side} {value} : une boucle fermée ne peut pas se refermer au-delà de cette limite",
"joint.limit_range": "{side} : aucun contact dans la plage {range} ; valeur inchangée",
"joint.limit_turn": "{side} {value} : aucun contact après un tour complet",
"joint.limits_overlapping": "Déjà en contact l'une avec l'autre ici : {pairs}. Elles n'interrompent la recherche que si elles s'enfoncent davantage l'une dans l'autre.",
"joint.one_body": "Les deux sélections sont sur {body}. Choisissez la seconde sur une autre pièce.",
"joint.one_component": "Ces pièces sont des corps d'un même composant : {bodies}. Une liaison déplace un composant par rapport à un autre, chaque pièce a donc besoin de son propre composant.",
"joint.rigid_group_one_component": "Ces {count} corps sont tous dans un même composant (ou dans la conception elle-même) : utilisez d'abord {command}.",
@@ -1844,8 +1935,8 @@
"joint_move.blocked_hint": "Vérifiez le type de liaison (par exemple rigide), la fixation de la pièce, les limites de la liaison et les valeurs pilotées par des paramètres.",
"joint_move.blocked_title": "Impossible de déplacer cette pièce",
"joint_move.coarse": "Pas de rotation près de l’axe (°)",
"joint_move.conflict": "Une liaison de cette pièce est en conflit avec les autres : {joint}.",
"joint_move.conflict_hint": "Modifier, désactiver ou supprimer la liaison en conflit pour que les autres liaisons puissent placer la pièce.",
"joint_move.conflict": "Une liaison de cette pièce est incompatible avec les autres : {joint}.",
"joint_move.conflict_hint": "Modifiez, supprimez ou désactivez la liaison incompatible afin que les autres liaisons puissent positionner la pièce.",
"joint_move.distance": "Distance depuis le départ",
"joint_move.done": "Terminé",
"joint_move.fine": "Pas de rotation loin de l’axe (°)",
@@ -1946,7 +2037,7 @@
"motion.track_name": "Piste {number}",
"nav.alias.help": "Maj+Alt+glisser gauche fait orbiter, Maj+Alt+milieu fait un panoramique, Maj+Alt+droit zoome ; glisser avec le milieu fait aussi un panoramique et glisser avec le droit fait orbiter",
"nav.blender.help": "Glisser avec le milieu fait orbiter, Maj+milieu fait un panoramique, Ctrl+milieu zoome ; glisser avec le droit ne touche pas la caméra",
"nav.creo.help": "Glisser avec le milieu fait orbiter, Maj+milieu fait un panoramique, Ctrl+glisser avec le milieu zoome verticalement (vers le bas pour zoomer) ; la molette zoome",
"nav.creo.help": "Faites glisser avec le bouton du milieu pour orbiter, Maj + bouton du milieu pour déplacer la vue, Ctrl + bouton du milieu pour zoomer verticalement (vers le bas pour zoomer avant) ; faites tourner la molette pour zoomer",
"nav.creo.label": "Creo",
"nav.free_orbit.help": "La souris et la souris 3D tournent en passant par les deux pôles et conservent le roulis. L'alignement des axes avec Maj est désactivé.",
"nav.free_orbit.label": "Orbite libre",
@@ -1957,7 +2048,7 @@
"nav.hfss.help": "Alt+glisser gauche fait un panoramique, Maj+Alt+gauche zoome, Ctrl+glisser gauche sur un espace vide fait orbiter",
"nav.inventor.help": "Glisser avec le milieu fait un panoramique, Maj+milieu fait orbiter, Ctrl+milieu zoome, glisser avec le droit fait orbiter",
"nav.maya.help": "Alt+glisser gauche fait orbiter, Alt+milieu fait un panoramique, Alt+droit zoome ; glisser avec le milieu fait aussi un panoramique",
"nav.nx.help": "Glisser avec le milieu fait orbiter, Maj+milieu fait un panoramique (milieu + droit dans NX), Ctrl+milieu zoome (milieu + gauche dans NX) ; glisser avec le droit ne touche pas la caméra",
"nav.nx.help": "Faites glisser avec le bouton du milieu pour orbiter, Maj + bouton du milieu pour déplacer la vue (boutons du milieu + droit dans NX), Ctrl + bouton du milieu pour zoomer (boutons du milieu + gauche dans NX) ; faites glisser avec le bouton droit pour laisser la caméra en place",
"nav.openscad.help": "Glisser avec le gauche dans le vide fait orbiter, Maj+glisser gauche sélectionne par rectangle, glisser la géométrie d'esquisse la modifie ; glisser avec le droit ou le milieu fait un panoramique, Maj+droit ou Maj+milieu zoome",
"nav.perspective.sketch": "La modification d'une esquisse utilise la vue orthographique. Terminer l'esquisse pour passer en perspective.",
"nav.right_drag_orbits.help": "Désactivé : glisser avec le droit ne touche pas la caméra et le bouton droit ouvre seulement le menu contextuel. Choisir l'affectation des boutons de la souris SolidWorks le désactive.",
@@ -1976,6 +2067,12 @@
"navbar.assistant": "Assistant",
"navbar.custom.add_slot": "Ajouter {slot}",
"navbar.custom.always": "Toujours visible",
"navbar.custom.anchor.bottom_centre": "En bas au centre",
"navbar.custom.anchor.bottom_left": "En bas à gauche",
"navbar.custom.anchor.bottom_right": "En bas à droite",
"navbar.custom.anchor.top_centre": "En haut au centre",
"navbar.custom.anchor.top_left": "En haut à gauche",
"navbar.custom.anchor.top_right": "En haut à droite",
"navbar.custom.available": "{available} · faire glisser sur la barre, ou appuyer sur Ajouter",
"navbar.custom.buttons": "Boutons",
"navbar.custom.compact": "Compacte",
@@ -2012,6 +2109,7 @@
"navbar.custom.reset_default": "Réinitialiser par défaut",
"navbar.custom.right": "Déplacer à droite",
"navbar.custom.select": "Aucun emplacement sélectionné. Sélectionner un emplacement sur la barre pour le déplacer, le retirer ou modifier son apparence.",
"navbar.custom.separator_hint": "Un séparateur entre des groupes de boutons. Le faire glisser sur la barre, ou appuyer sur Ajouter ; en utiliser autant que souhaité.",
"navbar.custom.separators_full": "La barre compte déjà quatre séparateurs.",
"navbar.custom.show": "Afficher la barre de navigation",
"navbar.custom.shows": "Affiche",
@@ -2151,8 +2249,28 @@
"prefs.alt_frees_manipulators": "Alt / Option libère aussi les flèches du manipulateur",
"prefs.anti_aliasing_amd_dx12": "L'anticrénelage est à 1× car la vérification au démarrage n'a rien dessiné avec le multiéchantillonnage et a réussi à 1×. Vous pouvez choisir un autre réglage ci-dessus ; redémarrez pour l'appliquer si la vérification réussit.",
"prefs.anti_aliasing_note": "Adoucit les bords crénelés.",
"prefs.appearance.colour_vision_help": "Modifie les couleurs porteuses de sens : états des esquisses, axes, pliages, analyses et icônes.",
"prefs.appearance.desktop_only": "Version de bureau uniquement",
"prefs.appearance.follow_help": "Recharge le fichier lorsqu'un autre outil le réécrit.",
"prefs.appearance.interface_scale": "Échelle de l'interface",
"prefs.appearance.next_themes": "Thèmes suivants",
"prefs.appearance.option_count": "{count} options",
"prefs.appearance.option_count_one": "{count} option",
"prefs.appearance.previous_themes": "Thèmes précédents",
"prefs.appearance.theme_count": "{count} thèmes",
"prefs.appearance.theme_own": "Propre au thème",
"prefs.appearance.viewport_colours": "Couleurs de la vue 3D",
"prefs.appearance.viewport_logo": "Vue 3D et logo",
"prefs.applies_on_restart": "Appliqué au redémarrage",
"prefs.assistant": "Assistant",
"prefs.assistant_connecting": "Connexion en cours",
"prefs.assistant_follow_help": "Les vues normales aux esquisses déplacent la vue avec le pointeur.",
"prefs.assistant_limit": "Limite",
"prefs.assistant_limited": "Limité",
"prefs.assistant_pointer_speed": "Vitesse du pointeur",
"prefs.assistant_seconds": "secondes",
"prefs.assistant_seconds_aria": "Secondes",
"prefs.assistant_use_care": "À utiliser avec précaution",
"prefs.auto_operation": "Choisir l'opération automatiquement",
"prefs.auto_operation_note": "Les boîtes de dialogue des fonctions choisissent Joindre, Nouveau corps ou Couper d'après ce que touche la nouvelle matière, tant que vous n'en choisissez pas une vous-même. Désactivé : elles gardent l'opération avec laquelle elles s'ouvrent.",
"prefs.axes": "Axes",
@@ -2193,13 +2311,24 @@
"prefs.curved_surfaces": "Surfaces courbes",
"prefs.curves": "Surfaces courbes",
"prefs.cut_preview_tint": "Afficher en rouge la matière retirée",
"prefs.cut_preview_tint_help": "Un aperçu remplit la matière qu'une fonction retire, et la forme qu'elle remplace, d'un fantôme rouge translucide. Désactivée, ces remplissages sont entièrement transparents et seuls leurs contours sont tracés.",
"prefs.dark_parts_shading": "Conserver la forme des pièces sombres",
"prefs.dark_parts_shading_help": "Ombrer la vue en lumière linéaire avec un léger éclairage de ciel, pour que les faces sombres gardent un dégradé au lieu de devenir noires",
"prefs.cut_preview_tint_help": "L'aperçu remplit d'une silhouette rouge translucide la matière retirée par une fonction ainsi que la forme qu'elle remplace. Lorsque cette option est désactivée, ces remplissages sont entièrement transparents et seuls leurs contours sont tracés.",
"prefs.dark_parts_shading": "Préserver la forme des pièces sombres",
"prefs.dark_parts_shading_help": "Éclaire la vue en lumière linéaire avec un remplissage doux simulant le ciel, afin que les faces sombres conservent un dégradé au lieu de devenir noires.",
"prefs.dead_zone_note": "La bande hachurée est la zone morte : les mouvements à l'intérieur sont ignorés.",
"prefs.default": "par défaut",
"prefs.design": "Valeurs par défaut des conceptions",
"prefs.design_note": "Ce avec quoi démarrent les nouvelles conceptions. Les conceptions ouvertes gardent les leurs.",
"prefs.design_tools.ask": "Demander",
"prefs.design_tools.degrees": "Degrés",
"prefs.design_tools.double_click_help": "Ou pour modifier sur place un élément lié.",
"prefs.design_tools.ghost": "Afficher l'ancienne position des pièces déplacées sous forme de fantôme",
"prefs.design_tools.hole_moves_help": "Sélectionner à nouveau la face déplace le perçage au lieu de le supprimer.",
"prefs.design_tools.hole_snaps_help": "Le milieu d'une face et les centres de ses arêtes circulaires.",
"prefs.design_tools.imported_files": "Fichiers importés",
"prefs.design_tools.note": "Remarque",
"prefs.design_tools.off": "Désactivé",
"prefs.design_tools.placement_group": "Appui, Bossage, Clip",
"prefs.design_tools.rows": "Lignes",
"prefs.devices": "Souris 3D",
"prefs.dialog_buttons": "Boutons OK",
"prefs.dialogs": "Dialogues",
@@ -2220,6 +2349,18 @@
"prefs.font_sample": "Portez ce vieux whisky au juge blond qui fume · Ø12,50 mm · 45,0° · 0123456789",
"prefs.font_unreadable": "La police sélectionnée n'a pas pu être lue.",
"prefs.general": "Général",
"prefs.general.active": "Actif",
"prefs.general.crash_reports": "Rapports de plantage",
"prefs.general.edited": "Modifié",
"prefs.general.held": "Maintenu",
"prefs.general.import": "Importer…",
"prefs.general.last_check": "Dernière vérification : {time}",
"prefs.general.minutes": "Minutes",
"prefs.general.name_setup": "Nommer cette configuration",
"prefs.general.profile_name": "Nom du profil",
"prefs.general.save_new": "Enregistrer comme nouveau",
"prefs.general.step_import": "STEP et importation",
"prefs.general.this_computer": "Cet ordinateur",
"prefs.general_note": "Langue, enregistrement et mises à jour.",
"prefs.gesture_orbit": "Orbite",
"prefs.gesture_pan": "Panoramique",
@@ -2229,8 +2370,25 @@
"prefs.graphics_card_auto": "Automatique",
"prefs.graphics_card_missing": "La carte graphique enregistrée n'est pas disponible ; Automatique est utilisé.",
"prefs.graphics_card_restart": "Prend effet après le redémarrage de SolidCraft. WGPU_ADAPTER_NAME prévaut sur ce choix.",
"prefs.graphics_card_unused": "La carte graphique enregistrée n'a pas été utilisée pour cette fenêtre ; la carte utilisée est indiquée dans Aide › À propos et dans la barre d'état. Essayer Automatique, ou définir WGPU_ADAPTER_NAME avec une partie unique du nom de la carte.",
"prefs.graphics_card_unused": "La carte graphique enregistrée n'a pas été utilisée pour cette fenêtre ; la carte utilisée est indiquée dans Aide › À propos et dans la barre d'état. Essayez le mode Automatique ou définissez WGPU_ADAPTER_NAME avec une partie unique du nom de la carte.",
"prefs.graphics_note": "Compromis entre vitesse et fluidité. Chaque choix montre son effet sur un exemple.",
"prefs.graphics_page.current_view": "Vue actuelle",
"prefs.graphics_page.fastest": "Le plus rapide",
"prefs.graphics_page.fold_items": "Replier les éléments",
"prefs.graphics_page.in_view": "Dans la vue",
"prefs.graphics_page.live_details": "Détails en direct",
"prefs.graphics_page.own_mix": "Votre propre combinaison",
"prefs.graphics_page.quick_measure": "Mesure rapide",
"prefs.graphics_page.reference_geometry_through_bodies": "Géométrie de référence à travers les corps",
"prefs.graphics_page.restart": "Redémarrage nécessaire",
"prefs.graphics_page.sharpest": "Le plus net",
"prefs.graphics_page.single_surface_analysis": "Analyse d'une seule surface",
"prefs.graphics_page.status_chips": "Pastilles d'état",
"prefs.graphics_page.subtitle": "Compromis entre vitesse et fluidité.",
"prefs.graphics_page.supersampling": "Suréchantillonnage",
"prefs.graphics_page.supersampling_adaptive": "Seulement lorsque la vue est immobile",
"prefs.graphics_page.surfaces_edges": "Surfaces et arêtes",
"prefs.graphics_page.view_bar": "Aussi dans la barre de vue",
"prefs.graphics_presets_note": "Les préréglages définissent ensemble les choix ci-dessous.",
"prefs.hide_constraint_glyphs_zoomed_out": "Masquer les symboles de contraintes en cas de zoom arrière",
"prefs.hide_constraint_glyphs_zoomed_out_note": "Les symboles de contraintes quittent la vue lorsque le zoom arrière sur l'esquisse est assez important pour qu'ils l'encombrent. Désactivé : ils gardent une taille fixe à l'écran quel que soit le zoom.",
@@ -2244,8 +2402,8 @@
"prefs.history_sketches_note": "Avec Esquisses réglé sur Sous leur fonction, l'historique de gauche liste chaque esquisse un niveau en retrait, sous la première fonction construite à partir d'elle, dès qu'il est assez large pour les noms. La chronologie en bas garde toujours l'ordre de création.",
"prefs.history_sketches_under_feature": "Sous leur fonction",
"prefs.hold_stop_snapping": "Maintenir pour désactiver l'accrochage",
"prefs.home_fit_size": "Taille de Accueil et Cadrer",
"prefs.home_fit_size_note": "Part de la vue que remplit le modèle quand Accueil, Cadrer, l'ouverture d'une conception ou une vue du repère de navigation recadre la vue, que le réglage ci-dessous soit activé ou non. 100 % : remplit la vue entre les panneaux, la boussole et la barre de navigation.",
"prefs.home_fit_size": "Taille de la vue initiale et ajustement",
"prefs.home_fit_size_note": "Détermine la place occupée par le modèle dans la vue lorsque la vue initiale, l'ajustement, une conception ouverte ou une vue du navigateur recadre l'affichage, que le réglage ci-dessous soit activé ou non. 100 % : le modèle remplit la zone entre les panneaux, la boussole et la barre de navigation.",
"prefs.icons_only": "Icônes seules",
"prefs.imported_file": "Fichier importé",
"prefs.in_browser": "Dans le navigateur",
@@ -2254,22 +2412,38 @@
"prefs.interface_language": "Langue de l'interface",
"prefs.interface_note": "L'apparence de SolidCraft et la place de ses éléments.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverser les flèches courbes de roulis",
"prefs.invert_curved_roll_arrows_note": "Les deux flèches courbes au coin du navigateur font rouler la vue dans le plan de l'écran. Activé : la flèche horaire fait rouler dans le sens antihoraire et la flèche antihoraire dans le sens horaire. Désactivé : chaque flèche fait rouler la vue dans le sens de sa courbure.",
"prefs.invert_navigator_arrows": "Inverser les flèches de rotation du navigateur de vue",
"prefs.invert_navigator_arrows_note": "Les flèches autour du navigateur font orbiter la caméra dans le sens où elles pointent, comme dans Fusion et Inventor : la flèche de gauche pointe vers la droite et fait pivoter la caméra vers la droite. Désactivé : une flèche fait tourner la vue vers le côté où elle se trouve, donc la flèche de gauche fait pivoter la caméra vers la gauche. Les flèches courbes de roulis ne sont pas concernées.",
"prefs.invert_curved_roll_arrows": "Inverser les flèches de rotation courbe",
"prefs.invert_curved_roll_arrows_note": "Les deux flèches courbes au coin du cube font pivoter la vue dans le plan de l'écran. Activé : la flèche horaire fait tourner la vue dans le sens antihoraire, et inversement. Désactivé : chaque flèche fait tourner la vue dans le sens indiqué par sa courbure.",
"prefs.invert_navigator_arrows": "Inverser les flèches de rotation du cube de vue",
"prefs.invert_navigator_arrows_note": "Les flèches autour du cube font orbiter la caméra dans la direction qu'elles indiquent, comme dans Fusion et Inventor : la flèche de gauche pointe vers la droite et fait pivoter la caméra vers la droite. Désactivé : une flèche fait tourner le cube vers le côté où elle se trouve ; la flèche de gauche fait donc pivoter la caméra vers la gauche. Les flèches courbes de rotation ne sont pas affectées.",
"prefs.keep_work_on_tab_switch": "Garder dialogues et outils ouverts en changeant de conception",
"prefs.keep_work_on_tab_switch_note": "Chaque onglet de conception garde son dialogue ou son outil ouvert, avec ce que vous y avez sélectionné et saisi, ainsi que son onglet de barre d'outils. Vous les retrouvez en revenant à la conception. Désactivé : changer de conception les annule et affiche l'onglet Modèle.",
"prefs.labels": "Libellés",
"prefs.language_system": "Système",
"prefs.layout": "Disposition",
"prefs.layout_note": "Compacte : ancre les panneaux aux bords de la fenêtre. La transparence du navigateur est disponible en mode Flottante. Changez le côté de l'assistant dans la page Assistant.",
"prefs.layout_page.active_commands": "Mettre en évidence les commandes actives",
"prefs.layout_page.always": "Toujours",
"prefs.layout_page.card": "Carte",
"prefs.layout_page.column": "Colonne",
"prefs.layout_page.hover": "Survol",
"prefs.layout_page.icons_labels": "Icônes + libellés",
"prefs.layout_page.ok_cancel": "OK et Annuler",
"prefs.layout_page.on_hover": "Au survol",
"prefs.layout_page.open": "Ouvert",
"prefs.layout_page.origin_bodies": "Origine et corps au premier plan",
"prefs.layout_page.panels": "Panneaux",
"prefs.layout_page.pinned_menus": "Commandes épinglées hors des menus",
"prefs.layout_page.play_history": "Bouton Lire l'historique",
"prefs.layout_page.slot_count": "{count} sur {max} emplacements",
"prefs.layout_page.view_corner": "Aussi dans le coin de la vue",
"prefs.layout_page.window": "Fenêtre",
"prefs.left": "Gauche",
"prefs.left_click": "Clic gauche",
"prefs.line_drag_draws_one": "Appuyer et glisser trace une seule ligne",
"prefs.line_drag_draws_one_note": "Dans l'outil Ligne, appuyer, faire glisser puis relâcher trace une seule ligne, du point d'appui au point de relâchement, et le tracé s'arrête là. Les clics tracent toujours une chaîne. Désactivé : un glissement place un point là où il est relâché, comme un clic.",
"prefs.line_hover_tangent_arc": "S'arrêter sur le dernier point d'une ligne pour passer à un arc tangent",
"prefs.line_hover_tangent_arc_note": "Dans l'outil Ligne, une fois un segment tracé, éloigner le pointeur du dernier point de la chaîne, revenir et le maintenir immobile dessus : le clic suivant termine un arc tangent, et le même geste revient aux lignes. Désactivé : s'arrêter là ne fait rien.",
"prefs.line_hover_tangent_arc": "Survoler le dernier point d'une ligne pour passer à un arc tangent",
"prefs.line_hover_tangent_arc_note": "Dans l'outil Ligne, après avoir tracé un segment, éloignez le pointeur du dernier point de la chaîne, revenez dessus et immobilisez le pointeur : le clic suivant termine un arc tangent. Le même geste permet de revenir aux lignes. Si l'option est désactivée, le survol immobile n'a aucun effet.",
"prefs.linked_designs": "Conceptions liées",
"prefs.live_input": "Saisie en direct",
"prefs.live_preview": "Aperçu en direct",
@@ -2294,9 +2468,16 @@
"prefs.move_drag_highlights": "Mettre en évidence ce qui est sous le pointeur pendant que les flèches de Déplacer font glisser un composant",
"prefs.move_drag_highlights_tip": "Désactivé : pendant que les flèches de Déplacer font glisser un composant, rien n’est mis en évidence sous le pointeur, ce qui garde les grands assemblages fluides. Avec une coupe ou une analyse affichée, la mise en évidence reste, et une pièce glissée le long de ses liaisons n’en montre jamais.",
"prefs.navigation": "Navigation",
"prefs.navigation.axes_signed": "Axes",
"prefs.navigation.cube_compact": "Cube",
"prefs.navigation.device": "Appareil",
"prefs.navigation.free": "Libre",
"prefs.navigation.orbit_style": "Style d'orbite",
"prefs.navigation.radial_help": "Maintenez ou balayez le bouton droit pour afficher un anneau d'outils.",
"prefs.navigation.turntable": "Plateau tournant",
"prefs.navigation_note": "Comment la souris, le pavé tactile et la souris 3D déplacent la vue.",
"prefs.navigator_fit": "Cadrer le modèle après un changement de vue du repère de navigation",
"prefs.navigator_fit_note": "Une face, un coin ou une flèche du navigateur de vue, ou un axe du gizmo, regarde aussi le milieu du modèle depuis la distance unique qui le cadre sous tous les côtés (sa sphère englobante). Accueil utilise le même zoom et le même centre tant que cette option est activée, de sorte que les vues choisies ensuite ne font que tourner. Désactivé : la vue tourne sur place, en gardant sa cible et son zoom.",
"prefs.navigator_fit": "Ajuster le modèle après un changement de vue du navigateur",
"prefs.navigator_fit_note": "Une face, un coin ou une flèche du cube de vue, ainsi qu'un axe du gizmo, centre aussi la vue sur le modèle à la distance permettant de le voir en entier depuis toutes les directions (sa sphère englobante). Tant que cette option est activée, la touche Accueil utilise le même zoom et le même centrage : les vues choisies ensuite ne font que tourner. Désactivée, la vue pivote sur place en conservant sa cible et son zoom.",
"prefs.network_host_remove": "Retirer",
"prefs.network_locations": "Autoriser les emplacements réseau dans les conceptions",
"prefs.network_locations_note": "Désactivé : les fichiers liés d'une conception situés sur un autre ordinateur (\\\\server\\share) ne sont ouverts que depuis les serveurs listés ici, ou après en avoir autorisé un sur demande.",
@@ -2315,10 +2496,14 @@
"prefs.persistent_ribbon_pressed_help": "Met en surbrillance les commandes du ruban tant que leurs effets sont actifs. Désactivez cette option pour conserver l'apparence neutre précédente et l'aide des commandes.",
"prefs.perspective_fov": "Champ de vision",
"prefs.placement": "Placement",
"prefs.plugins_enabled": "Activé",
"prefs.plugins_installed": "Installé",
"prefs.plugins_intro": "Modules externes en bac à sable.",
"prefs.plugins_show_folder": "Afficher le dossier des modules externes",
"prefs.prefer_free_sketch_points": "Privilégier les points d'esquisse déplaçables quand des points se superposent",
"prefs.preview_choices": "Aperçu de vos choix",
"prefs.preview_tint_new_faces": "Teinter la nouvelle surface dans un aperçu",
"prefs.preview_tint_new_faces_help": "L'aperçu d'une fonction qui modifie un corps peut tracer la surface qu'elle ajoute dans la couleur d'aperçu. Désactivée, le corps est tracé tel quel.",
"prefs.preview_tint_new_faces": "Colorer les nouvelles surfaces dans l'aperçu",
"prefs.preview_tint_new_faces_help": "L'aperçu d'une fonction qui modifie un corps peut colorer, avec la couleur d'aperçu, les surfaces qu'elle ajoute. Lorsque cette option est désactivée, le corps conserve son apparence normale.",
"prefs.print_face_highlight": "Mise en évidence de la face d’impression",
"prefs.print_face_highlight_tip": "Intensité de la teinte et du contour de la face d’impression d’un corps dans la vue. 0 % n’affiche aucune mise en évidence.",
"prefs.profile_active": "Profil actif",
@@ -2329,6 +2514,8 @@
"prefs.profile_exported": "Profil exporté.",
"prefs.profile_imported": "Profil importé. Choisissez-le sous Profil actif pour basculer dessus.",
"prefs.profile_name_hint": "Nom du profil, par ex. Portable",
"prefs.profile_operations": "Opérations du profil",
"prefs.profile_operations_note": "Enregistre la durée des appels à SMLib, des opérations du noyau, des fonctions, des commandes et des importations. Les outils automatisés peuvent consulter ces données avec diagnostics.profile.",
"prefs.profile_rename": "Renommer",
"prefs.profile_renamed": "Profil renommé.",
"prefs.profile_save": "Enregistrer",
@@ -2347,8 +2534,9 @@
"prefs.render_previous_geometry_budget": "Utiliser l'ancien budget de géométrie de l'aperçu Rendu",
"prefs.render_previous_geometry_budget_help": "Rétablir l'ancienne limite fixe de géométrie (512 Mio sur un ordinateur 64 bits, 128 Mio ailleurs) au lieu du budget basé sur l'appareil.",
"prefs.reports_saved": "Enregistrés : {n}",
"prefs.ribbon_click_ends_tool": "Cliquer sur le bouton de l'outil en cours le termine",
"prefs.ribbon_click_ends_tool_note": "Un clic sur le bouton allumé du ruban de l'outil d'esquisse en cours termine l'outil, et les clics dans la vue sélectionnent de nouveau. Désactivé : le clic relance l'outil.",
"prefs.restore_page_defaults": "Rétablir les valeurs par défaut de la page",
"prefs.ribbon_click_ends_tool": "Cliquer sur le bouton de l'outil actif termine l'outil",
"prefs.ribbon_click_ends_tool_note": "Cliquer sur le bouton en surbrillance de l'outil d'esquisse actif termine cet outil, afin que les clics dans la vue servent à nouveau à sélectionner. Si l'option est désactivée, le clic relance l'outil.",
"prefs.ribbon_reveal": "Montrer les résultats de recherche dans le ruban",
"prefs.ribbon_reveal_note": "Survoler un résultat dans Rechercher des commandes montre où se trouve la commande dans le ruban : son onglet, son bouton ou sa ligne dans le menu déroulant d'un panneau. Une commande lancée depuis la recherche y clignote, et une commande en cours issue d'un menu déroulant signale son panneau.",
"prefs.right_click": "Clic droit",
@@ -2357,6 +2545,9 @@
"prefs.scale_text": "Échelle et texte",
"prefs.search": "Rechercher dans les paramètres",
"prefs.search_empty": "Aucun paramètre correspondant",
"prefs.section_hatch": "Hachures de coupe",
"prefs.section_hatch_by_part": "Par pièce",
"prefs.section_hatch_one": "Un seul style",
"prefs.select": "Sélectionner",
"prefs.select_one_item": "Sélectionner un élément",
"prefs.select_other_hidden": "Sélectionner la géométrie masquée avec Sélectionner un autre",
@@ -2366,10 +2557,45 @@
"prefs.shift_add_ctrl_toggle": "Maj ajoute seulement ; Ctrl / Cmd bascule",
"prefs.shift_add_note": "Activé : Maj ajoute, Ctrl / Cmd bascule. Désactivé (par défaut) : les deux basculent.",
"prefs.shortcuts": "Raccourcis",
"prefs.shortcuts_import": "Importer",
"prefs.shortcuts_intro": "Les touches associées à chaque commande.",
"prefs.shortcuts_not_assigned": "Non attribué",
"prefs.shortcuts_press": "Appuyez sur une touche...",
"prefs.single_surface_analysis": "Utiliser une seule analyse de surface",
"prefs.single_surface_analysis_help": "Désactivé, l'ombrage de surface et Continuité peuvent rester actifs ensemble. Activé, seule la dernière analyse lancée ou modifiée est conservée.",
"prefs.sketch.align_points": "S'aligner sur les autres points d'esquisse",
"prefs.sketch.align_points_note": "Les lignes en cours de tracé s'alignent sur des points sur les deux axes à la fois.",
"prefs.sketch.auto_dimensions": "Coter entièrement les nouvelles formes",
"prefs.sketch.auto_dimensions_note": "Les valeurs saisies, plus toutes les cotes qui définissent la forme.",
"prefs.sketch.auto_locate": "Placer depuis l'origine de l'esquisse",
"prefs.sketch.auto_locate_note": "Avec cotation complète.",
"prefs.sketch.center_arc": "L'arc par centre suit le curseur",
"prefs.sketch.click_selects": "Le clic sélectionne",
"prefs.sketch.conflict_colour": "Couleur de conflit",
"prefs.sketch.drawing": "Dessin",
"prefs.sketch.escape_twice_finishes": "Un double Échap termine l'esquisse",
"prefs.sketch.escape_twice_finishes_note": "Deux pressions rapides sur Échap terminent l'esquisse. Désactivé : Échap annule seulement l'outil ou la sélection, et Terminer l'esquisse ferme l'esquisse.",
"prefs.sketch.exit_keep": "Conserver",
"prefs.sketch.exit_previous": "Revenir à la vue précédente",
"prefs.sketch.exit_unless_rotated": "Sauf si la vue a tourné",
"prefs.sketch.faces_edges": "Faces et arêtes",
"prefs.sketch.hide_glyphs": "Masquer les symboles en cas de zoom arrière",
"prefs.sketch.marks": "Repères dans l'esquisse",
"prefs.sketch.note": "Dessin, accrochage et sélection.",
"prefs.sketch.opening_closing": "Ouverture et fermeture",
"prefs.sketch.prefer_free_points": "Privilégier les points mobiles en cas de chevauchement",
"prefs.sketch.project_options": "Demander d'abord les options de projection",
"prefs.sketch.recent_snap": "S'accrocher à l'intersection de deux guides",
"prefs.sketch.select_other_hidden": "Sélectionner un autre atteint la géométrie masquée",
"prefs.sketch.shortcut_cycles_modes": "Un nouvel appui sur le raccourci change de mode",
"prefs.sketch.shortcut_cycles_modes_tip": "Désactivé : il relance l'outil.",
"prefs.sketch.snapping_guides": "Accrochage et guides",
"prefs.sketch.state_icons": "Icônes d'état",
"prefs.sketch.tracking_guides": "Guides de centre et de point milieu",
"prefs.sketch.tracking_guides_note": "Guides horizontaux et verticaux temporaires à partir des centres et des points milieux d'arêtes survolés.",
"prefs.sketch.tracking_points": "Guides aussi depuis les points d'esquisse",
"prefs.sketch.unless_turned_note": "retour si la vue n'a pas tourné",
"prefs.sketch.whole_bodies": "Corps entiers",
"prefs.sketch_align_points": "S'aligner sur d'autres points d'esquisse pendant le dessin",
"prefs.sketch_align_points_note": "Pendant le dessin, un point s'aligne à la fois horizontalement sur un point d'esquisse et verticalement sur un autre, avec un guide en pointillés, et le clic conserve les deux alignements. Désactivé : uniquement sur le point précédent, un axe à la fois.",
"prefs.sketch_conflict_colour": "Géométrie en conflit dans la couleur de conflit",
@@ -2380,8 +2606,8 @@
"prefs.sketch_exit_view.previous": "Revenir à la vue précédente",
"prefs.sketch_exit_view.unless_rotated": "Revenir, sauf si la vue a été tournée",
"prefs.sketch_exit_view_note": "Où va la vue après Terminer l'esquisse, Annuler ou un double Échap.",
"prefs.sketch_face_activates_part": "Esquisser sur la face d'une pièce active cette pièce",
"prefs.sketch_face_activates_part_note": "Une esquisse commencée sur une face du corps d'un autre composant active d'abord ce composant, de sorte que l'esquisse lui appartient et reste avec cette pièce dans le navigateur. La pièce reste ensuite active. Désactivé : l'esquisse appartient au composant actif.",
"prefs.sketch_face_activates_part": "Esquisser sur une face active la pièce correspondante",
"prefs.sketch_face_activates_part_note": "Lorsqu'une esquisse commence sur une face du corps d'un autre composant, ce composant est d'abord activé : l'esquisse lui appartient et reste avec cette pièce dans le navigateur. La pièce reste ensuite active. Si l'option est désactivée, l'esquisse appartient au composant actif.",
"prefs.sketch_open_look_at": "Se placer face à l'esquisse à son ouverture",
"prefs.sketch_open_look_at_note": "Désactivé : créer ou modifier une esquisse laisse la vue telle quelle. Vue normale place la vue face à l'esquisse quand vous le souhaitez.",
"prefs.sketch_recent_snap": "Accrocher automatiquement aux centres et points milieux récents",
@@ -2417,15 +2643,15 @@
"prefs.structure.appearance_note": "Couleurs, texte et accessibilité.",
"prefs.structure.in_profile": "Dans le profil",
"prefs.structure.layout": "Disposition",
"prefs.structure.layout_note": "Où se placent les parties de la fenêtre.",
"prefs.structure.layout_note": "Position des éléments de la fenêtre.",
"prefs.structure.look": "Aspect",
"prefs.structure.measure_pointer": "Mesure et pointeur",
"prefs.structure.mouse3d": "Souris 3D",
"prefs.structure.mouse3d_note": "SpaceMouse et SpaceNavigator.",
"prefs.structure.navigation_note": "Souris et pavé tactile. La souris 3D a sa propre page.",
"prefs.structure.navigation_note": "Souris et pavé tactile. La souris 3D possède sa propre page.",
"prefs.structure.profile": "Profil",
"prefs.structure.profile_edited": "Modifié depuis l'enregistrement",
"prefs.structure.profile_hover": "Enregistré dans les profils de réglages",
"prefs.structure.profile_hover": "Enregistré dans les profils de paramètres",
"prefs.structure.scale_percent": "{percent} %",
"prefs.structure.sketch": "Esquisse",
"prefs.structure.tools": "Outils",
@@ -2473,6 +2699,12 @@
"prefs.under_cursor": "Sous le curseur",
"prefs.units_precision": "Unités et précision",
"prefs.updates": "Mises à jour",
"prefs.validation": "Vérification du corps",
"prefs.validation.each_feature": "Une fois par fonction",
"prefs.validation.each_step": "Après chaque étape",
"prefs.validation.label": "Vérification complète du noyau géométrique",
"prefs.validation.off": "Désactivée (expérimental)",
"prefs.validation_note": "Après chaque étape : vérifie chaque balayage, opération booléenne et raccordement.\nUne fois par fonction : vérifie une seule fois le résultat de chaque fonction.\nDésactivée (expérimental) : aucune vérification.",
"prefs.value_boxes_in_view": "Afficher les valeurs à côté de leurs poignées dans la vue",
"prefs.value_boxes_in_view_tip": "La valeur d'une commande (distance, rayon…) dans une case à côté de sa poignée, par-dessus le modèle. Désactivé : vous la saisissez dans la fenêtre de la commande, qui prend le clavier après une sélection, et rien ne masque le modèle.",
"prefs.view": "Comportement de la vue",
@@ -2507,6 +2739,17 @@
"recovery.just_now": "à l’instant",
"recovery.min_ago": "il y a {count} min",
"recovery.never_saved": "jamais enregistré",
"refused.change": "Impossible de modifier {body}.",
"refused.cut": "Impossible de soustraire de la matière à {body}.",
"refused.face_curved": "L'une de ses faces courbes ne peut pas être utilisée pour la modélisation.",
"refused.face_flat": "L'une de ses faces planes ne peut pas être utilisée pour la modélisation.",
"refused.face_freeform": "L'une de ses faces de forme libre ne peut pas être utilisée pour la modélisation.",
"refused.face_rounded": "L'une de ses faces arrondies ne peut pas être utilisée pour la modélisation.",
"refused.faces_apart": "Ses faces ne sont pas suffisamment proches pour être utilisées en modélisation.",
"refused.intersect": "Impossible de réaliser l'intersection avec {body}.",
"refused.join": "Impossible de fusionner avec {body}.",
"refused.repair": "Réparer la pièce",
"refused.show_face": "Afficher la face",
"render.adaptive_absolute": "Plancher d'erreur RVB absolu",
"render.adaptive_coverage": "Erreur de couverture visée",
"render.adaptive_enable": "Répartir les échantillons avec des pilotes indépendants",
@@ -2618,9 +2861,9 @@
"render.base_color": "Couleur de base · sRVB",
"render.base_metallic": "Fraction métallique",
"render.base_opaque_only": "Cet éditeur conserve la sémantique des corps opaques. Utilisez les commandes de verre dédiées pour la transmission optique.",
"render.batch_all_shots": "Toutes les prises de vue ({count})",
"render.batch_empty": "Enregistrer une prise de vue avant de rendre toutes les prises de vue.",
"render.batch_limit": "Le rendu de toutes les prises de vue est limité à 32 prises de vue.",
"render.batch_all_shots": "Tous les rendus ({count})",
"render.batch_empty": "Enregistrez un rendu avant de lancer le rendu de tous les rendus.",
"render.batch_limit": "Le rendu de tous les rendus est limité à 32 vues.",
"render.batch_status": "{running} en cours · {waiting} en attente",
"render.bloom_enable": "Halo lumineux (bloom) à l'affichage",
"render.bloom_help": "Lueur créative appliquée à la sortie seulement, à partir des hautes lumières linéaires positives, étalée par trois passes de flou normalisées. Le rayon est en pixels de sortie. Ajoutée en lumière d'affichage linéaire avant sRVB ; ce n'est ni un effet d'objectif, ni un effet volumétrique, ni une amélioration de la convergence. L'EXR brut est inchangé.",
@@ -3950,7 +4193,7 @@
"sketch_text.formula": "Commencez par = pour composer le texte avec des paramètres : ='L' + number(Largeur)",
"sketch_text.italic": "Italique",
"sketch_text.loading_fonts": "Recherche des polices installées…",
"sketch_text.no_bold": "La police intégrée n'a pas de graisse grasse : choisir une police installée",
"sketch_text.no_bold": "La police intégrée ne possède pas de graisse ; choisissez une police installée.",
"sketch_text.on_path": "Le texte suit sa trajectoire : la courbe le positionne",
"sketch_text.path_clear": "Détacher le texte de sa courbe",
"sketch_text.path_hint": "Une courbe de l'esquisse que le texte suit : cliquer ici, puis sur la courbe",
@@ -3981,7 +4224,19 @@
"the section's profiles must be in one sketch": "les profils de la section doivent être dans une seule esquisse",
"the two origins are on the same component": "les deux origines se trouvent sur le même composant",
"thread.automatic_size": "Taille automatique",
"thread.chamfer_depth_needed": "nécessaire pour cette forme",
"thread.designation": "Désignation",
"thread.drill_range": "Le foret recommandé par le fabricant du taraud mesure {drill} mm. Le diamètre mineur normalisé du filetage intérieur est de {minor} mm. Un foret de {low} à {high} mm est accepté.",
"thread.drill_range_custom": "Le diamètre du foret correspond au diamètre nominal moins le pas, soit {drill} mm. Le diamètre mineur normalisé du filetage intérieur est de {minor} mm. Un foret de {low} à {high} mm est accepté.",
"thread.drill_range_taper": "Le foret recommandé par le fabricant du taraud mesure {drill} mm. Le diamètre mineur normalisé à l'extrémité du filetage est de {minor} mm. Un foret de {low} à {high} mm est accepté.",
"thread.end_square": "Carré",
"thread.fade_short": "1,25 P (ISO 3508)",
"thread.fade_standard": "2,5 P (ISO 3508)",
"thread.fits_the_face": "s'adapte à la face, par exemple {example}",
"thread.form_bspp": "Filetage de tuyauterie G (ISO 228-1)",
"thread.form_bspt": "Filetage conique de tuyauterie R, Rc (ISO 7-1)",
"thread.form_npt": "Filetage conique de tuyauterie NPT (ASME B1.20.1)",
"thread.form_rp": "Filetage de tuyauterie Rp (ISO 7-1)",
"thread.iso_metric": "Métrique ISO",
"thread.select_size": "Sélectionner la taille",
"timeline.delete_after_marker_one": "Supprimer 1 fonction après le marqueur d'historique",
@@ -4156,6 +4411,7 @@
"ui.agent_chat_auth_terminal": "Exécuter ceci dans un terminal, puis appuyer de nouveau sur Connecter :",
"ui.agent_chat_auth_title": "Authentification auprès de l'agent",
"ui.agent_chat_cancel": "Annuler",
"ui.agent_chat_cancel_timeout": "L'agent n'a pas répondu à la demande d'arrêt et a été déconnecté. Reconnectez-vous pour continuer.",
"ui.agent_chat_cannot_start": "Installé, mais ne démarre pas : {error}",
"ui.agent_chat_changes": "Modifications : {n}, en une seule étape d'annulation",
"ui.agent_chat_changes_n": "Modifications : {n}",
@@ -4215,16 +4471,16 @@
"ui.agent_chat_mode_all": "Tout",
"ui.agent_chat_mode_ask": "Demander",
"ui.agent_chat_mode_edits": "Édition",
"ui.agent_chat_model_custom": "Utiliser le modèle personnalisé : {model}",
"ui.agent_chat_model_custom": "Utiliser le modèle personnalisé : {model}",
"ui.agent_chat_model_no_tools": "{model} ne peut pas utiliser les outils de SolidCraft : il peut seulement discuter. Choisissez un modèle qui prend en charge les outils.",
"ui.agent_chat_model_rejected": "L'agent n'a pas accepté {model} : {error}",
"ui.agent_chat_model_rejected": "L'agent a refusé {model} : {error}",
"ui.agent_chat_model_search": "Rechercher des modèles…",
"ui.agent_chat_model_tip": "Le modèle utilisé par l'agent. Votre choix est mémorisé pour cet agent.",
"ui.agent_chat_models_failed": "Impossible de lister les modèles : {error}",
"ui.agent_chat_models_failed": "Impossible de répertorier les modèles : {error}",
"ui.agent_chat_models_heading": "Modèles disponibles",
"ui.agent_chat_models_listing": "Liste des modèles en cours…",
"ui.agent_chat_models_none": "Le point d'accès ne liste aucun modèle",
"ui.agent_chat_models_not_a_list": "La réponse n'était pas une liste de modèles",
"ui.agent_chat_models_listing": "Répertoriage des modèles…",
"ui.agent_chat_models_none": "Le point de terminaison ne répertorie aucun modèle",
"ui.agent_chat_models_not_a_list": "La réponse ne contenait aucune liste de modèles",
"ui.agent_chat_new": "Nouveau chat",
"ui.agent_chat_new_confirm": "Démarrer un nouveau chat ? Le chat actuel sera effacé.",
"ui.agent_chat_next_picture": "Image suivante",
@@ -4233,6 +4489,7 @@
"ui.agent_chat_no_images": "Cet agent n'accepte pas les images",
"ui.agent_chat_no_picture": "Il n'y a pas d'image dans le presse-papiers",
"ui.agent_chat_no_tool_call": "Le modèle n'a pas utilisé les outils de SolidCraft : la conception n'a donc pas été modifiée. Choisissez un modèle qui prend en charge l'appel d'outils ; voir Modèles locaux dans le guide du chat avec l'agent.",
"ui.agent_chat_node_too_old": "La version de Node.js {version} est trop ancienne pour cet agent. Installez Node.js 20.10 ou une version ultérieure, puis cliquez sur Actualiser.",
"ui.agent_chat_none_found": "Aucun agent de programmation trouvé. En installer un parmi ceux-ci, puis appuyer sur Actualiser :",
"ui.agent_chat_none_found_short": "Aucun agent trouvé",
"ui.agent_chat_not_installed": "Non installé",
@@ -4360,9 +4617,9 @@
"ui.ai_permissions": "Autorisations",
"ui.ai_preset": "Préréglage",
"ui.ai_protocol": "Protocole",
"ui.ai_reasoning_effort": "Effort de raisonnement",
"ui.ai_reasoning_effort": "Niveau de raisonnement",
"ui.ai_reasoning_effort_field_hint": "vide = valeur par défaut du fournisseur",
"ui.ai_reasoning_effort_hint": "Facultatif. Envoyé au point d'accès sous le nom `reasoning_effort` ; les valeurs acceptées varient selon le fournisseur (par exemple `low`, `high` ou `max`). Une valeur saisie ici n'est jamais remplacée par SolidCraft. Laisser vide pour ne rien envoyer et garder la valeur par défaut du fournisseur.",
"ui.ai_reasoning_effort_hint": "Facultatif. Envoyé au point de terminaison sous le nom `reasoning_effort` ; les valeurs acceptées varient selon le fournisseur (par exemple `low`, `high` ou `max`). Une valeur définie ici n'est jamais remplacée par SolidCraft. Laissez ce champ vide pour ne rien envoyer et conserver la valeur par défaut du fournisseur.",
"ui.ai_remove": "Retirer",
"ui.ai_request_timed_out": "Le modèle a mis plus de {seconds} s. Vous pouvez augmenter le délai d'expiration des requêtes de ce point d'accès dans Préférences › Assistant.",
"ui.ai_request_timeout": "Délai d'expiration des requêtes",
@@ -4452,6 +4709,8 @@
"ui.centerline": "Ligne de construction",
"ui.chain": "Chaîne",
"ui.chamfer": "Chanfrein",
"ui.chamfer_angle": "Angle du chanfrein",
"ui.chamfer_depth": "Profondeur du chanfrein",
"ui.chamfer_type": "Type de chanfrein",
"ui.change_workspace": "Changer d'espace de travail",
"ui.circle": "Cercle",
@@ -4483,10 +4742,16 @@
"ui.colour_vision_sample": "Exemple",
"ui.colour_vision_tritan": "Tritan",
"ui.colour_vision_tritan_tip": "Pour une perception du bleu faible ou absente",
"ui.comb_length": "Longueur des peignes",
"ui.comb_length_tip": "Longueur des dents : un multiple de la longueur automatique, qui donne à la dent la plus longue une longueur égale au cinquième de la taille des courbes affichées.",
"ui.comb_teeth": "Dents",
"ui.comb_teeth_tip": "Nombre de dents de chaque peigne, régulièrement espacées le long de la courbe. Plus il y a de dents, plus les variations de courbure sont détaillées.",
"ui.combine": "Combiner",
"ui.coming_later": "bientôt disponible",
"ui.command_done": "{command} terminé",
"ui.command_palette_hint": "Tapez une commande, ex. {example} — ou S pour chercher",
"ui.components_from_bodies_hint": "Crée un composant par corps sélectionné, portant le nom de ce corps, sous le composant actif.",
"ui.components_from_bodies_required": "Sélectionnez au moins un corps.",
"ui.concentric": "Concentricité",
"ui.cone": "Cône",
"ui.conic_curve": "Courbe conique",
@@ -4499,22 +4764,30 @@
"ui.construction.contact_hint": "Tangente : sélectionnez un cercle/arc ou une spline/conique ouverte, puis le point de contact (courbes libres : extrémités)",
"ui.construction.external_hint": "Tangente : sélectionnez un cercle ou un arc, un point extérieur, puis la solution souhaitée",
"ui.construction.free_hint": "Droite de construction : cliquez sur deux points ; clic droit pour recommencer",
"ui.construction.normal_needs_length": "Une ligne infinie est toujours de construction : saisir une longueur pour tracer une ligne normale",
"ui.construction.normal_needs_length": "Une droite infinie est toujours une ligne de construction : saisissez une longueur pour tracer une droite normale.",
"ui.construction.point_hint": "Droite de construction : cliquez sur le point de passage",
"ui.construction.reference_hint": "Droite de construction : sélectionnez une ligne droite, puis un point ; clic droit pour changer la référence",
"ui.construction.ribbon_label": "Lignes aux.",
"ui.construction.side_hint": "Ligne de construction : cliquer du côté vers lequel la ligne s'étend ; clic droit pour recommencer",
"ui.construction.side_hint": "Ligne de construction : cliquez du côté vers lequel la ligne doit se prolonger ; clic droit pour recommencer.",
"ui.context_menu": "Menu contextuel",
"ui.continuity_crease": "Angle vif",
"ui.continuity_curvature": "Courbure",
"ui.continuity_curvature_change": "Variation de courbure",
"ui.continuity_curvature_change_tip": "Variation de courbure (G3) : la courbure varie également de façon régulière de part et d'autre de la jonction.",
"ui.continuity_curvature_tip": "Continuité de courbure (G2) : les reflets se prolongent sans cassure.",
"ui.continuity_g0": "G0 angle vif",
"ui.continuity_g1": "G1 tangence",
"ui.continuity_g2": "G2 courbure",
"ui.continuity_gap": "Écart",
"ui.continuity_position": "Position",
"ui.continuity_position_tip": "Position (G0) : les surfaces se rejoignent, avec une arête visible à la jonction.",
"ui.continuity_smooth_curvature_change": "Variation régulière de la courbure",
"ui.continuity_smooth_curvature_change_tip": "Variation régulière de la courbure (G4) : même l'évolution de la courbure se prolonge sans rupture à la jonction.",
"ui.continuity_tangent": "Tangence",
"ui.continuity_tangent_tip": "Tangence (G1) : aucune arête visible, mais la courbure présente une discontinuité à la jonction.",
"ui.copy": "Copier",
"ui.copy_details": "Copier les détails",
"ui.copy_details_tip": "Copie le message complet pour permettre de le rechercher ou de le signaler.",
"ui.corner": "Angle",
"ui.corners": "Angles",
"ui.cosmetic_thread_markings": "Marquages de filetage cosmétiques",
@@ -4536,7 +4809,7 @@
"ui.dark": "Sombre",
"ui.default_modelling_orientation": "Orientation de modélisation par défaut",
"ui.delete": "Supprimer",
"ui.delete_select_first": "Sélectionner d'abord ce qu'il faut supprimer : fonctions, corps, composants ou géométrie d'esquisse",
"ui.delete_select_first": "Sélectionnez d'abord les éléments à supprimer : fonctions, corps, composants ou géométrie d'esquisse.",
"ui.depth": "Profondeur",
"ui.design": "Conception",
"ui.design_properties.author": "Auteur",
@@ -4632,17 +4905,19 @@
"ui.edit_sketch_empty": "Aucune esquisse à modifier",
"ui.ellipse": "Ellipse",
"ui.emboss_wrap_note": "Les profils de lignes orthogonales tangents à un cylindre pris en charge s'enroulent automatiquement. Choisir une paroi pour définir une cible.",
"ui.end": "Fin",
"ui.end_radius": "Rayon final",
"ui.end_scale": "Échelle finale",
"ui.ends": "Extrémités",
"ui.entities": "Entités",
"ui.equal": "Égalité",
"ui.equation_end": "Fin",
"ui.equation_explicit": "Explicite",
"ui.equation_form": "Forme",
"ui.equation_note": "La variable est un simple nombre : sin(t) la prend en radians. Un résultat sans unité est dans l'unité de la conception.",
"ui.equation_note_range": "La variable est une longueur, comme sa plage : la combiner avec des paramètres de longueur, et la diviser par une longueur pour sin(). Un résultat sans unité est dans l'unité de la conception.",
"ui.equation_note_range": "La variable est une longueur, comme l'indique son intervalle : combinez-la avec des paramètres de longueur et divisez-la par une longueur pour utiliser sin(). Un résultat sans unité est exprimé dans l'unité de la conception.",
"ui.equation_parametric": "Paramétrique",
"ui.equation_variable_unit": "La variable a l'unité de la plage",
"ui.equation_variable_unit": "La variable utilise l'unité de l'intervalle",
"ui.equation_x_of_t": "x(t)",
"ui.equation_y_of_t": "y(t)",
"ui.equation_y_of_x": "y(x)",
@@ -4653,6 +4928,7 @@
"ui.export_ellipsis_keymap": "Exporter…",
"ui.export_keymap_tip": "Raccourcis, favoris de la boîte S et barre d'outils, dans un fichier",
"ui.extend": "Prolonger",
"ui.extent": "Étendue",
"ui.extent_type": "Type de limite",
"ui.extract_component": "Extraire dans un fichier…",
"ui.extract_design_changed": "La conception a changé pendant le choix du fichier. Relancez Extraire dans un fichier.",
@@ -4661,11 +4937,39 @@
"ui.extrude_auto_to_object": "Extruder jusqu'à une cible choisie",
"ui.extrude_auto_to_object_tip": "Dans Extrusion, avec un profil choisi, choisir une face, un sommet ou un plan parallèle hors de son plan fait passer la limite à Jusqu'à l'objet",
"ui.factor": "Facteur",
"ui.fade": "Atténuation",
"ui.fade_length": "Longueur d'atténuation",
"ui.feature_history": "Historique des fonctions",
"ui.feature_options": "Options de la fonction",
"ui.features": "Fonctions",
"ui.file": "Fichier",
"ui.fillet": "Congé",
"ui.fillet_corner_ball": "Boule",
"ui.fillet_corner_ball_tip": "Une portion de la sphère de la boule de raccordement, tangente (G1) à chaque arrondi.",
"ui.fillet_corner_curvature_tip": "Courbure (G2) : un raccordement lisse. Le coin est reculé le long de chaque arête selon la valeur de retrait ({factor} × le rayon, sauf si vous saisissez une autre valeur), puis rempli par une surface de raccordement, afin que les reflets se prolongent sans cassure.",
"ui.fillet_corner_needs_constant": "Les coins à raccordement lisse (G2) nécessitent un rayon constant et un ajustement exact.",
"ui.fillet_corner_patch": "Raccordement lisse",
"ui.fillet_corner_patch_tip": "Continuité de courbure (G2) : le coin est reculé le long de chaque arête puis rempli par une surface de raccordement, afin que les reflets se prolongent sans cassure.",
"ui.fillet_corner_tangent_tip": "Tangence (G1) : un coin formé par une boule de raccordement, c'est-à-dire une portion de la sphère tangente à chaque arrondi.",
"ui.fillet_error_corner": "Impossible de construire le raccordement lisse à cet endroit. Essayez une autre valeur de retrait ou des coins tangents.",
"ui.fillet_error_failed": "Impossible de créer ce congé sur ces arêtes. Essayez un autre rayon ou arrondissez moins d'arêtes à la fois.",
"ui.fillet_error_setback_short": "Le retrait est trop court pour le raccordement de ce coin : la construction commence à partir de {least}. Essayez un retrait plus long.",
"ui.fillet_error_too_large": "Le rayon est trop grand pour les faces adjacentes à ces arêtes. Essayez un rayon plus petit ou réglez les limites des faces sur le rayon maximal.",
"ui.fillet_fit": "Limites des faces",
"ui.fillet_fit_exact": "Rayon exact",
"ui.fillet_fit_needs_constant": "L'ajustement du rayon nécessite un rayon constant.",
"ui.fillet_fit_reduce": "Rayon maximal",
"ui.fillet_fit_taper": "Rayon réduit localement",
"ui.fillet_fit_tip": "Lorsque le rayon dépasse ce que permettent les faces adjacentes à une arête :\nRayon exact : conserve le rayon demandé, ou ne crée aucun arrondi et indique pourquoi.\nRayon maximal : arrondit chaque arête avec le plus grand rayon compatible.\nRayon réduit localement : conserve le rayon demandé, mais réduit l'arrondi uniquement là où les faces ne le permettent plus.",
"ui.fillet_options_tip": "Chaîne tangente : arrondit également les arêtes qui prolongent régulièrement celles sélectionnées.\nAperçu : affiche le résultat dans la vue pendant la modification.",
"ui.fillet_setback": "Retrait",
"ui.fillet_setback_hint": "{factor} × rayon",
"ui.fillet_setback_least": "Supérieur à {least}",
"ui.fillet_setback_tip": "Position de départ du raccordement lisse : distance mesurée depuis le coin le long de chaque arête. La valeur par défaut est {factor} × le rayon. Elle doit dépasser le retrait minimal, là où les arrondis se rejoignent sans raccordement supplémentaire : le rayon lorsque les faces sont perpendiculaires.",
"ui.fillet_smooth_radius": "Variation progressive du rayon",
"ui.fillet_type_choices_tip": "Rayon constant : un seul rayon sur toute l'arête.\nLongueur de corde : la largeur de l'arrondi reste identique, quel que soit l'angle entre les faces.\nRayon variable : un rayon à chaque extrémité, et d'autres le long de l'arête si vous en ajoutez.\nContinuité de courbure : une section sans cassure des reflets à la jonction avec les faces planes (G2).\nSpline : le rayon le long de l'arête suit les rayons de contrôle que vous définissez.",
"ui.fillet_type_curvature": "Continuité de courbure",
"ui.fillet_type_tip": "Section transversale de l'arête. Continuité de courbure : section à continuité de courbure (G2) entre les faces planes, afin que les reflets passent des faces à l'arrondi sans cassure.",
"ui.filter_commands_or_keys": "Filtrer les commandes ou les touches",
"ui.findInTimeline": "Trouver dans la chronologie",
"ui.findInWindow": "Trouver dans la fenêtre",
@@ -4798,6 +5102,7 @@
"ui.history_sketch_listed_under": "Listé sous {feature}",
"ui.history_title": "Historique",
"ui.history_toggle_names": "Afficher ou masquer les noms des fonctions",
"ui.history_waits_for_editor": "Les commandes Annuler, Rétablir et Historique attendent l'ouverture de l'éditeur de fonction.",
"ui.hole": "Perçage",
"ui.hole_tap_type": "Type de taraudage",
"ui.hole_type": "Type de perçage",
@@ -4815,6 +5120,7 @@
"ui.inspect": "Inspecter",
"ui.instances": "Instances",
"ui.intersect": "Intersection",
"ui.iso_4753": "ISO 4753",
"ui.isolate": "Isoler",
"ui.join": "Joindre",
"ui.joint_play": "▶ Lire",
@@ -4822,14 +5128,14 @@
"ui.joints": "Liaisons",
"ui.keyboard_shortcuts": "Raccourcis clavier",
"ui.language": "Langue",
"ui.lasso_select": "Lasso (faire glisser une boucle libre : prend ce qui est entièrement à l'intérieur)",
"ui.lasso_select": "Lasso (dessinez une boucle à main levée : sélectionne les éléments entièrement à l'intérieur)",
"ui.layout_compact": "Compacte",
"ui.layout_floating": "Flottante",
"ui.length": "Longueur",
"ui.length_decimals": "Décimales des longueurs",
"ui.light": "Clair",
"ui.line": "Ligne",
"ui.line_arc_hint": "Arc tangent : cliquer sur l'extrémité de l'arc. S'arrêter de nouveau sur le dernier point pour revenir aux lignes ; clic droit ou Échap pour terminer",
"ui.line_arc_hint": "Arc tangent : cliquez sur l'extrémité de l'arc. Immobilisez de nouveau le pointeur sur le dernier point pour tracer des lignes ; clic droit ou Échap pour terminer.",
"ui.link_copies": "Lier les copies identiques",
"ui.link_copies_keep": "Conserver",
"ui.link_copies_link": "Lier",
@@ -4919,6 +5225,7 @@
"ui.part_size_needs_a_part": "Sélectionnez une pièce standard insérée (vis, écrou, rondelle ou goupille) pour changer sa taille. Pour agrandir ou réduire un corps, utilisez Échelle.",
"ui.part_size_shared": "Reconstruit la pièce en remplaçant les entités ajoutées. Toutes les occurrences de ce composant sont mises à jour.",
"ui.paste": "Coller",
"ui.patch_continuity_corner_tip": "La surface de raccordement rejoint les faces environnantes avec la continuité choisie le long de chaque côté. À un coin où ces faces se rejoignent avec des courbures différentes, elle reste tangente (G1).",
"ui.path": "Trajectoire",
"ui.pattern_object_type_tip": "Corps : formes pleines, choisies dans la vue ou le Navigateur ; chacun est copié en entier.\nFonctions : étapes de l'Historique, comme une extrusion ou un perçage, choisies dans l'Historique ou sur une face qu'elles ont créée ; l'étape est répétée.\nUne esquisse n'est ni l'un ni l'autre : répétez ses courbes avec la Répétition ou la Symétrie de l'esquisse, ou extrudez-la d'abord.",
"ui.pattern_on_path": "Répétition sur trajectoire",
@@ -5100,6 +5407,8 @@
"ui.sketch_intersect_geometry": "Géométrie",
"ui.sketch_intersect_projection_link": "Lien de projection",
"ui.sketch_intersect_selection_filter": "Filtre de sélection",
"ui.sketch_keys_only": "Désactiver les raccourcis du modèle dans les esquisses",
"ui.sketch_keys_only_tip": "Pendant la modification d'une esquisse, seules les touches propres aux esquisses et celles qui fonctionnent partout sont actives. Une touche du modèle, comme E ou F, n'a aucun effet, évitant ainsi de fermer accidentellement une esquisse complexe.",
"ui.sketch_modifiers": "Modificateurs d’esquisse",
"ui.sketch_project_geometry": "Géométrie",
"ui.sketch_report.all_constrained": "Tout est entièrement contraint.",
@@ -5210,7 +5519,7 @@
"ui.view_angles_roll": "Roulis",
"ui.view_angles_unlock": "Déverrouiller {axis}",
"ui.view_angles_yaw": "Lacet",
"ui.view_angles_zero": "Mettre {axis} à 0°",
"ui.view_angles_zero": "Régler {axis} sur 0°",
"ui.view_centre": "Centre de la vue",
"ui.viewport_status_clear": "Désactiver {name}",
"ui.viewport_status_clear_hint": "Désactiver {name} · Échap",
@@ -5312,7 +5621,7 @@
"web.open_link": "Ouvrir la conception liée ?",
"web.open_link_confirm": "Il y a des modifications non enregistrées. Ouvrir la conception liée dans un nouvel onglet ?",
"↑ ↓ choose · Enter / Tab complete · Esc dismiss": "↑ ↓ choisir · Entrée / Tab compléter · Échap fermer",
"↑ ↓ choose · Enter applies this value": "↑ ↓ choisir · Entrée applique cette valeur",
"↑ ↓ choose · Enter applies this value": "↑ ↓ pour choisir · Entrée pour appliquer cette valeur",
"↑ ↓ choose · Enter applies what you typed · Esc dismiss": "↑ ↓ choisir · Entrée applique la saisie · Échap fermer",
"⌘Enter continues on GitHub.": "⌘Entrée continue sur GitHub."
}
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Crear incidencia…",
"Cross curves": "Curvas transversais",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continúa en GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica actual (1:1 mm)",
"Current perspective view": "Vista en perspectiva actual",
"Current plane": "Plano actual",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Como se ve SolidCraft e onde están as súas partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter as frechas curvas de balanceo",
"prefs.invert_curved_roll_arrows_note": "As dúas frechas curvas da esquina do cubo fan xirar a vista no plano da pantalla. Activado: a frecha en sentido horario xira en sentido antihorario e a frecha en sentido antihorario xira en sentido horario. Desactivado: cada frecha xira a vista no sentido en que se curva.",
"prefs.invert_navigator_arrows": "Invertir as frechas de rotación do cubo de vistas",
"prefs.invert_navigator_arrows_note": "As frechas arredor do cubo fan orbitar a cámara na dirección na que apuntan, como en Fusion e Inventor: a frecha da esquerda apunta á dereita e move a cámara cara á dereita. Desactivado: unha frecha xira o cubo cara ao lado no que está, así que a frecha da esquerda move a cámara cara á esquerda. As frechas curvas de balanceo non se ven afectadas.",
"prefs.keep_work_on_tab_switch": "Manter abertos os diálogos e as ferramentas ao cambiar de deseño",
"prefs.keep_work_on_tab_switch_note": "Cada lapela de deseño conserva o seu diálogo ou ferramenta aberto, co que escolliches e escribiches nel, e a súa lapela da barra de ferramentas. Volven estar aí cando regresas ao deseño. Desactivado: cambiar de deseño cancélaos e mostra a lapela Modelo.",
"prefs.labels": "Etiquetas",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navegación",
"prefs.navigation_note": "Como moven a vista o rato, o panel táctil e o rato 3D.",
"prefs.navigator_fit": "Axustar o modelo despois dun cambio de vista do navegador",
"prefs.navigator_fit_note": "Unha cara, esquina ou frecha do cubo de vistas, ou un eixe do gizmo, tamén mira ao centro do modelo desde a única distancia que o abarca por todos os lados (a súa esfera delimitadora). Inicio usa o mesmo zoom e centro mentres isto está activado, así que as vistas escollidas despois só xiran. Desactivado: a vista xira no sitio, conservando o seu punto de mira e o seu zoom.",
"prefs.network_host_remove": "Quitar",
"prefs.network_locations": "Permitir ubicacións de rede nos deseños",
"prefs.network_locations_note": "Desactivado: os ficheiros ligados dun deseño que están noutro ordenador (\\\\server\\share) só se abren desde os servidores listados aquí, ou despois de que permitas un cando se che pregunte.",
+6 -4
View File
@@ -193,6 +193,7 @@
"Create Issue…": "יצירת דיווח…",
"Cross curves": "עקומות חוצות",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter ממשיך ב־GitHub.",
"Cube": "קובייה",
"Current orthographic view (1:1 mm)": "התצוגה האורתוגרפית הנוכחית (1:1 mm)",
"Current perspective view": "תצוגת הפרספקטיבה הנוכחית",
"Current plane": "המישור הנוכחי",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "איך SolidCraft נראה והיכן חלקיו ממוקמים.",
"prefs.interval_minutes": "{n} דק׳",
"prefs.invert_curved_roll_arrows": "היפוך חצי הגלילה המעוגלים",
"prefs.invert_curved_roll_arrows_note": "שני החצים המעוגלים בפינת הנווט מסובבים את התצוגה במישור המסך. פועל: החץ עם כיוון השעון מסובב נגד כיוון השעון, והחץ נגד כיוון השעון מסובב עם כיוון השעון. כבוי: כל חץ מסובב את התצוגה לפי העקום שלו.",
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב הנווט",
"prefs.invert_navigator_arrows_note": "החצים סביב הנווט מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את התצוגה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
"prefs.invert_curved_roll_arrows_note": "שני החצים המעוגלים בפינת הקובייה מסובבים את התצוגה במישור המסך. פועל: החץ עם כיוון השעון מסובב נגד כיוון השעון, והחץ נגד כיוון השעון מסובב עם כיוון השעון. כבוי: כל חץ מסובב את התצוגה לפי העקום שלו.",
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב קוביית התצוגה",
"prefs.invert_navigator_arrows_note": "החצים סביב הקובייה מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את הקובייה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
"prefs.keep_unsaved_also_asks": "לשאול גם כשהכרטיסייה נסגרת",
"prefs.keep_unsaved_also_asks_tip": "כשאפשרות זו כבויה, הכרטיסייה נסגרת ללא חלון הדפדפן לאחר שהעותק של כל תכן שלא נשמר עודכן.",
"prefs.keep_unsaved_in_browser": "לשמור עבודה שלא נשמרה בדפדפן זה",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "כבוי: בזמן שחצי ההזזה גוררים רכיב, דבר אינו מודגש מתחת לסמן, וכך מכלולים גדולים נשארים חלקים. כשמוצג חתך או ניתוח ההדגשה נשארת, וחלק שנגרר לאורך המפרקים שלו לעולם אינו מדגיש.",
"prefs.navigation": "ניווט",
"prefs.navigation.axes_signed": "צירים",
"prefs.navigation.cube_compact": "קובייה",
"prefs.navigation.device": "התקן",
"prefs.navigation.free": "חופשי",
"prefs.navigation.orbit_style": "סגנון סיבוב",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "שולחן מסתובב",
"prefs.navigation_note": "איך העכבר, משטח המגע והעכבר התלת־ממדי מזיזים את המבט.",
"prefs.navigator_fit": "התאמת המודל לאחר שינוי תצוגה בניווט התצוגה",
"prefs.navigator_fit_note": "לחיצה על פאה, פינה או חץ בנווט, או על ציר בגיזמו, גם מביטה אל מרכז המודל מהמרחק האחד שמכיל אותו מכל צד (הכדור החוסם שלו). תצוגת בית משתמשת באותו זום ובאותו מרכז כל עוד זה פעיל, כך שתצוגות שנבחרות אחריה רק מסתובבות. כבוי: התצוגה מסתובבת במקומה ושומרת על היעד ועל הזום.",
"prefs.navigator_fit_note": "לחיצה על פאה, פינה או חץ בקובייה, או על ציר בגיזמו, גם מביטה אל מרכז המודל מהמרחק האחד שמכיל אותו מכל צד (הכדור החוסם שלו). תצוגת בית משתמשת באותו זום ובאותו מרכז כל עוד זה פעיל, כך שתצוגות שנבחרות אחריה רק מסתובבות. כבוי: התצוגה מסתובבת במקומה ושומרת על היעד ועל הזום.",
"prefs.network_host_remove": "הסרה",
"prefs.network_locations": "התרת מיקומי רשת בתכנים",
"prefs.network_locations_note": "לארגונים השומרים תכנונים בשרתי קבצים. כשהאפשרות כבויה: רק שרתים שאישרתם.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Prijavi problem…",
"Cross curves": "Krivulje presjeka",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter nastavlja na GitHubu.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Trenutni ortografski prikaz (1:1 mm)",
"Current perspective view": "Trenutni perspektivni prikaz",
"Current plane": "Trenutna ravnina",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Kako SolidCraft izgleda i gdje su njegovi dijelovi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Obrni zakrivljene strelice za valjanje",
"prefs.invert_curved_roll_arrows_note": "Dvije zakrivljene strelice u kutu kocke valjaju prikaz unutar ravnine zaslona. Uključeno: strelica u smjeru kazaljke na satu valja prikaz suprotno od smjera kazaljke na satu, a strelica suprotno od smjera kazaljke na satu valja ga u smjeru kazaljke na satu. Isključeno: svaka strelica valja prikaz onako kako je zakrivljena.",
"prefs.invert_navigator_arrows": "Obrni strelice za rotaciju kocke prikaza",
"prefs.invert_navigator_arrows_note": "Strelice oko kocke orbitiraju kameru u smjeru u kojem pokazuju, kao u programima Fusion i Inventor: strelica s lijeve strane pokazuje udesno i zakreće kameru udesno. Isključeno: strelica okreće kocku prema strani na kojoj se nalazi, pa lijeva strelica zakreće kameru ulijevo. Postavka ne utječe na zakrivljene strelice za valjanje.",
"prefs.keep_work_on_tab_switch": "Zadrži dijaloge i alate otvorenima pri prebacivanju između dizajna",
"prefs.keep_work_on_tab_switch_note": "Svaka kartica dizajna zadržava svoj otvoreni dijalog ili alat, s onim što ste u njemu odabrali i upisali, te svoju karticu alatne trake. Kad se vratite na dizajn, ponovno su tu. Isključeno: prebacivanje između dizajna poništava ih i prikazuje karticu Model.",
"prefs.labels": "Oznake",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigacija",
"prefs.navigation_note": "Kako miš, dodirna pločica i 3D miš pomiču prikaz.",
"prefs.navigator_fit": "Uklopi model nakon promjene prikaza u navigatoru",
"prefs.navigator_fit_note": "Lice, kut ili strelica kocke prikaza, odnosno os orijentacijskog gizma, također usmjerava pogled na sredinu modela s jedne udaljenosti na kojoj se uklapa iz svakog smjera (njegova granična sfera). Početni prikaz koristi isti zum i središte dok je ova opcija uključena, pa se prikazi koje odaberete poslije njega samo okreću. Isključeno: prikaz se okreće na mjestu i zadržava svoj cilj i zum.",
"prefs.network_host_remove": "Ukloni",
"prefs.network_locations": "Dopusti mrežne lokacije u dizajnima",
"prefs.network_locations_note": "Isključeno: povezane datoteke dizajna na drugom računalu (\\\\server\\share) otvaraju se samo s poslužitelja navedenih ovdje ili nakon što ga dopustite kad se to zatraži.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Hibajegy létrehozása…",
"Cross curves": "Keresztgörbék",
"Ctrl+Enter continues on GitHub.": "A Ctrl+Enter a GitHubon folytatja.",
"Cube": "Kocka",
"Current orthographic view (1:1 mm)": "Aktuális ortografikus nézet (1:1 mm)",
"Current perspective view": "Aktuális perspektivikus nézet",
"Current plane": "Aktuális sík",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "A SolidCraft megjelenése és elemeinek elhelyezése.",
"prefs.interval_minutes": "{n} perc",
"prefs.invert_curved_roll_arrows": "Az íves gördülőnyilak megfordítása",
"prefs.invert_curved_roll_arrows_note": "A nézetkocka sarkában lévő két íves nyíl a nézetet a képernyő síkjában gördíti. Be: az óramutató járásával megegyező nyíl ellentétes irányba gördít, az ellentétes nyíl pedig az óramutató járásával megegyező irányba. Ki: minden nyíl abba az irányba gördíti a nézetet, amerre ível.",
"prefs.invert_navigator_arrows": "A nézetkocka forgatónyilainak megfordítása",
"prefs.invert_navigator_arrows_note": "A kocka körüli nyilak úgy keringetik a kamerát, ahogy mutatnak, mint a Fusion és az Inventor esetében: a bal oldali nyíl jobbra mutat, és a kamerát jobbra lendíti. Ki: a nyíl a kockát afelé az oldal felé forgatja, amelyiken van, így a bal nyíl a kamerát balra lendíti. Az íves gördülőnyilakat ez nem érinti.",
"prefs.keep_work_on_tab_switch": "A párbeszédablakok és eszközök nyitva tartása tervek közötti váltáskor",
"prefs.keep_work_on_tab_switch_note": "Minden tervfül megtartja a nyitott párbeszédablakát vagy eszközét azzal együtt, amit kijelölt és beírt benne, valamint a menüszalag-fülét. A tervhez visszatérve újra ott vannak. Ki: a tervek közötti váltás megszakítja őket, és a Modell fület mutatja.",
"prefs.labels": "Feliratok",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigáció",
"prefs.navigation_note": "Hogyan mozgatja a nézetet az egér, az érintőpad és a 3D-egér.",
"prefs.navigator_fit": "A modell illesztése navigátornézet-váltás után",
"prefs.navigator_fit_note": "A nézetkocka egy lapja, sarka vagy nyila, illetve a gizmo egy tengelye a modell közepére is ránéz abból az egyetlen távolságból, amelyből minden oldalról belefér (a határoló gömbje). Amíg ez be van kapcsolva, a Kezdőnézet ugyanazt a nagyítást és középpontot használja, így az utána választott nézetek csak elfordulnak. Ki: a nézet a helyén fordul el, megtartva a célpontját és a nagyítását.",
"prefs.network_host_remove": "Eltávolítás",
"prefs.network_locations": "Hálózati helyek engedélyezése a tervekben",
"prefs.network_locations_note": "Ki: egy terv másik számítógépen lévő hivatkozott fájljai (\\\\server\\share) csak az itt felsorolt kiszolgálókról nyílnak meg, vagy miután kérdésre engedélyez egyet.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Buat Issue…",
"Cross curves": "Kurva silang",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter melanjutkan di GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Tampilan ortografis saat ini (1:1 mm)",
"Current perspective view": "Tampilan perspektif saat ini",
"Current plane": "Bidang saat ini",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Tampilan SolidCraft dan letak bagian-bagiannya.",
"prefs.interval_minutes": "{n} mnt",
"prefs.invert_curved_roll_arrows": "Balikkan panah roll melengkung",
"prefs.invert_curved_roll_arrows_note": "Dua panah melengkung di sudut kubus memutar (roll) tampilan di dalam bidang layar. Aktif: panah searah jarum jam memutar berlawanan arah jarum jam dan panah berlawanan arah jarum jam memutar searah jarum jam. Mati: tiap panah memutar tampilan sesuai arah lengkungannya.",
"prefs.invert_navigator_arrows": "Balikkan panah rotasi kubus tampilan",
"prefs.invert_navigator_arrows_note": "Panah di sekeliling kubus memutar orbit kamera ke arah yang ditunjuknya, seperti di Fusion dan Inventor: panah di kiri menunjuk ke kanan dan mengayunkan kamera ke kanan. Mati: panah memutar kubus ke sisi tempatnya berada, sehingga panah kiri mengayunkan kamera ke kiri. Panah roll yang melengkung tidak terpengaruh.",
"prefs.keep_work_on_tab_switch": "Biarkan dialog dan alat tetap terbuka saat berpindah desain",
"prefs.keep_work_on_tab_switch_note": "Setiap tab desain mempertahankan dialog atau alat yang terbuka, beserta apa yang Anda pilih dan ketik di dalamnya, dan tab toolbar-nya. Semuanya kembali saat Anda kembali ke desain itu. Mati: berpindah desain membatalkannya dan menampilkan tab Model.",
"prefs.labels": "Label",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasi",
"prefs.navigation_note": "Cara mouse, trackpad, dan mouse 3D menggerakkan tampilan.",
"prefs.navigator_fit": "Buat model pas di tampilan setelah perubahan tampilan lewat navigator",
"prefs.navigator_fit_note": "Sebuah muka, sudut, atau panah pada kubus tampilan, atau sumbu pada gizmo, juga menghadap ke tengah model dari satu jarak yang membuatnya pas dari segala sisi (bola pembatasnya). Awal memakai zoom dan pusat yang sama selama opsi ini aktif, sehingga tampilan yang dipilih setelahnya hanya berputar. Mati: tampilan berputar di tempat, dengan target dan zoom tetap.",
"prefs.network_host_remove": "Hapus",
"prefs.network_locations": "Izinkan lokasi jaringan di desain",
"prefs.network_locations_note": "Nonaktif: file tertaut sebuah desain di komputer lain (\\\\server\\share) hanya dibuka dari server yang tercantum di sini, atau setelah Anda mengizinkan salah satunya saat ditanya.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Crea segnalazione…",
"Cross curves": "Curve trasversali",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continua su GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortografica corrente (1:1 mm)",
"Current perspective view": "Vista prospettica corrente",
"Current plane": "Piano corrente",
@@ -2682,6 +2683,9 @@
"prefs.interface_note": "Aspetto di SolidCraft e disposizione dei suoi elementi.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverti le frecce curve di rollio",
"prefs.invert_curved_roll_arrows_note": "Le due frecce curve all'angolo del cubo fanno ruotare la vista nel piano dello schermo. Attivato: la freccia oraria ruota in senso antiorario e la freccia antioraria ruota in senso orario. Disattivato: ogni freccia ruota la vista nel verso in cui si curva.",
"prefs.invert_navigator_arrows": "Inverti le frecce di rotazione del cubo della vista",
"prefs.invert_navigator_arrows_note": "Le frecce attorno al cubo fanno orbitare la camera nella direzione in cui puntano, come in Fusion e Inventor: la freccia a sinistra punta a destra e sposta la camera a destra. Disattivato: una freccia ruota il cubo verso il lato in cui si trova, quindi la freccia sinistra sposta la camera a sinistra. Le frecce curve di rollio non sono interessate.",
"prefs.keep_unsaved_also_asks": "Chiedi comunque alla chiusura della scheda",
"prefs.keep_unsaved_also_asks_tip": "Se disattivato, la scheda si chiude senza la finestra del browser quando la copia di ogni progetto non salvato è aggiornata.",
"prefs.keep_unsaved_in_browser": "Conserva il lavoro non salvato in questo browser",
@@ -2741,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Disattivato: mentre le frecce di Sposta trascinano un componente, niente sotto il puntatore viene evidenziato, così i grandi assiemi restano fluidi. Con una sezione o un'analisi visibile viene evidenziato comunque, e un pezzo trascinato lungo i suoi giunti non lo evidenzia mai.",
"prefs.navigation": "Navigazione",
"prefs.navigation.axes_signed": "Assi",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Libera",
"prefs.navigation.orbit_style": "Stile di orbita",
@@ -2748,6 +2753,7 @@
"prefs.navigation.turntable": "Piatto girevole",
"prefs.navigation_note": "Come mouse, trackpad e mouse 3D spostano la vista.",
"prefs.navigator_fit": "Adatta il modello dopo un cambio di vista dal navigatore",
"prefs.navigator_fit_note": "Una faccia, un angolo o una freccia del cubo della vista, o un asse del gizmo, guarda anche il centro del modello dall'unica distanza che lo inquadra da ogni lato (la sua sfera di ingombro). Inizio usa lo stesso zoom e lo stesso centro finché questa opzione è attiva, quindi le viste scelte dopo si limitano a ruotare. Disattivato: la vista ruota sul posto, mantenendo punto di mira e zoom.",
"prefs.network_host_remove": "Rimuovi",
"prefs.network_locations": "Consenti posizioni di rete nei progetti",
"prefs.network_locations_note": "Disattivato: i file collegati di un progetto su un altro computer (\\\\server\\share) vengono aperti solo dai server elencati qui, o dopo che ne consenti uno quando richiesto.",
+7 -5
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Issueを作成…",
"Cross curves": "交差する曲線",
"Ctrl+Enter continues on GitHub.": "Ctrl+EnterでGitHubに進みます。",
"Cube": "キューブ",
"Current orthographic view (1:1 mm)": "現在の平行投影(実寸・mm)",
"Current perspective view": "現在の透視投影",
"Current plane": "現在の平面",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "SolidCraft の外観と各パネルの配置。",
"prefs.interval_minutes": "{n} 分",
"prefs.invert_curved_roll_arrows": "カーブしたロール矢印を反転",
"prefs.invert_curved_roll_arrows_note": "ナビゲーターの隅にある2つのカーブした矢印は、画面内でビューをロールします。オン: 時計回りの矢印が反時計回りに、反時計回りの矢印が時計回りにロールします。オフ: 各矢印は、そのカーブの向きにビューをロールします。",
"prefs.invert_navigator_arrows": "ナビゲーターの回転矢印を反転",
"prefs.invert_navigator_arrows_note": "ナビゲーターの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、その側へビューを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
"prefs.invert_curved_roll_arrows_note": "キューブの隅にある2つのカーブした矢印は、画面内でビューをロールします。オン: 時計回りの矢印が反時計回りに、反時計回りの矢印が時計回りにロールします。オフ: 各矢印は、そのカーブの向きにビューをロールします。",
"prefs.invert_navigator_arrows": "ビューキューブの回転矢印を反転",
"prefs.invert_navigator_arrows_note": "キューブの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、そのある面の方へキューブを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
"prefs.keep_unsaved_also_asks": "タブを閉じるときにも確認する",
"prefs.keep_unsaved_also_asks_tip": "オフにすると、未保存の各デザインのコピーが最新であれば、ブラウザーの確認なしでタブが閉じます。",
"prefs.keep_unsaved_in_browser": "未保存の作業をこのブラウザーに保持する",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "オフ: 移動の矢印でコンポーネントをドラッグしている間はポインターの下をハイライトしないため、大きなアセンブリでも滑らかに動きます。断面や解析を表示中は通常どおりハイライトし、ジョイントに沿ってドラッグする部品ではハイライトしません。",
"prefs.navigation": "ナビゲーション",
"prefs.navigation.axes_signed": "軸",
"prefs.navigation.cube_compact": "キューブ",
"prefs.navigation.device": "デバイス",
"prefs.navigation.free": "自由",
"prefs.navigation.orbit_style": "回転方式",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "ターンテーブル",
"prefs.navigation_note": "マウス、トラックパッド、3Dマウスによるビューの操作。",
"prefs.navigator_fit": "ナビゲーターでの視点変更後にモデルを全体表示",
"prefs.navigator_fit_note": "ナビゲーターの面・角・矢印やギズモの軸をクリックすると、どの方向からでも全体が収まる一定の距離(外接球)からモデルの中心を見ます。オンの間はホームビューも同じズームと中心を使うため、その後に選んだ視点は向きだけが変わります。オフ: 視点はその場で回転し、注視点とズームを保ちます。",
"prefs.navigator_fit_note": "キューブの面・角・矢印やギズモの軸をクリックすると、どの方向からでも全体が収まる一定の距離(外接球)からモデルの中心を見ます。オンの間はホームビューも同じズームと中心を使うため、その後に選んだ視点は向きだけが変わります。オフ: 視点はその場で回転し、注視点とズームを保ちます。",
"prefs.network_host_remove": "削除",
"prefs.network_locations": "デザイン内のネットワーク上の場所を許可",
"prefs.network_locations_note": "ファイルサーバーでデザインを管理する組織向け。オフの場合は許可したサーバーのみ。",
@@ -5039,7 +5041,7 @@
"ui.agent_chat_permission": "エージェントが実行の許可を求めています: {title}",
"ui.agent_chat_pick": "エージェント",
"ui.agent_chat_pick_context": "コンテキストを選ぶ",
"ui.agent_chat_pick_context_tip": "エージェントに見てほしい面、エッジ、フィーチャ、ボディをモデルから選び、OK を押します",
"ui.agent_chat_pick_context_tip": "モデルの面、エッジ、フィーチャ、ボディを選んで OK を押すと、カーソルの位置にピルとしてメッセージに入ります(@ を入力しても同じです)",
"ui.agent_chat_placeholder": "デザインの変更をエージェントに依頼…",
"ui.agent_chat_placeholder_busy": "エージェントの作業が終わったら送るメッセージを入力(Ctrl+Enter: 今すぐ送信)",
"ui.agent_chat_pop_out": "独立したウィンドウで開く(別の画面に移動できます)",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "შეტყობინების შექმნა…",
"Cross curves": "განივი მრუდები",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter-ით GitHub-ზე გააგრძელებთ.",
"Cube": "კუბი",
"Current orthographic view (1:1 mm)": "მიმდინარე ორთოგრაფიული ხედი (1:1 mm)",
"Current perspective view": "მიმდინარე პერსპექტიული ხედი",
"Current plane": "მიმდინარე სიბრტყე",
@@ -2315,6 +2316,9 @@
"prefs.interface_note": "როგორ გამოიყურება SolidCraft და სად არის მისი ნაწილები.",
"prefs.interval_minutes": "{n} წთ",
"prefs.invert_curved_roll_arrows": "გორების მრუდე ისრების შებრუნება",
"prefs.invert_curved_roll_arrows_note": "კუბის კუთხესთან მდებარე ორი მრუდე ისარი ხედს ეკრანის სიბრტყეში აგორებს. ჩართული: საათის ისრის მიმართულების ისარი საათის ისრის საწინააღმდეგოდ აგორებს, საწინააღმდეგო კი — საათის ისრის მიმართულებით. გამორთული: თითოეული ისარი ხედს თავისი მოხრის მიმართულებით აგორებს.",
"prefs.invert_navigator_arrows": "ხედის კუბის ბრუნვის ისრების შებრუნება",
"prefs.invert_navigator_arrows_note": "კუბის გარშემო ისრები კამერას ორბიტაზე იმ მიმართულებით ატრიალებს, საითაც მიუთითებს, როგორც Fusion-სა და Inventor-ში: მარცხენა ისარი მარჯვნივ მიუთითებს და კამერას მარჯვნივ აბრუნებს. გამორთული: ისარი კუბს იმ მხრისკენ აბრუნებს, რომელზეც მდებარეობს, ამიტომ მარცხენა ისარი კამერას მარცხნივ აბრუნებს. გორების მრუდე ისრებზე ეს არ მოქმედებს.",
"prefs.keep_work_on_tab_switch": "პროექტებს შორის გადართვისას დიალოგებისა და ხელსაწყოების ღიად დატოვება",
"prefs.keep_work_on_tab_switch_note": "პროექტის თითოეული ჩანართი ინარჩუნებს თავის ღია დიალოგს ან ხელსაწყოს, მასში არჩეულსა და აკრეფილს, და ხელსაწყოთა ზოლის ჩანართს. პროექტში დაბრუნებისას ისინი ისევ იქ დაგხვდებათ. გამორთული: პროექტების გადართვა მათ აუქმებს და „მოდელის“ ჩანართს აჩვენებს.",
"prefs.labels": "წარწერები",
@@ -2351,6 +2355,7 @@
"prefs.navigation": "ნავიგაცია",
"prefs.navigation_note": "როგორ ამოძრავებს ხედს მაუსი, სენსორული პანელი და 3D მაუსი.",
"prefs.navigator_fit": "ნავიგატორით ხედის შეცვლის შემდეგ მოდელის ჩატევა",
"prefs.navigator_fit_note": "ხედის კუბის წახნაგი, კუთხე ან ისარი, ან მანიპულატორის ღერძი ასევე მოდელის შუაგულს უყურებს ერთი მანძილიდან, საიდანაც ის ყველა მხრიდან ეტევა (მისი შემომსაზღვრელი სფერო). სანამ ეს ჩართულია, საწყისი ხედი იმავე მასშტაბსა და ცენტრს იყენებს, ამიტომ მის შემდეგ არჩეული ხედები მხოლოდ ბრუნავს. გამორთული: ხედი ადგილზე ბრუნავს, სამიზნისა და მასშტაბის შენარჩუნებით.",
"prefs.network_host_remove": "წაშლა",
"prefs.network_locations": "პროექტებში ქსელური მდებარეობების დაშვება",
"prefs.network_locations_note": "ორგანიზაციებისთვის, რომლებიც პროექტებს ფაილურ სერვერებზე ინახავენ. გამორთული: მხოლოდ თქვენ მიერ დაშვებული სერვერები.",
+3
View File
@@ -151,6 +151,7 @@
"Create Issue — review draft": "이슈 만들기 — 초안 검토",
"Create Issue…": "이슈 만들기…",
"Cross curves": "교차 곡선",
"Cube": "큐브",
"Current orthographic view (1:1 mm)": "현재 직교 투영 뷰 (1:1 mm)",
"Current perspective view": "현재 원근 투영 뷰",
"Current plane": "현재 평면",
@@ -2082,6 +2083,7 @@
"prefs.move_drag_highlights_tip": "끄면 이동 화살표로 구성 요소를 끄는 동안 포인터 아래 항목을 강조 표시하지 않아 큰 어셈블리도 부드럽게 움직입니다. 단면이나 해석이 표시된 동안에는 그대로 강조 표시하며, 조인트를 따라 끄는 부품은 강조 표시하지 않습니다.",
"prefs.navigation": "탐색",
"prefs.navigation.axes_signed": "축",
"prefs.navigation.cube_compact": "큐브",
"prefs.navigation.device": "장치",
"prefs.navigation.free": "자유",
"prefs.navigation.orbit_style": "회전 방식",
@@ -2089,6 +2091,7 @@
"prefs.navigation.turntable": "턴테이블",
"prefs.navigation_note": "마우스, 트랙패드, 3D 마우스로 뷰를 움직이는 방식입니다.",
"prefs.navigator_fit": "뷰 탐색기로 뷰를 바꾼 뒤 모델 맞춤",
"prefs.navigator_fit_note": "큐브의 면, 모서리, 화살표나 기즈모의 축을 클릭하면 어느 방향에서든 전체가 들어가는 한 거리(경계 구)에서 모델의 중심을 바라봅니다. 켜져 있는 동안 홈 뷰도 같은 확대/축소와 중심을 쓰므로 그 뒤에 고른 뷰는 방향만 바뀝니다. 끄면 뷰가 제자리에서 회전하며 대상과 확대/축소를 유지합니다.",
"prefs.network_locations_note": "파일 서버에 디자인을 보관하는 조직용입니다. 끄면 허용한 서버만 사용합니다.",
"prefs.not_on_gpu": "이 GPU에서는 사용할 수 없음",
"prefs.on": "켜짐",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Izveidot ziņojumu…",
"Cross curves": "Šķērslīknes",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter turpina GitHub vietnē.",
"Cube": "Kubs",
"Current orthographic view (1:1 mm)": "Pašreizējais ortogrāfiskais skats (1:1 mm)",
"Current perspective view": "Pašreizējais perspektīvas skats",
"Current plane": "Pašreizējā plakne",
@@ -2682,6 +2683,9 @@
"prefs.interface_note": "Kā izskatās SolidCraft un kur atrodas tā daļas.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Apgriezt izliektās griešanas bultas",
"prefs.invert_curved_roll_arrows_note": "Divas izliektās bultas kuba stūrī griež skatu ekrāna plaknē. Ieslēgts: pulksteņrādītāja virziena bulta griež pretēji pulksteņrādītājam, bet pretējā virziena bulta griež pulksteņrādītāja virzienā. Izslēgts: katra bulta griež skatu tā, kā tā ir izliekta.",
"prefs.invert_navigator_arrows": "Apgriezt skata kuba rotācijas bultas",
"prefs.invert_navigator_arrows_note": "Bultas ap kubu orbitē kameru tajā virzienā, kurp tās norāda, kā Fusion un Inventor: kreisā bulta norāda pa labi un pagriež kameru pa labi. Izslēgts: bulta pagriež kubu uz to pusi, kurā tā atrodas, tāpēc kreisā bulta pagriež kameru pa kreisi. Izliektās griešanas bultas netiek ietekmētas.",
"prefs.keep_unsaved_also_asks": "Tomēr jautāt, kad cilne tiek aizvērta",
"prefs.keep_unsaved_also_asks_tip": "Ja šis ir izslēgts, cilne aizveras bez pārlūka dialoga, tiklīdz katra nesaglabātā modeļa kopija ir aktuāla.",
"prefs.keep_unsaved_in_browser": "Glabāt nesaglabāto darbu šajā pārlūkā",
@@ -2741,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Izslēgts: kamēr Pārvietot bultiņas velk komponenti, nekas zem kursora netiek izcelts, tāpēc lielas montāžas darbojas raiti. Ja tiek rādīts šķērsgriezums vai analīze, izcelšana notiek tik un tā, bet, velkot detaļu pa tās savienojumiem, tā nenotiek nekad.",
"prefs.navigation": "Navigācija",
"prefs.navigation.axes_signed": "Asis",
"prefs.navigation.cube_compact": "Kubs",
"prefs.navigation.device": "Ierīce",
"prefs.navigation.free": "Brīvs",
"prefs.navigation.orbit_style": "Orbitēšanas stils",
@@ -2748,6 +2753,7 @@
"prefs.navigation.turntable": "Grozāmgalds",
"prefs.navigation_note": "Kā pele, skārienpaliktnis un 3D pele pārvieto skatu.",
"prefs.navigator_fit": "Ietilpināt modeli pēc navigatora skata maiņas",
"prefs.navigator_fit_note": "Skata kuba skaldne, stūris vai bulta vai gizmo ass arī vērš skatu uz modeļa vidu no tāda attāluma, kas to ietilpina no jebkuras puses (tā aptverošā sfēra). Kamēr šis ir ieslēgts, Sākums izmanto to pašu tālummaiņu un centru, tāpēc pēc tam izvēlētie skati tikai pagriežas. Izslēgts: skats pagriežas uz vietas, saglabājot savu mērķi un tālummaiņu.",
"prefs.network_host_remove": "Noņemt",
"prefs.network_locations": "Atļaut tīkla atrašanās vietas modeļos",
"prefs.network_locations_note": "Organizācijām, kas glabā modeļus failu serveros. Izslēgts: tikai jūsu atļautie serveri.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Cipta Isu…",
"Cross curves": "Lengkung silang",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter meneruskan di GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Pandangan ortografik semasa (1:1 mm)",
"Current perspective view": "Pandangan perspektif semasa",
"Current plane": "Satah semasa",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Rupa SolidCraft dan kedudukan bahagiannya.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Songsangkan anak panah gelek melengkung",
"prefs.invert_curved_roll_arrows_note": "Dua anak panah melengkung di sudut kubus menggelek pandangan dalam satah skrin. Hidup: anak panah ikut arah jam menggelek lawan arah jam dan anak panah lawan arah jam menggelek ikut arah jam. Mati: setiap anak panah menggelek pandangan mengikut arah lengkungannya.",
"prefs.invert_navigator_arrows": "Songsangkan anak panah putaran kubus pandangan",
"prefs.invert_navigator_arrows_note": "Anak panah di sekeliling kubus mengorbit kamera mengikut arah yang ditunjuknya, seperti dalam Fusion dan Inventor: anak panah di kiri menunjuk ke kanan dan mengayunkan kamera ke kanan. Mati: anak panah memutarkan kubus ke arah sisi tempat ia berada, jadi anak panah kiri mengayunkan kamera ke kiri. Anak panah gelek yang melengkung tidak terjejas.",
"prefs.keep_work_on_tab_switch": "Kekalkan dialog dan alat terbuka apabila menukar reka bentuk",
"prefs.keep_work_on_tab_switch_note": "Setiap tab reka bentuk mengekalkan dialog atau alat yang dibukanya, bersama apa yang anda pilih dan taip di dalamnya, serta tab bar alatnya. Semuanya ada semula apabila anda kembali ke reka bentuk itu. Mati: menukar reka bentuk membatalkannya dan menunjukkan tab Model.",
"prefs.labels": "Label",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasi",
"prefs.navigation_note": "Cara tetikus, pad jejak dan tetikus 3D menggerakkan pandangan.",
"prefs.navigator_fit": "Muatkan model selepas perubahan pandangan navigator",
"prefs.navigator_fit_note": "Muka, sudut atau anak panah pada kubus pandangan, atau paksi pada gizmo, turut menghadap ke tengah model dari satu jarak yang memuatkannya dari semua sisi (sfera pembatasnya). Utama menggunakan zum dan pusat yang sama selagi ini dihidupkan, jadi pandangan yang dipilih selepasnya hanya berputar. Mati: pandangan berputar di tempat, dengan sasaran dan zumnya kekal.",
"prefs.network_host_remove": "Buang",
"prefs.network_locations": "Benarkan lokasi rangkaian dalam reka bentuk",
"prefs.network_locations_note": "Dimatikan: fail terpaut bagi reka bentuk pada komputer lain (\\\\server\\share) hanya dibuka daripada pelayan yang disenaraikan di sini, atau selepas anda membenarkannya apabila ditanya.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Opprett sak…",
"Cross curves": "Tverrkurver",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsetter på GitHub.",
"Cube": "Kube",
"Current orthographic view (1:1 mm)": "Gjeldende ortografisk visning (1:1 mm)",
"Current perspective view": "Gjeldende perspektivvisning",
"Current plane": "Gjeldende plan",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Hvordan SolidCraft ser ut, og hvor delene er plassert.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter de krumme rullepilene",
"prefs.invert_curved_roll_arrows_note": "De to krumme pilene i hjørnet av kuben ruller visningen i skjermplanet. På: pilen med klokken ruller mot klokken, og pilen mot klokken ruller med klokken. Av: hver pil ruller visningen i den retningen den krummer seg.",
"prefs.invert_navigator_arrows": "Inverter rotasjonspilene på visningskuben",
"prefs.invert_navigator_arrows_note": "Pilene rundt kuben roterer kameraet i den retningen de peker, som i Fusion og Inventor: pilen til venstre peker mot høyre og svinger kameraet mot høyre. Av: en pil roterer kuben mot siden den står på, så venstre pil svinger kameraet mot venstre. De krumme rullepilene påvirkes ikke.",
"prefs.keep_work_on_tab_switch": "Behold dialoger og verktøy åpne når du bytter design",
"prefs.keep_work_on_tab_switch_note": "Hver designfane beholder sin åpne dialog eller sitt åpne verktøy, med det du har valgt og skrevet i den, og sin fane på båndet. De er der igjen når du kommer tilbake til designet. Av: å bytte design avbryter dem og viser fanen Modell.",
"prefs.labels": "Etiketter",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigasjon",
"prefs.navigation_note": "Hvordan mus, styreflate og 3D-mus beveger visningen.",
"prefs.navigator_fit": "Tilpass modellen etter en visningsendring fra navigatoren",
"prefs.navigator_fit_note": "En flate, et hjørne eller en pil på visningskuben, eller en akse på orienteringsindikatoren, ser også mot midten av modellen fra den ene avstanden som får den til å passe fra alle sider (den omsluttende kulen). Hjem bruker samme zoom og senter mens dette er på, så visninger som velges etterpå bare dreier. Av: visningen dreier på stedet og beholder målpunktet og zoomen sin.",
"prefs.network_host_remove": "Fjern",
"prefs.network_locations": "Tillat nettverksplasseringer i design",
"prefs.network_locations_note": "Av: lenkede filer i et design på en annen datamaskin (\\\\server\\share) åpnes bare fra serverne som er oppført her, eller etter at du har tillatt en når du blir spurt.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Issue aanmaken…",
"Cross curves": "Kruiscurven",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter gaat verder op GitHub.",
"Cube": "Kubus",
"Current orthographic view (1:1 mm)": "Huidige orthografische weergave (1:1 mm)",
"Current perspective view": "Huidige perspectiefweergave",
"Current plane": "Huidig vlak",
@@ -2250,6 +2251,9 @@
"prefs.interface_note": "Hoe SolidCraft eruitziet en waar de onderdelen staan.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "De gebogen rolpijlen omkeren",
"prefs.invert_curved_roll_arrows_note": "De twee gebogen pijlen op de hoek van de kubus laten de weergave in het schermvlak rollen. Aan: de pijl met de klok mee rolt tegen de klok in en de pijl tegen de klok in rolt met de klok mee. Uit: elke pijl rolt de weergave in de richting waarin hij krult.",
"prefs.invert_navigator_arrows": "De rotatiepijlen van de weergavekubus omkeren",
"prefs.invert_navigator_arrows_note": "De pijlen rond de kubus laten de camera roteren in de richting waarin ze wijzen, zoals in Fusion en Inventor: de pijl links wijst naar rechts en zwaait de camera naar rechts. Uit: een pijl draait de kubus naar de kant waar hij staat, dus de linkerpijl zwaait de camera naar links. De gebogen rolpijlen worden hierdoor niet beïnvloed.",
"prefs.keep_work_on_tab_switch": "Dialoogvensters en gereedschappen open houden bij het wisselen van ontwerp",
"prefs.keep_work_on_tab_switch_note": "Elk ontwerptabblad behoudt zijn geopende dialoogvenster of gereedschap, met wat je erin hebt gekozen en getypt, en zijn lint-tabblad. Ze zijn er weer als je terugkeert naar het ontwerp. Uit: wisselen van ontwerp breekt ze af en toont het tabblad Model.",
"prefs.labels": "Labels",
@@ -2286,6 +2290,7 @@
"prefs.navigation": "Navigatie",
"prefs.navigation_note": "Hoe de muis, het trackpad en de 3D-muis de weergave verplaatsen.",
"prefs.navigator_fit": "Het model passend in beeld brengen na een wijziging van de navigatorweergave",
"prefs.navigator_fit_note": "Een vlak, hoek of pijl van de weergavekubus, of een as van de gizmo, kijkt ook naar het midden van het model, vanaf de ene afstand waarop het van alle kanten in beeld past (de omsluitende bol). Beginweergave gebruikt dezelfde zoom en hetzelfde middelpunt zolang dit aan staat, zodat weergaven die je daarna kiest alleen draaien. Uit: de weergave draait ter plaatse en behoudt het richtpunt en de zoom.",
"prefs.network_host_remove": "Verwijderen",
"prefs.network_locations": "Netwerklocaties in ontwerpen toestaan",
"prefs.network_locations_note": "Uit: gekoppelde bestanden van een ontwerp op een andere computer (\\\\server\\share) worden alleen geopend vanaf de servers in deze lijst, of nadat je er een toestaat wanneer erom wordt gevraagd.",
@@ -0,0 +1,34 @@
{
"en": {
"prefs.sketch.select_3d_curve_points": "Select 3D sketch curve points",
"prefs.sketch.select_3d_curve_points_help": "Show and select points on drawn 3D sketch curves for construction references."
},
"de": {
"prefs.sketch.select_3d_curve_points": "Punkte von 3D-Skizzenkurven auswählen",
"prefs.sketch.select_3d_curve_points_help": "Punkte auf gezeichneten 3D-Skizzenkurven als Referenzen für Konstruktionselemente anzeigen und auswählen."
},
"ja": {
"prefs.sketch.select_3d_curve_points": "3Dスケッチ曲線の点を選択",
"prefs.sketch.select_3d_curve_points_help": "描画した3Dスケッチ曲線の点を表示し、構築要素の参照として選択します。"
},
"ko": {
"prefs.sketch.select_3d_curve_points": "3D 스케치 곡선의 점 선택",
"prefs.sketch.select_3d_curve_points_help": "그린 3D 스케치 곡선의 점을 표시하고 구성 요소의 참조로 선택합니다."
},
"zh": {
"prefs.sketch.select_3d_curve_points": "选择 3D 草图曲线上的点",
"prefs.sketch.select_3d_curve_points_help": "显示绘制的 3D 草图曲线上的点,并将其选作构造参照。"
},
"ar": {
"prefs.sketch.select_3d_curve_points": "تحديد نقاط منحنيات الرسم ثلاثي الأبعاد",
"prefs.sketch.select_3d_curve_points_help": "إظهار نقاط منحنيات الرسم ثلاثي الأبعاد المرسومة وتحديدها كمراجع للإنشاء."
},
"he": {
"prefs.sketch.select_3d_curve_points": "בחירת נקודות על עקומות סקיצה תלת־ממדית",
"prefs.sketch.select_3d_curve_points_help": "הצגה ובחירה של נקודות על עקומות סקיצה תלת־ממדית שצוירו, לשימוש כהפניות בנייה."
},
"vi": {
"prefs.sketch.select_3d_curve_points": "Chọn điểm trên đường cong phác thảo 3D",
"prefs.sketch.select_3d_curve_points_help": "Hiển thị và chọn các điểm trên đường cong phác thảo 3D đã vẽ để làm tham chiếu dựng hình."
}
}
@@ -0,0 +1,20 @@
{
"en": {
"ui.agent_chat_ctx_gone": "No longer in the design: it was changed or deleted."
},
"ja": {
"ui.agent_chat_ctx_gone": "デザインにはもうありません(変更または削除されました)。"
},
"zh": {
"ui.agent_chat_ctx_gone": "已不在设计中:它被修改或删除了。"
},
"ar": {
"ui.agent_chat_ctx_gone": "لم يعد في التصميم: تم تغييره أو حذفه."
},
"he": {
"ui.agent_chat_ctx_gone": "כבר לא בעיצוב: הוא שונה או נמחק."
},
"vi": {
"ui.agent_chat_ctx_gone": "Không còn trong thiết kế: nó đã bị thay đổi hoặc xóa."
}
}
@@ -0,0 +1,10 @@
{
"en": { "ui.agent_chat_transcript_assistant": "Assistant:", "ui.agent_chat_transcript_user": "User:" },
"ar": { "ui.agent_chat_transcript_assistant": "المساعد:", "ui.agent_chat_transcript_user": "المستخدم:" },
"de": { "ui.agent_chat_transcript_assistant": "Assistent:", "ui.agent_chat_transcript_user": "Benutzer:" },
"he": { "ui.agent_chat_transcript_assistant": "עוזר:", "ui.agent_chat_transcript_user": "משתמש:" },
"ja": { "ui.agent_chat_transcript_assistant": "アシスタント:", "ui.agent_chat_transcript_user": "ユーザー:" },
"ko": { "ui.agent_chat_transcript_assistant": "어시스턴트:", "ui.agent_chat_transcript_user": "사용자:" },
"vi": { "ui.agent_chat_transcript_assistant": "Trợ lý:", "ui.agent_chat_transcript_user": "Người dùng:" },
"zh": { "ui.agent_chat_transcript_assistant": "助手:", "ui.agent_chat_transcript_user": "用户:" }
}
@@ -0,0 +1,32 @@
{
"en": {
"ui.agent_chat_state_no_design": "No design access",
"ui.agent_chat_no_design_hint": "The agent runs without SolidCraft's tools, so it can't read or change the design: solidcraft-cli was not found next to the app. Install SolidCraft with solidcraft-cli beside it (on Windows, the MSI or the portable zip), or set SOLIDCRAFT_CLI to its path, then connect again.",
"ui.agent_chat_tools_not_started": "The agent runs without SolidCraft's tools, so it can't read or change the design: solidcraft-cli was found, but its tools did not start (the error in the chat says why). Connect again; if it keeps happening, reinstall SolidCraft."
},
"ar": {
"ui.agent_chat_state_no_design": "لا وصول إلى التصميم",
"ui.agent_chat_no_design_hint": "يعمل الوكيل دون أدوات SolidCraft، لذا لا يستطيع قراءة التصميم أو تغييره: لم يُعثر على solidcraft-cli بجانب التطبيق. ثبّت SolidCraft مع solidcraft-cli بجانبه (في Windows: حزمة MSI أو ملف zip المحمول)، أو اضبط SOLIDCRAFT_CLI على مساره، ثم اتصل مرة أخرى.",
"ui.agent_chat_tools_not_started": "يعمل الوكيل دون أدوات SolidCraft، لذا لا يستطيع قراءة التصميم أو تغييره: عُثر على solidcraft-cli، لكن أدواته لم تبدأ (رسالة الخطأ في المحادثة توضح السبب). اتصل مرة أخرى، وإذا تكرر ذلك فأعد تثبيت SolidCraft."
},
"he": {
"ui.agent_chat_state_no_design": "אין גישה לתכן",
"ui.agent_chat_no_design_hint": "הסוכן פועל בלי הכלים של SolidCraft, ולכן אינו יכול לקרוא או לשנות את התכן: solidcraft-cli לא נמצא ליד היישום. התקינו את SolidCraft עם solidcraft-cli לצידו (ב-Windows: קובץ ה-MSI או ה-zip הנייד), או הגדירו את SOLIDCRAFT_CLI לנתיב שלו, ואז התחברו שוב.",
"ui.agent_chat_tools_not_started": "הסוכן פועל בלי הכלים של SolidCraft, ולכן אינו יכול לקרוא או לשנות את התכן: solidcraft-cli נמצא, אבל הכלים שלו לא הופעלו (הודעת השגיאה בצ'אט מסבירה למה). התחברו שוב, ואם זה חוזר, התקינו מחדש את SolidCraft."
},
"ja": {
"ui.agent_chat_state_no_design": "デザインにアクセスできません",
"ui.agent_chat_no_design_hint": "エージェントは SolidCraft のツールなしで動作しているため、デザインを読み取ることも変更することもできません。アプリの隣に solidcraft-cli が見つかりませんでした。solidcraft-cli が同梱された SolidCraft をインストールするか(Windows では MSI またはポータブル zip)、SOLIDCRAFT_CLI にそのパスを設定してから、もう一度接続してください。",
"ui.agent_chat_tools_not_started": "エージェントは SolidCraft のツールなしで動作しているため、デザインを読み取ることも変更することもできません。solidcraft-cli は見つかりましたが、そのツールが起動しませんでした(理由はチャットのエラーに表示されています)。もう一度接続してください。繰り返し起きる場合は SolidCraft を再インストールしてください。"
},
"vi": {
"ui.agent_chat_state_no_design": "Không truy cập được thiết kế",
"ui.agent_chat_no_design_hint": "Tác tử đang chạy mà không có công cụ của SolidCraft, nên không thể đọc hay thay đổi thiết kế: không tìm thấy solidcraft-cli cạnh ứng dụng. Hãy cài SolidCraft có solidcraft-cli đi kèm (trên Windows: bản MSI hoặc bản zip di động), hoặc đặt SOLIDCRAFT_CLI thành đường dẫn của nó, rồi kết nối lại.",
"ui.agent_chat_tools_not_started": "Tác tử đang chạy mà không có công cụ của SolidCraft, nên không thể đọc hay thay đổi thiết kế: đã tìm thấy solidcraft-cli, nhưng công cụ của nó không khởi động được (lỗi trong cuộc trò chuyện cho biết lý do). Hãy kết nối lại; nếu vẫn xảy ra, hãy cài lại SolidCraft."
},
"zh": {
"ui.agent_chat_state_no_design": "无法访问设计",
"ui.agent_chat_no_design_hint": "代理在没有 SolidCraft 工具的情况下运行,因此无法读取或修改设计:在应用旁边找不到 solidcraft-cli。请安装附带 solidcraft-cli 的 SolidCraft(在 Windows 上为 MSI 或便携版 zip),或将 SOLIDCRAFT_CLI 设置为它的路径,然后重新连接。",
"ui.agent_chat_tools_not_started": "代理在没有 SolidCraft 工具的情况下运行,因此无法读取或修改设计:已找到 solidcraft-cli,但其工具未能启动(聊天中的错误信息说明了原因)。请重新连接;如果问题仍然出现,请重新安装 SolidCraft。"
}
}
@@ -0,0 +1,90 @@
{
"en": {
"browser.straighten_angle": "Edge direction",
"browser.straighten_choose": "Choose Horizontal, Vertical or Angle for the edge, then press Straighten.",
"browser.straighten_click_a": "Click the image at one end of an edge that should be straight, or type its coordinates.",
"browser.straighten_click_b": "Click the other end of the edge, or type its coordinates.",
"browser.straighten_horizontal": "Horizontal",
"browser.straighten_title": "Straighten: {name}",
"browser.straighten_vertical": "Vertical",
"cmd.canvas_straighten": "Straighten Canvas",
"ui.straighten": "Straighten"
},
"ar": {
"browser.straighten_angle": "اتجاه الحافة",
"browser.straighten_choose": "اختر ما تصبح عليه الحافة، أفقية أو رأسية أو بزاوية، ثم اضغط تقويم.",
"browser.straighten_click_a": "انقر الصورة عند أحد طرفي حافة يجب أن تكون مستقيمة، أو اكتب إحداثياتها.",
"browser.straighten_click_b": "انقر الطرف الآخر للحافة، أو اكتب إحداثياته.",
"browser.straighten_horizontal": "أفقي",
"browser.straighten_title": "تقويم: {name}",
"browser.straighten_vertical": "رأسي",
"cmd.canvas_straighten": "تقويم اللوحة",
"ui.straighten": "تقويم"
},
"de": {
"browser.straighten_angle": "Richtung der Kante",
"browser.straighten_choose": "Wählen Sie, wie die Kante liegen soll (Horizontal, Vertikal oder ein Winkel), und klicken Sie dann auf Ausrichten.",
"browser.straighten_click_a": "Klicken Sie im Bild auf ein Ende einer Kante, die gerade sein soll, oder geben Sie die Koordinaten ein.",
"browser.straighten_click_b": "Klicken Sie auf das andere Ende der Kante, oder geben Sie die Koordinaten ein.",
"browser.straighten_horizontal": "Horizontal",
"browser.straighten_title": "Ausrichten: {name}",
"browser.straighten_vertical": "Vertikal",
"cmd.canvas_straighten": "Zeichenfläche ausrichten",
"ui.straighten": "Ausrichten"
},
"he": {
"browser.straighten_angle": "כיוון הקצה",
"browser.straighten_choose": "בחר מה יהיה הקצה, אופקי, אנכי או בזווית, ואז לחץ על יישור.",
"browser.straighten_click_a": "לחץ על התמונה בקצה אחד של קצה שאמור להיות ישר, או הקלד את הקואורדינטות שלו.",
"browser.straighten_click_b": "לחץ על הקצה השני, או הקלד את הקואורדינטות שלו.",
"browser.straighten_horizontal": "אופקי",
"browser.straighten_title": "יישור: {name}",
"browser.straighten_vertical": "אנכי",
"cmd.canvas_straighten": "יישור קנבס",
"ui.straighten": "יישור"
},
"ja": {
"browser.straighten_angle": "エッジの向き",
"browser.straighten_choose": "エッジの向き(水平、垂直、または角度)を選んでから、[傾き補正]を押してください。",
"browser.straighten_click_a": "まっすぐにしたいエッジの一端を画像上でクリックするか、座標を入力してください。",
"browser.straighten_click_b": "エッジのもう一端をクリックするか、座標を入力してください。",
"browser.straighten_horizontal": "水平",
"browser.straighten_title": "傾き補正: {name}",
"browser.straighten_vertical": "垂直",
"cmd.canvas_straighten": "キャンバスの傾き補正",
"ui.straighten": "傾き補正"
},
"ko": {
"browser.straighten_angle": "모서리 방향",
"browser.straighten_choose": "모서리 방향(수평, 수직 또는 각도)을 고른 다음 수평 맞추기를 누르세요.",
"browser.straighten_click_a": "곧아야 하는 모서리의 한쪽 끝을 이미지에서 클릭하거나 좌표를 입력하세요.",
"browser.straighten_click_b": "모서리의 다른 쪽 끝을 클릭하거나 좌표를 입력하세요.",
"browser.straighten_horizontal": "수평",
"browser.straighten_title": "수평 맞추기: {name}",
"browser.straighten_vertical": "수직",
"cmd.canvas_straighten": "캔버스 수평 맞추기",
"ui.straighten": "수평 맞추기"
},
"vi": {
"browser.straighten_angle": "Hướng của cạnh",
"browser.straighten_choose": "Chọn hướng cho cạnh (Ngang, Dọc hoặc một góc), rồi nhấn Làm thẳng.",
"browser.straighten_click_a": "Nhấp vào ảnh tại một đầu của cạnh cần thẳng, hoặc nhập tọa độ của nó.",
"browser.straighten_click_b": "Nhấp vào đầu kia của cạnh, hoặc nhập tọa độ của nó.",
"browser.straighten_horizontal": "Ngang",
"browser.straighten_title": "Làm thẳng: {name}",
"browser.straighten_vertical": "Dọc",
"cmd.canvas_straighten": "Làm thẳng hình ảnh Canvas",
"ui.straighten": "Làm thẳng"
},
"zh": {
"browser.straighten_angle": "边的方向",
"browser.straighten_choose": "选择边的方向(水平、垂直或角度),然后按“拉直”。",
"browser.straighten_click_a": "在图像上单击应为直线的边的一端,或输入其坐标。",
"browser.straighten_click_b": "单击该边的另一端,或输入其坐标。",
"browser.straighten_horizontal": "水平",
"browser.straighten_title": "拉直:{name}",
"browser.straighten_vertical": "垂直",
"cmd.canvas_straighten": "拉直画布",
"ui.straighten": "拉直"
}
}
@@ -0,0 +1,41 @@
{
"en": {
"ui.colour_vision_bends": "Bends"
},
"ar": {
"ui.colour_vision_bends": "الثنيات"
},
"cs": {
"ui.colour_vision_bends": "Ohyby"
},
"da": {
"ui.colour_vision_bends": "Bukninger"
},
"de": {
"ui.colour_vision_bends": "Biegungen"
},
"he": {
"ui.colour_vision_bends": "כיפופים"
},
"ja": {
"ui.colour_vision_bends": "曲げ"
},
"ko": {
"ui.colour_vision_bends": "벤딩"
},
"nb": {
"ui.colour_vision_bends": "Bøyninger"
},
"pl": {
"ui.colour_vision_bends": "Gięcia"
},
"ru": {
"ui.colour_vision_bends": "Гибы"
},
"vi": {
"ui.colour_vision_bends": "Các vị trí chấn"
},
"zh": {
"ui.colour_vision_bends": "折弯"
}
}
@@ -0,0 +1,38 @@
{
"en": {
"prefs.constraint_glyph_size": "Constraint glyph size",
"prefs.constraint_glyph_size_note": "How large constraint glyphs and their letters or icons are drawn in a sketch. 100% is the usual size; glyphs keep this screen size at every zoom."
},
"ar": {
"prefs.constraint_glyph_size": "حجم رموز القيود",
"prefs.constraint_glyph_size_note": "حجم رسم رموز القيود وحروفها أو أيقوناتها في الرسم. 100% هو الحجم المعتاد؛ وتحتفظ الرموز بهذا الحجم على الشاشة عند أي مستوى تكبير."
},
"de": {
"prefs.constraint_glyph_size": "Größe der Bindungssymbole",
"prefs.constraint_glyph_size_note": "Wie groß Bindungssymbole samt Buchstaben oder Icons in einer Skizze gezeichnet werden. 100 % ist die übliche Größe; die Symbole behalten diese Bildschirmgröße bei jedem Zoom."
},
"fr": {
"prefs.constraint_glyph_size": "Taille des symboles de contraintes",
"prefs.constraint_glyph_size_note": "Taille à laquelle les symboles de contraintes, avec leurs lettres ou icônes, sont dessinés dans une esquisse. 100 % est la taille habituelle ; les symboles gardent cette taille à l'écran quel que soit le zoom."
},
"he": {
"prefs.constraint_glyph_size": "גודל סמלי האילוצים",
"prefs.constraint_glyph_size_note": "הגודל שבו מצוירים סמלי האילוצים, עם האותיות או הסמלונים שלהם, בשרטוט. 100% הוא הגודל הרגיל; הסמלים שומרים על גודל המסך הזה בכל זום."
},
"ja": {
"prefs.constraint_glyph_size": "拘束グリフのサイズ",
"prefs.constraint_glyph_size_note": "スケッチ内の拘束グリフとその文字やアイコンを描く大きさ。100% が通常のサイズです。グリフはどのズームでもこの画面サイズを保ちます。"
},
"ko": {
"prefs.constraint_glyph_size": "구속 조건 기호 크기",
"prefs.constraint_glyph_size_note": "스케치에서 구속 조건 기호와 그 문자나 아이콘을 그리는 크기입니다. 100%가 기본 크기이며, 기호는 확대/축소와 관계없이 이 화면 크기를 유지합니다."
},
"vi": {
"prefs.constraint_glyph_size": "Kích thước biểu tượng ràng buộc",
"prefs.constraint_glyph_size_note": "Kích thước vẽ biểu tượng ràng buộc cùng chữ cái hoặc biểu tượng bên trong trong bản phác. 100% là kích thước thông thường; biểu tượng giữ kích thước màn hình này ở mọi mức thu phóng."
},
"zh": {
"prefs.constraint_glyph_size": "约束符号大小",
"prefs.constraint_glyph_size_note": "草图中约束符号及其字母或图标的绘制大小。100% 为常规大小;任意缩放比例下符号都保持此屏幕大小。"
}
}
@@ -0,0 +1,58 @@
{
"en": {
"ui.construct_planes": "Planes",
"ui.construct_axes": "Axes",
"ui.construct_points": "Points",
"prefs.construct_menu_groups": "Group Construct tools by entity type",
"prefs.construct_menu_groups_help": "Show Planes, Axes and Points headings. Off keeps the original menu order."
},
"ar": {
"ui.construct_planes": "المستويات",
"ui.construct_axes": "المحاور",
"ui.construct_points": "النقاط",
"prefs.construct_menu_groups": "تجميع أدوات الإنشاء حسب نوع العنصر",
"prefs.construct_menu_groups_help": "إظهار عناوين المستويات والمحاور والنقاط. يحافظ التعطيل على ترتيب القائمة الأصلي."
},
"he": {
"ui.construct_planes": "מישורים",
"ui.construct_axes": "צירים",
"ui.construct_points": "נקודות",
"prefs.construct_menu_groups": "קיבוץ כלי הבנייה לפי סוג ישות",
"prefs.construct_menu_groups_help": "הצגת כותרות מישורים, צירים ונקודות. כיבוי שומר על סדר התפריט המקורי."
},
"ja": {
"ui.construct_planes": "平面",
"ui.construct_axes": "軸",
"ui.construct_points": "点",
"prefs.construct_menu_groups": "構築ツールを要素の種類でグループ化",
"prefs.construct_menu_groups_help": "平面、軸、点の見出しを表示します。オフにすると元のメニュー順序を維持します。"
},
"zh": {
"ui.construct_planes": "平面",
"ui.construct_axes": "轴",
"ui.construct_points": "点",
"prefs.construct_menu_groups": "按实体类型分组构造工具",
"prefs.construct_menu_groups_help": "显示平面、轴和点标题。关闭时保留原始菜单顺序。"
},
"de": {
"ui.construct_planes": "Ebenen",
"ui.construct_axes": "Achsen",
"ui.construct_points": "Punkte",
"prefs.construct_menu_groups": "Konstruktionswerkzeuge nach Elementtyp gruppieren",
"prefs.construct_menu_groups_help": "Zeigt Überschriften für Ebenen, Achsen und Punkte. Aus behält die ursprüngliche Menüreihenfolge bei."
},
"ko": {
"ui.construct_planes": "평면",
"ui.construct_axes": "축",
"ui.construct_points": "점",
"prefs.construct_menu_groups": "요소 유형별로 구성 도구 그룹화",
"prefs.construct_menu_groups_help": "평면, 축, 점 제목을 표시합니다. 끄면 원래 메뉴 순서를 유지합니다."
},
"vi": {
"ui.construct_planes": "Các mặt phẳng",
"ui.construct_axes": "Các trục",
"ui.construct_points": "Các điểm",
"prefs.construct_menu_groups": "Nhóm công cụ dựng theo loại đối tượng",
"prefs.construct_menu_groups_help": "Hiện tiêu đề Mặt phẳng, Trục và Điểm. Tắt để giữ thứ tự menu ban đầu."
}
}
@@ -0,0 +1,74 @@
{
"en": {
"prefs.export": "Export",
"prefs.export_name": "Export file name",
"prefs.export_name.body": "Exported body's name (the first one when there are several)",
"prefs.export_name.design": "Design name",
"prefs.export_name_hint": "e.g. {design}-{body}",
"prefs.export_name_sample": "Exporting this design offers: {name}",
"prefs.export_name_tip": "The file name File › Export and Save As Mesh offer. These placeholders are replaced:\n{placeholders}\nA design property that is not set is left out. Leave the field empty to offer the design's name, or the body's for a mesh."
},
"ar": {
"prefs.export": "التصدير",
"prefs.export_name": "اسم ملف التصدير",
"prefs.export_name.body": "اسم الجسم المُصدَّر (الأول إن تعددت الأجسام)",
"prefs.export_name.design": "اسم التصميم",
"prefs.export_name_hint": "مثلاً {design}-{body}",
"prefs.export_name_sample": "تصدير هذا التصميم يقترح: {name}",
"prefs.export_name_tip": "اسم الملف الذي يقترحه ملف › تصدير وحفظ كشبكة. تُستبدل هذه العناصر النائبة:\n{placeholders}\nتُحذف خاصية التصميم غير المعيّنة. اترك الحقل فارغاً لاقتراح اسم التصميم، أو اسم الجسم للشبكة."
},
"de": {
"prefs.export": "Export",
"prefs.export_name": "Dateiname beim Export",
"prefs.export_name.body": "Name des exportierten Körpers (des ersten, wenn es mehrere sind)",
"prefs.export_name.design": "Name des Designs",
"prefs.export_name_hint": "z. B. {design}-{body}",
"prefs.export_name_sample": "Beim Export dieses Designs vorgeschlagen: {name}",
"prefs.export_name_tip": "Der Dateiname, den Datei › Exportieren und Als Netz speichern vorschlagen. Diese Platzhalter werden ersetzt:\n{placeholders}\nEine nicht gesetzte Konstruktionseigenschaft entfällt. Leer lassen, um den Namen des Designs vorzuschlagen, bei einem Netz den des Körpers."
},
"he": {
"prefs.export": "ייצוא",
"prefs.export_name": "שם קובץ הייצוא",
"prefs.export_name.body": "שם הגוף המיוצא (הראשון כשיש כמה)",
"prefs.export_name.design": "שם התכן",
"prefs.export_name_hint": "לדוגמה {design}-{body}",
"prefs.export_name_sample": "ייצוא התכן הזה מציע: {name}",
"prefs.export_name_tip": "שם הקובץ שמציעים קובץ › ייצוא ושמירה כרשת משולשים. מצייני המיקום האלה מוחלפים:\n{placeholders}\nמאפיין תכן שלא הוגדר מושמט. השאירו את השדה ריק כדי להציע את שם התכן, או את שם הגוף לרשת."
},
"ja": {
"prefs.export": "エクスポート",
"prefs.export_name": "エクスポートのファイル名",
"prefs.export_name.body": "エクスポートするボディ名(複数ある場合は最初のボディ)",
"prefs.export_name.design": "デザイン名",
"prefs.export_name_hint": "例: {design}-{body}",
"prefs.export_name_sample": "このデザインのエクスポート時の名前: {name}",
"prefs.export_name_tip": "ファイル › エクスポートとメッシュとして保存が提案するファイル名です。次のプレースホルダーが置き換えられます:\n{placeholders}\n設定されていないデザインのプロパティは省かれます。空のままにすると、デザイン名(メッシュではボディ名)を提案します。"
},
"ko": {
"prefs.export": "내보내기",
"prefs.export_name": "내보내기 파일 이름",
"prefs.export_name.body": "내보내는 바디 이름(여러 개면 첫 번째 바디)",
"prefs.export_name.design": "디자인 이름",
"prefs.export_name_hint": "예: {design}-{body}",
"prefs.export_name_sample": "이 디자인을 내보낼 때 제안되는 이름: {name}",
"prefs.export_name_tip": "파일 › 내보내기와 메쉬로 저장이 제안하는 파일 이름입니다. 다음 자리 표시자가 바뀝니다:\n{placeholders}\n설정되지 않은 설계 속성은 빠집니다. 비워 두면 디자인 이름(메쉬의 경우 바디 이름)을 제안합니다."
},
"vi": {
"prefs.export": "Xuất",
"prefs.export_name": "Tên tệp khi xuất",
"prefs.export_name.body": "Tên khối được xuất (khối đầu tiên nếu có nhiều)",
"prefs.export_name.design": "Tên thiết kế",
"prefs.export_name_hint": "vd. {design}-{body}",
"prefs.export_name_sample": "Xuất thiết kế này sẽ đề xuất: {name}",
"prefs.export_name_tip": "Tên tệp mà Tệp › Xuất tệp và Lưu dưới dạng lưới đa giác đề xuất. Các phần giữ chỗ này được thay thế:\n{placeholders}\nThuộc tính thiết kế chưa đặt sẽ bị bỏ qua. Để trống để đề xuất tên thiết kế, hoặc tên khối với lưới."
},
"zh": {
"prefs.export": "导出",
"prefs.export_name": "导出文件名",
"prefs.export_name.body": "导出实体的名称(有多个时取第一个)",
"prefs.export_name.design": "设计名称",
"prefs.export_name_hint": "例如 {design}-{body}",
"prefs.export_name_sample": "导出此设计时建议的名称:{name}",
"prefs.export_name_tip": "文件 › 导出和另存为网格时建议的文件名。以下占位符会被替换:\n{placeholders}\n未设置的设计属性会被省略。留空则建议设计名称,网格则建议实体名称。"
}
}
@@ -0,0 +1,34 @@
{
"en": {
"ui.export_selects_only_body": "Select the only body when exporting a mesh",
"ui.export_selects_only_body_tip": "Export STL, Export 3MF and Send to Slicer start with the design's body selected when it has just one."
},
"de": {
"ui.export_selects_only_body": "Einzigen Körper beim Mesh-Export auswählen",
"ui.export_selects_only_body_tip": "Als STL exportieren, Als 3MF exportieren und An Slicer senden starten mit dem Körper des Designs ausgewählt, wenn es nur einen hat."
},
"ar": {
"ui.export_selects_only_body": "تحديد الجسم الوحيد عند تصدير شبكة",
"ui.export_selects_only_body_tip": "تبدأ أوامر تصدير STL وتصدير 3MF والإرسال إلى برنامج التقطيع بتحديد جسم التصميم عندما لا يحتوي إلا على جسم واحد."
},
"he": {
"ui.export_selects_only_body": "בחירת הגוף היחיד בייצוא רשת",
"ui.export_selects_only_body_tip": "ייצוא STL, ייצוא 3MF ושליחה לסלייסר מתחילים כשגוף התכנון כבר נבחר, כשיש בו גוף אחד בלבד."
},
"ja": {
"ui.export_selects_only_body": "メッシュのエクスポート時に唯一のボディを選択する",
"ui.export_selects_only_body_tip": "デザインのボディが 1 つだけのとき、STL をエクスポート、3MF をエクスポート、スライサーに送るはそのボディを選択した状態で始まります。"
},
"ko": {
"ui.export_selects_only_body": "메시 내보내기 시 유일한 바디 선택",
"ui.export_selects_only_body_tip": "디자인에 바디가 하나뿐이면 STL 내보내기, 3MF 내보내기, 슬라이서로 보내기가 그 바디를 선택한 상태로 시작합니다."
},
"vi": {
"ui.export_selects_only_body": "Chọn khối duy nhất khi xuất lưới",
"ui.export_selects_only_body_tip": "Xuất tệp STL, Xuất tệp 3MF và Gửi sang phần mềm cắt lớp bắt đầu với khối của thiết kế đã được chọn khi thiết kế chỉ có một khối."
},
"zh": {
"ui.export_selects_only_body": "导出网格时选中唯一的实体",
"ui.export_selects_only_body_tip": "设计只有一个实体时,导出 STL、导出 3MF 和发送到切片软件会在打开时选中该实体。"
}
}
@@ -0,0 +1,34 @@
{
"ar": {
"prefs.fillet_legacy_radius": "استخدم نصف قطر Fillet الصلب الافتراضي السابق",
"prefs.fillet_legacy_radius.help": "مطفأ افتراضيًا. عند التشغيل، يفتح Fillet الصلب الجديد عند الرقم 2 مقروءًا بوحدات التصميم (\"2 بوصة\" في تصميم بالبوصة)، كما كان سابقًا؛ وعند الإيقاف، يفتح عند نصف القطر الذي تُسلَّم به الأداة، 2 مم، معروضًا بوحدات التصميم (\"0.07874 بوصة\" في تصميم بالبوصة)."
},
"de": {
"prefs.fillet_legacy_radius": "Den vorherigen Standardradius für Solid-Fillet verwenden",
"prefs.fillet_legacy_radius.help": "Standardmäßig aus. Ein: Ein neuer Solid-Fillet öffnet mit der in den Einheiten des Designs gelesenen Zahl 2 (\"2 in\" in einem Design in Zoll), wie zuvor; aus: Er öffnet mit dem Radius, mit dem das Werkzeug ausgeliefert wird, 2 mm, in den Einheiten des Designs angezeigt (\"0.07874 in\" in einem Design in Zoll)."
},
"en": {
"prefs.fillet_legacy_radius": "Use the previous Solid Fillet radius default",
"prefs.fillet_legacy_radius.help": "Off by default. When on, a new Solid Fillet opens at the number 2 read in the design's units (\"2 in\" in an inch design), as before; when off, it opens at the radius the tool ships with, 2 mm, shown in the design's units (\"0.07874 in\" in an inch design)."
},
"he": {
"prefs.fillet_legacy_radius": "השתמש בברירת המחדש הקודמת לרדיוס Fillet מוצק",
"prefs.fillet_legacy_radius.help": "כבוי כברירת מחדש. כשהוא פעיל, Solid Fillet חדש נפתח במספר 2 שנקרא ביחידות התכנון (\"2 אינץ\" בתכנון באינצ'ים), כמו קודם; כשהוא כבוי, הוא נפתח ברדיוס שבו הכלי נמסר, 2 מ\"מ, מוצג ביחידות התכנון (\"0.07874 אינץ\" בתכנון באינצ'ים)."
},
"ja": {
"prefs.fillet_legacy_radius": "以前のフィレット半径の既定値を使う",
"prefs.fillet_legacy_radius.help": "既定ではオフです。オンのとき:新しい Solid Fillet は設計の単位として読み取った数値 2(「2 in」)で始まり、以前と同じです。オフのとき:そのツールが標準で持つ半径 2 mm を設計の単位に換算した値(「0.07874 in」)で始まります。"
},
"ko": {
"prefs.fillet_legacy_radius": "이전 필렛 반지름 기본값 사용",
"prefs.fillet_legacy_radius.help": "기본적으로 꺼짐입니다. 켜면: 새 Solid Fillet은 설계 단위로 읽힌 숫자 2(\"2 in\")로 시작하며 이전과 같습니다. 끄면: 그 도구가 기본으로 제공하는 반지름 2 mm를 설계 단위로 표시한 값(\"0.07874 in\")으로 시작합니다."
},
"vi": {
"prefs.fillet_legacy_radius": "Dùng giá trị mặc định bán kính Fillet trước đây",
"prefs.fillet_legacy_radius.help": "Mặc định tắt. Khi bật: Solid Fillet mới bắt đầu với số 2 được đọc theo đơn vị của thiết kế (\"2 in\"), như trước; khi tắt: nó bắt đầu với bán kính mà công cụ được giao, 2 mm, hiển thị theo đơn vị của thiết kế (\"0.07874 in\")."
},
"zh": {
"prefs.fillet_legacy_radius": "使用之前的圆角半径默认值",
"prefs.fillet_legacy_radius.help": "默认关闭。开启时:新的 Solid Fillet 以按设计单位读取的数字 2(\"2 in\")开始,与之前相同。关闭时:它以该工具自带的半径 2 mm 开始,并按设计的单位显示(\"0.07874 in\")。"
}
}
@@ -0,0 +1,34 @@
{
"en": {
"ui.first_dimension_scales_about_origin": "Scale about the sketch origin",
"ui.first_dimension_scales_about_origin_tip": "On: the drawing always grows or shrinks about the sketch origin, so a shape drawn away from the origin moves. Off: a drawing that nothing ties to the origin scales about its own middle and stays where it was drawn."
},
"ar": {
"ui.first_dimension_scales_about_origin": "تغيير المقياس حول أصل الرسم التخطيطي",
"ui.first_dimension_scales_about_origin_tip": "عند التفعيل: يكبر الرسم أو يصغر دائمًا حول أصل الرسم التخطيطي، فيتحرك الشكل المرسوم بعيدًا عن الأصل. عند الإيقاف: الرسم غير المرتبط بالأصل يتغير مقياسه حول منتصفه ويبقى في مكانه."
},
"de": {
"ui.first_dimension_scales_about_origin": "Um den Skizzenursprung skalieren",
"ui.first_dimension_scales_about_origin_tip": "Ein: Die Zeichnung wird immer um den Skizzenursprung vergrößert oder verkleinert, eine vom Ursprung entfernt gezeichnete Form verschiebt sich also. Aus: Eine Zeichnung, die nichts an den Ursprung bindet, wird um ihre eigene Mitte skaliert und bleibt an ihrem Platz."
},
"he": {
"ui.first_dimension_scales_about_origin": "שינוי קנה מידה סביב ראשית הסקיצה",
"ui.first_dimension_scales_about_origin_tip": "מופעל: הציור תמיד גדל או קטן סביב ראשית הסקיצה, כך שצורה שצוירה הרחק מהראשית זזה. כבוי: ציור שדבר אינו קושר לראשית משנה קנה מידה סביב מרכזו ונשאר במקומו."
},
"ja": {
"ui.first_dimension_scales_about_origin": "スケッチ原点を中心にスケールする",
"ui.first_dimension_scales_about_origin_tip": "オン: 図形は常にスケッチ原点を中心に拡大・縮小されるため、原点から離れて描いた図形は移動します。オフ: 原点に拘束されていない図形は自身の中心を基準にスケールし、描いた位置に留まります。"
},
"ko": {
"ui.first_dimension_scales_about_origin": "스케치 원점을 기준으로 배율 조정",
"ui.first_dimension_scales_about_origin_tip": "켜기: 도면이 항상 스케치 원점을 기준으로 커지거나 작아지므로 원점에서 떨어져 그린 도형은 이동합니다. 끄기: 원점에 묶이지 않은 도면은 자신의 중심을 기준으로 배율이 바뀌고 그린 자리에 그대로 있습니다."
},
"vi": {
"ui.first_dimension_scales_about_origin": "Co giãn quanh gốc phác thảo",
"ui.first_dimension_scales_about_origin_tip": "Bật: bản vẽ luôn phóng to hoặc thu nhỏ quanh gốc phác thảo, nên hình vẽ cách xa gốc sẽ di chuyển. Tắt: bản vẽ không gắn với gốc sẽ co giãn quanh tâm của chính nó và giữ nguyên vị trí."
},
"zh": {
"ui.first_dimension_scales_about_origin": "以草图原点为中心缩放",
"ui.first_dimension_scales_about_origin_tip": "开启:图形总是以草图原点为中心放大或缩小,因此远离原点绘制的形状会移动。关闭:未与原点关联的图形以其自身中心缩放,并保持在绘制的位置。"
}
}
+206
View File
@@ -0,0 +1,206 @@
{
"en": {
"cmd.frame_end_cap": "End Cap",
"error.end_cap_faces": "Pick at least one open end face of a frame member",
"error.end_cap_unresolved": "End {ends} of this cap is no longer on the model. Pick the end faces again",
"help.frame.end_cap": "Closes the open ends of frame members with plates shaped like the profile's outline. Use it to seal tubes, angles and beams, on top of the end or set into it.",
"ui.end_cap.chamfer": "Corner Chamfer",
"ui.end_cap.direction": "Direction",
"ui.end_cap.faces": "End Faces",
"ui.end_cap.inset": "Inset",
"ui.end_cap.inset_kind": "Inset By",
"ui.end_cap.inset_ratio": "Inset Ratio",
"ui.end_cap.inward": "Inward",
"ui.end_cap.length": "Length",
"ui.end_cap.outward": "Outward",
"ui.end_cap.ratio": "Ratio of thickness",
"ui.end_cap_title": "END CAP"
},
"ar": {
"cmd.frame_end_cap": "غطاء طرفي",
"error.end_cap_faces": "اختر وجهًا طرفيًا مفتوحًا واحدًا على الأقل لعضو إطار",
"error.end_cap_unresolved": "الطرف {ends} لهذا الغطاء لم يعد موجودًا في النموذج. اختر الأوجه الطرفية مرة أخرى",
"help.frame.end_cap": "يغلق الأطراف المفتوحة لأعضاء الإطار بألواح على شكل محيط المقطع. استخدمه لسد الأنابيب والزوايا والعوارض، فوق الطرف أو مغروسًا فيه.",
"ui.end_cap.chamfer": "شطف الزوايا",
"ui.end_cap.direction": "الاتجاه",
"ui.end_cap.faces": "الوجوه الطرفية",
"ui.end_cap.inset": "الإزاحة للداخل",
"ui.end_cap.inset_kind": "الإزاحة حسب",
"ui.end_cap.inset_ratio": "نسبة الإزاحة",
"ui.end_cap.inward": "للداخل",
"ui.end_cap.length": "الطول",
"ui.end_cap.outward": "للخارج",
"ui.end_cap.ratio": "نسبة من السماكة",
"ui.end_cap_title": "غطاء طرفي"
},
"de": {
"cmd.frame_end_cap": "Endkappe",
"error.end_cap_faces": "Mindestens eine offene Stirnfläche eines Rahmenelements auswählen",
"error.end_cap_unresolved": "Ende {ends} dieser Abdeckung ist nicht mehr im Modell. Stirnflächen erneut auswählen",
"help.frame.end_cap": "Schließt offene Enden von Rahmenelementen mit Platten in der Form des Profilumrisses. Damit verschließen Sie Rohre, Winkel und Träger, auf dem Ende oder darin eingelassen.",
"ui.end_cap.chamfer": "Eckfase",
"ui.end_cap.direction": "Richtung",
"ui.end_cap.faces": "Stirnflächen",
"ui.end_cap.inset": "Einzug",
"ui.end_cap.inset_kind": "Einzug als",
"ui.end_cap.inset_ratio": "Einzugsverhältnis",
"ui.end_cap.inward": "Nach innen",
"ui.end_cap.length": "Länge",
"ui.end_cap.outward": "Nach außen",
"ui.end_cap.ratio": "Anteil der Dicke",
"ui.end_cap_title": "ENDKAPPE"
},
"es": {
"cmd.frame_end_cap": "Tapa de extremo",
"error.end_cap_faces": "Selecciona al menos una cara de extremo abierta de un miembro",
"error.end_cap_unresolved": "El extremo {ends} de esta tapa ya no está en el modelo. Vuelve a seleccionar las caras de extremo",
"help.frame.end_cap": "Cierra los extremos abiertos de los miembros de una estructura con placas con la forma del contorno del perfil. Úsalo para tapar tubos, angulares y vigas, sobre el extremo o embutidas en él.",
"ui.end_cap.chamfer": "Chaflán de esquina",
"ui.end_cap.direction": "Dirección",
"ui.end_cap.faces": "Caras de extremo",
"ui.end_cap.inset": "Retranqueo",
"ui.end_cap.inset_kind": "Retranqueo por",
"ui.end_cap.inset_ratio": "Proporción de retranqueo",
"ui.end_cap.inward": "Hacia dentro",
"ui.end_cap.length": "Longitud",
"ui.end_cap.outward": "Hacia fuera",
"ui.end_cap.ratio": "Proporción del espesor",
"ui.end_cap_title": "TAPA DE EXTREMO"
},
"fr": {
"cmd.frame_end_cap": "Bouchon d'extrémité",
"error.end_cap_faces": "Sélectionnez au moins une face d'extrémité ouverte d'un élément de structure",
"error.end_cap_unresolved": "L'extrémité {ends} de ce bouchon n'est plus sur le modèle. Sélectionnez à nouveau les faces d'extrémité",
"help.frame.end_cap": "Ferme les extrémités ouvertes des éléments de structure avec des plaques à la forme du contour du profil. Utilisez-le pour boucher tubes, cornières et poutres, sur l'extrémité ou encastrées.",
"ui.end_cap.chamfer": "Chanfrein d'angle",
"ui.end_cap.direction": "Direction",
"ui.end_cap.faces": "Faces d'extrémité",
"ui.end_cap.inset": "Retrait",
"ui.end_cap.inset_kind": "Retrait en",
"ui.end_cap.inset_ratio": "Rapport de retrait",
"ui.end_cap.inward": "Vers l'intérieur",
"ui.end_cap.length": "Longueur",
"ui.end_cap.outward": "Vers l'extérieur",
"ui.end_cap.ratio": "Rapport de l'épaisseur",
"ui.end_cap_title": "BOUCHON D'EXTRÉMITÉ"
},
"he": {
"cmd.frame_end_cap": "מכסה קצה",
"error.end_cap_faces": "בחר לפחות פאת קצה פתוחה אחת של איבר מסגרת",
"error.end_cap_unresolved": "קצה {ends} של מכסה זה כבר אינו במודל. בחר שוב את פאות הקצה",
"help.frame.end_cap": "סוגר קצוות פתוחים של איברי מסגרת בלוחות בצורת קו המתאר של הפרופיל. השתמש בו כדי לאטום צינורות, זוויתנים וקורות, מעל הקצה או שקוע בו.",
"ui.end_cap.chamfer": "שיפוע פינות",
"ui.end_cap.direction": "כיוון",
"ui.end_cap.faces": "פאות קצה",
"ui.end_cap.inset": "היסט פנימה",
"ui.end_cap.inset_kind": "היסט לפי",
"ui.end_cap.inset_ratio": "יחס היסט",
"ui.end_cap.inward": "פנימה",
"ui.end_cap.length": "אורך",
"ui.end_cap.outward": "החוצה",
"ui.end_cap.ratio": "יחס מהעובי",
"ui.end_cap_title": "מכסה קצה"
},
"it": {
"cmd.frame_end_cap": "Tappo di estremità",
"error.end_cap_faces": "Seleziona almeno una faccia di estremità aperta di un elemento",
"error.end_cap_unresolved": "L'estremità {ends} di questa chiusura non è più nel modello. Seleziona di nuovo le facce di estremità",
"help.frame.end_cap": "Chiude le estremità aperte degli elementi con piastre sagomate sul contorno del profilo. Usalo per chiudere tubi, angolari e travi, sopra l'estremità o incassate.",
"ui.end_cap.chamfer": "Smusso degli angoli",
"ui.end_cap.direction": "Direzione",
"ui.end_cap.faces": "Facce di estremità",
"ui.end_cap.inset": "Rientro",
"ui.end_cap.inset_kind": "Rientro come",
"ui.end_cap.inset_ratio": "Rapporto di rientro",
"ui.end_cap.inward": "Verso l'interno",
"ui.end_cap.length": "Lunghezza",
"ui.end_cap.outward": "Verso l'esterno",
"ui.end_cap.ratio": "Rapporto dello spessore",
"ui.end_cap_title": "TAPPO DI ESTREMITÀ"
},
"ja": {
"cmd.frame_end_cap": "エンドキャップ",
"error.end_cap_faces": "フレーム部材の開いた端面を1つ以上選択してください",
"error.end_cap_unresolved": "このエンドキャップの端 {ends} はモデル上にありません。端面を選択し直してください",
"help.frame.end_cap": "フレーム部材の開いた端を、プロファイルの外形に沿ったプレートで閉じます。パイプ、アングル、梁の端をふさぐときに、端の上に載せるか端に埋め込んで使います。",
"ui.end_cap.chamfer": "角の面取り",
"ui.end_cap.direction": "方向",
"ui.end_cap.faces": "端面",
"ui.end_cap.inset": "内側オフセット",
"ui.end_cap.inset_kind": "オフセットの指定",
"ui.end_cap.inset_ratio": "オフセット比",
"ui.end_cap.inward": "内向き",
"ui.end_cap.length": "長さ",
"ui.end_cap.outward": "外向き",
"ui.end_cap.ratio": "厚さに対する比",
"ui.end_cap_title": "エンドキャップ"
},
"pt-BR": {
"cmd.frame_end_cap": "Tampa de extremidade",
"error.end_cap_faces": "Selecione pelo menos uma face de extremidade aberta de um membro",
"error.end_cap_unresolved": "A extremidade {ends} desta tampa não está mais no modelo. Selecione as faces de extremidade novamente",
"help.frame.end_cap": "Fecha as extremidades abertas dos membros com placas no formato do contorno do perfil. Use para tampar tubos, cantoneiras e vigas, sobre a extremidade ou embutidas nela.",
"ui.end_cap.chamfer": "Chanfro dos cantos",
"ui.end_cap.direction": "Direção",
"ui.end_cap.faces": "Faces de extremidade",
"ui.end_cap.inset": "Recuo",
"ui.end_cap.inset_kind": "Recuo por",
"ui.end_cap.inset_ratio": "Proporção de recuo",
"ui.end_cap.inward": "Para dentro",
"ui.end_cap.length": "Comprimento",
"ui.end_cap.outward": "Para fora",
"ui.end_cap.ratio": "Proporção da espessura",
"ui.end_cap_title": "TAMPA DE EXTREMIDADE"
},
"vi": {
"cmd.frame_end_cap": "Nắp đầu",
"error.end_cap_faces": "Chọn ít nhất một mặt đầu hở của một thanh khung",
"error.end_cap_unresolved": "Đầu {ends} của nắp này không còn trên mô hình. Hãy chọn lại các mặt đầu",
"help.frame.end_cap": "Đóng các đầu hở của thanh khung bằng tấm có hình đường bao của tiết diện. Dùng để bịt ống, thép góc và dầm, đặt lên đầu hoặc lắp chìm vào đầu.",
"ui.end_cap.chamfer": "Vát góc",
"ui.end_cap.direction": "Hướng",
"ui.end_cap.faces": "Mặt đầu",
"ui.end_cap.inset": "Thụt vào",
"ui.end_cap.inset_kind": "Thụt vào theo",
"ui.end_cap.inset_ratio": "Tỉ lệ thụt vào",
"ui.end_cap.inward": "Vào trong",
"ui.end_cap.length": "Chiều dài",
"ui.end_cap.outward": "Ra ngoài",
"ui.end_cap.ratio": "Tỉ lệ theo độ dày",
"ui.end_cap_title": "NẮP ĐẦU"
},
"zh": {
"cmd.frame_end_cap": "端盖",
"error.end_cap_faces": "请至少选择一个框架构件的开放端面",
"error.end_cap_unresolved": "此端盖的端 {ends} 已不在模型上。请重新选择端面",
"help.frame.end_cap": "用符合型材外形的板封闭框架构件的开放端。用于封住管材、角钢和梁的端部,可盖在端面上或嵌入端部。",
"ui.end_cap.chamfer": "角部倒角",
"ui.end_cap.direction": "方向",
"ui.end_cap.faces": "端面",
"ui.end_cap.inset": "内缩",
"ui.end_cap.inset_kind": "内缩方式",
"ui.end_cap.inset_ratio": "内缩比例",
"ui.end_cap.inward": "向内",
"ui.end_cap.length": "长度",
"ui.end_cap.outward": "向外",
"ui.end_cap.ratio": "厚度比例",
"ui.end_cap_title": "端盖"
},
"zh-TW": {
"cmd.frame_end_cap": "端蓋",
"error.end_cap_faces": "請至少選取一個框架構件的開放端面",
"error.end_cap_unresolved": "此端蓋的端 {ends} 已不在模型上。請重新選取端面",
"help.frame.end_cap": "以符合型材外形的板封閉框架構件的開放端。用於封住管材、角鋼與樑的端部,可蓋在端面上或嵌入端部。",
"ui.end_cap.chamfer": "角落倒角",
"ui.end_cap.direction": "方向",
"ui.end_cap.faces": "端面",
"ui.end_cap.inset": "內縮",
"ui.end_cap.inset_kind": "內縮方式",
"ui.end_cap.inset_ratio": "內縮比例",
"ui.end_cap.inward": "向內",
"ui.end_cap.length": "長度",
"ui.end_cap.outward": "向外",
"ui.end_cap.ratio": "厚度比例",
"ui.end_cap_title": "端蓋"
}
}
@@ -0,0 +1,155 @@
{
"en": {
"prefs.graphics_api": "Graphics API",
"prefs.graphics_api_auto": "Automatic",
"prefs.graphics_api_help": "Choose the graphics API used to open SolidCraft. If the next start cannot open the window, the previous choice is restored.",
"prefs.graphics_api_override": "A launch override is controlling the graphics API. The saved choice will apply when SolidCraft is opened normally.",
"prefs.graphics_api_restart_note": "Applies after a restart. Unsaved designs are handled before closing.",
"prefs.graphics_api_restart_unavailable": "Restart SolidCraft to apply the saved graphics API.",
"prefs.graphics_api_running": "Current: {current}. Selected for next start: {selected}.",
"prefs.graphics_api_save_failed": "The graphics API choice could not be saved: {error}",
"prefs.graphics_api_start_failed": "The selected graphics API could not be prepared: {error}",
"prefs.graphics_api_start_reverted": "The previous start with {requested} did not open the window. SolidCraft restored {previous}.",
"prefs.graphics_api_unavailable": "Graphics API selection is available in the desktop app.",
"render.graphics_api_restart_vulkan": "Restart with Vulkan",
"render.graphics_api_restart_warning": "Changing graphics API restarts SolidCraft and asks you to save unsaved designs. If the new API cannot open the window, the previous choice is restored on the next start.",
"render.graphics_api_settings": "Graphics settings",
"render.graphics_api_vulkan_required": "GPU path tracing needs Vulkan in this session. Restart with Vulkan, or keep using a CPU image method."
},
"ar": {
"prefs.graphics_api": "واجهة برمجة تطبيقات الرسوميات",
"prefs.graphics_api_auto": "تلقائي",
"prefs.graphics_api_help": "اختر واجهة الرسوميات المستخدمة لفتح SolidCraft. إذا تعذّر فتح النافذة عند التشغيل التالي، فستُستعاد السابقة.",
"prefs.graphics_api_override": "يتحكم إعداد عند التشغيل في واجهة الرسوميات. سيُطبّق الاختيار المحفوظ عند فتح SolidCraft بالطريقة العادية.",
"prefs.graphics_api_restart_note": "يُطبّق بعد إعادة التشغيل. تُعالَج التصميمات غير المحفوظة قبل الإغلاق.",
"prefs.graphics_api_restart_unavailable": "أعد تشغيل SolidCraft لتطبيق واجهة الرسوميات المحفوظة.",
"prefs.graphics_api_running": "الحالية: {current}. المختارة للتشغيل التالي: {selected}.",
"prefs.graphics_api_save_failed": "تعذّر حفظ اختيار واجهة الرسوميات: {error}",
"prefs.graphics_api_start_failed": "تعذّر تجهيز واجهة الرسوميات المختارة: {error}",
"prefs.graphics_api_start_reverted": "لم يفتح التشغيل السابق باستخدام {requested} النافذة. استعاد SolidCraft الاختيار {previous}.",
"prefs.graphics_api_unavailable": "اختيار واجهة الرسوميات متاح في تطبيق سطح المكتب.",
"render.graphics_api_restart_vulkan": "إعادة التشغيل باستخدام Vulkan",
"render.graphics_api_restart_warning": "يؤدي تغيير واجهة الرسوميات إلى إعادة تشغيل SolidCraft ويطلب منك حفظ التصميمات غير المحفوظة. إذا تعذّر فتح النافذة بالواجهة الجديدة، فسيُستعاد الاختيار السابق عند التشغيل التالي.",
"render.graphics_api_settings": "إعدادات الرسوميات",
"render.graphics_api_vulkan_required": "يتطلب تتبّع المسارات بمعالج الرسوميات Vulkan في هذه الجلسة. أعد التشغيل باستخدام Vulkan، أو واصل استخدام طريقة صور بمعالج CPU."
},
"he": {
"prefs.graphics_api": "ממשק גרפי",
"prefs.graphics_api_auto": "אוטומטי",
"prefs.graphics_api_help": "בחרו את הממשק הגרפי המשמש לפתיחת SolidCraft. אם ההפעלה הבאה לא תצליח לפתוח את החלון, הבחירה הקודמת תשוחזר.",
"prefs.graphics_api_override": "הגדרת הפעלה עוקפת קובעת את הממשק הגרפי. הבחירה השמורה תחול כאשר SolidCraft ייפתח כרגיל.",
"prefs.graphics_api_restart_note": "חל לאחר הפעלה מחדש. עיצובים שלא נשמרו יטופלו לפני הסגירה.",
"prefs.graphics_api_restart_unavailable": "הפעילו מחדש את SolidCraft כדי להחיל את הממשק הגרפי השמור.",
"prefs.graphics_api_running": "נוכחי: {current}. נבחר להפעלה הבאה: {selected}.",
"prefs.graphics_api_save_failed": "לא ניתן לשמור את בחירת הממשק הגרפי: {error}",
"prefs.graphics_api_start_failed": "לא ניתן להכין את הממשק הגרפי שנבחר: {error}",
"prefs.graphics_api_start_reverted": "ההפעלה הקודמת עם {requested} לא פתחה את החלון. SolidCraft שחזר את {previous}.",
"prefs.graphics_api_unavailable": "בחירת ממשק גרפי זמינה ביישום שולחן העבודה.",
"render.graphics_api_restart_vulkan": "הפעלה מחדש עם Vulkan",
"render.graphics_api_restart_warning": "שינוי הממשק הגרפי מפעיל מחדש את SolidCraft ומבקש לשמור עיצובים שלא נשמרו. אם הממשק החדש לא יצליח לפתוח את החלון, הבחירה הקודמת תשוחזר בהפעלה הבאה.",
"render.graphics_api_settings": "הגדרות גרפיקה",
"render.graphics_api_vulkan_required": "מעקב נתיבים ב־GPU דורש Vulkan בהפעלה זו. הפעילו מחדש עם Vulkan, או המשיכו להשתמש בשיטת תמונה ב־CPU."
},
"ja": {
"prefs.graphics_api": "グラフィックスAPI",
"prefs.graphics_api_auto": "自動",
"prefs.graphics_api_help": "SolidCraftの起動に使用するグラフィックスAPIを選択します。次回起動時にウィンドウを開けなかった場合は、以前の選択に戻ります。",
"prefs.graphics_api_override": "起動時の上書き設定がグラフィックスAPIを指定しています。SolidCraftを通常どおり開くと、保存した選択が適用されます。",
"prefs.graphics_api_restart_note": "再起動後に適用されます。閉じる前に未保存のデザインを確認します。",
"prefs.graphics_api_restart_unavailable": "保存したグラフィックスAPIを適用するには、SolidCraftを再起動してください。",
"prefs.graphics_api_running": "現在: {current}。次回起動時の選択: {selected}。",
"prefs.graphics_api_save_failed": "グラフィックスAPIの選択を保存できませんでした: {error}",
"prefs.graphics_api_start_failed": "選択したグラフィックスAPIを準備できませんでした: {error}",
"prefs.graphics_api_start_reverted": "前回は{requested}でウィンドウを開けませんでした。SolidCraftは{previous}に戻しました。",
"prefs.graphics_api_unavailable": "グラフィックスAPIの選択はデスクトップアプリで利用できます。",
"render.graphics_api_restart_vulkan": "Vulkanで再起動",
"render.graphics_api_restart_warning": "グラフィックスAPIを変更するとSolidCraftが再起動し、未保存のデザインの保存を確認します。新しいAPIでウィンドウを開けない場合は、次回起動時に以前の選択に戻ります。",
"render.graphics_api_settings": "グラフィックス設定",
"render.graphics_api_vulkan_required": "このセッションでGPUパストレーシングを使用するにはVulkanが必要です。Vulkanで再起動するか、CPUの画像方式を引き続き使用してください。"
},
"vi": {
"prefs.graphics_api": "API đồ họa",
"prefs.graphics_api_auto": "Tự động",
"prefs.graphics_api_help": "Chọn API đồ họa dùng để mở SolidCraft. Nếu lần khởi động tiếp theo không mở được cửa sổ, lựa chọn trước sẽ được khôi phục.",
"prefs.graphics_api_override": "Một thiết lập ghi đè khi khởi chạy đang điều khiển API đồ họa. Lựa chọn đã lưu sẽ áp dụng khi mở SolidCraft bình thường.",
"prefs.graphics_api_restart_note": "Áp dụng sau khi khởi động lại. Các thiết kế chưa lưu được xử lý trước khi đóng.",
"prefs.graphics_api_restart_unavailable": "Khởi động lại SolidCraft để áp dụng API đồ họa đã lưu.",
"prefs.graphics_api_running": "Hiện tại: {current}. Đã chọn cho lần khởi động tiếp theo: {selected}.",
"prefs.graphics_api_save_failed": "Không thể lưu lựa chọn API đồ họa: {error}",
"prefs.graphics_api_start_failed": "Không thể chuẩn bị API đồ họa đã chọn: {error}",
"prefs.graphics_api_start_reverted": "Lần khởi động trước với {requested} không mở được cửa sổ. SolidCraft đã khôi phục {previous}.",
"prefs.graphics_api_unavailable": "Có thể chọn API đồ họa trong ứng dụng máy tính.",
"render.graphics_api_restart_vulkan": "Khởi động lại với Vulkan",
"render.graphics_api_restart_warning": "Đổi API đồ họa sẽ khởi động lại SolidCraft và yêu cầu lưu các thiết kế chưa lưu. Nếu API mới không mở được cửa sổ, lựa chọn trước sẽ được khôi phục ở lần khởi động tiếp theo.",
"render.graphics_api_settings": "Cài đặt đồ họa",
"render.graphics_api_vulkan_required": "Truy vết đường đi bằng GPU cần Vulkan trong phiên này. Khởi động lại với Vulkan hoặc tiếp tục dùng phương pháp tạo ảnh bằng CPU."
},
"zh": {
"prefs.graphics_api": "图形 API",
"prefs.graphics_api_auto": "自动",
"prefs.graphics_api_help": "选择用于启动 SolidCraft 的图形 API。如果下次启动无法打开窗口,将恢复之前的选择。",
"prefs.graphics_api_override": "启动覆盖设置正在控制图形 API。正常打开 SolidCraft 时将应用已保存的选择。",
"prefs.graphics_api_restart_note": "重启后生效。关闭前会处理未保存的设计。",
"prefs.graphics_api_restart_unavailable": "重启 SolidCraft 以应用已保存的图形 API。",
"prefs.graphics_api_running": "当前:{current}。下次启动的选择:{selected}。",
"prefs.graphics_api_save_failed": "无法保存图形 API 选择:{error}",
"prefs.graphics_api_start_failed": "无法准备所选图形 API:{error}",
"prefs.graphics_api_start_reverted": "上次使用 {requested} 启动时未能打开窗口。SolidCraft 已恢复为 {previous}。",
"prefs.graphics_api_unavailable": "图形 API 选择功能可在桌面应用中使用。",
"render.graphics_api_restart_vulkan": "使用 Vulkan 重启",
"render.graphics_api_restart_warning": "更改图形 API 将重启 SolidCraft,并提示保存未保存的设计。如果新 API 无法打开窗口,下次启动时将恢复之前的选择。",
"render.graphics_api_settings": "图形设置",
"render.graphics_api_vulkan_required": "本次会话的 GPU 路径追踪需要 Vulkan。请使用 Vulkan 重启,或继续使用 CPU 图像方式。"
},
"de": {
"prefs.graphics_api": "Grafik-API",
"prefs.graphics_api_auto": "Automatisch",
"prefs.graphics_api_help": "Wählen Sie die Grafik-API zum Starten von SolidCraft. Wenn sich beim nächsten Start kein Fenster öffnen lässt, wird die vorherige Auswahl wiederhergestellt.",
"prefs.graphics_api_override": "Eine Startvorgabe bestimmt die Grafik-API. Die gespeicherte Auswahl gilt, wenn SolidCraft normal geöffnet wird.",
"prefs.graphics_api_restart_note": "Gilt nach einem Neustart. Ungespeicherte Entwürfe werden vor dem Schließen berücksichtigt.",
"prefs.graphics_api_restart_unavailable": "Starten Sie SolidCraft neu, um die gespeicherte Grafik-API anzuwenden.",
"prefs.graphics_api_running": "Aktuell: {current}. Für den nächsten Start ausgewählt: {selected}.",
"prefs.graphics_api_save_failed": "Die Auswahl der Grafik-API konnte nicht gespeichert werden: {error}",
"prefs.graphics_api_start_failed": "Die ausgewählte Grafik-API konnte nicht vorbereitet werden: {error}",
"prefs.graphics_api_start_reverted": "Der vorherige Start mit {requested} konnte kein Fenster öffnen. SolidCraft hat {previous} wiederhergestellt.",
"prefs.graphics_api_unavailable": "Die Grafik-API kann in der Desktop-App ausgewählt werden.",
"render.graphics_api_restart_vulkan": "Mit Vulkan neu starten",
"render.graphics_api_restart_warning": "Ein Wechsel der Grafik-API startet SolidCraft neu und fragt nach dem Speichern ungespeicherter Entwürfe. Wenn die neue API kein Fenster öffnen kann, wird beim nächsten Start die vorherige Auswahl wiederhergestellt.",
"render.graphics_api_settings": "Grafikeinstellungen",
"render.graphics_api_vulkan_required": "GPU-Pathtracing benötigt Vulkan in dieser Sitzung. Starten Sie mit Vulkan neu oder verwenden Sie weiterhin ein CPU-Bildverfahren."
},
"ko": {
"prefs.graphics_api": "그래픽 API",
"prefs.graphics_api_auto": "자동",
"prefs.graphics_api_help": "SolidCraft를 시작할 그래픽 API를 선택합니다. 다음 시작에서 창을 열지 못하면 이전 선택으로 복원됩니다.",
"prefs.graphics_api_override": "시작 시 재정의 설정이 그래픽 API를 제어하고 있습니다. SolidCraft를 일반적인 방법으로 열면 저장된 선택이 적용됩니다.",
"prefs.graphics_api_restart_note": "다시 시작한 후 적용됩니다. 닫기 전에 저장하지 않은 설계를 처리합니다.",
"prefs.graphics_api_restart_unavailable": "저장된 그래픽 API를 적용하려면 SolidCraft를 다시 시작하세요.",
"prefs.graphics_api_running": "현재: {current}. 다음 시작 시 선택: {selected}.",
"prefs.graphics_api_save_failed": "그래픽 API 선택을 저장할 수 없습니다: {error}",
"prefs.graphics_api_start_failed": "선택한 그래픽 API를 준비할 수 없습니다: {error}",
"prefs.graphics_api_start_reverted": "{requested}을(를) 사용한 이전 시작에서 창을 열지 못했습니다. SolidCraft가 {previous}(으)로 복원했습니다.",
"prefs.graphics_api_unavailable": "그래픽 API는 데스크톱 앱에서 선택할 수 있습니다.",
"render.graphics_api_restart_vulkan": "Vulkan으로 다시 시작",
"render.graphics_api_restart_warning": "그래픽 API를 변경하면 SolidCraft가 다시 시작되고 저장하지 않은 설계를 저장할지 묻습니다. 새 API로 창을 열지 못하면 다음 시작에서 이전 선택으로 복원됩니다.",
"render.graphics_api_settings": "그래픽 설정",
"render.graphics_api_vulkan_required": "이 세션의 GPU 경로 추적에는 Vulkan이 필요합니다. Vulkan으로 다시 시작하거나 CPU 이미지 방식을 계속 사용하세요."
},
"es": {
"prefs.graphics_api": "API gráfica",
"prefs.graphics_api_auto": "Automático",
"prefs.graphics_api_help": "Elige la API gráfica usada para abrir SolidCraft. Si el próximo inicio no puede abrir la ventana, se restaurará la selección anterior.",
"prefs.graphics_api_override": "Una configuración de arranque está imponiendo la API gráfica. La selección guardada se aplicará al abrir SolidCraft de forma normal.",
"prefs.graphics_api_restart_note": "Se aplica después de reiniciar. Antes de cerrar se revisan los diseños sin guardar.",
"prefs.graphics_api_restart_unavailable": "Reinicia SolidCraft para aplicar la API gráfica guardada.",
"prefs.graphics_api_running": "Actual: {current}. Seleccionada para el próximo inicio: {selected}.",
"prefs.graphics_api_save_failed": "No se pudo guardar la selección de API gráfica: {error}",
"prefs.graphics_api_start_failed": "No se pudo preparar la API gráfica seleccionada: {error}",
"prefs.graphics_api_start_reverted": "El inicio anterior con {requested} no abrió la ventana. SolidCraft ha restaurado {previous}.",
"prefs.graphics_api_unavailable": "La selección de API gráfica está disponible en la aplicación de escritorio.",
"render.graphics_api_restart_vulkan": "Reiniciar con Vulkan",
"render.graphics_api_restart_warning": "Cambiar la API gráfica reinicia SolidCraft y te pide guardar los diseños sin guardar. Si la nueva API no puede abrir la ventana, se restaurará la selección anterior en el próximo inicio.",
"render.graphics_api_settings": "Ajustes gráficos",
"render.graphics_api_vulkan_required": "El trazado de trayectorias por GPU necesita Vulkan en esta sesión. Reinicia con Vulkan o sigue usando un método de imagen por CPU."
}
}
@@ -0,0 +1,20 @@
{
"en": {
"dialog.hole_held_off_its_line": "The reference edge holds this hole on a line that leaves the face before the picked point. Pick where the line crosses the face, or take the edge out to move the hole freely."
},
"ar": {
"dialog.hole_held_off_its_line": "الحافة المرجعية تُبقي هذا الثقب على خط يغادر الوجه قبل النقطة المختارة. اختر حيث يعبر الخط الوجه، أو أزل الحافة لتحريك الثقب بحرية."
},
"he": {
"dialog.hole_held_off_its_line": "קצה הייחוס מחזיק את החור על קו שיוצא מהפאה לפני הנקודה שנבחרה. יש לבחור במקום שבו הקו עובר על הפאה, או להסיר את הקצה כדי להזיז את החור בחופשיות."
},
"ja": {
"dialog.hole_held_off_its_line": "参照エッジがこの穴を直線上に固定していますが、その直線は選択した点より手前で面の外に出ます。直線が面の上を通る位置を選択するか、エッジを外すと穴を自由に移動できます。"
},
"vi": {
"dialog.hole_held_off_its_line": "Cạnh tham chiếu giữ lỗ này trên một đường thẳng ra khỏi mặt trước điểm đã chọn. Hãy chọn chỗ đường thẳng đi qua mặt, hoặc bỏ cạnh để di chuyển lỗ tự do."
},
"zh": {
"dialog.hole_held_off_its_line": "参考边将此孔固定在一条直线上,该直线在所选点之前就离开了该面。请在直线经过该面的位置选取,或移除该边以自由移动孔。"
}
}
@@ -0,0 +1,34 @@
{
"en": {
"nav.maya_horizontal_zoom.help": "Alt+right drag: right zooms in, left zooms out. Turn off to restore vertical drag zoom.",
"nav.maya_horizontal_zoom.label": "Maya: horizontal drag zoom"
},
"ar": {
"nav.maya_horizontal_zoom.help": "اسحب مع Alt وزر الفأرة الأيمن: إلى اليمين للتكبير وإلى اليسار للتصغير. عطّل هذا الخيار لاستعادة التكبير بالسحب العمودي.",
"nav.maya_horizontal_zoom.label": "Maya: التكبير بالسحب الأفقي"
},
"he": {
"nav.maya_horizontal_zoom.help": "Alt וגרירה עם לחצן העכבר הימני: ימינה לקירוב, שמאלה להרחקה. כבו כדי לחזור לזום בגרירה אנכית.",
"nav.maya_horizontal_zoom.label": "Maya: זום בגרירה אופקית"
},
"ja": {
"nav.maya_horizontal_zoom.help": "Alt+右ドラッグで右に動かすと拡大、左に動かすと縮小します。オフにすると従来の垂直ドラッグに戻ります。",
"nav.maya_horizontal_zoom.label": "Maya: 水平方向のドラッグでズーム"
},
"vi": {
"nav.maya_horizontal_zoom.help": "Alt+kéo chuột phải: kéo sang phải để phóng to, sang trái để thu nhỏ. Tắt để khôi phục thu phóng bằng cách kéo dọc.",
"nav.maya_horizontal_zoom.label": "Maya: thu phóng bằng cách kéo ngang"
},
"zh": {
"nav.maya_horizontal_zoom.help": "Alt+右键拖动:向右放大,向左缩小。关闭此选项可恢复垂直拖动缩放。",
"nav.maya_horizontal_zoom.label": "Maya:水平拖动缩放"
},
"de": {
"nav.maya_horizontal_zoom.help": "Alt+Rechtsziehen: nach rechts vergrößern, nach links verkleinern. Ausschalten, um wieder vertikal zu zoomen.",
"nav.maya_horizontal_zoom.label": "Maya: horizontal ziehen zum Zoomen"
},
"ko": {
"nav.maya_horizontal_zoom.help": "Alt+오른쪽 버튼 드래그: 오른쪽으로 움직이면 확대하고 왼쪽으로 움직이면 축소합니다. 끄면 세로 드래그 확대/축소로 돌아갑니다.",
"nav.maya_horizontal_zoom.label": "Maya: 가로 드래그로 확대/축소"
}
}
@@ -0,0 +1,74 @@
{
"en": {
"ai.prefs.control_port": "Port",
"ai.prefs.control_port_note": "The port AI agents connect to on this computer (127.0.0.1). 27878 is the default: when it is in use, the next free port is taken. Any other port is used exactly. Point your MCP client at the same port, for example solidcraft-cli mcp --connect 127.0.0.1:7878.",
"ai.prefs.control_listening": "Listening on 127.0.0.1:{port}",
"ai.prefs.control_not_listening": "Not listening",
"ai.prefs.control_port_taken": "Port {port} is in use by another program (or another SolidCraft window). Choose another port.",
"ai.prefs.control_failed": "The control channel could not start: {error}",
"ai.prefs.control_from_launch": "Started with --control on port {port} for this run. Changes here take effect the next time SolidCraft starts without --control."
},
"de": {
"ai.prefs.control_port": "Port",
"ai.prefs.control_port_note": "Der Port, über den sich KI-Agenten auf diesem Computer verbinden (127.0.0.1). Standard ist 27878: Ist er belegt, wird der nächste freie Port genommen. Jeder andere Port wird genau so verwendet. Richte deinen MCP-Client auf denselben Port, zum Beispiel solidcraft-cli mcp --connect 127.0.0.1:7878.",
"ai.prefs.control_listening": "Wartet auf 127.0.0.1:{port}",
"ai.prefs.control_not_listening": "Nicht aktiv",
"ai.prefs.control_port_taken": "Port {port} wird von einem anderen Programm (oder einem anderen SolidCraft-Fenster) verwendet. Wähle einen anderen Port.",
"ai.prefs.control_failed": "Der Steuerkanal konnte nicht starten: {error}",
"ai.prefs.control_from_launch": "Für diese Sitzung mit --control auf Port {port} gestartet. Änderungen hier gelten beim nächsten Start von SolidCraft ohne --control."
},
"ja": {
"ai.prefs.control_port": "ポート",
"ai.prefs.control_port_note": "このコンピューター上で AI エージェントが接続するポート (127.0.0.1)。既定は 27878 で、使用中の場合は次の空いているポートを使います。それ以外のポートはそのまま使います。MCP クライアントも同じポートに向けてください (例: solidcraft-cli mcp --connect 127.0.0.1:7878)。",
"ai.prefs.control_listening": "127.0.0.1:{port} で待機中",
"ai.prefs.control_not_listening": "待機していません",
"ai.prefs.control_port_taken": "ポート {port} は別のプログラム (または別の SolidCraft ウィンドウ) が使用しています。別のポートを選んでください。",
"ai.prefs.control_failed": "コントロールチャネルを開始できませんでした: {error}",
"ai.prefs.control_from_launch": "この実行は --control でポート {port} を使って開始されました。ここでの変更は、次に --control なしで SolidCraft を起動したときに反映されます。"
},
"zh": {
"ai.prefs.control_port": "端口",
"ai.prefs.control_port_note": "AI 代理在本机上连接的端口 (127.0.0.1)。默认为 27878:若被占用,则使用下一个空闲端口。其他端口按原样使用。请让 MCP 客户端指向同一端口,例如 solidcraft-cli mcp --connect 127.0.0.1:7878。",
"ai.prefs.control_listening": "正在监听 127.0.0.1:{port}",
"ai.prefs.control_not_listening": "未在监听",
"ai.prefs.control_port_taken": "端口 {port} 已被其他程序(或另一个 SolidCraft 窗口)占用。请选择其他端口。",
"ai.prefs.control_failed": "控制通道无法启动:{error}",
"ai.prefs.control_from_launch": "本次运行通过 --control 在端口 {port} 上启动。此处的更改将在下次不带 --control 启动 SolidCraft 时生效。"
},
"ko": {
"ai.prefs.control_port": "포트",
"ai.prefs.control_port_note": "이 컴퓨터에서 AI 에이전트가 연결하는 포트(127.0.0.1)입니다. 기본값은 27878이며, 사용 중이면 다음 빈 포트를 사용합니다. 다른 포트는 그대로 사용합니다. MCP 클라이언트도 같은 포트를 가리키게 하세요(예: solidcraft-cli mcp --connect 127.0.0.1:7878).",
"ai.prefs.control_listening": "127.0.0.1:{port}에서 대기 중",
"ai.prefs.control_not_listening": "대기하지 않음",
"ai.prefs.control_port_taken": "포트 {port}을(를) 다른 프로그램(또는 다른 SolidCraft 창)이 사용 중입니다. 다른 포트를 선택하세요.",
"ai.prefs.control_failed": "제어 채널을 시작할 수 없습니다: {error}",
"ai.prefs.control_from_launch": "이번 실행은 --control로 포트 {port}에서 시작되었습니다. 여기서 바꾼 내용은 다음에 --control 없이 SolidCraft를 시작할 때 적용됩니다."
},
"vi": {
"ai.prefs.control_port": "Cổng",
"ai.prefs.control_port_note": "Cổng mà các tác tử AI kết nối trên máy tính này (127.0.0.1). Mặc định là 27878: nếu cổng đang được dùng, cổng trống tiếp theo sẽ được dùng. Mọi cổng khác được dùng đúng như vậy. Hãy trỏ ứng dụng MCP của bạn đến cùng cổng, ví dụ solidcraft-cli mcp --connect 127.0.0.1:7878.",
"ai.prefs.control_listening": "Đang lắng nghe trên 127.0.0.1:{port}",
"ai.prefs.control_not_listening": "Không lắng nghe",
"ai.prefs.control_port_taken": "Cổng {port} đang được một chương trình khác (hoặc một cửa sổ SolidCraft khác) sử dụng. Hãy chọn cổng khác.",
"ai.prefs.control_failed": "Không thể khởi động kênh điều khiển: {error}",
"ai.prefs.control_from_launch": "Lần chạy này được khởi động với --control trên cổng {port}. Các thay đổi ở đây có hiệu lực vào lần tới SolidCraft khởi động mà không có --control."
},
"ar": {
"ai.prefs.control_port": "المنفذ",
"ai.prefs.control_port_note": "المنفذ الذي يتصل عبره وكلاء الذكاء الاصطناعي على هذا الحاسوب (127.0.0.1). الافتراضي هو 27878: إذا كان مستخدمًا يُستخدم المنفذ الحر التالي. أي منفذ آخر يُستخدم كما هو. وجّه عميل MCP إلى المنفذ نفسه، مثل solidcraft-cli mcp --connect 127.0.0.1:7878.",
"ai.prefs.control_listening": "يستمع على 127.0.0.1:{port}",
"ai.prefs.control_not_listening": "لا يستمع",
"ai.prefs.control_port_taken": "المنفذ {port} يستخدمه برنامج آخر (أو نافذة SolidCraft أخرى). اختر منفذًا آخر.",
"ai.prefs.control_failed": "تعذّر بدء قناة التحكم: {error}",
"ai.prefs.control_from_launch": "بدأ هذا التشغيل باستخدام --control على المنفذ {port}. تسري التغييرات هنا عند تشغيل SolidCraft في المرة القادمة دون --control."
},
"he": {
"ai.prefs.control_port": "פורט",
"ai.prefs.control_port_note": "הפורט שאליו סוכני AI מתחברים במחשב זה (127.0.0.1). ברירת המחדל היא 27878: אם הוא תפוס, נלקח הפורט הפנוי הבא. כל פורט אחר משמש בדיוק כפי שהוא. כוונו את לקוח ה-MCP לאותו פורט, למשל solidcraft-cli mcp --connect 127.0.0.1:7878.",
"ai.prefs.control_listening": "מאזין ב-127.0.0.1:{port}",
"ai.prefs.control_not_listening": "לא מאזין",
"ai.prefs.control_port_taken": "פורט {port} בשימוש של תוכנה אחרת (או חלון SolidCraft אחר). בחרו פורט אחר.",
"ai.prefs.control_failed": "לא ניתן היה להפעיל את ערוץ הבקרה: {error}",
"ai.prefs.control_from_launch": "הפעלה זו התחילה עם --control בפורט {port}. שינויים כאן ייכנסו לתוקף בפעם הבאה ש-SolidCraft יופעל ללא --control."
}
}
@@ -0,0 +1,106 @@
{
"en": {
"operations.cancel": "Cancel {name}",
"operations.cancelled": "{name} cancelled",
"operations.cancelling": "Cancelling…",
"operations.cannot_cancel": "{name} can't be cancelled",
"operations.feature": "Feature",
"operations.feature_edit": "Edit feature",
"operations.meshing": "Loading parts",
"operations.queued": "Queued",
"operations.stopped": "Cancelled",
"prefs.operations_panel": "Show operations in the view",
"prefs.operations_panel_note": "Long operations (opening a file, computing a feature, an agent's command) show in the view's bottom-right corner with their progress and a button that cancels them. Off: a Computing notice, as before."
},
"de": {
"operations.cancel": "{name} abbrechen",
"operations.cancelled": "{name} abgebrochen",
"operations.cancelling": "Wird abgebrochen…",
"operations.cannot_cancel": "{name} kann nicht abgebrochen werden",
"operations.feature": "Feature",
"operations.feature_edit": "Feature bearbeiten",
"operations.meshing": "Teile werden geladen",
"operations.queued": "Wartet",
"operations.stopped": "Abgebrochen",
"prefs.operations_panel": "Vorgänge in der Ansicht zeigen",
"prefs.operations_panel_note": "Lange Vorgänge (eine Datei öffnen, ein Feature berechnen, der Befehl eines Agenten) erscheinen unten rechts in der Ansicht mit ihrem Fortschritt und einer Schaltfläche zum Abbrechen. Aus: wie bisher ein Hinweis „Berechnung“."
},
"ja": {
"operations.cancel": "{name} をキャンセル",
"operations.cancelled": "{name} をキャンセルしました",
"operations.cancelling": "キャンセル中…",
"operations.cannot_cancel": "{name} はキャンセルできません",
"operations.feature": "フィーチャー",
"operations.feature_edit": "フィーチャーを編集",
"operations.meshing": "パーツを読み込み中",
"operations.queued": "待機中",
"operations.stopped": "キャンセル済み",
"prefs.operations_panel": "ビューに処理を表示",
"prefs.operations_panel_note": "時間のかかる処理(ファイルを開く、フィーチャーの計算、エージェントのコマンド)が、進行状況とキャンセルボタンとともにビューの右下に表示されます。オフ:従来どおり「計算中」の通知を表示します。"
},
"ko": {
"operations.cancel": "{name} 취소",
"operations.cancelled": "{name} 취소됨",
"operations.cancelling": "취소하는 중…",
"operations.cannot_cancel": "{name}은(는) 취소할 수 없습니다",
"operations.feature": "피처",
"operations.feature_edit": "피처 편집",
"operations.meshing": "파트 불러오는 중",
"operations.queued": "대기 중",
"operations.stopped": "취소됨",
"prefs.operations_panel": "뷰에 작업 표시",
"prefs.operations_panel_note": "오래 걸리는 작업(파일 열기, 피처 계산, 에이전트 명령)이 진행 상황과 취소 버튼과 함께 뷰의 오른쪽 아래에 표시됩니다. 끄면: 이전처럼 계산 중 알림이 표시됩니다."
},
"zh": {
"operations.cancel": "取消{name}",
"operations.cancelled": "已取消{name}",
"operations.cancelling": "正在取消…",
"operations.cannot_cancel": "无法取消{name}",
"operations.feature": "特征",
"operations.feature_edit": "编辑特征",
"operations.meshing": "正在加载零件",
"operations.queued": "排队中",
"operations.stopped": "已取消",
"prefs.operations_panel": "在视图中显示操作",
"prefs.operations_panel_note": "耗时的操作(打开文件、计算特征、智能体的命令)会连同进度和取消按钮显示在视图右下角。关闭:与以前一样显示“正在计算”提示。"
},
"ar": {
"operations.cancel": "إلغاء {name}",
"operations.cancelled": "تم إلغاء {name}",
"operations.cancelling": "جارٍ الإلغاء…",
"operations.cannot_cancel": "لا يمكن إلغاء {name}",
"operations.feature": "ميزة",
"operations.feature_edit": "تحرير الميزة",
"operations.meshing": "جارٍ تحميل الأجزاء",
"operations.queued": "في الانتظار",
"operations.stopped": "أُلغي",
"prefs.operations_panel": "إظهار العمليات في العرض",
"prefs.operations_panel_note": "تظهر العمليات الطويلة (فتح ملف، حساب ميزة، أمر من وكيل) في الزاوية السفلية اليمنى من العرض مع تقدّمها وزر لإلغائها. عند الإيقاف: إشعار «جارٍ الحساب» كما كان من قبل."
},
"he": {
"operations.cancel": "ביטול {name}",
"operations.cancelled": "{name} בוטל",
"operations.cancelling": "מבטל…",
"operations.cannot_cancel": "לא ניתן לבטל את {name}",
"operations.feature": "פיצ'ר",
"operations.feature_edit": "עריכת פיצ'ר",
"operations.meshing": "טוען חלקים",
"operations.queued": "ממתין",
"operations.stopped": "בוטל",
"prefs.operations_panel": "הצגת פעולות בתצוגה",
"prefs.operations_panel_note": "פעולות ארוכות (פתיחת קובץ, חישוב פיצ'ר, פקודה של סוכן) מוצגות בפינה הימנית התחתונה של התצוגה עם ההתקדמות שלהן וכפתור לביטולן. כבוי: הודעת „מחשב” כמו קודם."
},
"vi": {
"operations.cancel": "Hủy {name}",
"operations.cancelled": "Đã hủy {name}",
"operations.cancelling": "Đang hủy…",
"operations.cannot_cancel": "Không thể hủy {name}",
"operations.feature": "Đặc trưng",
"operations.feature_edit": "Sửa đặc trưng",
"operations.meshing": "Đang tải chi tiết",
"operations.queued": "Đang chờ",
"operations.stopped": "Đã hủy",
"prefs.operations_panel": "Hiện các thao tác trong khung nhìn",
"prefs.operations_panel_note": "Các thao tác dài (mở tệp, tính đặc trưng, lệnh của tác tử) hiện ở góc dưới bên phải khung nhìn cùng tiến độ và nút hủy. Tắt: thông báo Đang tính như trước."
}
}
@@ -0,0 +1,29 @@
{
"en": {
"Drag to place it on another face.": "Drag to place it on another face."
},
"ar": {
"Drag to place it on another face.": "اسحب لوضعه على وجه آخر."
},
"de": {
"Drag to place it on another face.": "Ziehen, um es auf eine andere Fläche zu setzen."
},
"he": {
"Drag to place it on another face.": "יש לגרור כדי להציב אותו על פאה אחרת."
},
"ja": {
"Drag to place it on another face.": "ドラッグして別の面に配置します。"
},
"ko": {
"Drag to place it on another face.": "드래그하여 다른 면에 배치합니다."
},
"pl": {
"Drag to place it on another face.": "Przeciągnij, aby umieścić go na innej ścianie."
},
"vi": {
"Drag to place it on another face.": "Kéo để đặt nó lên một bề mặt khác."
},
"zh": {
"Drag to place it on another face.": "拖动以将其放置到另一个面上。"
}
}
@@ -0,0 +1,10 @@
{
"en": { "cmd.ui.toggle_visibility": "Show/Hide Selection" },
"de": { "cmd.ui.toggle_visibility": "Auswahl ein-/ausblenden" },
"ar": { "cmd.ui.toggle_visibility": "إظهار/إخفاء التحديد" },
"he": { "cmd.ui.toggle_visibility": "הצגה/הסתרה של הבחירה" },
"ja": { "cmd.ui.toggle_visibility": "選択項目の表示/非表示" },
"ko": { "cmd.ui.toggle_visibility": "선택 항목 표시/숨기기" },
"vi": { "cmd.ui.toggle_visibility": "Hiển thị/Ẩn mục đã chọn" },
"zh": { "cmd.ui.toggle_visibility": "显示/隐藏所选项" }
}
@@ -0,0 +1,30 @@
{
"en": {
"ui.relink_one_done": "Source relinked for this instance.",
"ui.relink_source_one": "Relink Source…"
},
"ar": {
"ui.relink_one_done": "أُعيد ربط المصدر لهذه النسخة.",
"ui.relink_source_one": "إعادة ربط المصدر…"
},
"de": {
"ui.relink_one_done": "Quelle für diese Instanz neu verknüpft.",
"ui.relink_source_one": "Quelle neu verknüpfen…"
},
"he": {
"ui.relink_one_done": "המקור קושר מחדש למופע זה.",
"ui.relink_source_one": "קישור מחדש למקור…"
},
"ja": {
"ui.relink_one_done": "このインスタンスの参照元を再リンクしました。",
"ui.relink_source_one": "参照元を再リンク…"
},
"vi": {
"ui.relink_one_done": "Đã liên kết lại nguồn cho thể hiện này.",
"ui.relink_source_one": "Liên kết lại nguồn…"
},
"zh": {
"ui.relink_one_done": "已为此实例重新链接源文件。",
"ui.relink_source_one": "重新链接源文件…"
}
}
@@ -0,0 +1,132 @@
{
"en": {
"dialog.right_click_pick": "Select {input} first",
"ui.right_click_confirms": "Right-click confirms dialog inputs",
"ui.right_click_confirms_tip": "With a dialog open, a right-click in the view goes on to its next empty input, and on the last one runs OK"
},
"cs": {
"dialog.right_click_pick": "Nejprve vyberte {input}",
"ui.right_click_confirms": "Pravé kliknutí potvrzuje vstupy dialogu",
"ui.right_click_confirms_tip": "Při otevřeném dialogu přejde pravé kliknutí v zobrazení na další prázdný vstup a u posledního provede OK"
},
"da": {
"dialog.right_click_pick": "Vælg først {input}",
"ui.right_click_confirms": "Højreklik bekræfter dialogens input",
"ui.right_click_confirms_tip": "Med en dialog åben går et højreklik i visningen videre til næste tomme input, og ved det sidste udføres OK"
},
"de": {
"dialog.right_click_pick": "Zuerst {input} auswählen",
"ui.right_click_confirms": "Rechtsklick bestätigt Dialogeingaben",
"ui.right_click_confirms_tip": "Bei offenem Dialog springt ein Rechtsklick in der Ansicht zur nächsten leeren Eingabe und führt bei der letzten OK aus"
},
"es": {
"dialog.right_click_pick": "Selecciona primero {input}",
"ui.right_click_confirms": "El clic derecho confirma las entradas del diálogo",
"ui.right_click_confirms_tip": "Con un diálogo abierto, un clic derecho en la vista pasa a la siguiente entrada vacía y, en la última, ejecuta OK"
},
"fr": {
"dialog.right_click_pick": "Sélectionner d’abord {input}",
"ui.right_click_confirms": "Le clic droit valide les entrées du dialogue",
"ui.right_click_confirms_tip": "Avec un dialogue ouvert, un clic droit dans la vue passe à l’entrée vide suivante et, sur la dernière, exécute OK"
},
"gl": {
"dialog.right_click_pick": "Selecciona primeiro {input}",
"ui.right_click_confirms": "O clic dereito confirma as entradas do diálogo",
"ui.right_click_confirms_tip": "Cun diálogo aberto, un clic dereito na vista pasa á seguinte entrada baleira e, na última, executa OK"
},
"hu": {
"dialog.right_click_pick": "Előbb jelölje ki ezt: {input}",
"ui.right_click_confirms": "A jobb kattintás jóváhagyja a párbeszédablak bemeneteit",
"ui.right_click_confirms_tip": "Nyitott párbeszédablaknál a nézetben a jobb kattintás a következő üres bemenetre lép, az utolsónál pedig OK-t nyom"
},
"id": {
"dialog.right_click_pick": "Pilih {input} terlebih dahulu",
"ui.right_click_confirms": "Klik kanan mengonfirmasi input dialog",
"ui.right_click_confirms_tip": "Saat dialog terbuka, klik kanan di tampilan berpindah ke input kosong berikutnya, dan pada input terakhir menjalankan OK"
},
"it": {
"dialog.right_click_pick": "Seleziona prima {input}",
"ui.right_click_confirms": "Il clic destro conferma gli input della finestra di dialogo",
"ui.right_click_confirms_tip": "Con una finestra di dialogo aperta, un clic destro nella vista passa al successivo input vuoto e, sull’ultimo, esegue OK"
},
"ja": {
"dialog.right_click_pick": "先に {input} を選択",
"ui.right_click_confirms": "右クリックでダイアログの入力を確定",
"ui.right_click_confirms_tip": "ダイアログが開いているとき、ビューで右クリックすると次の空の入力へ進み、最後の入力では OK を実行します"
},
"ko": {
"dialog.right_click_pick": "먼저 {input} 선택",
"ui.right_click_confirms": "오른쪽 클릭으로 대화 상자 입력 확인",
"ui.right_click_confirms_tip": "대화 상자가 열려 있을 때 뷰에서 오른쪽 클릭하면 다음 빈 입력으로 이동하고, 마지막 입력에서는 OK를 실행합니다"
},
"ms": {
"dialog.right_click_pick": "Pilih {input} dahulu",
"ui.right_click_confirms": "Klik kanan mengesahkan input dialog",
"ui.right_click_confirms_tip": "Apabila dialog dibuka, klik kanan dalam paparan beralih ke input kosong seterusnya, dan pada input terakhir menjalankan OK"
},
"nl": {
"dialog.right_click_pick": "Eerst {input} selecteren",
"ui.right_click_confirms": "Rechtsklik bevestigt dialooginvoer",
"ui.right_click_confirms_tip": "Met een dialoog open gaat een rechtsklik in de weergave naar de volgende lege invoer, en bij de laatste voert hij OK uit"
},
"pl": {
"dialog.right_click_pick": "Najpierw zaznacz {input}",
"ui.right_click_confirms": "Prawy klik zatwierdza pola okna dialogowego",
"ui.right_click_confirms_tip": "Przy otwartym oknie dialogowym prawy klik w widoku przechodzi do następnego pustego pola, a przy ostatnim wykonuje OK"
},
"pt-BR": {
"dialog.right_click_pick": "Selecione {input} primeiro",
"ui.right_click_confirms": "O clique direito confirma as entradas da caixa de diálogo",
"ui.right_click_confirms_tip": "Com uma caixa de diálogo aberta, um clique direito na vista passa para a próxima entrada vazia e, na última, executa OK"
},
"ro": {
"dialog.right_click_pick": "Selectați mai întâi {input}",
"ui.right_click_confirms": "Clicul dreapta confirmă intrările dialogului",
"ui.right_click_confirms_tip": "Cu un dialog deschis, un clic dreapta în vedere trece la următoarea intrare goală, iar la ultima rulează OK"
},
"ru": {
"dialog.right_click_pick": "Сначала выберите {input}",
"ui.right_click_confirms": "Правый щелчок подтверждает поля диалога",
"ui.right_click_confirms_tip": "При открытом диалоге правый щелчок в виде переходит к следующему пустому полю, а на последнем выполняет OK"
},
"sv": {
"dialog.right_click_pick": "Markera {input} först",
"ui.right_click_confirms": "Högerklick bekräftar dialogens indata",
"ui.right_click_confirms_tip": "Med en dialog öppen går ett högerklick i vyn vidare till nästa tomma indata, och vid den sista körs OK"
},
"tr": {
"dialog.right_click_pick": "Önce {input} seçin",
"ui.right_click_confirms": "Sağ tıklama iletişim kutusu girişlerini onaylar",
"ui.right_click_confirms_tip": "Bir iletişim kutusu açıkken görünümde sağ tıklama bir sonraki boş girişe geçer, sonuncusunda ise OK çalıştırır"
},
"uk": {
"dialog.right_click_pick": "Спочатку виберіть {input}",
"ui.right_click_confirms": "Правий клік підтверджує поля діалогу",
"ui.right_click_confirms_tip": "Коли діалог відкрито, правий клік у вигляді переходить до наступного порожнього поля, а на останньому виконує OK"
},
"vi": {
"dialog.right_click_pick": "Chọn {input} trước",
"ui.right_click_confirms": "Nhấp chuột phải xác nhận đầu vào của hộp thoại",
"ui.right_click_confirms_tip": "Khi hộp thoại đang mở, nhấp chuột phải trong khung nhìn chuyển sang đầu vào trống tiếp theo, và ở đầu vào cuối cùng sẽ chạy OK"
},
"zh": {
"dialog.right_click_pick": "请先选择{input}",
"ui.right_click_confirms": "右键确认对话框输入",
"ui.right_click_confirms_tip": "对话框打开时,在视图中右键单击会转到下一个空输入,在最后一个输入上执行 OK"
},
"zh-TW": {
"dialog.right_click_pick": "請先選擇{input}",
"ui.right_click_confirms": "右鍵確認對話方塊輸入",
"ui.right_click_confirms_tip": "對話方塊開啟時,在視圖中按右鍵會轉到下一個空白輸入,在最後一個輸入上執行 OK"
},
"ar": {
"dialog.right_click_pick": "اختر {input} أولاً",
"ui.right_click_confirms": "النقر بزر الماوس الأيمن يؤكد مدخلات مربع الحوار",
"ui.right_click_confirms_tip": "عندما يكون مربع حوار مفتوحاً، ينتقل النقر بزر الماوس الأيمن في العرض إلى المدخل الفارغ التالي، وعند المدخل الأخير ينفّذ موافق"
},
"he": {
"dialog.right_click_pick": "יש לבחור תחילה {input}",
"ui.right_click_confirms": "לחיצה ימנית מאשרת קלטים בתיבת דו-שיח",
"ui.right_click_confirms_tip": "כאשר תיבת דו-שיח פתוחה, לחיצה ימנית בתצוגה עוברת לקלט הריק הבא, ובקלט האחרון מבצעת אישור"
}
}
@@ -0,0 +1,8 @@
{
"en": { "cmd.selection_get": "Get Selection" },
"ar": { "cmd.selection_get": "الحصول على التحديد" },
"he": { "cmd.selection_get": "קבלת הבחירה" },
"ja": { "cmd.selection_get": "選択を取得" },
"vi": { "cmd.selection_get": "Lấy vùng chọn" },
"zh": { "cmd.selection_get": "获取选择" }
}
@@ -0,0 +1,62 @@
{
"en": {
"prefs.sketch.cursor_coordinates": "Show the cursor's coordinates in a sketch",
"prefs.sketch.cursor_coordinates_note": "Beside the pointer, its X and Y from the sketch origin, also with no tool running. Off: only while a tool places a point."
},
"ar": {
"prefs.sketch.cursor_coordinates": "إظهار إحداثيات المؤشر في الرسم",
"prefs.sketch.cursor_coordinates_note": "بجانب المؤشر، قيمتا X وY من أصل الرسم، حتى دون تشغيل أي أداة. إيقاف: فقط أثناء وضع أداة لنقطة."
},
"de": {
"prefs.sketch.cursor_coordinates": "Cursorkoordinaten in der Skizze anzeigen",
"prefs.sketch.cursor_coordinates_note": "Neben dem Zeiger seine X- und Y-Werte vom Skizzenursprung, auch ohne aktives Werkzeug. Aus: nur während ein Werkzeug einen Punkt setzt."
},
"es": {
"prefs.sketch.cursor_coordinates": "Mostrar las coordenadas del cursor en un croquis",
"prefs.sketch.cursor_coordinates_note": "Junto al puntero, su X e Y desde el origen del croquis, también sin ninguna herramienta activa. Desactivado: solo mientras una herramienta coloca un punto."
},
"fr": {
"prefs.sketch.cursor_coordinates": "Afficher les coordonnées du curseur dans une esquisse",
"prefs.sketch.cursor_coordinates_note": "À côté du pointeur, ses X et Y depuis l'origine de l'esquisse, même sans outil actif. Désactivé : seulement pendant qu'un outil place un point."
},
"he": {
"prefs.sketch.cursor_coordinates": "הצגת קואורדינטות הסמן בסקיצה",
"prefs.sketch.cursor_coordinates_note": "ליד הסמן, ערכי X ו-Y שלו מראשית הסקיצה, גם כשאין כלי פעיל. כבוי: רק בזמן שכלי ממקם נקודה."
},
"it": {
"prefs.sketch.cursor_coordinates": "Mostra le coordinate del cursore in uno schizzo",
"prefs.sketch.cursor_coordinates_note": "Accanto al puntatore, la sua X e Y dall'origine dello schizzo, anche senza strumenti attivi. Disattivato: solo mentre uno strumento posiziona un punto."
},
"ja": {
"prefs.sketch.cursor_coordinates": "スケッチでカーソル座標を表示",
"prefs.sketch.cursor_coordinates_note": "ツールを実行していないときも、ポインターの横にスケッチ原点からの X と Y を表示します。オフ: ツールで点を配置している間だけ表示します。"
},
"ko": {
"prefs.sketch.cursor_coordinates": "스케치에서 커서 좌표 표시",
"prefs.sketch.cursor_coordinates_note": "도구를 실행하지 않을 때도 포인터 옆에 스케치 원점 기준 X와 Y를 표시합니다. 끄기: 도구로 점을 배치하는 동안에만 표시합니다."
},
"pl": {
"prefs.sketch.cursor_coordinates": "Pokazuj współrzędne kursora w szkicu",
"prefs.sketch.cursor_coordinates_note": "Obok wskaźnika jego X i Y od początku szkicu, także gdy żadne narzędzie nie działa. Wyłączone: tylko gdy narzędzie umieszcza punkt."
},
"pt-BR": {
"prefs.sketch.cursor_coordinates": "Mostrar as coordenadas do cursor em um esboço",
"prefs.sketch.cursor_coordinates_note": "Ao lado do ponteiro, seu X e Y a partir da origem do esboço, também sem nenhuma ferramenta ativa. Desativado: só enquanto uma ferramenta posiciona um ponto."
},
"ru": {
"prefs.sketch.cursor_coordinates": "Показывать координаты курсора в эскизе",
"prefs.sketch.cursor_coordinates_note": "Рядом с указателем его X и Y от начала координат эскиза, даже без активного инструмента. Выкл.: только пока инструмент ставит точку."
},
"vi": {
"prefs.sketch.cursor_coordinates": "Hiển thị tọa độ con trỏ trong bản phác thảo",
"prefs.sketch.cursor_coordinates_note": "Bên cạnh con trỏ, X và Y của nó tính từ gốc bản phác thảo, kể cả khi không có công cụ nào chạy. Tắt: chỉ khi một công cụ đang đặt điểm."
},
"zh": {
"prefs.sketch.cursor_coordinates": "在草图中显示光标坐标",
"prefs.sketch.cursor_coordinates_note": "即使没有运行工具,也在指针旁显示其相对于草图原点的 X 和 Y。关闭:仅在工具放置点时显示。"
},
"zh-TW": {
"prefs.sketch.cursor_coordinates": "在草圖中顯示游標座標",
"prefs.sketch.cursor_coordinates_note": "即使沒有執行工具,也在指標旁顯示其相對於草圖原點的 X 和 Y。關閉:僅在工具放置點時顯示。"
}
}
@@ -0,0 +1,74 @@
{
"en": {
"ui.sketch_links_added_curve": "{command} added 1 curve to the sketch.",
"ui.sketch_links_added_curves": "{command} added {count} curves to the sketch.",
"ui.sketch_links_added_point": "{command} added 1 point to the sketch.",
"ui.sketch_links_added_points": "{command} added {count} points to the sketch.",
"ui.sketch_links_hidden": "The result is hidden because {option} is off in the sketch palette.",
"ui.sketch_links_added_curves_and_points": "{command} added {curves} and {points} to the sketch.",
"ui.sketch_links_curve_count_one": "1 curve",
"ui.sketch_links_curve_count": "{count} curves",
"ui.sketch_links_point_count_one": "1 point",
"ui.sketch_links_point_count": "{count} points"
},
"ar": {
"ui.sketch_links_added_curve": "أضاف {command} منحنى واحدًا إلى الرسم.",
"ui.sketch_links_added_curves": "أضاف {command} منحنيات إلى الرسم (العدد: {count}).",
"ui.sketch_links_added_point": "أضاف {command} نقطة واحدة إلى الرسم.",
"ui.sketch_links_added_points": "أضاف {command} نقاطًا إلى الرسم (العدد: {count}).",
"ui.sketch_links_hidden": "النتيجة مخفية لأن خيار {option} مُعطَّل في خيارات الرسم.",
"ui.sketch_links_added_curves_and_points": "أضاف {command} إلى الرسم {curves} و{points}.",
"ui.sketch_links_curve_count_one": "منحنى واحدًا",
"ui.sketch_links_curve_count": "منحنيات (العدد: {count})",
"ui.sketch_links_point_count_one": "نقطة واحدة",
"ui.sketch_links_point_count": "نقاطًا (العدد: {count})"
},
"he": {
"ui.sketch_links_added_curve": "{command} הוסיף עקומה אחת לסקיצה.",
"ui.sketch_links_added_curves": "{command} הוסיף {count} עקומות לסקיצה.",
"ui.sketch_links_added_point": "{command} הוסיף נקודה אחת לסקיצה.",
"ui.sketch_links_added_points": "{command} הוסיף {count} נקודות לסקיצה.",
"ui.sketch_links_hidden": "התוצאה מוסתרת כי האפשרות {option} כבויה באפשרויות הסקיצה.",
"ui.sketch_links_added_curves_and_points": "{command} הוסיף לסקיצה {curves} ו־{points}.",
"ui.sketch_links_curve_count_one": "עקומה אחת",
"ui.sketch_links_curve_count": "{count} עקומות",
"ui.sketch_links_point_count_one": "נקודה אחת",
"ui.sketch_links_point_count": "{count} נקודות"
},
"ja": {
"ui.sketch_links_added_curve": "{command} でスケッチに曲線を 1 本追加しました。",
"ui.sketch_links_added_curves": "{command} でスケッチに曲線を {count} 本追加しました。",
"ui.sketch_links_added_point": "{command} でスケッチに点を 1 個追加しました。",
"ui.sketch_links_added_points": "{command} でスケッチに点を {count} 個追加しました。",
"ui.sketch_links_hidden": "スケッチオプションの {option} がオフのため、結果は表示されていません。",
"ui.sketch_links_added_curves_and_points": "{command} でスケッチに{curves}と{points}を追加しました。",
"ui.sketch_links_curve_count_one": "曲線 1 本",
"ui.sketch_links_curve_count": "曲線 {count} 本",
"ui.sketch_links_point_count_one": "点 1 個",
"ui.sketch_links_point_count": "点 {count} 個"
},
"vi": {
"ui.sketch_links_added_curve": "{command} đã thêm 1 đường cong vào bản phác thảo.",
"ui.sketch_links_added_curves": "{command} đã thêm {count} đường cong vào bản phác thảo.",
"ui.sketch_links_added_point": "{command} đã thêm 1 điểm vào bản phác thảo.",
"ui.sketch_links_added_points": "{command} đã thêm {count} điểm vào bản phác thảo.",
"ui.sketch_links_hidden": "Kết quả bị ẩn vì {option} đang tắt trong Tùy chọn phác thảo.",
"ui.sketch_links_added_curves_and_points": "{command} đã thêm {curves} và {points} vào bản phác thảo.",
"ui.sketch_links_curve_count_one": "1 đường cong",
"ui.sketch_links_curve_count": "{count} đường cong",
"ui.sketch_links_point_count_one": "1 điểm",
"ui.sketch_links_point_count": "{count} điểm"
},
"zh": {
"ui.sketch_links_added_curve": "{command} 已向草图添加 1 条曲线。",
"ui.sketch_links_added_curves": "{command} 已向草图添加 {count} 条曲线。",
"ui.sketch_links_added_point": "{command} 已向草图添加 1 个点。",
"ui.sketch_links_added_points": "{command} 已向草图添加 {count} 个点。",
"ui.sketch_links_hidden": "结果已隐藏,因为草图选项中的“{option}”已关闭。",
"ui.sketch_links_added_curves_and_points": "{command} 已向草图添加{curves}和{points}。",
"ui.sketch_links_curve_count_one": "1 条曲线",
"ui.sketch_links_curve_count": "{count} 条曲线",
"ui.sketch_links_point_count_one": "1 个点",
"ui.sketch_links_point_count": "{count} 个点"
}
}
@@ -0,0 +1,42 @@
{
"en": {
"prefs.sketch.max_points": "Largest sketch",
"prefs.sketch.max_points_note": "The most points or curves one sketch holds: 20000 by default, at most 200000. Insert SVG and Insert DXF refuse a larger drawing. A large sketch solves and draws more slowly.",
"prefs.sketch.max_points_unit": "points"
},
"ar": {
"prefs.sketch.max_points": "أكبر رسم تخطيطي",
"prefs.sketch.max_points_note": "أكبر عدد من النقاط أو المنحنيات في رسم تخطيطي واحد: 20000 افتراضيًا، و200000 كحد أقصى. يرفض إدراج SVG وإدراج DXF رسمًا أكبر. الرسم التخطيطي الكبير يُحل ويُعرض بشكل أبطأ.",
"prefs.sketch.max_points_unit": "نقطة"
},
"de": {
"prefs.sketch.max_points": "Größte Skizze",
"prefs.sketch.max_points_note": "Die meisten Punkte oder Kurven, die eine Skizze aufnimmt: standardmäßig 20000, höchstens 200000. SVG einfügen und DXF einfügen lehnen eine größere Zeichnung ab. Eine große Skizze wird langsamer gelöst und gezeichnet.",
"prefs.sketch.max_points_unit": "Punkte"
},
"he": {
"prefs.sketch.max_points": "הסקיצה הגדולה ביותר",
"prefs.sketch.max_points_note": "המספר המרבי של נקודות או עקומות בסקיצה אחת: 20000 כברירת מחדל, ועד 200000. הוספת SVG והוספת DXF דוחות שרטוט גדול יותר. סקיצה גדולה נפתרת ומוצגת לאט יותר.",
"prefs.sketch.max_points_unit": "נקודות"
},
"ja": {
"prefs.sketch.max_points": "最大スケッチ",
"prefs.sketch.max_points_note": "1 つのスケッチに入る点または曲線の最大数です。既定は 20000、上限は 200000 です。SVG を挿入と DXF を挿入は、これより大きい図面を受け付けません。大きなスケッチは解決と描画が遅くなります。",
"prefs.sketch.max_points_unit": "点"
},
"ko": {
"prefs.sketch.max_points": "최대 스케치",
"prefs.sketch.max_points_note": "스케치 하나에 들어가는 점 또는 곡선의 최대 개수입니다. 기본값은 20000, 최대 200000입니다. SVG 삽입과 DXF 삽입은 이보다 큰 도면을 거부합니다. 큰 스케치는 해석과 그리기가 느려집니다.",
"prefs.sketch.max_points_unit": "점"
},
"vi": {
"prefs.sketch.max_points": "Phác thảo lớn nhất",
"prefs.sketch.max_points_note": "Số điểm hoặc đường cong tối đa trong một phác thảo: mặc định 20000, tối đa 200000. Chèn tệp SVG và Chèn tệp DXF từ chối bản vẽ lớn hơn. Phác thảo lớn được giải và vẽ chậm hơn.",
"prefs.sketch.max_points_unit": "điểm"
},
"zh": {
"prefs.sketch.max_points": "最大草图",
"prefs.sketch.max_points_note": "一个草图可容纳的点或曲线的最大数量:默认 20000,最多 200000。插入 SVG 和插入 DXF 会拒绝更大的图形。大型草图的求解和绘制会更慢。",
"prefs.sketch.max_points_unit": "点"
}
}
@@ -0,0 +1,34 @@
{
"en": {
"prefs.sketch.snap_to_visible_grid": "Snap to the grid's visible crossings",
"prefs.sketch_snap_to_visible_grid_note": "A point in a sketch snaps to the crossings of the lines the grid draws when the pointer means one, and to the finer lattice between them otherwise. Off: the point snaps to the finer lattice only, as before."
},
"ar": {
"prefs.sketch.snap_to_visible_grid": "الالتقاط عند تقاطع الشبكة المرئي",
"prefs.sketch_snap_to_visible_grid_note": "تلتصق النقطة في الرسم عند تقاطع الخطوط التي ترسمها الشبكة عندما يشير المؤشر إلى أحدها، وإلا تلتصق بالشبكة الأدق بينها. عند الإيقاف: تلتصق النقطة بالشبكة الأدق فقط، كما كان."
},
"de": {
"prefs.sketch.snap_to_visible_grid": "Am sichtbaren Schnittpunkt des Rasters fangen",
"prefs.sketch_snap_to_visible_grid_note": "Ein Punkt in einer Skizze rastet am Schnittpunkt der vom Raster gezeichneten Linien ein, wenn der Zeiger auf einen davon zeigt, sonst am feineren Gitter zwischen ihnen. Aus: Der Punkt rastet nur am feineren Gitter ein, wie zuvor."
},
"he": {
"prefs.sketch.snap_to_visible_grid": "הצמדה למפגשים הנראים של הרשת",
"prefs.sketch_snap_to_visible_grid_note": "נקודה בסקיצה נצמדת למפגש של הקווים שהרשת מציירת כשהמצביע מכוון לאחד מהם, ולרשת הדקה שביניהם אחרת. כבוי: הנקודה נצמדת לרשת הדקה בלבד, כמו קודם."
},
"ja": {
"prefs.sketch.snap_to_visible_grid": "グリッドの交点にスナップ",
"prefs.sketch_snap_to_visible_grid_note": "スケッチ内の点は、グリッドが描画する線の交点にポインターが指しているときはその交点にスナップし、それ以外ではその間のより細かい格子の交点にスナップします。オフ: 前也是一样で、点はより細かい格子の交点にだけスナップします。"
},
"ko": {
"prefs.sketch.snap_to_visible_grid": "격자의 보이는 교차점에 스냅",
"prefs.sketch_snap_to_visible_grid_note": "스케치의 점은 포인터가 가리키는 경우 격자가 그리는 선들의 교차점에 스냅되고, 그렇지 않으면 그 사이의 더 촘촘한 격자에 스냅됩니다. 끄기: 이전과 같이 점은 촘촘한 격자에만 스냅됩니다."
},
"vi": {
"prefs.sketch.snap_to_visible_grid": "Bắt vào giao điểm nhìn thấy của lưới",
"prefs.sketch_snap_to_visible_grid_note": "Một điểm trong phác thảo bắt vào giao điểm của các đường mà lưới vẽ khi con trỏ chỉ vào một giao điểm, và vào lưới mịn hơn giữa chúng trong trường hợp khác. Tắt: điểm chỉ bắt vào lưới mịn hơn, như trước."
},
"zh": {
"prefs.sketch.snap_to_visible_grid": "捕捉网格可见的交点",
"prefs.sketch_snap_to_visible_grid_note": "当指针指向网格绘制的线的交点时,草图中的点捕捉到该交点,否则捕捉到交点之间更细的网格。关闭:点只捕捉到更细的网格,与之前相同。"
}
}
@@ -0,0 +1,62 @@
{
"uk": {
"prefs.render_legacy_memory_admission": "Використовувати попередні перевірки пам'яті рендерингу",
"prefs.render_legacy_memory_admission_help": "Дозволяє нативний рендеринг у межах фіксованих бюджетів спільної пам'яті та пам'яті хоста, навіть коли оцінка перевищує доступну RAM. Обмеження пристрою й перевірки виділення пам'яті все одно діють.",
"render.caustics_area_lights": "Каустика площинних джерел світла",
"render.caustics_environment": "Каустика середовища",
"render.cpu_threads": "Робочі потоки CPU",
"render.cpu_threads_auto": "Авто",
"render.cpu_threads_custom": "Власна",
"render.cpu_threads_help": "«Авто» використовує доступні робочі потоки CPU. Один потік працює послідовно. Більше потоків може потребувати більше пам'яті.",
"render.cpu_threads_single": "Один",
"render.cpu_threads_web": "Рендеринг у браузері використовує один кооперативний робочий потік. Вибір робочих потоків, збережений для настільного застосунку, не змінюється.",
"render.denoise_class_background": "Пропущено: фон",
"render.denoise_class_coverage": "Пропущено: часткове покриття",
"render.denoise_class_degenerate": "Пропущено: вироджений шлях",
"render.denoise_class_depth": "Пропущено: ліміт глибини шляху",
"render.denoise_class_emitter": "Пропущено: джерело світла",
"render.denoise_class_exit": "Пропущено: несумісний вихід",
"render.denoise_class_identity": "Пропущено: ліміт ідентичності напрямних даних",
"render.denoise_class_lens": "Пропущено: глибина різкості",
"render.denoise_class_material": "Пропущено: непідтримуваний матеріал",
"render.denoise_class_nested": "Пропущено: вкладене середовище",
"render.denoise_class_optical": "Придатне: заломлена поверхня",
"render.denoise_class_reflection": "Пропущено: відбивна кінцева точка",
"render.denoise_class_surface": "Придатне: поверхня",
"render.denoise_class_tir": "Пропущено: повне внутрішнє відбиття",
"render.denoise_class_transmission": "Пропущено: подальше пропускання",
"render.denoise_class_unavailable": "Пропущено: немає напрямних даних",
"render.denoise_class_volume": "Пропущено: об'ємне розсіювання",
"render.denoise_diagnostics_counts": "Придатні: {eligible} · Пропущені: {skipped}",
"render.denoise_diagnostics_enable": "Збирати діагностику шумозаглушення",
"render.denoise_diagnostics_grid": "Кількість пікселів у внутрішньому розмірі {width} × {height}.",
"render.denoise_diagnostics_help": "Збирає кількість придатних і пропущених пікселів, навіть коли шумозаглушення вимкнено. Лічба використовує внутрішній розмір рендерингу, а маска — вихідний розмір.",
"render.denoise_diagnostics_title": "Діагностика шумозаглушення",
"render.denoise_export_mask": "Експортувати маску PNG",
"render.denoise_firefly": "Пригнічувати ізольовані яскраві пікселі",
"render.denoise_format_mask": "Маска PNG",
"render.denoise_mask_copy_help": "Експортуйте маску шумозаглушення як PNG або поверніться до відрендереного зображення, щоб скопіювати його.",
"render.denoise_mask_unavailable": "Увімкніть діагностику шумозаглушення й відрендерте зображення, щоб оглянути його маску.",
"render.denoise_optical_filter": "Фільтрувати дзеркала й скло",
"render.denoise_optical_filter_help": "Фільтрувати придатне відбите й пропущене світло. Вимкніть, щоб шумозаглушувати лише непрозорі поверхні.",
"render.denoise_passes": "Проходи фільтрації",
"render.denoise_settings_help": "Більше проходів згладжує ширшу область. Сила визначає, скільки фільтрації застосовує кожен прохід. Непідтримувані оптичні шляхи залишаються нефільтрованими.",
"render.denoise_strength": "Сила шумозаглушення",
"render.denoise_view_image": "Відрендерене зображення",
"render.denoise_view_mask": "Маска шумозаглушення",
"render.metal_energy_compensation": "Відновлювати відбивну здатність шорсткого металу",
"render.metal_energy_compensation_help": "Компенсує втрати світла між мікрогранями шорсткого металу. Рендеринг на CPU потребує непрямого освітлення.",
"render.quality_legacy_samples": "Збережене значення: {samples} вибірок на піксель. Нові значення обмежено {maximum} вибірками на піксель.",
"render.quality_preset_limit": "Цей пресет перевищує ліміт вибору 16384 вибірок на піксель. Виберіть кількість вибірок до 16384.",
"render.size_8k_uhd": "8K UHD",
"render.supersampling": "Наддискретизація",
"render.supersampling_dimensions": "Рендерить {width} × {height} і зменшує до {output_width} × {output_height}. Використовує вчетверо більше пікселів.",
"render.supersampling_help": "Рендерить із подвійною шириною та висотою, потім зменшує в лінійному світлі. Вихідний розмір не змінюється.",
"render.supersampling_off": "Вимкнено",
"render.supersampling_x2": "2×",
"render.texture_filtering": "Фільтрувати деталі текстури",
"render.texture_filtering_help": "Використовує mip-рівні й анізотропну фільтрацію, щоб зменшити аліасинг текстури під час мінімізації. Потребує більше пам'яті; вимкнено зберігає попередню фільтрацію.",
"ui.construction.axis_hint": "Допоміжна пряма: клацніть точку або введіть її відстань від осі ескізу",
"ui.construction.parallel_hint": "Допоміжна пряма: виберіть пряму, потім клацніть або введіть зсув; клацніть правою кнопкою, щоб змінити опорний об'єкт"
}
}
@@ -0,0 +1,34 @@
{
"en": {
"ui.view_compass_tip": "View from {axis}. Click again to reverse. Drag to orbit.",
"ui.view_compass_tip_snap": "View from {axis}. Click again to reverse. Drag to orbit; hold Shift to snap."
},
"ar": {
"ui.view_compass_tip": "العرض من {axis}. انقر مرة أخرى للعكس. اسحب لتدوير العرض.",
"ui.view_compass_tip_snap": "العرض من {axis}. انقر مرة أخرى للعكس. اسحب لتدوير العرض؛ اضغط مطولًا على Shift للالتقاط."
},
"de": {
"ui.view_compass_tip": "Ansicht von {axis}. Erneut klicken zum Umkehren. Ziehen zum Drehen.",
"ui.view_compass_tip_snap": "Ansicht von {axis}. Erneut klicken zum Umkehren. Ziehen zum Drehen; Umschalttaste halten zum Einrasten."
},
"he": {
"ui.view_compass_tip": "מבט מ־{axis}. לחיצה נוספת הופכת את הכיוון. גרירה מסובבת את המבט.",
"ui.view_compass_tip_snap": "מבט מ־{axis}. לחיצה נוספת הופכת את הכיוון. גרירה מסובבת את המבט; יש להחזיק את Shift כדי להצמיד."
},
"ja": {
"ui.view_compass_tip": "{axis}方向から表示します。もう一度クリックすると反転します。ドラッグでオービットします。",
"ui.view_compass_tip_snap": "{axis}方向から表示します。もう一度クリックすると反転します。ドラッグでオービットし、Shiftを押すとスナップします。"
},
"ko": {
"ui.view_compass_tip": "{axis} 방향에서 봅니다. 다시 클릭하면 반대 방향으로 바뀝니다. 드래그하여 회전합니다.",
"ui.view_compass_tip_snap": "{axis} 방향에서 봅니다. 다시 클릭하면 반대 방향으로 바뀝니다. 드래그하여 회전하고, Shift를 누르면 스냅됩니다."
},
"vi": {
"ui.view_compass_tip": "Nhìn từ {axis}. Bấm lần nữa để đảo ngược. Kéo để xoay góc nhìn.",
"ui.view_compass_tip_snap": "Nhìn từ {axis}. Bấm lần nữa để đảo ngược. Kéo để xoay góc nhìn; giữ Shift để bắt dính."
},
"zh": {
"ui.view_compass_tip": "从 {axis} 方向查看。再次单击可反向。拖动可环绕。",
"ui.view_compass_tip_snap": "从 {axis} 方向查看。再次单击可反向。拖动可环绕;按住 Shift 可吸附。"
}
}
+295 -289
View File
File diff suppressed because it is too large Load Diff
+133
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Criar issue…",
"Cross curves": "Curvas transversais",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continua no GitHub.",
"Cube": "Cubo",
"Current orthographic view (1:1 mm)": "Vista ortográfica atual (1:1 mm)",
"Current perspective view": "Vista em perspectiva atual",
"Current plane": "Plano atual",
@@ -264,6 +265,7 @@
"Edge": "Aresta",
"Edges": "Arestas",
"Edit": "Editar",
"Edit Holes": "Editar furos",
"Edit Profile Sketch": "Editar esboço do perfil",
"Edit shortcuts": "Editar atalhos",
"Enable rule": "Ativar regra",
@@ -975,6 +977,7 @@
"browser.calibrate_click_a": "Clique na imagem para o ponto A ou digite suas coordenadas.",
"browser.calibrate_click_b": "Clique na imagem para o ponto B ou digite suas coordenadas.",
"browser.calibrate_title": "Calibrar: {name}",
"browser.canvas_locked": "A tela está bloqueada. Desbloqueie-a primeiro.",
"browser.capture_many": "{count} componentes foram movidos, mas suas posições não foram capturadas.",
"browser.capture_note": "Capturar posição mantém a nova posição; Reverter posição restaura a anterior.",
"browser.capture_one": "Um componente foi movido, mas sua posição não foi capturada.",
@@ -1204,6 +1207,7 @@
"cmd.material_properties_directional": "Módulo de elasticidade direcional",
"cmd.material_properties_validate": "Validar dados do material físico",
"cmd.mesh_convert": "Converter malha",
"cmd.model_body_features": "Listar características do corpo",
"cmd.model_edges": "Listar arestas",
"cmd.model_faces": "Listar faces",
"cmd.model_threads": "Listar roscas",
@@ -1232,8 +1236,11 @@
"cmd.panel.dismiss": "Dispensar prévia do painel",
"cmd.panel.float": "Desacoplar painel",
"cmd.panel.focus": "Focar painel",
"cmd.panel.focus.next": "Focar no próximo painel",
"cmd.panel.focus.previous": "Focar no painel anterior",
"cmd.panel.list": "Listar painéis",
"cmd.panel.move": "Mover painel",
"cmd.panel.move.next_zone": "Mover painel para a próxima zona",
"cmd.panel.native_close": "Reacoplar seção de painel nativo",
"cmd.panel.open": "Abrir painel",
"cmd.panel.peek": "Espiar painel recolhido",
@@ -1241,6 +1248,12 @@
"cmd.panel.reset_pair": "Redefinir divisor do painel",
"cmd.panel.resize": "Redimensionar seção do painel",
"cmd.panel.resize_pair": "Redimensionar divisor do painel",
"cmd.panel.sash.down": "Redimensionar divisor do painel para baixo",
"cmd.panel.sash.left": "Redimensionar divisor do painel para a esquerda",
"cmd.panel.sash.reset": "Redefinir divisor do painel focado",
"cmd.panel.sash.right": "Redimensionar divisor do painel para a direita",
"cmd.panel.sash.up": "Redimensionar divisor do painel para cima",
"cmd.panel.toggle": "Alternar o painel focado",
"cmd.parameters_add": "Adicionar parâmetro do usuário",
"cmd.parameters_change": "Alterar parâmetros",
"cmd.parameters_comment": "Comentar parâmetro",
@@ -1364,6 +1377,7 @@
"cmd.sketch.construction_line.tangent_external": "Tangente por um ponto externo",
"cmd.sketch.construction_line.tangent_two": "Tangente comum",
"cmd.sketch.construction_line.vertical": "Reta de construção vertical",
"cmd.sketch.replace": "Substituir esboço",
"cmd.sketch_arc3d": "Arco 3D",
"cmd.sketch_arc_center_point": "Arco por ponto central",
"cmd.sketch_arc_tangent": "Arco tangente",
@@ -1495,6 +1509,7 @@
"cmd.timeline_stop": "Parar histórico",
"cmd.timeline_suppress": "Suprimir recurso",
"cmd.ui.assistant": "Alternar assistente",
"cmd.ui.palette": "Pesquisar comandos",
"cmd.view.navigator": "Navegador de vistas personalizadas",
"cmd.view.render_browser": "Navegador de renderização",
"cmd.view.render_dock": "Mover dock de renderização",
@@ -2014,6 +2029,7 @@
"help.view.visual_style": "Muda como o modelo é desenhado: sombreado com ou sem arestas, aramado ou com arestas ocultas. Use aramado para ver o interior e sombreado para uma aparência limpa.",
"history.sketch_under_constrained": "Subrestrito ({count} graus de liberdade)",
"history.sketch_under_constrained_one": "Subrestrito ({count} grau de liberdade)",
"hole_folder.applies_to": "As alterações se aplicam aos {count} furos em {folder}; cada um mantém seu lugar.",
"hole_presets.confirm_delete": "Confirmar exclusão",
"hole_presets.delete": "Excluir",
"hole_presets.delete_prompt": "Excluir esta predefinição pessoal? Os furos existentes não mudam.",
@@ -2416,6 +2432,7 @@
"parts.dimension.width": "Largura",
"parts.family.bearing": "Rolamento rígido de esferas (envoltória)",
"parts.family.button_head_cap_screw": "Parafuso de cabeça abaulada com sextavado interno",
"parts.family.countersunk_socket_screw": "Parafuso de cabeça cônica com sextavado interno",
"parts.family.dowel_pin": "Pino paralelo (cavilha)",
"parts.family.hex_bolt": "Parafuso de cabeça sextavada",
"parts.family.hex_cap_screw_inch": "Parafuso de cabeça sextavada (polegada)",
@@ -2514,6 +2531,8 @@
"prefs.bottom_centre": "Inferior central",
"prefs.bottom_right": "Inferior direito",
"prefs.browser": "Navegador",
"prefs.browser_body_features": "Características sob os corpos",
"prefs.browser_body_features_note": "Cada corpo no navegador expande para mostrar as características da linha do tempo que o construíram, na ordem da linha do tempo.",
"prefs.browser_components_open": "Componentes começam abertos",
"prefs.browser_components_open_note": "Cada componente no navegador começa aberto, como antes, em vez de fechado até que você o abra.",
"prefs.browser_eye_left": "Olho ao lado da seta de recolher",
@@ -2554,7 +2573,11 @@
"prefs.design_tools.degrees": "Graus",
"prefs.design_tools.double_click_help": "Ou para editar um vinculado no local.",
"prefs.design_tools.ghost": "Mostrar o lugar antigo das peças movidas como fantasma",
"prefs.design_tools.hole_group": "Agrupar furos feitos juntos",
"prefs.design_tools.hole_group_help": "Furos feitos de uma vez compartilham uma pasta no Histórico, fechada inicialmente; abra-a para editar um furo separadamente.",
"prefs.design_tools.hole_moves_help": "Escolher a face novamente move o furo em vez de removê-lo.",
"prefs.design_tools.hole_several": "Vários furos em uma face",
"prefs.design_tools.hole_several_help": "Clicar em outro lugar na face adiciona outro furo; clicar em um furo o remove.",
"prefs.design_tools.hole_snaps_help": "O meio de uma face e os centros de suas arestas circulares.",
"prefs.design_tools.imported_files": "Arquivos importados",
"prefs.design_tools.note": "Observação",
@@ -2636,6 +2659,8 @@
"prefs.history": "Histórico",
"prefs.history_bar_groups": "Agrupar a barra de histórico em grupos",
"prefs.history_bar_groups_note": "Em um histórico longo, uma sequência de recursos de um componente se agrupa em um único indicador, e as pastas de recursos começam recolhidas. Uma montagem STEP inserida vai para uma pasta Grupo. Desativado mostra cada recurso, começa com as pastas abertas e não cria pasta.",
"prefs.history_folder_kind_icon": "Ícone da pasta baseado em suas características",
"prefs.history_folder_kind_icon_note": "Uma pasta do Histórico cujas características são todas do mesmo tipo mostra o ícone delas.",
"prefs.history_group_joints": "Agrupar juntas no Histórico",
"prefs.history_group_joints_note": "Duas ou mais juntas aparecem como um único botão com sua contagem, e um clique mostra cada uma. Desativado mostra cada junta.",
"prefs.history_origin_bodies": "Mostrar origem e corpos no topo",
@@ -2658,6 +2683,9 @@
"prefs.interface_note": "A aparência do SolidCraft e onde ficam suas partes.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inverter as setas curvas de rolagem",
"prefs.invert_curved_roll_arrows_note": "As duas setas curvas no canto do cubo rolam a vista no plano da tela. Ativado: a seta horária rola no sentido anti-horário e a seta anti-horária rola no sentido horário. Desativado: cada seta rola a vista no sentido em que se curva.",
"prefs.invert_navigator_arrows": "Inverter as setas de rotação do cubo de vista",
"prefs.invert_navigator_arrows_note": "As setas em volta do cubo orbitam a câmera para onde apontam, como no Fusion e no Inventor: a seta da esquerda aponta para a direita e gira a câmera para a direita. Desativado: uma seta gira o cubo em direção ao lado em que está, então a seta da esquerda gira a câmera para a esquerda. As setas curvas de rolagem não são afetadas.",
"prefs.keep_unsaved_also_asks": "Perguntar mesmo assim ao fechar a aba",
"prefs.keep_unsaved_also_asks_tip": "Com isto desativado, a aba fecha sem a caixa do navegador quando a cópia de cada projeto não salvo estiver atualizada.",
"prefs.keep_unsaved_in_browser": "Guardar trabalho não salvo neste navegador",
@@ -2717,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Desativado: enquanto as setas de Mover arrastam um componente, nada sob o ponteiro é destacado, o que mantém montagens grandes fluidas. Com um corte ou uma análise exibidos, o destaque acontece mesmo assim, e uma peça arrastada ao longo de suas juntas nunca o destaca.",
"prefs.navigation": "Navegação",
"prefs.navigation.axes_signed": "Eixos",
"prefs.navigation.cube_compact": "Cubo",
"prefs.navigation.device": "Dispositivo",
"prefs.navigation.free": "Livre",
"prefs.navigation.orbit_style": "Estilo de órbita",
@@ -2724,6 +2753,7 @@
"prefs.navigation.turntable": "Mesa giratória",
"prefs.navigation_note": "Como o mouse, o trackpad e o mouse 3D movem a vista.",
"prefs.navigator_fit": "Ajustar o modelo após uma mudança de vista do navegador",
"prefs.navigator_fit_note": "Uma face, um canto ou uma seta do cubo de vista, ou um eixo do gizmo, também olha para o meio do modelo a partir da distância única que o enquadra de todos os lados (sua esfera envolvente). Início usa o mesmo zoom e centro enquanto isto estiver ativado, então as vistas escolhidas depois só giram. Desativado: a vista gira no lugar, mantendo seu alvo e zoom.",
"prefs.network_host_remove": "Remover",
"prefs.network_locations": "Permitir locais de rede nos projetos",
"prefs.network_locations_note": "Para organizações que mantêm projetos em servidores de arquivos. Desativado: apenas servidores que você permitir.",
@@ -2736,6 +2766,7 @@
"prefs.origin_plane_names": "Nomes dos planos da origem",
"prefs.origin_plane_names_note": "Nomes mostrados no navegador, nas caixas de diálogo e nas listas. {top} é XY, {front} é XZ e {right} é YZ, com Z para cima. Comandos, scripts e projetos salvos mantêm XY, XZ e YZ.",
"prefs.overall_speed": "Velocidade geral",
"prefs.panel_layout.recovery": "Não foi possível restaurar os layouts de painéis salvos. Os dados salvos são mantidos; o estilo Clássico permanece disponível.",
"prefs.parameter_list_rows": "Linhas da lista de parâmetros",
"prefs.parameter_list_rows_tip": "O máximo de parâmetros que a seta para baixo lista em uma caixa de expressão vazia.",
"prefs.persistent_ribbon_pressed": "Destacar comandos ativos da faixa de opções",
@@ -2797,6 +2828,8 @@
"prefs.remember_dialog_values.help": "Desativado por padrão. Quando ativado, depois que um comando dá certo, seus valores e opções seguros são reutilizados na próxima vez que você abrir o mesmo comando, até o SolidCraft fechar.",
"prefs.render_legacy_image_defaults": "Usar os padrões anteriores da imagem de Renderizar",
"prefs.render_legacy_image_defaults_help": "Manter o fluxo manual anterior: novas configurações usam rasterização em CPU, o ray tracing em CPU mantém amostragem fixa e você abre os resultados renderizados manualmente. Reenquadrar ao entrar em Renderizar, trocar de tomada sem restaurar as câmeras e usar o enquadramento e a navegação anteriores. Desativar o retorno automático da imagem ao vivo. As configurações salvas não mudam.",
"prefs.render_legacy_memory_admission": "Usar verificações de memória de renderizações anteriores",
"prefs.render_legacy_memory_admission_help": "Permitir renderizações nativas dentro dos orçamentos fixos de memória compartilhada e do host mesmo quando a estimativa excede a RAM disponível. Limites do dispositivo e verificações de alocação ainda se aplicam.",
"prefs.render_previous_geometry_budget": "Usar o orçamento de geometria anterior da prévia de Renderizar",
"prefs.render_previous_geometry_budget_help": "Restaurar o limite fixo de geometria anterior (512 MiB em desktop de 64 bits, 128 MiB nos demais) em vez do orçamento baseado no dispositivo.",
"prefs.reports_saved": "{n} salvos",
@@ -2823,6 +2856,8 @@
"prefs.select_other_hidden": "Selecionar geometria oculta com Selecionar outro",
"prefs.select_other_hidden_help": "Ativado: incluir corpos ocultos, esboços e arestas encobertas perto do ponteiro. Desativado: usar a lista original de geometria visível sob o ponteiro.",
"prefs.selecting": "Seleção",
"prefs.shared_panel_layout": "Usar layout de painel compartilhado",
"prefs.shared_panel_layout_help": "Mostrar o Navegador, Histórico e Assistente existentes em painéis móveis. A alteração tem efeito quando as preferências são aplicadas.",
"prefs.shift": "Shift",
"prefs.shift_add_ctrl_toggle": "Shift só adiciona; Ctrl / Cmd alterna",
"prefs.shift_add_note": "Ativado: Shift adiciona, Ctrl / Cmd alterna. Desativado (padrão): ambos alternam.",
@@ -2845,6 +2880,8 @@
"prefs.sketch.drawing": "Desenho",
"prefs.sketch.ellipse_axes": "Desenhar elipses com seus eixos",
"prefs.sketch.ellipse_axes_note": "Os eixos maior e menor como linhas de construção, para que os semieixos e eixos possam ser cotados. Desativado: apenas a elipse, e D nela dá o raio menor onde quer que o valor seja puxado, desenhado e rotulado R como antes.",
"prefs.sketch.escape_twice_finishes": "Duplo Esc finaliza o esboço",
"prefs.sketch.escape_twice_finishes_note": "Dois toques rápidos no Esc encerram o esboço. Desligado: Esc apenas cancela a ferramenta ou a seleção, e Finalizar Esboço encerra o esboço.",
"prefs.sketch.exit_keep": "Manter",
"prefs.sketch.exit_previous": "Voltar à vista anterior",
"prefs.sketch.exit_unless_rotated": "A menos que girada",
@@ -3187,8 +3224,10 @@
"render.category_paint": "Tinta",
"render.category_plastic": "Plástico",
"render.category_wood": "Madeira",
"render.caustics_area_lights": "Cáusticas de luzes de área",
"render.caustics_depth": "Profundidade de caminho das cáusticas",
"render.caustics_enable": "Cáusticas de vidro a partir de luzes pontuais e direcionais",
"render.caustics_environment": "Cáusticas do ambiente",
"render.caustics_help": "A contagem de fótons controla o ruído e o trabalho. O raio de coleta troca detalhe nítido por uma estimativa mais suave. A CPU exige Iluminação indireta.",
"render.caustics_path_required": "As cáusticas em CPU exigem Iluminação indireta.",
"render.caustics_photons": "Fótons",
@@ -3405,6 +3444,12 @@
"render.cpu_subsurface_denoise_reason": "O espalhamento subsuperficial em CPU precisa de Redução de ruído desativada. Suas configurações são mantidas.",
"render.cpu_subsurface_help": "O espalhamento redireciona a luz dentro do Vidro fechado. Taxas positivas precisam de Iluminação indireta com Redução de ruído desativada. A taxa é de colisões por mm; 0 não adiciona espalhamento. Um viés de fase positivo favorece direções para a frente; negativo favorece para trás.",
"render.cpu_summary": "Ray tracing em CPU · reflexos · HDR · luzes direcionais e pontuais",
"render.cpu_threads": "CPU workers",
"render.cpu_threads_auto": "Automático",
"render.cpu_threads_custom": "Personalizado",
"render.cpu_threads_help": "Automático usa CPU workers disponíveis. Um worker roda em série. Mais workers podem precisar de mais memória.",
"render.cpu_threads_single": "Único",
"render.cpu_threads_web": "Renderização no navegador usa um cooperative worker. A escolha de worker do desktop salva é preservada.",
"render.cpu_transparent_help": "PNG transparente remove o fundo e mantém a cobertura das bordas. A opacidade de corpos e faces deve ficar em 100%.",
"render.cpu_volume_enable_path": "Ativar Iluminação indireta",
"render.cpu_volume_enable_path_plan": "Ray tracing em CPU · profundidade de caminho {depth} · {spp} amostras/pixel · semente {seed} · sombras traçadas. Mantém a atmosfera criada e o orçamento da imagem.",
@@ -3413,6 +3458,40 @@
"render.cpu_volume_method_incompatible": "Estas configurações de luz, amostragem ou atmosfera não podem ser transferidas para este método. Suas configurações são mantidas.",
"render.cpu_volume_path_required": "Ative Iluminação indireta para usar a Atmosfera em CPU.",
"render.cpu_warm_cool": "Quente e frio",
"render.denoise_class_background": "Ignorado: fundo",
"render.denoise_class_coverage": "Ignorado: cobertura parcial",
"render.denoise_class_degenerate": "Ignorado: caminho degenerado",
"render.denoise_class_depth": "Ignorado: limite de profundidade do caminho",
"render.denoise_class_emitter": "Ignorado: emissor de luz",
"render.denoise_class_exit": "Ignorado: saída incompatível",
"render.denoise_class_identity": "Ignorado: limite de identidade do guia",
"render.denoise_class_lens": "Ignorado: profundidade de campo",
"render.denoise_class_material": "Ignorado: material não suportado",
"render.denoise_class_nested": "Ignorado: meio aninhado",
"render.denoise_class_optical": "Elegível: superfície refratada",
"render.denoise_class_reflection": "Ignorado: ponto final reflexivo",
"render.denoise_class_surface": "Elegível: superfície",
"render.denoise_class_tir": "Ignorado: reflexão total interna",
"render.denoise_class_transmission": "Ignorado: transmissão adicional",
"render.denoise_class_unavailable": "Ignorado: sem guia",
"render.denoise_class_volume": "Ignorado: espalhamento de volume",
"render.denoise_diagnostics_counts": "Elegíveis: {eligible} · Ignorados: {skipped}",
"render.denoise_diagnostics_enable": "Coletar diagnósticos de redução de ruído",
"render.denoise_diagnostics_grid": "Contagens de pixels no tamanho interno {width} × {height}.",
"render.denoise_diagnostics_help": "Coleta contagens de pixels elegíveis e ignorados mesmo quando a redução de ruído está desligada. As contagens usam o tamanho de renderização interno; a máscara usa o tamanho de saída.",
"render.denoise_diagnostics_title": "Diagnósticos de redução de ruído",
"render.denoise_export_mask": "Exportar máscara PNG",
"render.denoise_firefly": "Suprimir pixels brilhantes isolados",
"render.denoise_format_mask": "Máscara PNG",
"render.denoise_mask_copy_help": "Exportar a máscara de redução de ruído como PNG, ou voltar à imagem renderizada para copiá-la.",
"render.denoise_mask_unavailable": "Ative diagnósticos de redução de ruído e renderize uma imagem para inspecionar sua máscara.",
"render.denoise_optical_filter": "Filtrar espelho e vidro",
"render.denoise_optical_filter_help": "Filtrar luz refletida e transmitida elegível. Desligue para redução de ruído apenas em superfícies opacas.",
"render.denoise_passes": "Passagens de filtro",
"render.denoise_settings_help": "Mais passagens suavizam uma área maior. A intensidade controla quanto cada passagem aplica de filtro. Caminhos ópticos não suportados permanecem sem filtro.",
"render.denoise_strength": "Intensidade da redução de ruído",
"render.denoise_view_image": "Imagem renderizada",
"render.denoise_view_mask": "Máscara de redução de ruído",
"render.diag_bodies": "Corpos visíveis",
"render.diag_job_details": "Detalhes do trabalho capturado",
"render.diag_last_check": "Última pré-verificação",
@@ -3618,6 +3697,7 @@
"render.glass_model_help": "A rugosidade do vidro espalha os raios transmitidos. A dispersão e a cor da película usam três bandas de comprimento de onda. Chapas ásperas exigem sombras transmitidas retas desativadas.",
"render.glass_roughness": "Rugosidade do vidro",
"render.gpu_depth": "Profundidade máxima de caminho",
"render.gpu_job_shader_wait": "Configuração do shader pode levar minutos",
"render.gpu_options_help": "Amostras, profundidade, semente e exposição são salvas com esta configuração. Apenas o método de imagem ativo é salvo.",
"render.gpu_path_crashed": "O SolidCraft fechou durante a configuração neste adaptador gráfico da última vez, muito provavelmente dentro do driver gráfico, então ele não é configurado de novo sozinho. Escolha ray tracing em CPU ou tente novamente (uma atualização do driver também tenta de novo).",
"render.gpu_path_failed": "Path tracer em GPU indisponível",
@@ -3966,6 +4046,8 @@
"render.material_transient": "Substituições ópticas temporárias para esta aba de documento. Elas não são salvas no projeto, na configuração de renderização nem na biblioteca de materiais.",
"render.material_v_up": "O V da textura aponta para cima na imagem",
"render.material_weight": "Peso do verniz (0–1)",
"render.metal_energy_compensation": "Recuperar reflectância de metal rugoso",
"render.metal_energy_compensation_help": "Compensar luz perdida entre microfaceta de metal rugoso. Renderização CPU precisa de Iluminação indireta.",
"render.method_cpu": "Ray tracing em CPU",
"render.method_gpu": "Path tracing em GPU",
"render.method_limit_raster": "A rasterização usa a prévia de estúdio opaca fixa. Selecione um método de ray tracing explícito para os controles ópticos suportados.",
@@ -4094,6 +4176,8 @@
"render.quality_denoise_on": "Redução de ruído: Ativada",
"render.quality_draft": "Rascunho",
"render.quality_high": "Alta",
"render.quality_legacy_samples": "Valor salvo: {samples} spp. Novas seleções são limitadas a {maximum} spp.",
"render.quality_preset_limit": "Esta predefinição excede o limite de seleção de 16384 spp. Escolha uma contagem de amostras até 16384.",
"render.quality_projection_help": "Esta revisão altera apenas resolução, orçamento de amostras, profundidade de caminho, semente e redução de ruído. As outras configurações são mantidas; o orçamento não certifica a convergência.",
"render.quality_review": "Revisar orçamento de amostragem",
"render.quality_summary": "{width} × {height} · {samples} amostras · profundidade {depth} · semente {seed} · {denoise}",
@@ -4241,6 +4325,7 @@
"render.show_shots_label": "Mostrar faixa de tomadas",
"render.size_4k": "4K",
"render.size_4k_uhd": "4K UHD",
"render.size_8k_uhd": "8K UHD",
"render.size_custom": "Personalizado…",
"render.size_full_hd": "Full HD",
"render.size_hd": "HD",
@@ -4403,6 +4488,11 @@
"render.subsurface_enable": "Passeio aleatório de espalhamento interior",
"render.subsurface_help": "Apenas dielétrico fechado. O espalhamento e a absorção RGB são coeficientes separados por mm. Os caminhos se espalham dentro da geometria real e depois refratam ou refletem no contorno. Desative a transmissão de sombra reta, a redução de ruído de superfície e o volume exterior; use um estrato de Fresnel. Não é um shader de difusão, uma grade de densidade nem um material medido. Meios densos podem precisar de mais amostras e profundidade de caminho.",
"render.subsurface_rate": "Taxa de colisão de espalhamento",
"render.supersampling": "Superamostragem",
"render.supersampling_dimensions": "Renderiza {width} × {height} e reduz para {output_width} × {output_height}. Usa quatro vezes os pixels.",
"render.supersampling_help": "Renderiza com o dobro da largura e altura, depois reduz em luz linear. O tamanho de saída permanece inalterado.",
"render.supersampling_off": "Desligado",
"render.supersampling_x2": "2×",
"render.surface_import.author": "Autor",
"render.surface_import.busy": "Importando imagem…",
"render.surface_import.complete": "Escolha uma imagem e informe seu autor, fonte e licença.",
@@ -4416,6 +4506,8 @@
"render.surface_import.saved_cpu": "Salve os mapas para usá-los com a renderização em CPU.",
"render.surface_import.source": "Fonte",
"render.surface_import.title": "Importar imagem",
"render.texture_filtering": "Filtrar detalhes de textura",
"render.texture_filtering_help": "Usa níveis mip e filtragem anisotrópica para reduzir aliasing de textura sob minificação. Usa mais memória; desligado mantém a filtragem anterior.",
"render.tone_aces_fitted": "ACES ajustado",
"render.tone_reinhard": "Reinhard",
"render.transmission_scope": "O vidro em GPU suporta meios disjuntos certificados. Meios aninhados irrestritos e um estimador de transmissão sem ruído não são fornecidos.",
@@ -5510,6 +5602,7 @@
"ui.heading_plastic": "PLÁSTICO",
"ui.heading_position": "POSIÇÃO",
"ui.heading_prepare": "PREPARAR",
"ui.heading_press_pull": "Puxar / Empurrar",
"ui.heading_rectangular_pattern": "PADRÃO RETANGULAR",
"ui.heading_revolve": "REVOLUÇÃO",
"ui.heading_right": "DIREITA",
@@ -5752,6 +5845,42 @@
"ui.panel_host.surface": "Painel",
"ui.panel_host.tab": "Aba do painel",
"ui.panel_host.tabs": "Todas as abas",
"ui.panel_layout.applied": "Aplicado {name} a {workspace}",
"ui.panel_layout.cancel": "Cancelar",
"ui.panel_layout.confirm_replace": "Substituir \"{name}\"?",
"ui.panel_layout.copy": "Copiar",
"ui.panel_layout.current": "Layout atual",
"ui.panel_layout.custom": "Personalizado",
"ui.panel_layout.custom_hint": "Painéis foram movidos desde {name}.",
"ui.panel_layout.details": "Detalhes",
"ui.panel_layout.layout_workspace": "Layout do espaço de trabalho",
"ui.panel_layout.page_defaults_hint": "Redefine as configurações desta página. Arranjos de painéis e layouts salvos são mantidos.",
"ui.panel_layout.panel_layout": "Layout de painéis",
"ui.panel_layout.panel_style": "Estilo do painel",
"ui.panel_layout.replace": "Substituir layout",
"ui.panel_layout.replace_current": "Substituir pelo atual",
"ui.panel_layout.replace_short": "Substituir",
"ui.panel_layout.reset": "Redefinir espaço de trabalho",
"ui.panel_layout.reset_hint": "Redefinir {workspace} para seu arranjo padrão. Layouts salvos são mantidos.",
"ui.panel_layout.reset_short": "Redefinir",
"ui.panel_layout.restore_failed": "Não foi possível restaurar seu layout",
"ui.panel_layout.save": "Salvar layout",
"ui.panel_layout.save_as": "Salvar como",
"ui.panel_layout.save_as_tile": "Salvar como…",
"ui.panel_layout.selected": "selecionado",
"ui.panel_layout.suggested_name": "Layout {n}",
"ui.panel_layout.try_again": "Tentar novamente",
"ui.panel_layout.validation.builtin": "Layouts integrados não podem ser alterados",
"ui.panel_layout.validation.duplicate": "Você já tem este nome",
"ui.panel_layout.validation.empty": "Insira um nome",
"ui.panel_layout.validation.full": "64 de 64 salvos. Escolha um para substituir.",
"ui.panel_layout.validation.invalid": "Use 1–64 caracteres, sem caracteres de controle",
"ui.panel_layout.workspace.classic": "Clássico",
"ui.panel_layout.workspace.modelling": "Modelagem",
"ui.panel_layout.workspace.render": "Renderização",
"ui.panel_layout.workspace.review": "Revisão",
"ui.panel_layout.workspace.sketch": "Esboço",
"ui.panel_layout.your_layout": "seu layout",
"ui.parallel": "Paralelo",
"ui.parameters": "Parâmetros",
"ui.part_size_needs_a_part": "Selecione uma peça padrão inserida (um parafuso, uma porca, uma arruela ou um pino) para alterar o tamanho. Para aumentar ou diminuir um corpo, use Escala.",
@@ -5817,6 +5946,8 @@
"ui.profiles": "Perfis",
"ui.project": "Projetar",
"ui.project_face_edges_sketch": "Projetar arestas da face em novos esboços",
"ui.project_references_construction": "Projetar referências como geometria de construção",
"ui.project_references_construction_note": "Projetar, Intersectar, Incluir Geometria 3D e as arestas da face de um novo esboço em uma face criam geometria de construção: referências para desenhar, deixadas fora dos perfis. Elas permanecem vinculadas ao modelo.",
"ui.properties": "Propriedades",
"ui.properties.copy_matrix": "Copiar matriz",
"ui.properties.first_moments": "Primeiros momentos",
@@ -5860,6 +5991,8 @@
"ui.renderer": "Renderizador",
"ui.repeat": "Repetir",
"ui.repeat_nothing": "Ainda não há nada para repetir: inicie primeiro uma ferramenta ou caixa de diálogo.",
"ui.replace_sketch.from_file": "De um Arquivo de Projeto…",
"ui.replace_sketch.no_sketches": "Esse projeto não tem esboço para usar",
"ui.replace_with_link_done": "As cópias agora são posicionamentos do projeto vinculado.",
"ui.report_a_bug": "Relatar um bug",
"ui.report_characters_left_one": "{count} caractere restante",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Creează raport…",
"Cross curves": "Curbe transversale",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter continuă pe GitHub.",
"Cube": "Cub",
"Current orthographic view (1:1 mm)": "Vizualizare ortografică curentă (1:1 mm)",
"Current perspective view": "Vizualizare în perspectivă curentă",
"Current plane": "Planul curent",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Cum arată SolidCraft și unde sunt așezate elementele sale.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Inversează săgețile curbe de ruliu",
"prefs.invert_curved_roll_arrows_note": "Cele două săgeți curbe din colțul cubului rotesc vizualizarea în planul ecranului. Activat: săgeata în sens orar rotește în sens antiorar, iar săgeata în sens antiorar rotește în sens orar. Dezactivat: fiecare săgeată rotește vizualizarea în direcția în care se curbează.",
"prefs.invert_navigator_arrows": "Inversează săgețile de rotație ale cubului de vizualizare",
"prefs.invert_navigator_arrows_note": "Săgețile din jurul cubului rotesc camera în jurul modelului în direcția în care indică, ca în Fusion și Inventor: săgeata din stânga indică spre dreapta și rotește camera spre dreapta. Dezactivat: o săgeată rotește cubul spre partea pe care se află, deci săgeata din stânga rotește camera spre stânga. Săgețile curbe de ruliu nu sunt afectate.",
"prefs.keep_work_on_tab_switch": "Păstrează deschise dialogurile și instrumentele la schimbarea proiectului",
"prefs.keep_work_on_tab_switch_note": "Fiecare filă de proiect își păstrează dialogul sau instrumentul deschis, cu ce ați ales și ați tastat în el, și fila ei din bara de instrumente. Le regăsiți când reveniți la proiect. Dezactivat: schimbarea proiectului le anulează și afișează fila Model.",
"prefs.labels": "Etichete",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Navigare",
"prefs.navigation_note": "Cum mută vizualizarea mouse-ul, trackpadul și mouse-ul 3D.",
"prefs.navigator_fit": "Potrivește modelul după o schimbare de vizualizare din navigator",
"prefs.navigator_fit_note": "O față, un colț sau o săgeată a cubului de vizualizare ori o axă a reperului de orientare privește și spre mijlocul modelului, de la singura distanță care îl cuprinde din toate părțile (sfera lui de încadrare). Acasă folosește același zoom și același centru cât timp opțiunea este activată, așa că vizualizările alese după aceea doar se rotesc. Dezactivat: vizualizarea se rotește pe loc, păstrându-și ținta și zoomul.",
"prefs.network_host_remove": "Elimină",
"prefs.network_locations": "Permite locațiile de rețea în proiecte",
"prefs.network_locations_note": "Dezactivat: fișierele legate ale unui proiect aflate pe alt computer (\\\\server\\share) se deschid doar de pe serverele listate aici sau după ce permiteți unul, când vi se cere.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Создать Issue…",
"Cross curves": "Поперечные кривые",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter — продолжить на GitHub.",
"Cube": "Куб",
"Current orthographic view (1:1 mm)": "Текущий ортогональный вид (1:1 мм)",
"Current perspective view": "Текущий перспективный вид",
"Current plane": "Текущая плоскость",
@@ -2231,6 +2232,9 @@
"prefs.interface_note": "Как выглядит SolidCraft и где расположены его части.",
"prefs.interval_minutes": "{n} мин",
"prefs.invert_curved_roll_arrows": "Инвертировать изогнутые стрелки крена",
"prefs.invert_curved_roll_arrows_note": "Две изогнутые стрелки в углу куба поворачивают вид в плоскости экрана. Вкл.: стрелка по часовой стрелке поворачивает вид против часовой, а стрелка против часовой — по часовой. Выкл.: каждая стрелка поворачивает вид в ту сторону, куда она изогнута.",
"prefs.invert_navigator_arrows": "Инвертировать стрелки вращения куба видов",
"prefs.invert_navigator_arrows_note": "Стрелки вокруг куба вращают камеру в ту сторону, куда указывают, как в Fusion и Inventor: стрелка слева указывает вправо и поворачивает камеру вправо. Выкл.: стрелка поворачивает куб в сторону, где она расположена, поэтому левая стрелка поворачивает камеру влево. Изогнутые стрелки крена не затрагиваются.",
"prefs.keep_work_on_tab_switch": "Сохранять открытые диалоги и инструменты при переключении между дизайнами",
"prefs.keep_work_on_tab_switch_note": "Каждая вкладка дизайна сохраняет свой открытый диалог или инструмент вместе с тем, что вы в нём выбрали и ввели, а также свою вкладку панели инструментов. Они снова на месте, когда вы возвращаетесь к дизайну. Выкл.: при переключении дизайнов они отменяются, и показывается вкладка «Модель».",
"prefs.labels": "Подписи",
@@ -2267,6 +2271,7 @@
"prefs.navigation": "Навигация",
"prefs.navigation_note": "Как мышь, тачпад и 3D-мышь двигают вид.",
"prefs.navigator_fit": "Вписывать модель после смены вида в навигаторе",
"prefs.navigator_fit_note": "Грань, угол или стрелка куба видов либо ось гизмо также направляет взгляд на середину модели с единственного расстояния, с которого она целиком видна со всех сторон (её габаритная сфера). «Главная» при включённом параметре использует тот же масштаб и центр, поэтому выбранные после неё виды только поворачиваются. Выкл.: вид поворачивается на месте, сохраняя свою цель и масштаб.",
"prefs.network_host_remove": "Убрать",
"prefs.network_locations": "Разрешить сетевые расположения в дизайнах",
"prefs.network_locations_note": "Выкл.: связанные файлы дизайна на другом компьютере (\\\\server\\share) открываются только с перечисленных здесь серверов или после того, как вы разрешите сервер по запросу.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Пријави проблем…",
"Cross curves": "Пресечне криве",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter наставља на GitHub-у.",
"Cube": "Коцка",
"Current orthographic view (1:1 mm)": "Тренутни ортографски приказ (1:1 mm)",
"Current perspective view": "Тренутни перспективни приказ",
"Current plane": "Тренутна раван",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "Како SolidCraft изгледа и где су његови делови.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Обрни закривљене стрелице за ваљање",
"prefs.invert_curved_roll_arrows_note": "Две закривљене стрелице у углу коцке ваљају приказ унутар равни екрана. Укључено: стрелица у смеру казаљке на сату ваља приказ супротно од смера казаљке на сату, а стрелица супротно од смера казаљке на сату ваља га у смеру казаљке на сату. Искључено: свака стрелица ваља приказ онако како је закривљена.",
"prefs.invert_navigator_arrows": "Обрни стрелице за ротацију коцке приказа",
"prefs.invert_navigator_arrows_note": "Стрелице око коцке орбитирају камеру у смеру у којем показују, као у програмима Fusion и Inventor: стрелица са леве стране показује удесно и закреће камеру удесно. Искључено: стрелица окреће коцку ка страни на којој се налази, па лева стрелица закреће камеру улево. Подешавање не утиче на закривљене стрелице за ваљање.",
"prefs.keep_work_on_tab_switch": "Задржи дијалоге и алате отвореним при пребацивању између дизајна",
"prefs.keep_work_on_tab_switch_note": "Свака картица дизајна задржава свој отворени дијалог или алат, са оним што сте у њему изабрали и уписали, те своју картицу траке са алатима. Када се вратите на дизајн, поново су ту. Искључено: пребацивање између дизајна отказује их и приказује картицу Модел.",
"prefs.labels": "Ознаке",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Навигација",
"prefs.navigation_note": "Како миш, додирна табла и 3D миш померају приказ.",
"prefs.navigator_fit": "Уклопи модел након промене приказа у навигатору",
"prefs.navigator_fit_note": "Лице, угао или стрелица коцке приказа, односно оса гизма оријентације, такође усмерава поглед на средину модела са једног растојања на којем се уклапа из сваког смера (његова гранична сфера). Почетни приказ користи исти зум и центар док је ова опција укључена, па се прикази које изаберете после њега само окрећу. Искључено: приказ се окреће на месту и задржава свој циљ и зум.",
"prefs.network_host_remove": "Уклони",
"prefs.network_locations": "Дозволи мрежне локације у дизајнима",
"prefs.network_locations_note": "Искључено: повезане датотеке дизајна на другом рачунару (\\\\server\\share) отварају се само са сервера наведених овде или након што га дозволите када се то затражи.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Skapa ärende…",
"Cross curves": "Korskurvor",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter fortsätter på GitHub.",
"Cube": "Kub",
"Current orthographic view (1:1 mm)": "Aktuell ortografisk vy (1:1 mm)",
"Current perspective view": "Aktuell perspektivvy",
"Current plane": "Aktuellt plan",
@@ -2240,6 +2241,9 @@
"prefs.interface_note": "Hur SolidCraft ser ut och var dess delar placeras.",
"prefs.interval_minutes": "{n} min",
"prefs.invert_curved_roll_arrows": "Invertera de böjda rullningspilarna",
"prefs.invert_curved_roll_arrows_note": "De två böjda pilarna vid kubens hörn rullar vyn i skärmplanet. På: medurspilen rullar moturs och moturspilen rullar medurs. Av: varje pil rullar vyn åt det håll den kröker sig.",
"prefs.invert_navigator_arrows": "Invertera rotationspilarna på vykuben",
"prefs.invert_navigator_arrows_note": "Pilarna runt kuben orbiterar kameran åt det håll de pekar, som i Fusion och Inventor: pilen till vänster pekar åt höger och svänger kameran åt höger. Av: en pil roterar kuben mot den sida den sitter på, så den vänstra pilen svänger kameran åt vänster. De böjda rullningspilarna påverkas inte.",
"prefs.keep_work_on_tab_switch": "Behåll dialoger och verktyg öppna när du byter konstruktion",
"prefs.keep_work_on_tab_switch_note": "Varje konstruktionsflik behåller sin öppna dialog eller sitt öppna verktyg, med det du har valt och skrivit i den, och sin flik i menyfliksområdet. De finns kvar när du kommer tillbaka till konstruktionen. Av: att byta konstruktion avbryter dem och visar fliken Modell.",
"prefs.labels": "Etiketter",
@@ -2276,6 +2280,7 @@
"prefs.navigation": "Navigering",
"prefs.navigation_note": "Hur musen, styrplattan och 3D-musen flyttar vyn.",
"prefs.navigator_fit": "Anpassa modellen efter en vyändring i navigatorn",
"prefs.navigator_fit_note": "En yta, ett hörn eller en pil på vykuben, eller en axel på orienteringsgizmot, tittar också mot modellens mitt från det enda avstånd som får den att rymmas från alla sidor (dess begränsningssfär). Hem använder samma zoom och centrum medan detta är på, så vyer som väljs efteråt bara vrids. Av: vyn vrids på stället och behåller sitt mål och sin zoom.",
"prefs.network_host_remove": "Ta bort",
"prefs.network_locations": "Tillåt nätverksplatser i konstruktioner",
"prefs.network_locations_note": "Av: en konstruktions länkade filer på en annan dator (\\\\server\\share) öppnas bara från de servrar som listas här, eller efter att du tillåtit en när du tillfrågas.",
+5
View File
@@ -154,6 +154,7 @@
"Create Issue…": "Sorun Oluştur…",
"Cross curves": "Çapraz eğriler",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter ile GitHub'da devam edilir.",
"Cube": "Küp",
"Current orthographic view (1:1 mm)": "Geçerli ortografik görünüm (1:1 mm)",
"Current perspective view": "Geçerli perspektif görünüm",
"Current plane": "Geçerli düzlem",
@@ -2239,6 +2240,9 @@
"prefs.interface_note": "SolidCraft'ın nasıl göründüğü ve parçalarının nerede durduğu.",
"prefs.interval_minutes": "{n} dk",
"prefs.invert_curved_roll_arrows": "Eğri yuvarlanma oklarını ters çevir",
"prefs.invert_curved_roll_arrows_note": "Küpün köşesindeki iki eğri ok, görünümü ekran düzlemi içinde yuvarlar. Açık: saat yönündeki ok saat yönünün tersine, saat yönünün tersindeki ok saat yönünde yuvarlar. Kapalı: her ok görünümü kıvrıldığı yöne yuvarlar.",
"prefs.invert_navigator_arrows": "Görünüm küpünün döndürme oklarını ters çevir",
"prefs.invert_navigator_arrows_note": "Küpün çevresindeki oklar kamerayı gösterdikleri yönde döndürür, tıpkı Fusion ve Inventor'daki gibi: soldaki ok sağı gösterir ve kamerayı sağa savurur. Kapalı: bir ok küpü bulunduğu tarafa doğru döndürür, yani sol ok kamerayı sola savurur. Kıvrık yuvarlanma okları bundan etkilenmez.",
"prefs.keep_work_on_tab_switch": "Tasarımlar arasında geçerken diyalogları ve araçları açık tut",
"prefs.keep_work_on_tab_switch_note": "Her tasarım sekmesi, açık diyaloğunu veya aracını, içinde seçtiklerinizi ve yazdıklarınızı ve şerit sekmesini korur. Tasarıma döndüğünüzde yeniden oradadırlar. Kapalı: tasarımlar arasında geçmek bunları iptal eder ve Model sekmesini gösterir.",
"prefs.labels": "Etiketler",
@@ -2275,6 +2279,7 @@
"prefs.navigation": "Gezinme",
"prefs.navigation_note": "Farenin, trackpad'in ve 3B farenin görünümü nasıl hareket ettirdiği.",
"prefs.navigator_fit": "Gezgin görünümü değiştikten sonra modeli sığdır",
"prefs.navigator_fit_note": "Görünüm küpünün bir yüzü, köşesi veya oku ya da gizmonun bir ekseni, modelin ortasına da modeli her yönden sığdıran tek bir uzaklıktan (sınırlayıcı küresi) bakar. Bu açıkken Ana görünüm aynı yakınlaştırmayı ve merkezi kullanır; böylece sonrasında seçilen görünümler yalnızca döner. Kapalı: görünüm hedefini ve yakınlaştırmasını koruyarak yerinde döner.",
"prefs.network_host_remove": "Kaldır",
"prefs.network_locations": "Tasarımlarda ağ konumlarına izin ver",
"prefs.network_locations_note": "Kapalı: bir tasarımın başka bir bilgisayardaki bağlı dosyaları (\\\\server\\paylaşım) yalnızca burada listelenen sunuculardan veya sorulduğunda izin verdiklerinizden açılır.",
+6
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Створити повідомлення про проблему…",
"Cross curves": "Поперечні криві",
"Ctrl+Enter continues on GitHub.": "Ctrl+Enter продовжує на GitHub.",
"Cube": "Куб",
"Current orthographic view (1:1 mm)": "Поточний ортографічний вид (1:1 mm)",
"Current perspective view": "Поточний перспективний вид",
"Current plane": "Поточна площина",
@@ -2651,6 +2652,9 @@
"prefs.interface_note": "Як виглядає SolidCraft і де розташовані його частини.",
"prefs.interval_minutes": "{n} хв",
"prefs.invert_curved_roll_arrows": "Інвертувати вигнуті стрілки обертання",
"prefs.invert_curved_roll_arrows_note": "Дві вигнуті стрілки в куті куба обертають вид у площині екрана. Увімкнено: стрілка за годинниковою стрілкою обертає проти годинникової, а стрілка проти годинникової — за годинниковою. Вимкнено: кожна стрілка обертає вид у напрямку свого завитку.",
"prefs.invert_navigator_arrows": "Інвертувати стрілки обертання куба виду",
"prefs.invert_navigator_arrows_note": "Стрілки навколо куба обертають камеру в той бік, куди вказують, як у Fusion та Inventor: стрілка ліворуч вказує праворуч і повертає камеру праворуч. Вимк.: стрілка обертає куб у той бік, де вона розташована, тож ліва стрілка повертає камеру ліворуч. Вигнуті стрілки крену не змінюються.",
"prefs.keep_unsaved_also_asks": "Усе одно запитувати під час закриття вкладки",
"prefs.keep_unsaved_also_asks_tip": "Коли це вимкнено, вкладка закривається без вікна браузера, щойно копія кожного незбереженого проєкту актуальна.",
"prefs.keep_unsaved_in_browser": "Зберігати незбережену роботу в цьому браузері",
@@ -2710,6 +2714,7 @@
"prefs.move_drag_highlights_tip": "Вимкнено: коли стрілки «Перемістити» тягнуть компонент, нічого під вказівником не підсвічується, що зберігає плавність великих збірок. Якщо показано переріз чи аналіз, підсвічування все одно працює, а деталь, яку тягнуть уздовж її з’єднань, ніколи його не вмикає.",
"prefs.navigation": "Навігація",
"prefs.navigation.axes_signed": "Осі",
"prefs.navigation.cube_compact": "Куб",
"prefs.navigation.device": "Пристрій",
"prefs.navigation.free": "Вільне",
"prefs.navigation.orbit_style": "Стиль обертання",
@@ -2717,6 +2722,7 @@
"prefs.navigation.turntable": "Поворотний стіл",
"prefs.navigation_note": "Як миша, трекпад і 3D-миша рухають вид.",
"prefs.navigator_fit": "Вміщувати модель після зміни виду в навігаторі",
"prefs.navigator_fit_note": "Грань, кут або стрілка куба виду чи вісь гізмо також дивляться на середину моделі з єдиної відстані, з якої її видно цілком з усіх боків (її обмежувальна сфера). «Головний вид» за ввімкненого параметра використовує той самий масштаб і центр, тож види, вибрані після нього, лише повертаються. Вимк.: вид повертається на місці, зберігаючи свою ціль і масштаб.",
"prefs.network_host_remove": "Вилучити",
"prefs.network_locations": "Дозволяти мережеві розташування в проєктах",
"prefs.network_locations_note": "Для організацій, які зберігають проєкти на файлових серверах. Вимкнено: лише дозволені вами сервери.",
+5 -3
View File
@@ -193,6 +193,7 @@
"Create Issue…": "Tạo Issue…",
"Cross curves": "Đường cong giao cắt",
"Ctrl+Enter continues on GitHub.": "Nhấn Ctrl+Enter để tiếp tục trên GitHub.",
"Cube": "Khối lập phương",
"Current orthographic view (1:1 mm)": "Góc nhìn trực giao hiện tại (1:1 mm)",
"Current perspective view": "Góc nhìn phối cảnh hiện tại",
"Current plane": "Mặt phẳng hiện tại",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "Diện mạo của SolidCraft và cách bố trí các bảng điều khiển.",
"prefs.interval_minutes": "{n} phút",
"prefs.invert_curved_roll_arrows": "Đảo ngược mũi tên cuộn cong",
"prefs.invert_curved_roll_arrows_note": "Hai mũi tên cong ở góc bộ điều hướng cuộn khung nhìn trong mặt phẳng màn hình. Khi bật: mũi tên theo chiều kim đồng hồ cuộn ngược chiều kim đồng hồ và ngược lại. Khi tắt: mỗi mũi tên cuộn khung nhìn theo chiều cong của nó.",
"prefs.invert_curved_roll_arrows_note": "Hai mũi tên cong ở góc khối cuộn khung nhìn trong mặt phẳng màn hình. Khi bật: mũi tên theo chiều kim đồng hồ cuộn ngược chiều kim đồng hồ và ngược lại. Khi tắt: mỗi mũi tên cuộn khung nhìn theo chiều cong của nó.",
"prefs.invert_navigator_arrows": "Đảo ngược mũi tên xoay của khối điều hướng",
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh bộ điều hướng xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khung nhìn về phía chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh khối xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khối về phía cạnh chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
"prefs.keep_unsaved_also_asks": "Vẫn hỏi khi đóng thẻ",
"prefs.keep_unsaved_also_asks_tip": "Khi tắt, thẻ sẽ đóng mà không có hộp thoại của trình duyệt khi bản sao của mọi thiết kế chưa lưu đã được cập nhật.",
"prefs.keep_unsaved_in_browser": "Giữ công việc chưa lưu trong trình duyệt này",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "Tắt: khi các mũi tên của Di chuyển kéo một thành phần, không có gì dưới con trỏ được tô sáng, nhờ đó các cụm lắp ráp lớn vẫn mượt. Khi đang hiện mặt cắt hoặc phân tích thì vẫn tô sáng như thường, và chi tiết được kéo dọc theo khớp nối không bao giờ tô sáng.",
"prefs.navigation": "Điều hướng góc nhìn",
"prefs.navigation.axes_signed": "Trục",
"prefs.navigation.cube_compact": "Khối lập phương",
"prefs.navigation.device": "Thiết bị",
"prefs.navigation.free": "Tự do",
"prefs.navigation.orbit_style": "Kiểu xoay",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "Bàn xoay",
"prefs.navigation_note": "Cách chuột, bàn di cảm ứng và chuột 3D di chuyển góc nhìn.",
"prefs.navigator_fit": "Khớp mô hình sau khi đổi góc nhìn bằng khối điều hướng",
"prefs.navigator_fit_note": "Nhấp vào một mặt, góc hoặc mũi tên của bộ điều hướng, hoặc một trục của gizmo, cũng nhìn vào tâm mô hình từ một khoảng cách duy nhất chứa trọn nó từ mọi phía (khối cầu bao). Khi bật, góc nhìn chuẩn (Home) dùng cùng mức thu phóng và tâm đó, nên các góc nhìn chọn sau chỉ xoay. Tắt: góc nhìn xoay tại chỗ, giữ nguyên điểm nhìn và mức thu phóng.",
"prefs.navigator_fit_note": "Nhấp vào một mặt, góc hoặc mũi tên của khối lập phương, hoặc một trục của gizmo, cũng nhìn vào tâm mô hình từ một khoảng cách duy nhất chứa trọn nó từ mọi phía (khối cầu bao). Khi bật, góc nhìn chuẩn (Home) dùng cùng mức thu phóng và tâm đó, nên các góc nhìn chọn sau chỉ xoay. Tắt: góc nhìn xoay tại chỗ, giữ nguyên điểm nhìn và mức thu phóng.",
"prefs.network_host_remove": "Xóa",
"prefs.network_locations": "Cho phép các vị trí mạng trong thiết kế",
"prefs.network_locations_note": "Dành cho tổ chức lưu thiết kế trên máy chủ tệp. Khi tắt: chỉ các máy chủ bạn cho phép.",
+1215 -208
View File
File diff suppressed because it is too large Load Diff
+7 -5
View File
@@ -193,6 +193,7 @@
"Create Issue…": "创建 Issue…",
"Cross curves": "交叉曲线",
"Ctrl+Enter continues on GitHub.": "按Ctrl+Enter在GitHub中继续。",
"Cube": "立方体",
"Current orthographic view (1:1 mm)": "当前正交视图(1:1毫米)",
"Current perspective view": "当前透视视图",
"Current plane": "当前平面",
@@ -2682,9 +2683,9 @@
"prefs.interface_note": "SolidCraft 的外观和面板布局。",
"prefs.interval_minutes": "{n} 分钟",
"prefs.invert_curved_roll_arrows": "反转弯曲的翻滚箭头",
"prefs.invert_curved_roll_arrows_note": "导航器角落的两个弯曲箭头在屏幕平面内翻滚视图。开启:顺时针箭头逆时针翻滚,逆时针箭头顺时针翻滚。关闭:每个箭头按其弯曲方向翻滚视图。",
"prefs.invert_navigator_arrows": "反转导航器的旋转箭头",
"prefs.invert_navigator_arrows_note": "导航器周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把视图转向它所在的那一侧,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
"prefs.invert_curved_roll_arrows_note": "立方体角落的两个弯曲箭头在屏幕平面内翻滚视图。开启:顺时针箭头逆时针翻滚,逆时针箭头顺时针翻滚。关闭:每个箭头按其弯曲方向翻滚视图。",
"prefs.invert_navigator_arrows": "反转视图立方体的旋转箭头",
"prefs.invert_navigator_arrows_note": "立方体周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把立方体转向它所在的那一面,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
"prefs.keep_unsaved_also_asks": "关闭标签页时仍然询问",
"prefs.keep_unsaved_also_asks_tip": "关闭此项后,只要每个未保存设计的副本都是最新的,标签页就会直接关闭,不显示浏览器的提示框。",
"prefs.keep_unsaved_in_browser": "在此浏览器中保留未保存的工作",
@@ -2744,6 +2745,7 @@
"prefs.move_drag_highlights_tip": "关闭:用移动的箭头拖动组件时,不高亮指针下的对象,大型装配体也能保持流畅。显示剖切或分析时仍照常高亮;沿关节拖动零件时从不高亮。",
"prefs.navigation": "导航",
"prefs.navigation.axes_signed": "坐标轴",
"prefs.navigation.cube_compact": "立方体",
"prefs.navigation.device": "设备",
"prefs.navigation.free": "自由",
"prefs.navigation.orbit_style": "旋转方式",
@@ -2751,7 +2753,7 @@
"prefs.navigation.turntable": "转台",
"prefs.navigation_note": "鼠标、触控板和3D鼠标如何移动视图。",
"prefs.navigator_fit": "视图导航器切换视图后适配模型",
"prefs.navigator_fit_note": "点击导航器的面、角或箭头,或坐标轴指示器的轴时,也会从各个方向都能容纳模型的同一距离(其包围球)注视模型中心。开启期间主视图使用相同的缩放和中心,因此之后选择的视图只改变方向。关闭:视图原地旋转,保持目标点和缩放。",
"prefs.navigator_fit_note": "点击立方体的面、角或箭头,或坐标轴指示器的轴时,也会从各个方向都能容纳模型的同一距离(其包围球)注视模型中心。开启期间主视图使用相同的缩放和中心,因此之后选择的视图只改变方向。关闭:视图原地旋转,保持目标点和缩放。",
"prefs.network_host_remove": "删除",
"prefs.network_locations": "允许设计中的网络位置",
"prefs.network_locations_note": "适用于将设计存放在文件服务器上的组织。关闭时:仅允许您授权的服务器。",
@@ -5039,7 +5041,7 @@
"ui.agent_chat_permission": "智能体请求运行:{title}",
"ui.agent_chat_pick": "智能体",
"ui.agent_chat_pick_context": "选择上下文",
"ui.agent_chat_pick_context_tip": "在模型中选择要让智能体查看的面、边、特征和实体,然后点击确定",
"ui.agent_chat_pick_context_tip": "在模型中选择面、边、特征和实体,然后点击确定:它们会作为标签放入消息中光标所在的位置(输入 @ 效果相同)",
"ui.agent_chat_placeholder": "让智能体修改设计…",
"ui.agent_chat_placeholder_busy": "输入消息,待智能体完成后发送(Ctrl+Enter:立即发送)",
"ui.agent_chat_pop_out": "在独立窗口中打开(可移到另一个屏幕)",
@@ -23,7 +23,7 @@ from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
HERE = Path(__file__).resolve().parent
FONTS = HERE.parents[2] / "fonts"
FONTS = HERE.parents[3] / "crates/look/fonts"
LAYOUT = json.loads((HERE / "layout.json").read_text())
W, H = LAYOUT["window"]
ICON = LAYOUT["icon_size"]
@@ -0,0 +1 @@
| assets/locales/pending/agent-chat-select-all.json | SolidCraft contributors | Original assistant chat select-all strings and translations | MIT OR Apache-2.0 |
@@ -0,0 +1,5 @@
| docs/book/src/media/ui-tour/window.light.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (`solidcraft --sample`, light theme, software renderer, 1280x800) with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py --light | MIT OR Apache-2.0 |
| docs/book/src/media/sketching/parts.light.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (light theme, software renderer, 1280x800) showing a fully constrained sketch, with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py --light | MIT OR Apache-2.0 |
| docs/book/src/media/parameters/dialog.light.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (light theme, software renderer) showing the Parameters dialog, with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py --light | MIT OR Apache-2.0 |
| docs/book/src/media/getting-started/start.light.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (light theme, software renderer, 1280x800) showing the start page with its built-in sample thumbnails, with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py --light | MIT OR Apache-2.0 |
| docs/book/src/media/files/menu.light.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (`--sample`, light theme, software renderer) showing the File menu, with original numbered callouts (digits set in DejaVu Sans Bold), captured with examples/demo/doc_shots.py --light | MIT OR Apache-2.0 |
@@ -0,0 +1 @@
| assets/locales/pending/constraint-glyph-size.json | SolidCraft contributors | Original constraint glyph size preference label and help text | MIT OR Apache-2.0 |
+3
View File
@@ -0,0 +1,3 @@
| crates/look/icons/design/svg/model/end_cap.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/end_cap_inward.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
| crates/look/icons/design/svg/model/end_cap_outward.svg | SolidCraft contributors | original icon master (64 grid) | SolidCraft Brand and Interface Licence (LICENSE-BRAND) |
+106 -2
View File
@@ -94,28 +94,101 @@ impl Hub {
/// on it). A listener that is not on a loopback address is refused: the channel never goes on
/// the network.
pub fn listen(self: &Arc<Self>, listener: TcpListener, token: String, requests: Sender<ControlRequest>, patient: bool) -> std::io::Result<()> {
self.listen_stoppable(listener, token, requests, patient).map(drop)
}
/// [`Hub::listen`], and a [`Stop`] that closes the listener and the connections it accepted
/// (a channel turned off in the app's settings). Dropping the [`Stop`] leaves it serving.
pub fn listen_stoppable(
self: &Arc<Self>,
listener: TcpListener,
token: String,
requests: Sender<ControlRequest>,
patient: bool,
) -> std::io::Result<Stop> {
let addr = listener.local_addr()?;
if !addr.ip().is_loopback() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("the control channel listens on loopback only, not {addr}")));
}
let hub = Arc::clone(self);
let token = Arc::new(token);
let shared = Arc::new(Accepted::default());
let (closed_tx, closed) = channel::<()>();
let stop = Stop { addr, shared: Arc::clone(&shared), closed };
std::thread::spawn(move || {
// Dropped when this thread ends, with the listener: `Stop::stop` waits for that.
let _closed = closed_tx;
for stream in listener.incoming().flatten() {
if shared.stopped.load(Ordering::SeqCst) {
break;
}
if hub.open.fetch_add(1, Ordering::Relaxed) >= MAX_CONNECTIONS {
hub.open.fetch_sub(1, Ordering::Relaxed);
let mut refused = stream;
let _ = send(&mut refused, &json!({"ok": false, "error": "too many connections"}));
continue;
}
let (hub, tx, token) = (Arc::clone(&hub), requests.clone(), Arc::clone(&token));
let id = shared.next.fetch_add(1, Ordering::Relaxed);
if let Ok(copy) = stream.try_clone() {
shared.lock().push((id, copy));
}
// Stopped while this one was being accepted: it is closed with the rest.
if shared.stopped.load(Ordering::SeqCst) {
shared.close_all();
}
let (hub, tx, token, shared) = (Arc::clone(&hub), requests.clone(), Arc::clone(&token), Arc::clone(&shared));
std::thread::spawn(move || {
hub.serve(stream, &token, tx, patient);
hub.open.fetch_sub(1, Ordering::Relaxed);
shared.lock().retain(|(i, _)| *i != id);
});
}
});
Ok(())
Ok(stop)
}
}
/// The connections a stoppable listener accepted, so stopping it can close them too.
#[derive(Default)]
struct Accepted {
stopped: AtomicBool,
next: AtomicU64,
streams: Mutex<Vec<(u64, TcpStream)>>,
}
impl Accepted {
fn lock(&self) -> MutexGuard<'_, Vec<(u64, TcpStream)>> {
self.streams.lock().unwrap_or_else(PoisonError::into_inner)
}
fn close_all(&self) {
for (_, stream) in self.lock().drain(..) {
let _ = stream.shutdown(std::net::Shutdown::Both);
}
}
}
/// Stops a listener started with [`Hub::listen_stoppable`].
pub struct Stop {
addr: std::net::SocketAddr,
shared: Arc<Accepted>,
closed: Receiver<()>,
}
impl Stop {
/// The port the listener is on.
pub fn port(&self) -> u16 {
self.addr.port()
}
/// Stop accepting, close the port and end every connection it accepted. Returns once the
/// port is closed (at most a couple of seconds), so the same port can be bound again at once.
pub fn stop(self) {
self.shared.stopped.store(true, Ordering::SeqCst);
// The listener waits in `accept`: a connection of our own wakes it to see the flag.
let _ = TcpStream::connect_timeout(&self.addr, Duration::from_secs(1));
let _ = self.closed.recv_timeout(Duration::from_secs(2));
self.shared.close_all();
}
}
@@ -1154,4 +1227,35 @@ mod tests {
assert_eq!(out.bytes.last(), Some(&b'\n'));
assert_eq!(serde_json::from_slice::<Value>(&out.bytes).unwrap(), reply);
}
/// A stopped listener frees its port at once and ends the connections it had, so a channel
/// turned off in the settings leaves nothing listening and can be turned on again on the
/// same port.
#[test]
fn a_stopped_listener_closes_its_port_and_its_connections() {
use std::io::Read;
let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
let port = listener.local_addr().unwrap().port();
let (tx, _rx) = channel();
let stop = hub(Waits::default(), &DOCUMENT_WATCH).listen_stoppable(listener, "0123456789abcdef0123456789abcdef".into(), tx, false).unwrap();
assert_eq!(stop.port(), port);
let mut client = TcpStream::connect(("127.0.0.1", port)).unwrap();
client.set_read_timeout(Some(Duration::from_secs(4))).unwrap();
// Wait until the server holds the connection, so stopping has one to close.
let held = Instant::now();
while stop.shared.lock().is_empty() && held.elapsed() < Duration::from_secs(4) {
std::thread::sleep(Duration::from_millis(5));
}
let started = Instant::now();
stop.stop();
let mut byte = [0u8; 1];
match client.read(&mut byte) {
Ok(n) => assert_eq!(n, 0, "the connection ends"),
Err(e) => {
assert!(!matches!(e.kind(), std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut), "the connection ends, not waits: {e}")
}
}
assert!(started.elapsed() < Duration::from_secs(3), "before the token wait runs out");
assert!(TcpListener::bind(("127.0.0.1", port)).is_ok(), "the port is free again");
}
}
+2 -2
View File
@@ -221,8 +221,8 @@ fn map_plane_ref(m: &Mat, p: &mut PlaneRef) {
map_geo_ref(m, g);
}
}
// Named origin planes and construction planes are the component's own.
PlaneRef::Origin { .. } | PlaneRef::Construction { .. } => {}
// Named origin planes, construction planes and placement datums are the component's own.
PlaneRef::Origin { .. } | PlaneRef::Datum { .. } | PlaneRef::Construction { .. } => {}
PlaneRef::Tangent { face, at, reference, .. } => {
*at = apply_point(m, *at);
map_geo_ref(m, face);
+10
View File
@@ -213,6 +213,11 @@ impl crate::Feature {
checked_link(&link.source, 0)?;
}
}
K::FrameEndCap { ends, .. } => {
for end in ends {
checked_plane(&end.plane, 0)?;
}
}
K::ConstructionPlane { plane }
| K::Split { plane, .. }
| K::SplitFace { plane, .. }
@@ -283,6 +288,11 @@ impl crate::Feature {
}
}
}
K::FrameEndCap { ends, .. } => {
for end in ends {
remap_plane(&mut end.plane, ids, bodies, 0)?;
}
}
K::ConstructionPlane { plane }
| K::Split { plane, .. }
| K::SplitFace { plane, .. }
+2 -2
View File
@@ -78,7 +78,7 @@ impl Document {
.assembly
.joints
.iter()
.filter(|j| occurrences.contains(&j.a.occurrence) || occurrences.contains(&j.b.occurrence))
.filter(|j| j.a.occurrences().chain(j.b.occurrences()).any(|o| occurrences.contains(&o)))
.map(|j| j.id)
.collect();
for group in &mut self.timeline_groups {
@@ -87,7 +87,7 @@ impl Document {
let assembly = &mut self.assembly;
assembly.joints.retain(|j| !joints.contains(&j.id));
assembly.links.retain(|l| !joints.contains(&l.a) && !joints.contains(&l.b));
assembly.origins.retain(|o| !occurrences.contains(&o.origin.occurrence));
assembly.origins.retain(|o| !o.origin.occurrences().any(|o| occurrences.contains(&o)));
for set in &mut assembly.contact_sets {
set.occurrences.retain(|o| !occurrences.contains(o));
}
+1 -1
View File
@@ -211,7 +211,7 @@ pub enum FaceCertificate {
},
/// A flat face known by its exact history name (the target's `name`, without piece
/// numbers): what the kernel's face history says it came from, followed through every
/// feature since (a cut wall `F5:side:l1`, a chamfer `F7:blend:…`, a pattern copy
/// feature since (a cut wall `F5:side:l1`, a chamfer `F7:blend(…)`, a pattern copy
/// `F4:top@F6.2`, a face a join merged from two features). Used where no construction
/// certificate above names the face uniquely. Its plane is the face's exact current plane in
/// the frame [`lineage_frame`] gives it. See docs/face-attachments.md.
+177 -14
View File
@@ -10,7 +10,7 @@ use solidcraft_geom::prelude::*;
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use solidcore_record::{Plane, Vec2, Vec3};
use solidcore_record::{Plane, Vec3};
use solidcraft_kernel::{self as kernel, FaceSurface};
use crate::eval::{ModelBody, ModelState};
@@ -23,6 +23,9 @@ use crate::{DocError, Document, PlaneRef, Result};
pub enum GeoRef {
/// A fixed point.
Point { p: Vec3 },
/// An origin datum of an exact placement (its O point, an axis or a plane), found again on
/// each evaluation, so it follows the component the way a named reference does.
Datum { datum: DatumRef },
/// The design origin.
Origin,
/// A body vertex: where the edges named `edges` meet (the end they share), else the one
@@ -52,7 +55,7 @@ pub enum GeoRef {
Axis { name: crate::FeatureName },
/// A construction point feature, by name.
ConstructPoint { name: crate::FeatureName },
/// A sketch point (by sketch feature id and point id).
/// A sketch point (by sketch feature id and point id), or a drawn wire node as `wire:index`.
SketchPoint { sketch: u64, point: String },
/// A sketch curve (by sketch feature id and curve id).
SketchCurve { sketch: u64, curve: String },
@@ -112,6 +115,129 @@ impl ConstructGeom {
}
}
/// One of the seven named items of a placement's Origin folder: the O point, the X, Y and Z
/// axes, and the XY, XZ and YZ planes. Case-insensitive to parse; the `Plane::named` aliases
/// (TOP/FRONT/RIGHT) stay root-only.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DatumItem {
O,
X,
Y,
Z,
XY,
XZ,
YZ,
}
impl DatumItem {
/// The item's name as a key spells it.
pub fn name(self) -> &'static str {
match self {
DatumItem::O => "O",
DatumItem::X => "X",
DatumItem::Y => "Y",
DatumItem::Z => "Z",
DatumItem::XY => "XY",
DatumItem::XZ => "XZ",
DatumItem::YZ => "YZ",
}
}
/// Case-insensitive; the Plane::named aliases (TOP/FRONT/RIGHT) stay root-only.
pub fn parse(name: &str) -> Option<Self> {
Some(match name.to_ascii_uppercase().as_str() {
"O" => DatumItem::O,
"X" => DatumItem::X,
"Y" => DatumItem::Y,
"Z" => DatumItem::Z,
"XY" => DatumItem::XY,
"XZ" => DatumItem::XZ,
"YZ" => DatumItem::YZ,
_ => return None,
})
}
/// The item in its component's own frame: O the point, X/Y/Z the axes, XY/XZ/YZ the planes.
pub fn geom(self) -> ConstructGeom {
match self {
DatumItem::O => ConstructGeom::Point(Vec3::ZERO),
DatumItem::X => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::X },
DatumItem::Y => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::Y },
DatumItem::Z => ConstructGeom::Axis { origin: Vec3::ZERO, dir: Vec3::Z },
DatumItem::XY => ConstructGeom::Plane(Plane::XY),
DatumItem::XZ => ConstructGeom::Plane(Plane::XZ),
DatumItem::YZ => ConstructGeom::Plane(Plane::YZ),
}
}
}
/// An origin datum of an exact placement. The empty path is never a `DatumRef`: the root keeps
/// `PlaneRef::Origin` and `GeoRef::Origin` as they are.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DatumRef {
/// The occurrence ids of the placement, root first.
pub path: Vec<u64>,
pub item: DatumItem,
}
impl DatumRef {
/// The datum's Browser key: `o:2/3/origin/XY`.
pub fn key(&self) -> String {
format!("o:{}/origin/{}", self.path.iter().map(|id| id.to_string()).collect::<Vec<_>>().join("/"), self.item.name())
}
/// Strict: canonical non-zero decimal ids, depth at most 64, length at most 2048. Rejects
/// `c0/origin`, `o:01/origin/X` and `o:0/origin/X`.
pub fn parse_key(key: &str) -> Option<Self> {
if key.len() > 2048 {
return None;
}
let rest = key.strip_prefix("o:")?;
let (ids, item) = rest.rsplit_once("/origin/")?;
if ids.is_empty() || ids.split('/').count() > 64 {
return None;
}
let path = ids.split('/').map(|id| id.parse::<u64>().ok().filter(|n| *n != 0 && n.to_string() == id)).collect::<Option<Vec<_>>>()?;
Some(DatumRef { path, item: DatumItem::parse(item)? })
}
}
impl Serialize for DatumRef {
/// Saved as its Browser key: `o:2/3/origin/XY`.
fn serialize<S: serde::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
s.serialize_str(&self.key())
}
}
impl<'de> Deserialize<'de> for DatumRef {
/// Reads a saved reference back from its Browser key: anything that is not a bounded
/// datum key is a deserialize error, so an older release never mis-reads a newer design.
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
let key = String::deserialize(d)?;
DatumRef::parse_key(&key).ok_or_else(|| serde::de::Error::custom(format!("not a datum key: `{key}`")))
}
}
/// An origin datum of an exact placement, resolved at evaluation time: the item in its own
/// component's frame, placed by the placement's world frame. It follows the component on every
/// evaluation, the way `PlaneRef::Face` re-finds its face.
pub fn resolve_datum(doc: &Document, d: &DatumRef) -> Result<ConstructGeom> {
Ok(d.item.geom().placed(&doc.placement_frame(&d.path)?))
}
/// [`resolve_datum`] as the component `component` sees it: placed by the placements, then
/// mapped back through that component's frame, since a feature evaluated in its own frame
/// places what it reads into the world again through that frame (the world pass). The root
/// (0) reads the world as it is.
pub fn resolve_datum_in(doc: &Document, d: &DatumRef, component: u64) -> Result<ConstructGeom> {
if component == 0 {
return resolve_datum(doc, d);
}
let inverse =
crate::mat_inverse(&doc.component_transform(component)).ok_or_else(|| DocError::Invalid("the component's placement is singular".into()))?;
Ok(resolve_datum(doc, d)?.placed(&inverse))
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Construct {
pub feature: u64,
@@ -133,6 +259,10 @@ pub(crate) struct Ctx<'a> {
/// geometry resolves its sides through the document again, so the count has to continue
/// across that hop; restarting it lets a plane that refers to itself recurse forever.
pub depth: usize,
/// The component the reading feature lives in: a datum it reads is found through the
/// placements and mapped back into this frame ([`resolve_datum_in`]). The root (0) is
/// the world.
pub component: u64,
}
fn bad(m: impl Into<String>) -> DocError {
@@ -308,11 +438,6 @@ fn as_circle(pts: &[Vec3]) -> Option<(Vec3, Vec3, f64)> {
.then_some((centre, unit, r))
}
fn sketch_world(ctx: &Ctx, sketch: u64, q: Vec2) -> Result<Vec3> {
let ss = ctx.st.sketch(sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
Ok(ss.plane.to_world(q))
}
fn sketch_curve_points(ctx: &Ctx, sketch: u64, curve: &str) -> Result<Vec<Vec3>> {
let ss = ctx.st.sketch(sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
if let Some(wire) = ss.sketch.wires.iter().find(|wire| wire.id == curve) {
@@ -358,17 +483,30 @@ pub(crate) fn point(ctx: &Ctx, g: &GeoRef) -> Result<Vec3> {
_ => Err(bad(format!("`{name}` is not a point"))),
},
GeoRef::SketchPoint { sketch, point } => {
let ss = ctx.st.sketch(*sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
let q =
ss.sketch.point_index(point).and_then(|i| ss.sketch.point(i)).ok_or_else(|| DocError::Unknown(format!("sketch point `{point}`")))?;
sketch_world(ctx, *sketch, q)
sketch_point_position(ctx.st, *sketch, point).ok_or_else(|| DocError::Unknown(format!("sketch point `{point}`")))
}
// A round edge or face: its centre.
GeoRef::Edge { .. } | GeoRef::Face { .. } | GeoRef::SketchCurve { .. } => centre(ctx, g),
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
ConstructGeom::Point(p) => Ok(p),
_ => Err(bad("the datum is not a point (pick the O of a component)")),
},
_ => Err(bad("pick a point, vertex or sketch point")),
}
}
/// Resolve a planar point or a drawn 3D wire's `wire:index` node in the evaluated state's frame.
/// Wire coordinates have already been placed; applying the sketch plane again would move them twice.
pub fn sketch_point_position(st: &ModelState, sketch: u64, point: &str) -> Option<Vec3> {
let ss = st.sketch(sketch)?;
if let Some(p) = ss.sketch.point_index(point).and_then(|i| ss.sketch.point(i)) {
return Some(ss.plane.to_world(p));
}
let (wire, index) = point.rsplit_once(':')?;
let index = index.parse::<usize>().ok()?;
ss.sketch.wires.get(ss.sketch.wire_index(wire)?)?.fit.get(index).copied()
}
/// An edge or face of the model as a line: along a straight edge, through the centre of a
/// circular edge along its normal, or the axis of a cylinder, cone or torus face.
fn model_line(st: &ModelState, g: &GeoRef) -> Result<(Vec3, Vec3)> {
@@ -403,6 +541,23 @@ pub fn model_axis(st: &ModelState, g: &GeoRef) -> Result<(Vec3, Vec3)> {
Ok((o, canonical_dir(d)))
}
/// [`model_axis`] for references that may name a component's origin datum: the datum is placed
/// through the document's placements ([`resolve_datum_in`], as the component `component` sees
/// it), the rest as [`model_axis`] finds it in the model state. `None` for a datum asks for an
/// evaluation.
pub fn model_axis_in(doc: Option<&Document>, st: &ModelState, g: &GeoRef, component: u64) -> Result<(Vec3, Vec3)> {
match g {
GeoRef::Datum { datum } => {
let doc = doc.ok_or_else(|| bad("this axis is built from a component's origin: evaluate first"))?;
match resolve_datum_in(doc, datum, component)? {
ConstructGeom::Axis { origin, dir } => Ok((origin, dir)),
_ => Err(bad("the datum is not an axis (pick the X, Y or Z of a component)")),
}
}
_ => model_axis(st, g),
}
}
/// `d` or `-d`, whichever has its largest component (the first of equal ones) positive: how
/// [`model_axis`] orients an axis, for a preview of one to point the same way.
pub fn canonical_dir(d: Vec3) -> Vec3 {
@@ -417,6 +572,10 @@ pub fn canonical_dir(d: Vec3) -> Vec3 {
/// A reference as a line (origin, unit direction).
pub(crate) fn line(ctx: &Ctx, g: &GeoRef) -> Result<(Vec3, Vec3)> {
match g {
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
ConstructGeom::Axis { origin, dir } => Ok((origin, dir)),
_ => Err(bad("the datum is not an axis (pick the X, Y or Z of a component)")),
},
GeoRef::Edge { .. } | GeoRef::Face { .. } => model_line(ctx.st, g),
GeoRef::SketchCurve { sketch, curve } => {
let pts = sketch_curve_points(ctx, *sketch, curve)?;
@@ -442,7 +601,7 @@ pub(crate) fn line(ctx: &Ctx, g: &GeoRef) -> Result<(Vec3, Vec3)> {
/// A reference as a plane.
pub(crate) fn plane(ctx: &Ctx, g: &GeoRef) -> Result<Plane> {
match g {
GeoRef::Plane { plane } => ctx.doc.resolve_plane_in(ctx.vals, plane, ctx.depth + 1, Some(ctx.st)),
GeoRef::Plane { plane } => ctx.doc.resolve_plane_in(ctx.vals, plane, ctx.depth + 1, ctx.component, Some(ctx.st)),
GeoRef::Face { at, name } => {
let (b, fi, q) = face_of(ctx.st, *at, name)?;
match kernel::face_surface(&b.body, fi) {
@@ -453,6 +612,10 @@ pub(crate) fn plane(ctx: &Ctx, g: &GeoRef) -> Result<Plane> {
_ => Err(bad("the face is not planar")),
}
}
GeoRef::Datum { datum } => match resolve_datum_in(ctx.doc, datum, ctx.component)? {
ConstructGeom::Plane(p) => Ok(p),
_ => Err(bad("the datum is not a plane (pick the XY, XZ or YZ of a component)")),
},
_ => Err(bad("pick a plane or planar face")),
}
}
@@ -846,11 +1009,11 @@ pub(crate) fn resolve_geo_plane(ctx: &Ctx, p: &PlaneRef) -> Result<Plane> {
Plane::from_normal(p, tan).ok_or_else(degenerate)
}
PlaneRef::ThroughPoint { base, point: at } => {
let b = ctx.doc.resolve_plane_in(ctx.vals, base, ctx.depth + 1, Some(ctx.st))?;
let b = ctx.doc.resolve_plane_in(ctx.vals, base, ctx.depth + 1, ctx.component, Some(ctx.st))?;
let n = b.normal().normalized().ok_or_else(degenerate)?;
Ok(Plane { origin: b.origin + n * (point(ctx, at)? - b.origin).dot(n), ..b })
}
_ => ctx.doc.resolve_plane_in(ctx.vals, p, ctx.depth + 1, Some(ctx.st)),
_ => ctx.doc.resolve_plane_in(ctx.vals, p, ctx.depth + 1, ctx.component, Some(ctx.st)),
}
}
+94 -19
View File
@@ -45,6 +45,9 @@ pub enum PlaneRef {
Origin { name: String },
/// An explicit plane (e.g. picked from a planar face).
Custom { plane: Plane },
/// An origin datum of an exact placement (its XY, XZ or YZ), found again on each evaluation
/// so it follows the component the way a named plane does.
Datum { datum: crate::construct::DatumRef },
/// An explicit plane whose origin is given as length expressions
/// (`{origin: ["half", 0, 0], normal: [1, 0, 0]}`), so it follows parameter changes.
Placed {
@@ -540,31 +543,68 @@ impl EmbossFace {
/// Resolve one saved component path without expanding other occurrences.
pub fn component_frame(doc: &Document, owner: u64, path: &[u64]) -> Result<crate::Mat> {
if path.len() > 64 || doc.occurrences.len() > 100_000 {
return Err(DocError::Invalid("selected cylinder path exceeds work limits".into()));
let frame = doc.placement_frame(path)?;
match path.split_last() {
None => Ok(doc.component_transform(owner)),
Some((last, _)) => {
let component = doc.occurrences.iter().find(|o| o.id == *last).map(|o| o.component);
if component == Some(owner) {
Ok(frame)
} else {
Err(DocError::Invalid("selected cylinder path belongs to another component".into()))
}
}
}
}
}
impl Document {
/// The world frame of one exact placement, without expanding every occurrence: the frame
/// every origin datum of the placement resolves in ([`crate::construct::resolve_datum`]).
/// The empty path is the root design frame. The shared walk of an exact placement (the
/// Emboss selection's `component_frame` delegates to it): depth at most 64, non-zero
/// canonical ids, no id repeated in a path, at most 100 000 occurrences.
pub fn placement_frame(&self, path: &[u64]) -> Result<crate::Mat> {
if path.len() > 64 || self.occurrences.len() > 100_000 {
return Err(DocError::Invalid("the placement path exceeds work limits".into()));
}
let mut frame = crate::IDENTITY;
let mut component = 0;
let mut seen = std::collections::BTreeSet::new();
for id in path {
if *id == 0 || !seen.insert(*id) {
return Err(DocError::Invalid("invalid selected cylinder path".into()));
return Err(DocError::Invalid("invalid placement path".into()));
}
let occurrence = doc
let occurrence = self
.occurrences
.iter()
.find(|o| o.id == *id && o.parent == component)
.ok_or_else(|| DocError::Invalid("selected cylinder placement no longer exists".into()))?;
.ok_or_else(|| DocError::Invalid("the placement no longer exists".into()))?;
frame = crate::mat_mul(&frame, &occurrence.transform);
component = occurrence.component;
}
if path.is_empty() {
frame = doc.component_transform(owner);
} else if component != owner {
return Err(DocError::Invalid("selected cylinder path belongs to another component".into()));
}
Ok(frame)
}
/// The complete occurrence path of one occurrence, root first (the ids
/// [`Self::placement_frame`] walks): the occurrence itself, then its ancestors, each stepped
/// through its parent component's first occurrence, as `occurrence_world` reads a parent.
/// `None` when the occurrence is missing or its chain is broken, cyclic or deeper than 64.
pub fn occurrence_path(&self, occurrence: u64) -> Option<Vec<u64>> {
let mut path = Vec::new();
let mut cur = occurrence;
while let Some(o) = self.occurrences.iter().find(|o| o.id == cur) {
if path.len() >= 64 {
return None;
}
path.insert(0, o.id);
if o.parent == 0 {
return Some(path);
}
cur = self.occurrence_of(o.parent)?.id;
}
None
}
}
/// One edge of an edge flange feature: a point on the sheet's edge and, where given, this
@@ -993,6 +1033,10 @@ pub enum FeatureKind {
length: Option<Expr>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
modeled: bool,
/// Continuous flank faces for this feature. Missing in older designs: keep
/// their half-turn faces and groove-before-chamfer order for saved references.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
continuous_flanks: bool,
/// A point near the end of the face the thread starts at; `None`: the face's only free
/// end (no material past it), or the end the pick at `face` lies near.
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -1190,6 +1234,25 @@ pub enum FeatureKind {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
targets: Vec<BodyName>,
},
/// Plates closing open ends of frame members (#4003), one body per end, each the outside of
/// the member's profile, optionally set in from its edge.
FrameEndCap {
ends: Vec<crate::end_cap::End>,
#[walk(length = "Thickness")]
thickness: Expr,
/// The inset from the outline's edge as a length, or `ratio` of the thickness; neither:
/// flush with the outside of the profile.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(length = "Inset")]
offset: Option<Expr>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[walk(unitless = "Inset Ratio")]
ratio: Option<Expr>,
#[walk(length = "Corner Chamfer")]
chamfer: Expr,
#[serde(default)]
direction: crate::end_cap::Direction,
},
/// Structural members (#4003): one body per straight line of a frame sketch (2D sketch lines
/// and 3D sketch lines), its cross-section the profile, square to the line from end to end.
FrameMember {
@@ -2733,6 +2796,7 @@ impl FeatureKind {
FeatureKind::SurfaceOffset { .. } => "OffsetSurfaceFeature",
FeatureKind::BoundingSolid { .. } => "BoundingSolidFeature",
FeatureKind::Pipe { .. } => "PipeFeature",
FeatureKind::FrameEndCap { .. } => "EndCapFeature",
FeatureKind::FrameMember { .. } => "FrameMemberFeature",
FeatureKind::Emboss { .. } => "EmbossFeature",
FeatureKind::Boss { .. } => "BossFeature",
@@ -2815,6 +2879,7 @@ impl FeatureKind {
FeatureKind::DeleteFace { .. } => "delete_face",
FeatureKind::BoundingSolid { .. } => "bounding_solid",
FeatureKind::Pipe { .. } => "pipe",
FeatureKind::FrameEndCap { .. } => "frame_end_cap",
FeatureKind::FrameMember { .. } => "frame_member",
FeatureKind::Emboss { .. } => "emboss",
FeatureKind::Rib { .. } => "rib",
@@ -2899,6 +2964,7 @@ impl FeatureKind {
"OffsetSurfaceFeature" => "surface_offset",
"BoundingSolidFeature" => "bounding_solid",
"PipeFeature" => "pipe",
"EndCapFeature" => "frame_end_cap",
"FrameMemberFeature" => "frame_member",
"EmbossFeature" => "emboss",
"BossFeature" => "boss",
@@ -2982,6 +3048,7 @@ impl FeatureKind {
FeatureKind::SurfaceOffset { .. } => "OffsetSurface",
FeatureKind::BoundingSolid { .. } => "BoundingSolid",
FeatureKind::Pipe { .. } => "Pipe",
FeatureKind::FrameEndCap { .. } => "EndCap",
FeatureKind::FrameMember { .. } => "Member",
FeatureKind::Emboss { .. } => "Emboss",
FeatureKind::Boss { .. } => "Boss",
@@ -4512,18 +4579,22 @@ impl Document {
expr::eval_with(e, &|n| vals.get(n).copied().ok_or_else(|| DocError::Expr(format!("unknown parameter `{n}`"))))?.to_kind(kind)
}
/// Resolve a plane reference.
/// Resolve a plane reference (in the world: the root's frame).
pub fn resolve_plane(&self, vals: &std::collections::BTreeMap<String, expr::Value>, p: &PlaneRef, depth: usize) -> Result<Plane> {
self.resolve_plane_in(vals, p, depth, None)
self.resolve_plane_in(vals, p, depth, 0, None)
}
/// Resolve a plane; planes built from model geometry (edges, faces, construction axes and
/// points) need the model state `st`, and construction planes are read from it when given.
/// `component` is the frame the plane is read for: a component origin datum resolves as
/// that component sees it ([`crate::construct::resolve_datum_in`]), since a feature places
/// what it read into the world again through its own frame. The root (0) is the world.
pub fn resolve_plane_in(
&self,
vals: &std::collections::BTreeMap<String, expr::Value>,
p: &PlaneRef,
depth: usize,
component: u64,
st: Option<&crate::ModelState>,
) -> Result<Plane> {
if depth > 32 {
@@ -4543,17 +4614,21 @@ impl Document {
}
Plane::new(o, *x_dir, *y_dir).ok_or_else(|| DocError::Invalid("degenerate plane".into()))
}
PlaneRef::Datum { datum } => match crate::construct::resolve_datum_in(self, datum, component)? {
crate::construct::ConstructGeom::Plane(p) => Ok(p),
_ => Err(DocError::Invalid("the datum is not a plane (pick the XY, XZ or YZ of a component)".into())),
},
PlaneRef::Offset { base, distance } => {
let b = self.resolve_plane_in(vals, base, depth + 1, st)?;
let b = self.resolve_plane_in(vals, base, depth + 1, component, st)?;
Ok(b.offset(Self::eval_in(vals, distance, Kind::Length)?))
}
PlaneRef::AtAngle { base, axis_origin, axis_dir, angle, line, direction_only, pivot } => {
let b = self.resolve_plane_in(vals, base, depth + 1, st)?;
let b = self.resolve_plane_in(vals, base, depth + 1, component, st)?;
let a = Self::eval_in(vals, angle, Kind::Angle)?;
let (axis_origin, axis_dir) = match line {
Some(g) => {
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
crate::construct::model_axis(st, g)?
crate::construct::model_axis_in(Some(self), st, g, component)?
}
None => (*axis_origin, *axis_dir),
};
@@ -4566,7 +4641,7 @@ impl Document {
let pivot = match pivot {
Some(g) => {
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
crate::construct::point(&crate::construct::Ctx { doc: self, vals, st, depth }, g)?
crate::construct::point(&crate::construct::Ctx { doc: self, vals, st, depth, component }, g)?
}
None => b.origin,
};
@@ -4581,7 +4656,7 @@ impl Document {
let o = axis_origin + rot(b.origin - axis_origin);
Plane::new(o, rot(b.x), rot(b.y)).ok_or_else(|| DocError::Invalid("degenerate plane".into()))
}
PlaneRef::Flipped { base, about_y } => Ok(self.resolve_plane_in(vals, base, depth + 1, st)?.flipped(*about_y)),
PlaneRef::Flipped { base, about_y } => Ok(self.resolve_plane_in(vals, base, depth + 1, component, st)?.flipped(*about_y)),
PlaneRef::Construction { feature } => {
// Evaluated already: as it came out.
if let Some(c) = st.and_then(|st| st.construct.iter().find(|c| c.feature == feature.0))
@@ -4590,7 +4665,7 @@ impl Document {
return Ok(*pl);
}
match self.feature(feature.0).map(|f| &f.kind) {
Some(FeatureKind::ConstructionPlane { plane }) => self.resolve_plane_in(vals, plane, depth + 1, st),
Some(FeatureKind::ConstructionPlane { plane }) => self.resolve_plane_in(vals, plane, depth + 1, component, st),
// A name that could not be resolved when an older design opened keeps id 0,
// which no feature has (#1134): the reference dangles, as it always did.
_ => {
@@ -4608,7 +4683,7 @@ impl Document {
| PlaneRef::Perpendicular { .. }
| PlaneRef::ThroughPoint { .. } => {
let st = st.ok_or_else(|| DocError::Invalid("this plane is built from the model: evaluate first".into()))?;
crate::construct::resolve_geo_plane(&crate::construct::Ctx { doc: self, vals, st, depth }, p)
crate::construct::resolve_geo_plane(&crate::construct::Ctx { doc: self, vals, st, depth, component }, p)
}
}
}
+582
View File
@@ -0,0 +1,582 @@
//! End caps (#4003): a plate closing the open end of a frame member, its outline the member
//! profile's outer outline set in from the edge, built from existing extrude and boolean
//! operations.
use std::collections::BTreeMap;
use crate::expr::{Kind, Value};
use crate::{DocError, Document, Feature, FeatureKind, ModelBody, ModelState, PlaneRef, Result};
use serde::{Deserialize, Serialize};
use solidcore_record::{Loop2, Plane, Region2, Seg2, Vec2};
use solidcraft_geom::prelude::*;
use solidcraft_kernel::{self as kernel, BoolOp};
/// Most end faces one end cap feature closes.
pub const MAX_FACES: usize = 256;
/// The member a capped face belongs to: its feature and line, which outlive body renames.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(deny_unknown_fields)]
pub struct Member {
pub feature: crate::FeatureId,
pub line: String,
}
/// One capped end: the member's planar end face and the member it belongs to.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(deny_unknown_fields)]
pub struct End {
pub plane: PlaneRef,
pub member: Member,
}
/// Which way the cap goes from the end face.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, solidcraft_derive::Walk)]
#[serde(rename_all = "snake_case")]
pub enum Direction {
/// Past the end: the frame gets longer by the thickness.
#[default]
Outward,
/// Into the member, which is cut back by the thickness: the frame keeps its length.
Inward,
}
fn invalid(s: impl Into<String>) -> DocError {
DocError::Invalid(s.into())
}
/// The member that `plane`'s face belongs to; an error when it is no frame member's face.
pub fn member(doc: &Document, st: &ModelState, plane: &PlaneRef) -> Result<Member> {
let PlaneRef::Face { anchor: Some(anchor), .. } = plane else { return Err(invalid("an end cap needs a planar face picked on a frame member")) };
let source = doc.feature(anchor.target.origin_feature).ok_or_else(|| invalid("the capped member's feature no longer exists"))?;
let FeatureKind::FrameMember { names, .. } = &source.kind else { return Err(invalid("the face is not on a frame member")) };
let ids = crate::frame::member_line_ids(st, &source.kind)?;
let line = if source.body_names.is_empty() {
ids.iter().find(|line| names.get(*line).is_some_and(|name| *name == anchor.target.body))
} else {
source.body_names.iter().position(|name| *name == anchor.target.body).and_then(|i| ids.get(i))
}
.ok_or_else(|| invalid("the face is no longer on the member it was picked on"))?;
Ok(Member { feature: source.id.into(), line: line.clone() })
}
fn length(v: f64, what: &str, min: f64) -> Result<f64> {
if !v.is_finite() || v > 1e6 || v < min {
return Err(invalid(format!("the end cap's {what} must be a length from {min} to 1e6 mm")));
}
Ok(v)
}
/// Most edges in an outline an end cap follows.
const MAX_EDGES: usize = 4096;
/// Where a segment of the outline goes when it moves in: a line through a point along a unit
/// direction, or a circle.
#[derive(Clone, Copy)]
enum Carrier {
Line(Vec2, Vec2),
Circle(Vec2, f64),
}
/// The points where two carriers cross.
fn crossings(c1: Carrier, c2: Carrier) -> Vec<Vec2> {
match (c1, c2) {
(Carrier::Line(p1, t1), Carrier::Line(p2, t2)) => {
let den = t1.cross(t2);
if den.abs() < 1e-9 { Vec::new() } else { vec![p1 + t1 * ((p2 - p1).cross(t2) / den)] }
}
(Carrier::Line(p, t), Carrier::Circle(c, r)) | (Carrier::Circle(c, r), Carrier::Line(p, t)) => {
let foot = p + t * (c - p).dot(t);
let h2 = r * r - (c - foot).dot(c - foot);
if h2 < -1e-9 * r.max(1.0) {
return Vec::new();
}
let h = h2.max(0.0).sqrt();
vec![foot - t * h, foot + t * h]
}
(Carrier::Circle(c1, r1), Carrier::Circle(c2, r2)) => {
let dd = c1.dist(c2);
if dd < 1e-12 {
return Vec::new();
}
let u = (c2 - c1) / dd;
let along = (r1 * r1 - r2 * r2 + dd * dd) / (2.0 * dd);
let h2 = r1 * r1 - along * along;
if h2 < -1e-9 * r1.max(1.0) {
return Vec::new();
}
let h = h2.max(0.0).sqrt();
let foot = c1 + u * along;
vec![foot - u.perp() * h, foot + u.perp() * h]
}
}
}
/// How far `p` is from segment `s` (a line or an arc).
fn distance(s: &Seg2, p: Vec2) -> f64 {
match *s {
Seg2::Line { a, b } => {
let ab = b - a;
let l2 = ab.dot(ab);
let u = if l2 > 0.0 { ((p - a).dot(ab) / l2).clamp(0.0, 1.0) } else { 0.0 };
p.dist(a + ab * u)
}
Seg2::Arc { center, radius, start, sweep } => {
let tau = std::f64::consts::TAU;
let rel = (p - center).angle() - start;
let u = if sweep >= 0.0 { rel.rem_euclid(tau) } else { (-rel).rem_euclid(tau) };
if u <= sweep.abs() { (p.dist(center) - radius).abs() } else { p.dist(s.start()).min(p.dist(s.end())) }
}
_ => p.dist(s.start()).min(p.dist(s.end())),
}
}
/// Points along `s`: a few on a line, more on an arc.
fn samples(s: &Seg2) -> Vec<Vec2> {
let k = match *s {
Seg2::Arc { sweep, .. } => ((sweep.abs() / (std::f64::consts::PI / 32.0)).ceil() as usize).clamp(2, 128),
_ => 8,
};
(0..=k).map(|i| s.point_at(i as f64 / k as f64)).collect()
}
/// Whether two straight pieces cross (touching at their ends does not count).
fn pieces_cross(a: Vec2, b: Vec2, c: Vec2, d: Vec2) -> bool {
let (o1, o2) = ((b - a).cross(c - a), (b - a).cross(d - a));
let (o3, o4) = ((d - c).cross(a - c), (d - c).cross(b - c));
let eps = 1e-12 * (1.0 + a.dist(b) + c.dist(d)).powi(2);
o1 * o2 < -eps && o3 * o4 < -eps
}
/// Whether `lp`'s edges cross one another.
fn crosses_itself(lp: &Loop2) -> bool {
let pts: Vec<Vec2> = lp
.segs
.iter()
.flat_map(|s| {
let mut v = samples(s);
v.pop();
v
})
.collect();
let n = pts.len();
for i in 0..n {
for j in i + 2..n {
if i == 0 && j + 1 == n {
continue;
}
let (Some(&a), Some(&b), Some(&c), Some(&d)) = (pts.get(i), pts.get((i + 1) % n), pts.get(j), pts.get((j + 1) % n)) else {
continue;
};
if pieces_cross(a, b, c, d) {
return true;
}
}
}
false
}
/// `outline`, a counter-clockwise loop of lines and arcs, moved in by `d` all round: lines move
/// along their inward normal, arcs that bulge out lose `d` of radius and arcs that curve in (the
/// root of an angle or a beam) gain it. An arc that shrinks away leaves its neighbours meeting
/// at a corner. Any shape works: round and rectangular tubes as well as angles, channels and
/// beams. An inset more than half a wall somewhere (an angle's leg, a beam's web) is refused.
pub(crate) fn inset(outline: &Loop2, d: f64) -> Result<Loop2> {
let no_plate = || {
invalid(format!(
"an inset of {} mm leaves no plate inside the profile's outline (it is more than half a wall somewhere)",
crate::frame::short(d)
))
};
if !d.is_finite() || d < 0.0 {
return Err(invalid("the end cap's inset must be a length of 0 or more"));
}
let segs = &outline.segs;
let n = segs.len();
if n == 0 || outline.signed_area() <= 0.0 {
return Err(invalid("the profile's outline has no area"));
}
if n > MAX_EDGES {
return Err(invalid(format!("end caps follow outlines of at most {MAX_EDGES} edges")));
}
// A full circle (arcs on one circle): its radius shrinks.
if let Some(Seg2::Arc { center, radius, .. }) = segs.first().copied()
&& segs
.iter()
.all(|s| matches!(*s, Seg2::Arc { center: c, radius: r, sweep, .. } if c.dist(center) < 1e-9 && (r - radius).abs() < 1e-9 && sweep > 0.0))
{
return if radius - d > 1e-6 { Ok(Loop2::circle(center, radius - d)) } else { Err(no_plate()) };
}
let mut carriers = Vec::with_capacity(n);
for s in segs {
carriers.push(match *s {
Seg2::Line { a, b } => {
let t = (b - a).normalized().ok_or_else(|| invalid("the profile's outline has an edge of no length"))?;
Some(Carrier::Line(a + t.perp() * d, t))
}
// Counter-clockwise arcs bulge out and shrink; clockwise ones curve in and grow.
Seg2::Arc { center, radius, sweep, .. } if sweep.abs() > 1e-12 && radius > 0.0 => {
let r = radius - d * sweep.signum();
(r > 1e-6).then_some(Carrier::Circle(center, r))
}
Seg2::Arc { .. } => return Err(invalid("the profile's outline has an arc of no length")),
_ => return Err(invalid("end caps follow outlines of lines and arcs (a spline or conic outline is not supported)")),
});
}
let kept: Vec<usize> = (0..n).filter(|i| carriers.get(*i).is_some_and(Option::is_some)).collect();
let m = kept.len();
if m < 2 {
return Err(no_plate());
}
// Where kept segment `k` starts: after a smooth join, the old point moved in; otherwise (a
// corner, or arcs shrunk away between) where it meets the previous kept segment, nearest the
// corner it replaces.
let mut starts = Vec::with_capacity(m);
for (j, &k) in kept.iter().enumerate() {
let p = kept.get((j + m - 1) % m).copied().ok_or_else(no_plate)?;
let (Some(prev), Some(this)) = (segs.get(p), segs.get(k)) else { return Err(no_plate()) };
let (tin, tout) = (prev.end_tangent(), this.start_tangent());
if (p + 1) % n == k && tin.cross(tout).abs() < 1e-7 && tin.dot(tout) > 0.0 {
starts.push(this.start() + tout.perp() * d);
continue;
}
let (Some(Some(c1)), Some(Some(c2))) = (carriers.get(p).copied(), carriers.get(k).copied()) else { return Err(no_plate()) };
let near = prev.end().lerp(this.start(), 0.5);
let best = crossings(c1, c2).into_iter().min_by(|a, b| a.dist(near).total_cmp(&b.dist(near))).ok_or_else(no_plate)?;
starts.push(best);
}
let mut out = Vec::with_capacity(m);
for (j, &k) in kept.iter().enumerate() {
let (Some(&a), Some(&b)) = (starts.get(j), starts.get((j + 1) % m)) else { return Err(no_plate()) };
match (segs.get(k).copied(), carriers.get(k).copied()) {
(Some(Seg2::Line { a: oa, b: ob }), _) => {
if (b - a).dot(ob - oa) <= 1e-6 * oa.dist(ob) || a.dist(b) < 1e-6 {
return Err(no_plate());
}
out.push(Seg2::Line { a, b });
}
(Some(Seg2::Arc { sweep, .. }), Some(Some(Carrier::Circle(center, r)))) => {
let tau = std::f64::consts::TAU;
let (s, e) = ((a - center).angle(), (b - center).angle());
let sw = if sweep > 0.0 { (e - s).rem_euclid(tau) } else { -(s - e).rem_euclid(tau) };
// An arc turned inside out shows as one sweeping most of the way round.
if sw.abs() < 1e-9 || sw.abs() > sweep.abs() + std::f64::consts::FRAC_PI_2 {
return Err(no_plate());
}
out.push(Seg2::Arc { center, radius: r, start: s, sweep: sw });
}
_ => return Err(no_plate()),
}
}
let lp = Loop2 { segs: out };
// Every point of the plate's edge is at least `d` from the profile's: closer means the inset
// reached across a wall thinner than twice the inset.
let tol = 1e-6 * (1.0 + d);
let far_enough = lp.segs.iter().flat_map(samples).all(|q| segs.iter().map(|s| distance(s, q)).fold(f64::INFINITY, f64::min) >= d - tol);
if !(lp.signed_area() > 1e-6) || !far_enough || crosses_itself(&lp) {
return Err(no_plate());
}
Ok(lp)
}
/// `outline` (as [`inset`] makes it) with every outside corner cut by a chamfer `c` long along
/// each edge, measured from where the edges meet. A rounded corner is cut away whole, so `c`
/// must be at least as long as its rounding. Inside corners (the root of an angle or a beam)
/// stay as they are.
pub(crate) fn chamfered(outline: &Loop2, c: f64) -> Result<Loop2> {
if !c.is_finite() || c < 0.0 {
return Err(invalid("the end cap's chamfer must be a length of 0 or more"));
}
if c == 0.0 {
return Ok(outline.clone());
}
let segs = &outline.segs;
let n = segs.len();
let round = || invalid("a round end cap has no corners to chamfer (set the chamfer to 0)");
// The lines in order from the first; an outline with none is round.
let first = segs.iter().position(|s| matches!(s, Seg2::Line { .. })).ok_or_else(round)?;
let lines: Vec<usize> = (0..n).map(|i| (first + i) % n).filter(|i| matches!(segs.get(*i), Some(Seg2::Line { .. }))).collect();
let k = lines.len();
if k < 2 {
return Err(round());
}
let line = |i: usize| -> Result<(Vec2, Vec2, Vec2)> {
match lines.get(i % k).and_then(|j| segs.get(*j)).copied() {
Some(Seg2::Line { a, b }) => Ok((a, b, (b - a).normalized().ok_or_else(|| invalid("the end cap's outline has an edge of no length"))?)),
_ => Err(invalid("the end cap's outline lost an edge")),
}
};
// The segments between line `i` and the next line.
let between = |i: usize| -> Vec<Seg2> {
let (Some(&a), Some(&b)) = (lines.get(i % k), lines.get((i + 1) % k)) else { return Vec::new() };
let count = (b + n - a - 1) % n;
(1..=count).filter_map(|o| segs.get((a + o) % n).copied()).collect()
};
// Each line's corner at its end, where chamfered: an outside corner, sharp or rounded by arcs
// that bulge out.
let mut corners = Vec::with_capacity(k);
for i in 0..k {
let (a1, b1, t1) = line(i)?;
let (a2, _, t2) = line(i + 1)?;
let den = t1.cross(t2);
let outside = den > 1e-9 && between(i).iter().all(|s| matches!(*s, Seg2::Arc { sweep, .. } if sweep > 0.0));
if !outside {
corners.push(None);
continue;
}
let v = a1 + t1 * ((a2 - a1).cross(t2) / den);
let setback = v.dist(b1).max(v.dist(a2));
if c + 1e-9 < setback {
return Err(invalid(format!(
"the chamfer must be at least the corner rounding it cuts away ({} mm), or 0",
crate::frame::short(setback)
)));
}
corners.push(Some((v - t1 * c, v + t2 * c)));
}
if corners.iter().all(Option::is_none) {
return Err(invalid("the end cap has no outside corners to chamfer (set the chamfer to 0)"));
}
let too_large = || invalid("the chamfer is too large for the end cap's edges");
let mut out = Vec::with_capacity(2 * n);
for i in 0..k {
let (a, b, t) = line(i)?;
let start = match corners.get((i + k - 1) % k) {
Some(Some((_, s))) => *s,
_ => a,
};
let end = match corners.get(i) {
Some(Some((e, _))) => *e,
_ => b,
};
if (end - start).dot(t) <= 1e-6 {
return Err(too_large());
}
out.push(Seg2::Line { a: start, b: end });
match corners.get(i) {
Some(Some((e, s))) => out.push(Seg2::Line { a: *e, b: *s }),
_ => out.extend(between(i)),
}
}
let lp = Loop2 { segs: out };
if !(lp.signed_area() > 1e-6) || crosses_itself(&lp) {
return Err(too_large());
}
Ok(lp)
}
/// A free body name for the cap on `member`: `<member> End Cap`, then `… (2)`, `… (3)`…
fn cap_name(st: &mut ModelState, f: &Feature, k: usize, member: &str) -> String {
if f.body_names.get(k).is_some_and(|n| !n.is_empty()) {
return crate::eval::new_name(st, f, k);
}
let base = format!("{member} End Cap");
// Not a name the design keeps for a suppressed feature or a rename (#4302, #4957): a cap
// made while another is suppressed must not take that one's name. Nor one another end of
// this cap has stored, which is built after this one when an end is added before it.
let tries = st.bodies.len() + st.reserved_body_names.len() + f.body_names.len() + 2;
(1..=tries)
.map(|i| if i == 1 { base.clone() } else { format!("{base} ({i})") })
.find(|n| st.body(n).is_none() && !st.reserved_body_names.contains(n) && !f.body_names.contains(n))
.unwrap_or(base)
}
/// A capped end, worked out before any body changes.
struct Planned {
body: String,
plane: Plane,
region: Region2,
/// The cap's extent along the plane's normal, and the slab cut from an inward cap's member.
cap: (f64, f64),
cut: Option<(Region2, f64, f64)>,
/// The cap's frame to the member body's own: the cap is authored in this feature's frame, the
/// member is stored in its component's (moved by its body offset), and the cut is made there.
to_member: crate::Mat,
}
pub(crate) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut ModelState) -> Result<()> {
let FeatureKind::FrameEndCap { ends, thickness, offset, ratio, chamfer, direction } = &f.kind else {
return Err(invalid("not an end cap"));
};
if ends.is_empty() {
return Err(invalid("pick at least one open end face of a frame member"));
}
if ends.len() > MAX_FACES {
return Err(invalid(format!("at most {MAX_FACES} end faces in one end cap feature")));
}
let t = length(crate::eval::val(vals, thickness, Kind::Length)?, "thickness", 0.01)?;
let d = match (offset, ratio) {
(Some(e), None) => length(crate::eval::val(vals, e, Kind::Length)?, "inset", 0.0)?,
(None, Some(e)) => {
let r = crate::eval::val(vals, e, Kind::Unitless)?;
if !r.is_finite() || !(0.0..=1000.0).contains(&r) {
return Err(invalid("the end cap's inset ratio must be from 0 to 1000 times the thickness"));
}
r * t
}
// Neither: flush with the outside of the profile.
(None, None) => 0.0,
_ => return Err(invalid("give the end cap's inset as either a length or a ratio of the thickness, not both")),
};
let c = length(crate::eval::val(vals, chamfer, Kind::Length)?, "chamfer", 0.0)?;
let mut planned = Vec::with_capacity(ends.len());
for end in ends {
let PlaneRef::Face { anchor: Some(anchor), .. } = &end.plane else {
return Err(invalid("an end cap needs a planar face picked on a frame member"));
};
if member(doc, st, &end.plane)? != end.member {
return Err(invalid("the capped face is no longer on the member it was picked on"));
}
let face = doc.resolve_face_anchor(anchor, f.component, st).map_err(|e| invalid(format!("the capped end face: {e}")))?;
let body = st.body(&anchor.target.body).ok_or_else(|| invalid("the capped member's body no longer exists"))?;
let source = doc.feature(end.member.feature.0).ok_or_else(|| invalid("the capped member's feature no longer exists"))?;
let (section, len, region) = crate::eval::frame_member::member_section(doc, vals, source, st, &end.member.line)?;
let to_author = anchor.source_to_author(doc, f.component, body)?;
let section = Plane::new(
crate::apply_point(&to_author, section.origin),
crate::apply_vector(&to_author, section.x),
crate::apply_vector(&to_author, section.y),
)
.ok_or_else(|| invalid("the member's placement is degenerate"))?;
let along = section.normal();
let facing = face.normal().dot(along);
if facing.abs() < 1.0 - 1e-7 {
return Err(invalid("the picked face is not an end of the member (it is not square to the member's line)"));
}
let plane = Plane::new(section.origin + along * (face.origin - section.origin).dot(along), section.x, section.y)
.ok_or_else(|| invalid("the end face's plane is degenerate"))?;
// The same end, however it was picked (another point on its face, another anchor): the
// same body with an earlier cap on this exact end plane.
let same_end = |p: &Planned| {
p.body == anchor.target.body && p.plane.origin.dist(plane.origin) < 1e-6 && p.plane.normal().dot(plane.normal()).abs() > 1.0 - 1e-9
};
if planned.iter().any(same_end) {
return Err(invalid("an end face is picked twice"));
}
let outline = chamfered(&inset(&cap_outline(&region.outer), d)?, c)?;
let cap_region = Region2 { outer: outline, holes: Vec::new() };
// Along the plane's normal: the member lies behind an end facing that way.
let s = facing.signum();
let (cap, cut) = match direction {
Direction::Outward => (if s > 0.0 { (0.0, t) } else { (-t, 0.0) }, None),
Direction::Inward => {
if t >= len - 1e-3 {
return Err(invalid(format!("an inward end cap {} mm thick needs a longer member", crate::frame::short(t))));
}
// A slab wider than the profile and past the end, so no face of it lies on the
// member's.
let bb = region.outer.polyline(1e-3).bounds();
let m = 1.0 + 0.01 * (bb.max - bb.min).len();
let (lo, hi) = (bb.min - Vec2::new(m, m), bb.max + Vec2::new(m, m));
let slab = Region2 { outer: Loop2::polygon(&[lo, Vec2::new(hi.x, lo.y), hi, Vec2::new(lo.x, hi.y)]), holes: Vec::new() };
let (a, b) = if s > 0.0 { (-t, m) } else { (-m, t) };
(if s > 0.0 { (-t, 0.0) } else { (0.0, t) }, Some((slab, a, b)))
}
};
let to_member = crate::mat_inverse(&to_author).ok_or_else(|| invalid("the member's placement is degenerate"))?;
planned.push(Planned { body: anchor.target.body.clone(), plane, region: cap_region, cap, cut, to_member });
}
for (k, p) in planned.into_iter().enumerate() {
if let Some((slab, a, b)) = &p.cut {
let i = st.bodies.iter().position(|b| b.name == p.body).ok_or_else(|| invalid("the capped member's body no longer exists"))?;
let mb = st.bodies.get(i).cloned().ok_or_else(|| invalid("the capped member's body no longer exists"))?;
let at = Plane::new(
crate::apply_point(&p.to_member, p.plane.origin),
crate::apply_vector(&p.to_member, p.plane.x),
crate::apply_vector(&p.to_member, p.plane.y),
)
.ok_or_else(|| invalid("the member's placement is degenerate"))?;
let tool = one(kernel::extrude(&at, std::slice::from_ref(slab), *a, *b)?)?;
let tool = crate::lineage::numbered_tool(tool);
let cut = kernel::boolean(&mb.body, &tool.body, BoolOp::Cut)?
.ok_or_else(|| invalid("cutting the member back for an inward end cap left nothing"))?;
let cut = crate::lineage::Traced::step(cut, &[&mb.traced(), &tool]);
if let Some(slot) = st.bodies.get_mut(i) {
*slot = ModelBody::traced_new(mb.name, cut, mb.feature);
}
}
let body = one(kernel::extrude(&p.plane, std::slice::from_ref(&p.region), p.cap.0, p.cap.1)?)?;
let name = cap_name(st, f, k, &p.body);
st.bodies.push(ModelBody::traced_new(name, crate::lineage::numbered_tool(body), f.id));
}
Ok(())
}
/// The outline an end cap is cut from: the outside of the profile. A closed section (a tube, a
/// pipe, a bar) keeps its own outline. An open section that turns inward somewhere (an angle, a
/// channel, a beam, an extrusion with slots) keeps the edges on its bounding rectangle and the
/// rounds and chamfers turning between them, and bridges each inward stretch along the
/// rectangle, so the plate closes the whole end with the profile's own outside corners.
pub(crate) fn cap_outline(outer: &Loop2) -> Loop2 {
let ring = outer.polyline(1e-3);
let convex = ring.corners().all(|(p, c, n)| (*c - *p).cross(*n - *c) >= -1e-9);
if convex {
return outer.clone();
}
let bb = ring.bounds();
let rect = Loop2::polygon(&[bb.min, Vec2::new(bb.max.x, bb.min.y), bb.max, Vec2::new(bb.min.x, bb.max.y)]);
let tol = 1e-6 * (1.0 + bb.max.dist(bb.min));
// How far a point is off each side of the rectangle (0 bottom, 1 right, 2 top, 3 left,
// counter-clockwise); a line lies on a side when both its ends do.
let off = |q: Vec2| [(q.y - bb.min.y).abs(), (q.x - bb.max.x).abs(), (q.y - bb.max.y).abs(), (q.x - bb.min.x).abs()];
let on_side = |s: &Seg2| match *s {
Seg2::Line { a, b } => (0..4).find(|i| off(a).get(*i).is_some_and(|e| *e < tol) && off(b).get(*i).is_some_and(|e| *e < tol)),
_ => None,
};
let segs = &outer.segs;
let n = segs.len();
let sides: Vec<Option<usize>> = segs.iter().map(on_side).collect();
let Some(first) = sides.iter().position(Option::is_some) else { return rect };
let corner = |i: usize| [Vec2::new(bb.max.x, bb.min.y), bb.max, Vec2::new(bb.min.x, bb.max.y), bb.min].get(i % 4).copied();
let mut out: Vec<Seg2> = Vec::with_capacity(n + 4);
let mut i = first;
for _ in 0..n {
let (Some(&seg), Some(&Some(si))) = (segs.get(i), sides.get(i)) else { return rect };
out.push(seg);
// The stretch up to the next edge on the rectangle.
let mut j = (i + 1) % n;
let mut run = Vec::new();
while sides.get(j).is_some_and(Option::is_none) {
run.push(j);
j = (j + 1) % n;
}
let (Some(&next), Some(&Some(sj))) = (segs.get(j), sides.get(j)) else { return rect };
// Kept when it only turns outward from one side to the next: a round or a chamfer.
let mut chain = vec![seg];
chain.extend(run.iter().filter_map(|k| segs.get(*k).copied()));
chain.push(next);
let turns_out = chain.windows(2).all(|w| matches!(w, [a, b] if a.end_tangent().cross(b.start_tangent()) >= -1e-9))
&& chain.iter().all(|s| !matches!(*s, Seg2::Arc { sweep, .. } if sweep < 0.0));
if !run.is_empty() && turns_out && sj == (si + 1) % 4 {
out.extend(run.iter().filter_map(|k| segs.get(*k).copied()));
} else if !run.is_empty() || seg.end().dist(next.start()) > tol {
// Along the rectangle from this side round to the next one's.
let mut p = seg.end();
let steps = (sj + 4 - si) % 4;
let steps = if steps == 0 && (next.start() - p).dot(corner(si).unwrap_or(p) - p) < 0.0 { 4 } else { steps };
for k in 0..steps {
let Some(c) = corner(si + k) else { return rect };
if p.dist(c) > tol {
out.push(Seg2::Line { a: p, b: c });
}
p = c;
}
if p.dist(next.start()) > tol {
out.push(Seg2::Line { a: p, b: next.start() });
}
}
if j == first {
break;
}
i = j;
}
let lp = Loop2 { segs: out };
if lp.signed_area() > 0.0 && lp.is_closed(tol) && !crosses_itself(&lp) { lp } else { rect }
}
fn one(mut bodies: Vec<solidcraft_kernel::Body>) -> Result<solidcraft_kernel::Body> {
let body = bodies.pop().ok_or_else(|| invalid("the end cap is not one solid"))?;
if !bodies.is_empty() {
return Err(invalid("the end cap is not one solid"));
}
Ok(body)
}
+932 -405
View File
File diff suppressed because it is too large Load Diff
+23 -4
View File
@@ -132,8 +132,8 @@ fn joint_face_measurements_are_shared_across_motion_samples_and_snap_kinds() {
id: 100,
name: "Pivot".into(),
kind: JointKind::Revolute,
a: JointOrigin { occurrence: 0, snap: Snap::Frame { origin: pick, z: Vec3::Z, x: Some(Vec3::X) } },
b: JointOrigin { occurrence, snap: Snap::FaceCenter { pick, face: None, x: Some(XRef::Dir(Vec3::X)) } },
a: JointOrigin::new(0, Snap::Frame { origin: pick, z: Vec3::Z, x: Some(Vec3::X) }),
b: JointOrigin::new(occurrence, Snap::FaceCenter { pick, face: None, x: Some(XRef::Dir(Vec3::X)) }),
values: vec![0.0],
limits: Vec::new(),
flip: true,
@@ -181,7 +181,7 @@ fn joint_face_measurements_never_follow_a_replaced_body_or_stale_offset() {
let mut doc = Document::new("replaced joint geometry");
let mut state = ModelState::default();
state.bodies.push(ModelBody::new("Pin".into(), kernel::cylinder(Vec3::ZERO, Vec3::Z, 2.0, 10.0).unwrap(), 0));
let origin = JointOrigin { occurrence: 0, snap: Snap::FaceCenter { pick: Vec3::new(0.0, 0.0, 10.0), face: None, x: None } };
let origin = JointOrigin::new(0, Snap::FaceCenter { pick: Vec3::new(0.0, 0.0, 10.0), face: None, x: None });
let work = counted(|| {
joints::resolve_origin(&doc, &state, &origin).unwrap();
});
@@ -210,7 +210,7 @@ fn an_edge_origin_measures_its_faces_once() {
let mut state = ModelState::default();
state.bodies.push(ModelBody::new("Block".into(), kernel::box_solid(Vec3::ZERO, Vec3::new(10.0, 10.0, 10.0)).unwrap(), 0));
let pick = Vec3::new(5.0, 0.0, 10.0);
let origin = JointOrigin { occurrence: 0, snap: Snap::Edge { pick, edge: None, face: None, corner: None, axis: None } };
let origin = JointOrigin::new(0, Snap::Edge { pick, edge: None, face: None, corner: None, axis: None });
let work = counted(|| {
for _ in 0..8 {
let frame = joints::resolve_origin(&doc, &state.clone(), &origin).unwrap();
@@ -1412,6 +1412,7 @@ fn marking(p: Vec3) -> FeatureKind {
chamfer_angle: None,
chamfer_depth: None,
steep_flank: Default::default(),
continuous_flanks: false,
old_auto_size: false,
}
}
@@ -1999,3 +2000,21 @@ fn a_hole_classifies_the_faces_it_reads_not_every_face_of_the_design() {
let side = super::hole_direction_at(&st, Vec3::new(252.0, 0.0, 5.0), &[]).unwrap();
assert!((side - Vec3::new(-1.0, 0.0, 0.0)).len() < 1e-6, "into the side wall: {side:?}");
}
/// A hole's look at the material over its entry face (#10695) is best effort: when the kernel
/// cannot build the run-on's column (here a column of no width), the hole keeps its full run-on
/// and cuts nothing out of its tools, as before the check, instead of failing.
#[test]
fn a_hole_whose_run_on_column_cannot_be_built_keeps_its_run_on() {
let mut state = ModelState::default();
state.bodies.push(ModelBody::new("Over".into(), kernel::box_solid(Vec3::new(-5.0, -5.0, 0.5), Vec3::new(5.0, 5.0, 2.0)).unwrap(), 0));
for reach in [0.0, f64::NAN] {
let (top, near) = super::hole_run_on(&state, &Plane::XY, reach, 1.0);
assert_eq!(top, 1.0, "reach {reach}");
assert!(near.is_empty(), "reach {reach}");
}
// With a column, the body 0.5 over the face halves the run-on to its gap.
let (top, near) = super::hole_run_on(&state, &Plane::XY, 3.0, 1.0);
assert!((top - 0.25).abs() < 1e-6, "top {top}");
assert!(near.is_empty());
}
+50 -15
View File
@@ -25,23 +25,10 @@ const STRAIGHT_TOL: f64 = 1e-3;
/// Evaluate a `FrameMember` feature: one new body per line, each named
/// ([`member_names`], or by position for a copy whose `body_names` were set).
pub(super) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut ModelState) -> Result<()> {
let FeatureKind::FrameMember { path_sketch, lines, profile, anchor, angle, mirror, body_name, names } = &f.kind else {
let FeatureKind::FrameMember { body_name, names, .. } = &f.kind else {
return Err(DocError::Invalid("not a frame member feature".into()));
};
let ps = st.sketch(path_sketch.0).ok_or_else(|| DocError::Unknown(format!("sketch {path_sketch} (it must come earlier in the timeline)")))?;
// The frame sketch in this feature's component frame: its plane, and its 3D lines.
let mapped =
if ps.sketch.wires.is_empty() { Cow::Owned(sketch_in_feature_frame(doc, ps, f.component)?) } else { path_in_frame(doc, ps, f.component)? };
let segments = member_lines(mapped.as_ref(), lines)?;
let (mut regions, description) = profile_regions(vals, st, profile)?;
if *mirror {
regions = regions.iter().map(frame::mirrored).collect();
}
let at = frame::anchor_point(&regions, *anchor);
let turn = match angle {
Some(e) => val(vals, e, Kind::Angle)?,
None => 0.0,
};
let Layout { segments, regions, description, at, turn } = layout(doc, vals, f, st)?;
let mut made = Vec::with_capacity(segments.len());
for (id, a, b) in &segments {
let (x, y) = frame::member_axes(*b - *a, turn).ok_or_else(|| DocError::Invalid(format!("line `{id}` has no length")))?;
@@ -70,6 +57,54 @@ pub(super) fn evaluate(doc: &Document, vals: &BTreeMap<String, Value>, f: &Featu
Ok(())
}
/// A member feature's lines (in its component frame), profile regions, default name, the
/// profile point that sits on the lines and the profile's turn about them.
struct Layout {
segments: Vec<(String, Vec3, Vec3)>,
regions: Vec<Region2>,
description: String,
at: Vec2,
turn: f64,
}
fn layout(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &ModelState) -> Result<Layout> {
let FeatureKind::FrameMember { path_sketch, lines, profile, anchor, angle, mirror, .. } = &f.kind else {
return Err(DocError::Invalid("not a frame member feature".into()));
};
let ps = st.sketch(path_sketch.0).ok_or_else(|| DocError::Unknown(format!("sketch {path_sketch} (it must come earlier in the timeline)")))?;
// The frame sketch in this feature's component frame: its plane, and its 3D lines.
let mapped =
if ps.sketch.wires.is_empty() { Cow::Owned(sketch_in_feature_frame(doc, ps, f.component)?) } else { path_in_frame(doc, ps, f.component)? };
let segments = member_lines(mapped.as_ref(), lines)?;
let (mut regions, description) = profile_regions(vals, st, profile)?;
if *mirror {
regions = regions.iter().map(frame::mirrored).collect();
}
let at = frame::anchor_point(&regions, *anchor);
let turn = match angle {
Some(e) => val(vals, e, Kind::Angle)?,
None => 0.0,
};
Ok(Layout { segments, regions, description, at, turn })
}
/// The member of feature `f` on line `line`, as its body was made: the plane square to the line
/// at its start (x × y along the line), its length, and its profile in that plane.
pub(crate) fn member_section(
doc: &Document,
vals: &BTreeMap<String, Value>,
f: &Feature,
st: &ModelState,
line: &str,
) -> Result<(Plane, f64, Region2)> {
let Layout { segments, regions, at, turn, .. } = layout(doc, vals, f, st)?;
let (_, a, b) = segments.iter().find(|(id, _, _)| id == line).ok_or_else(|| DocError::Unknown(format!("line `{line}` of the member feature")))?;
let (x, y) = frame::member_axes(*b - *a, turn).ok_or_else(|| DocError::Invalid(format!("line `{line}` has no length")))?;
let plane = Plane::new(*a - x * at.x - y * at.y, x, y).ok_or_else(|| DocError::Invalid(format!("line `{line}`: no plane square to it")))?;
let region = regions.into_iter().next().ok_or_else(|| DocError::Invalid("the member profile has no area".into()))?;
Ok((plane, a.dist(*b), region))
}
/// The body name of the member on each of `lines`: its own name from `pinned` (by line id) when no
/// other body has it, else the first free one of `base`, `base (2)`, `base (3)`… that no line has
/// pinned. A member therefore keeps its name when other lines are added, deleted or reordered.

Some files were not shown because too many files have changed in this diff Show More