Compare commits

..

159 Commits

Author SHA1 Message Date
fnoppix 73e188df52 Add Solarized Dark theme (#7852)
* Add Solarized Dark theme

* Add attribution

* Make Solarized Dark pass the theme checks and register it in the new theme order

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

* Theme filter test: count the new Solarized Dark theme

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

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:09:34 +00:00
github-actions[bot] c571a133dc Regenerate generated files and fold pending files [skip ci] 2026-11-06 17:22:05 +00:00
PaddleStroke a2218e8a8d Sketch: Divide Curve places N-1 points on a curve at equal spacing (#8969) (#9664)
* claim: #8969

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

* Sketch: Divide Curve places points at equal lengths along curves (#8969)

A new PointAlong constraint holds a point at its share of a curve's
length (measured along the exact curve), so the points follow edits.
sketch.point.divide places them on lines, arcs, circles, ellipses,
splines and conics; trim and break loosen them to point-on-curve.

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

* Divide Curve: use the solidcore_record segment and vector types after the layer split

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

* Divide Curve: exempt sketch.point.divide from kernel cases and show PointAlong glyphs

PointAlong constraints now get a glyph on their point (the midpoint icon),
light their point and curve, and hold an end against Extend like
PointOnCurve does.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 16:44:37 +00:00
bherbruck c36860e773 Tests: skip the progressive render test on a software GPU (#12664) (#12665)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 16:43:49 +00:00
austin62jake 5faacb55d6 Tests: the helical-chain and face-classification scaling tests count work, not time (#9901) (#9912)
* Claim #9901

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

* Tests: the helical-chain and face-classification scaling tests count work, not time (#9901)

Both timed a small run and one four times larger and compared the times,
which load arriving between the two runs can fail. They now count the
work that would grow quadratically, through test-only counters: the edges
Mesh::tangent_chain looks at to extend a chain, and the triangles
SurfaceIndex::contains measures a point against. Four times the input
must cost at most eight times the count, as the time ratio allowed. The
counts are the same on every run (2248 -> 8998 edges, 80250 -> 421776
triangles). scales_linearly and its test go from both files.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-06 13:23:06 +00:00
yoyomaimai 6c2ac96a09 Traditional Chinese: update the zh-TW translation (#10152)
* Update zh-TW.json

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

* i18n test: expect the updated zh-TW wording

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 13:16:29 +00:00
austin62jake cccef6dccd Agents and scripts: Set, Inspect and Frame Render Camera and Apply Render Camera describe their exact parameters and reply (#12288) (#12289)
* claim: #12288

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

* Render camera: input and output schemas for Set, Inspect and Frame Render Camera and Apply Render Camera (#12288)

The four commands that set, read, fit and apply the render camera get
typed contracts and replies, in a new `schema/render_camera.rs`, and
leave `schema/unconverted.txt`.

- `RenderCamera` is a saved render setup's camera: its keys, and the
  bounds `RenderSetup::validate` keeps (1e9 mm, 1e6 radians, a positive
  distance, 0 <= fov < pi). The reader decodes it as the handler does,
  through a setup holding only that camera, so each refusal keeps the
  handler's message. The bounds are in the input schema only: a reply
  gives back the camera in the view, which Frame Render Subject can move
  beyond them, so the output schema has the camera's shape alone.
- `camera` and `name` are optional in the types and required in the
  schemas (a `require` transform), so a call without them still gets
  the handler's own message; `#[schemars(required)]` doesn't do this
  next to `serde(default)`.
- The handlers build their replies from the reply types through a small
  `typed_reply`; the JSON is unchanged.

Tests check each camera and aspect case against both the schema and the
handler, keep today's messages in strict, and match every reply against
its schema in warn.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-06 13:16:05 +00:00
semmelrinde 5a630606a4 Sketch: a tangent to an ellipse or a conic touches it and never crosses it (#11535) (#11562)
* Sketch: a tangent to an ellipse or a conic touches it and never crosses it (#11535)

A tangent between a free-form curve (ellipse, conic, spline) and another
curve, with no shared end point, brought the sample gap nearest zero to
zero. Curves that cross have a zero gap too, so a line or circle could
cut through an ellipse while the Tangent still showed as held. The solver
now brings the extremum of the gap nearest zero to zero (refined between
samples by a parabola), which only a touch satisfies. Where the gap has
no extremum, as on an open curve running away, it keeps the old gap.

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

* Tangent: a monotone gap takes the end nearer zero, not a crossing's zero (#11535)

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

* Tangent: an open free-form curve touching at its end has no residual (#11535)

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 13:09:52 +00:00
thocsmith 7139ee9d20 Sketch: the Fix constraint accepts a box selection that includes dimensions (#11663) (#11671)
* claim: #11663

* Fix: a box selection with dimensions in it is fixed at once (#11663)

A box drawn over a sketch also takes its dimensions and constraint icons.
Fix started with that selection ignored all of it and fell back to the
pick tool, so nothing was fixed. It now passes over the dimensions and
constraint icons and fixes the boxed points and curves, up to the 10,000
names the command takes (the shared constraint limit of 200 no longer
applies to Fix).

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

* Fix constraint test: a selection of only points gives each its own Fix (#11663)

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

* Fix from a selection: a curve of another sketch goes to the pick tool (#11663)

Co-Authored-By: Claude Sonnet 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-06 12:51:12 +00:00
Thijs Damsma 5818c3eb3b Kernel tests: export discarded tool operations and handled refusals (#12099)
* claim: preserve complete kernel-case traces

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

* fix: preserve complete kernel-case execution traces

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

---------

Co-authored-by: Codex <noreply@openai.com>
2026-11-06 12:50:56 +00:00
NOWN-DEV 9c2b888b40 Sheet metal: a cut or outline corner a hair from a bend line no longer breaks unfold and refold (#12224)
Three ways a flat pattern whose edges come within 50 nm of a bend zone's edge failed:

- An outline with a vertex a hair from where a bend zone ends (a collinear vertex, as a DXF
  split at its bend lines has) is split there, and the panel's loop keeps an edge that short.
  SMLib's face builder refuses it ("SMLib failed (status 1001)"), so unfold fails. Such hair
  edges are now merged into the line they run along.
- A cut-out whose edge stops a hair short of a bend line, or past it, or whose rounded corner
  ends tangent a hair beside it, leaves a sliver face along the line, which the sew cannot tell
  apart from its neighbour ("ambiguous edge contact"), so refold fails. Corners that close are
  now moved onto the bend zone's edge (an arc moves with its centre); the cut moves under 0.05 µm.
- The planar booleans close a loop within 1 nm, but hand back free-form loops whose pieces are
  up to tens of nm apart, which a following extrude or boolean refused. Gaps under 50 nm are now
  welded before a loop is extruded or combined.

A cut-out that encloses no area is skipped.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 12:50:38 +00:00
sascha2101 0678ec98c3 Joint symbols: a square for rigid joints, sized to the joined parts, faint where they pile up (#6404) (#6742)
* claim: #6404

* Joint symbols: a square for rigid joints, sized to the joined parts, faint where they pile up (#6404)

In an assembly with many joints the symbols covered the model: rigid
joints drew the same motion axis and ring as moving ones, and every
symbol was a fixed 5 % of the view height, so zoomed out a cluster of
joints swamped the parts.

- A rigid joint draws a small square, with no axis or ring. This covers
  every rigid joint, including those joint.rigid_group saves.
- A moving joint's axis is at most 5 % of the view height, as before,
  and at most a quarter of the smaller joined part's size (its bodies'
  box diagonal, found once per design revision), so zoomed out the
  symbols shrink with the parts.
- Symbols are planned picked first, then moving, then rigid joints; one
  whose centre falls inside a symbol planned before it is drawn faint,
  unless it is picked.

The planning is joint_glyph_plan, tested without painting.

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

* Joint symbols: hovering one names the joint and its type (#6404)

A tooltip on a joint symbol in the 3D view shows the joint's name and
type, e.g. "Glue · Rigid", so the square, ring and axis explain
themselves, as the timeline and browser entries already do. The pointer
picks the nearest symbol within 8 points; of symbols piled on one spot,
the one drawn on top. No tooltip while a mouse button is held.

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

* Joint symbols: the tooltip names the type only where the name doesn't (#6404)

Review on #6742: "Rigid 7 · Rigid" said the type twice. A name that
already contains the type's label is shown alone ("Rigid 7"); any other
name is followed by the type in brackets ("Glue (Rigid)"). The type is the
Type box's label (kind_label, "Pin-slot" rather than "PinSlot"), translated
like the rest of the interface.

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

* Fix compile after the layer split

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

* Use the current egui id calls

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

* Format the joint tooltip call

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

---------

Co-authored-by: sascha2101 <221609842+sascha2101@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 12:44:37 +00:00
github-actions[bot] b8aa83c6d9 Regenerate generated files and fold pending files [skip ci] 2026-11-06 10:14:16 +00:00
github-actions[bot] 8ad0cce768 Regenerate generated files and fold pending files [skip ci] 2026-11-06 10:01:43 +00:00
yhamil04 3bcd93e2ca Sketch: a preference to turn off scaling the sketch to its first dimension (#4109) (#6807)
* claim: #4109

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

* Sketch: a preference to turn off scaling the sketch to its first dimension (#4109)

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

* Test the first-dimension preference at small, typical and large values

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

* Engine: the scale_sketch doc names the Sketch preference

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

* Translate the first-dimension preference into the complete catalogs (ja, zh)

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

* Add the Arabic, Hebrew and Vietnamese texts for the first-dimension preference

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 09:31:40 +00:00
selune 3a70b43708 render: add CPU and GPU rough Glass, films, dispersion and caustics (#12200)
Add saved optical models, reciprocal rough interface transport, hard-light
connections, and bounded photon caustics for surfaces and selected media.
Keep inactive Glass sampling behavior and document admission and model limits.

Expose native controls and provide original CPU/GPU diagnostic captures.
2026-11-06 09:05:30 +00:00
github-actions[bot] 1bbb18494e Regenerate generated files and fold pending files [skip ci] 2026-11-06 09:26:30 +00:00
Sloptimum 8e55033d9a Orbit drags keep turning at the edge of the view (#3459)
* Orbit drags keep turning at the edge of the view

An orbit drag that reached the edge of the screen stopped turning: the cursor
stops there, so the pointer reports no more motion. Now, when an orbit drag
reaches the edge of the view, the cursor moves to the opposite edge and the
frame that reports the jump turns the view only by the hand's motion, so the
drag can go round the model as far as the user likes. Synthetic drags
(control channel, scripts) never move the real cursor. Where the cursor can't
be moved (Wayland, the browser) nothing changes.

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

* Orbit cursor wrap: a Navigation preference keeps the old behaviour

Wrapping the cursor during an orbit changes what an orbit drag does out of the
box, so Preferences › Navigation gets "Wrap the cursor while orbiting" (on by
default, `orbit_cursor_wrap` in ui.prefs). Off, wrap_cursor never moves the
cursor and the drag stops at the edge of the screen as before. The new strings
are a pending locale file, with Arabic, Hebrew, Japanese, Vietnamese and Chinese
for the complete catalogs.

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

* Use the current egui id calls

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

---------

Co-authored-by: rootarchitect <7781866+rootarchitect@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 08:49:18 +00:00
Robson Pereira a1d2b6d05b Hole: placing a hole is faster in assemblies with many parts (#7175)
* Hole: read the faces nearest its position, not every face of the design

`hole_direction_at` classified the surface of every face of every body
(`faces_through` with an infinite reach) and then used the nearest one,
nearly always the first. In an assembly of hundreds of imported parts that
was most of a hole's time, on every preview and apply, and the viewport's
hole manipulator calls it too.

- Faces are now sorted by their mesh distance first (cheap) and each surface
  is classified only when the direction rules reach it, in the same order, so
  the direction is the same.
- `hole_on_surface` skips meshes whose box the drilling line does not meet
  (it only casts along that line), and `faces_through` skips meshes farther
  than its reach.

A cost test counts the surfaces classified for one hole among forty parts.

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

* Hole: fix the new test for the references field

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

* Rename the faces_through line in mesh-decisions to faces_near

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 08:27:20 +00:00
Ahmad Khan 89191a1278 Parameters: the parameter list names the sketch that reads a parameter in a point coordinate (#12293) (#12350)
* claim: #12293

* Test: a parameter read only by a sketch point lists the sketch in used_by (#12293)

* Parameters: used_by names the feature that reads a parameter itself, as the graph does (#12293)

parameters.list built used_by from named parameter expressions only, so a
parameter read by a sketch point coordinate, a sketch pattern or a sheet
metal or plastic rule listed no user. The names a feature reads through its
own expressions now come from one helper that both parameters.graph and the
parameter table use.

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-06 08:03:55 +00:00
github-actions[bot] dad363980b Regenerate generated files and fold pending files [skip ci] 2026-11-06 07:58:48 +00:00
Ahmad Khan 55d07a258c Insert Fastener: one fastener per hole, head at the open end, when a hole is picked at both ends (#12191) (#12404)
* claim: #12191

* Test: a hole picked at both ends gets one fastener at its open end (#12191)

* Insert Fastener: picks on one hole seat one part, at the hole's open end (#12191)

Picks were merged only when they seated at the same point, so a hole picked
at both ends (a blind hole's rim and floor edge, a through hole's two rims)
got a second fastener, turned over. Picks on one axis line of one body now
seat one part. When one of them is a blind hole's floor edge, the part is
seated at the rim instead: hole_wall now says whether the picked end of the
wall opens onto air, by classifying a point on the axis just past it.

* Insert Fastener: coaxial blind holes from opposite faces stay two holes, a fastener each (#12191)

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-06 07:11:07 +00:00
Mario Geiger 1589e18f2a Point clouds: remember the source file and reload it (#8818) (#8821)
* Point clouds: remember the source file and reload it (#8818)

A cloud keeps the absolute path it was inserted from. pointcloud.reload
reads it again, keeping the cloud's name, placement, units and colouring,
and the filters on properties the file still has; the Edit Point Cloud card
has a Reload from file button.

The file is read beside the window through the file loader, with progress
and Cancel, as an insert is. A thinned cloud stays thinned to as many points,
which reads an unchanged file as the same points; any other is read as a new
insert would be, so a file that grew comes in whole.

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

* Point clouds: a reload asks before it reaches a network location (#8818)

A design names the cloud's file, and a design may come from anyone. On
Windows, only asking about `\\host\share\x` connects to that computer and
may send it the user's sign-in. So `pointcloud.reload` now reads through
`vfs::read_design_path`, as linked designs do, and Reload from file asks
with the same prompt as Update Links.

The button's label uses its stable message id. The strings gain Korean,
which a new label needs. `pointcloud.reload` gets its line in
tests/kernel-cases/EXEMPT, which the "Every command has a case" job needs.

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

* Point clouds: a reload reads under the limit the cloud was read under (#8818)

The limit was inferred from the counts, as if a cloud with fewer points than its
file had been thinned. A point that cannot be read makes the same difference:
such a PLY read as half its points on an unchanged file, since a limit one below
the file's count is a stride of two, and a file that grew was cut to the old count.
Keep the limit itself: a read is a function of the file and the limit.

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

* Point clouds: a reload drops a value filter when the file stops naming the values (#8818)

A set of values filters a label, and `pointcloud.edit` refuses one on a property with no names.
A reload kept such a filter while the property stayed, so a file that dropped its names comment
left a cloud every later edit refused. One predicate now says what is refused and what a reload
drops.

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

* Point clouds: a reload keeps its undo step and ends a play it moved (#8818)

A reload accepted with the Edit Point Cloud card open left the card's undo
boundary before it, so the card's next edit folded the reload into itself and
one Undo took back both. The boundary now moves past the reload.

A play told its filter by place alone. When a filter before it went, by a
reload, an agent's edit or an undo, the next filter took that place and the
play's range, on screen and written when the play ended. A play now names its
filter's property and ends, unwritten, when that place holds another.

`engine.batch` and the control hook compared command ids exactly, while the
engine takes any case: `POINTCLOUD.RELOAD` passed the refusal and read the file
on the window thread. Both now resolve the id as the engine does, for every
command that loads a file. The batch row of the protocol said the refusal held
only with the agent cursor shown; it always holds.

No test was run locally, at the owner's request: compile, clippy and fmt only.

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

* Point clouds: a file load keeps the request's own param_check (#8818)

`file_load::control` takes a command the file loader runs before
`control::handle` does, so that command skipped the request's `param_check`:
`pointcloud.reload` accepted a word that is no level, a `strict` call with an
unknown parameter read the file anyway, and the reply did not say the level.
`doc.open`, the imports and the DXF export went the same way.

The hook now takes the level itself and checks the call before the file is
touched, as a command that switches designs does: the worker's session goes on
to be the design's, which keeps its own level. Both share the same check, and
the reply says the level and any warnings.

No test was run locally, at the owner's request: compile, clippy and fmt only.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 06:56:52 +00:00
github-actions[bot] ee43b7d478 Regenerate generated files and fold pending files [skip ci] 2026-11-06 07:23:06 +00:00
JK3D ed30a59795 History: joints as one grouped button, and the History bar folded into groups, both off by default (#8884, #8885) (#8886)
Rebased onto main as one change: the joints group into one button in the timeline, and the History bar folds into component runs, feature folders and STEP inserts. Both views are Preferences > Layout settings and off by default.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 06:10:37 +00:00
austin62jake c66752e8d3 Agents and scripts: the render binding commands for library surfaces and optics describe their exact parameters and reply (#11741) (#11742)
* claim: #11741

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

* Render bindings: input and output schemas for the surface and optical bind and unbind commands (#11741)

describe_command now gives the exact parameters and reply of the four
commands that bind a library surface or an optical profile to bodies in
a saved render setup, and unbind them, and the warn and strict
parameter checks use them. The handlers already read their parameters
with strict serde types; those types move to the new
schema/render_bindings.rs, gain descriptions and JsonSchema, and become
the contracts. The doc crate's target and setup types have no
JsonSchema, so their schemas are written by hand. The replies are built
from typed values instead of json! literals, with the same JSON, and
the saved setup is serialized before the document changes.

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

* Render bindings schema: `set` names the setup's fields, and `origin`'s default is the body's centre

`patched_settings` reads a `set` patch onto the saved setup as a
RenderSetup, which refuses unknown fields, so the schema now names the
setup's 14 fields with additionalProperties false (still at most 13 at
once). Without `surface.origin`, render.library.surface.prepare starts
the maps at the centre of the body's bounding box, not at the origin;
the description now says so. A new test covers the field names.

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

* Render bindings: keep main's CPU and GPU wording and the OpticalMaterial import after the rebase

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 05:47:42 +00:00
PeppaWutz 429520088a Agents and scripts: the view navigation and layout commands describe their exact parameters and reply (#12278) (#12353)
* Agents and scripts: the view navigation and layout commands describe their exact parameters and reply (#12278)

describe_command now gives the exact parameters and reply of view.navigate,
view.layout, view.history_layout, view.graphics_preset and
view.ambient_occlusion, and the warn and strict parameter checks use them.

The handlers still read their parameters from the raw JSON, so the new types
read each key as its handler does and give its message. Keys the handlers
refuse when left out (mode, preset, enabled, camera) are required in the
schema but left to the handlers' messages. The replies are built from typed
values instead of json! literals, with the same JSON as before.

* view.navigate: the contract reads only the keys of the form the handler takes (#12278)

The handler reads a motion's keys when motion is given (each motion its own), else direction, else degrees and action, and never the keys of another form. The contract is now read by hand in the same order, so a key of another form is not checked in warn or strict either, and a call that works with the check off works in both.

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 05:39:22 +00:00
Thijs Damsma 54b4bb3f44 STEP import: decode unterminated Unicode escapes in linear time (#11947) (#12109)
* claim: bound STEP escape terminator searches (#11947)

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

* fix: stop rescanning unterminated STEP escape tails

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

---------

Co-authored-by: Codex <noreply@openai.com>
2026-11-06 05:23:13 +00:00
PaddleStroke d8bf4c9bed Sketch palette: drag it by its header to move it (#8923) (#9671)
* claim: #8923

* Sketch palette: drag it by its header to move it (#8923)

The palette docks at the right edge as before; its status header now drags it like a
command dialog's title, and it keeps its place for the rest of the session. It stays on
screen and never goes so low that Finish scrolls out of view. A wide dialog docked at
the left no longer shrinks to the sliver left of a palette that was moved there.

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

* Dialogs: drop the token the palette's room no longer needs (#8923)

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

* Sketch palette: keep the token binding the dialog still uses after the rebase

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 05:09:41 +00:00
Enoch d68970dd97 test(extrude): cover rotated side-face preview (#3699)
* claim: #3426

* test(ui): cover angled-face extrusion preview direction

* Unwrap the world state in the side-face preview test

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

---------

Co-authored-by: Odunayo Balogun <odunayobalogun@users.noreply.github.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 05:01:54 +00:00
github-actions[bot] a6644ef0d2 Regenerate generated files and fold pending files [skip ci] 2026-11-06 06:01:07 +00:00
Matthew Davis 48bab1a65a Design tabs: double-click a tab to rename the design (#10364)
* Design tabs: double-click a tab to rename the design

A double-click on the selected design's tab opens a name field in the tab
with the name selected, so typing replaces it. Enter or a click anywhere
else keeps the new name; Escape keeps the old one. The tab grows with the
name while it is typed (up to the tab's usual 200 pt). The rename goes
through component.rename with component 0, so it is undoable, marks the
design unsaved and is what Save As offers next. A name left as it was or
left blank changes nothing, and names are cut to the 128 characters the
command takes.

On desktop the bar is the window's title bar, and a double-click on a tab
used to maximize the window. Double-clicking the bar's empty space still
does; the tabs now rename. The preference tab_double_click_renames
(Preferences > Interface, "Double-click a design tab to rename it") brings
the old behaviour back.

Changes a default: yes - a double-click on a design tab renames the
design, old behaviour (maximize the window) kept behind preference
tab_double_click_renames.

Strings in assets/locales/pending/design-tab-rename.json (en, ar, de, he,
ja, ko, vi, zh). Docs: the UI tour and the preference list in
control-protocol.md (handle tab:rename).

Tests in documents.rs: Enter renames and undo restores; a click elsewhere
keeps the name and the tab grows while typing; Escape, a blank name and
the same name change nothing; an over-long name is cut to fit; with the
preference off a double-click does not rename.

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

* Fix the tab rename for the current egui and ignore the rename result

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-06 04:53:05 +00:00
Daniel Dimitrov 25d7a6b0c3 Hole: the same parameter definition typed for several holes uses that parameter (#12472) (#12473)
Single holes on several faces send one solid.hole command per face, each
carrying the same `name = expression` text. The second command was refused
because the name was already taken. A definition typed again exactly as an
existing user parameter was defined (same expression, same unit) now names
that parameter; a different value is still refused.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 04:41:09 +00:00
DuBearte 8505c77f5b Open: check timeline folders for cycles in one pass (#12416)
Loading a design walked every folder's chain of parents with a linear
search per step, so the check grew with the cube of the folder count: a
588 KB design with 10 000 nested folders took over three minutes to
open (also as a recovery autosave or over the control channel). Each
chain is now walked once through an id -> parent map, stopping at a
folder already known to end at the top. Cycles are still refused.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 04:32:49 +00:00
Ahmad Khan 7ecb3934a6 Tests: the Assistant start-page scenario scrolls to Add agent before clicking it, so it passes with an agent installed (#12354) (#12397)
* claim: #12354

* Tests: agent_chat_home_page scrolls Add agent into view before clicking it (#12354)

With an AI agent installed, its card on Preferences > Assistant pushes Add
agent below the visible page. The scenario clicked the button's handle
point, which then lies on the empty footer, and timed out waiting for the
dialog. A widget step scrolls the button into view first.

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-06 04:28:46 +00:00
Ahmad Khan b5a5412d48 Command line: run --out exports meshes at a chosen quality with --quality fine or finest (#12270) (#12386)
* claim: #12270

* Test: run --out writes meshes at the --quality asked for (#12270)

* Command line: run --quality standard|fine|finest sets the mesh quality of --out exports (#12270)

file.export already took quality, but run --out passed the path alone, so a
fine STL needed a script. --quality is checked before anything runs and goes
to every --out export; the usage text and the getting-started guide say so.

* Command line: run refuses --quality given twice, and the docs say the mesh chord never goes under 1 µm (#12270)

---------

Co-authored-by: Ahmad Khan <ahmad.khan@shiritai.co>
2026-11-06 04:28:23 +00:00
github-actions[bot] c4e1a3a756 Regenerate generated files and fold pending files [skip ci] 2026-11-06 03:24:10 +00:00
raykholo b432b4484b Kernel cases: match the reorder refusal's new wording (#12392)
#12171 changed the reorder refusal to "moving Notch to position 0 breaks
Notch (...)", so the history case that expected "moving Notch there breaks
Notch" now fails in the kernel rig on every pull request that runs it.
The case checks a substring, so expect "breaks Notch", which both wordings
contain.
2026-11-06 02:56:29 +00:00
selune 068c46cf8b Render: restore saved shots, progressive CPU/GPU images and exports (#6201) (#11087)
* Render: restore saved shots, progressive images and exports

* Render: register existing live and coat command tests

* Render: isolate lens saves and retain bounded previews

Save only lens parameters on existing CPU/GPU jobs while keeping unrelated
draft settings dirty. Retain pinned checkpoints through preview and status,
and release host-only snapshots outside the status lock.

Use the admitted PNG bound for registered-executor checkpoint slots. Preserve
executor work credits, final publication and regrade ownership. Add regression
coverage and align help, translations and capability documentation.

* Render: preserve live feedback and address review regressions

* Preserve saved cameras when applying Render library edits

Keep the saved camera when lighting or maps are applied to an existing shot. Fit and centre the measured Render host using the painted picture. Carry forward the upstream CPU and GPU preset and ZoomTool contracts.
2026-11-06 02:47:52 +00:00
github-actions[bot] d7cad1005a Regenerate generated files and fold pending files [skip ci] 2026-11-06 02:12:45 +00:00
bherbruck 8564006ffb Drawing: format_pending is one of the record's fields (#12448)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 01:45:23 +00:00
ReDead 708d5a149d Plane at Angle: use axis direction only with a pivot (#12041) (#12131)
* claim: #12041

Co-authored-by: ReDead <ReDead@users.noreply.github.com>

* Plane at Angle: use axis direction only with a pivot (#12041)

Add a direction_only option that projects the axis onto the base and
turns about a pivot (or the base origin), with dialog checkbox and
conditional Pivot pick. Older designs keep turning about the full line.

Co-authored-by: ReDead <ReDead@users.noreply.github.com>

* i18n: add ar, he, vi for Use axis direction only (#12041)

Complete catalogs need every English message; the pending locale file
was missing those three so cargo xtask i18n --check failed.

Co-authored-by: ReDead <ReDead@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: ReDead <ReDead@users.noreply.github.com>
2026-11-06 01:38:49 +00:00
Daniel 0c094142d3 Sketch Break and Extend: a cut or stop on a shape's centre ends there, with no second point (#12299) (#12301)
* Sketch Break and Extend: tests for a cut or stop on a center rectangle's centre

Breaking a center rectangle's diagonal at the centre leaves two points there, and extending a line up to the centre ends it on one diagonal only. These tests fail on main.

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

* Sketch Break and Extend: a cut or stop on a held midpoint ends there, as Trim does

Break dropped the broken line's Midpoint and joined the pieces at a new point held only on the cutter, so a center rectangle's centre came loose and a corner drag pulled the two points apart. It now uses Trim's rule (one helper, hold_cut): the pieces meet at the held point, which moves its hold to the cutter's middle when the sketch already implies that, and otherwise stays on the cutter.

Extend stopped on a point it lays on the curve it meets unless that curve ends there. A point held at another line's middle (a center rectangle's centre) is now a stop too, so the extension joins it.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 23:27:01 +00:00
Martin Pålsson 1939adba6b Sketch Dimension: pick an origin axis as a reference (#2364) (#2373)
* claim: #2364

* Sketch Dimension: an origin axis can be picked as a reference (#2364)

The dimension tool ignored clicks on an origin axis and the engine's
sketch.dimension did not resolve x/y. Axis picks now map to the sketch's
linked axis line, as Symmetry and the other line constraints already do,
in all three entry points (click-then-pick, select-then-D, and the command).

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

* Sketch Dimension: tests for a circle centre and a line against the sketch axes (#3137, #3320)

Folds in the cases from #3298: a circle's centre point dimensioned to the
x / y axis (#3137), and a line's angle and an end's distance to the x axis
(#3320). The axis resolution from #2364 already covers them; a plain circle
or arc with a line still measures to its edge (#1803).

Co-authored-by: Phanoob <phanoob@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Sketch Dimension: the axis test picks the line off its midpoint, which is a point pick (#4872)

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Phanoob <phanoob@gmail.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 23:13:42 +00:00
Robson Pereira 207679e261 Face and edge dialogs name the body of their picks (#7174)
Fillet, Chamfer, Offset Face (and Press Pull on a curved face, which opens
it), Draft, Replace Face and Delete Faces sent only the picked points. The
feature then checked every body's edges for them and evaluated on the body
whose mesh box is nearest the first point (`body_at`):

- In an assembly, a bore or pin inside a housing that comes first in the
  body list was looked for on the housing, which has no face there, and the
  command failed with "no face at [...]".
- In a large design, `body_at` meshed every body (and Fillet/Chamfer worked
  out every body's edges) on each preview and apply: seconds per change.

These dialogs now name the body when every pick lies on one, as Shell does
since #4555; picks on several bodies name none, as before. Press Pull passes
a given body on to Offset Face.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:38:11 +00:00
github-actions[bot] 4cbbccb935 Regenerate generated files and fold pending files [skip ci] 2026-11-05 22:50:08 +00:00
PaddleStroke 22f8da2689 View: hold a shortcut to drag and zoom (#11701) (#11706)
* claim: #11701

* Allow assigned shortcuts to drag the view to zoom
2026-11-05 22:08:53 +00:00
semmelrinde 51d8842e8a Create Sketch: the flat faces of a cone take an attached sketch (#7476) (#7772)
* claim: #7476

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

* Create Sketch: the flat faces of a cone take an attached sketch (#7476)

The cone primitive was evaluated as an unnamed tool, so its faces had
only geometric names, which a face attachment refuses as not exact.
Its faces are now named from the revolve that builds it, as a
cylinder's are: `bottom`, `side` and, on a cut-off cone, `top`. A
sketch on its base or top attaches by that history name and follows
the cone's height.

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

* Fix compile after the layer split

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 21:54:30 +00:00
kaltenbrunnermarkus 95fd121bb3 Mesh export: mesh bodies in parallel and weld seams through a grid (#9613)
* claim: Mesh export: mesh bodies in parallel and weld seams through a grid

* Mesh export: mesh bodies on threads and find seam splits through a grid

STL, OBJ and 3MF exports meshed and welded one body after the other on
one core. Each body is now meshed (and welded) on its own thread with
map_on_threads, as the model cache encodes them; results stay in body
order and every body is welded on its own, so the files are the same,
byte for byte. Of several failing bodies the first one's error is the
export's, as before.

The search for vertices lying on open sides (T-junctions) looked at
every open-side vertex for every open side. It now bins those vertices
on a grid and looks only in the cells around each side; the vertices it
finds come out in the same ascending order, so the splits are the same.
A side whose box spans more cells than there are vertices, or that is
not finite, still looks at all of them. A test compares the result with
the previous all-pairs search (kept in the test module) on a cube meshed
at six resolutions per face with jittered vertices and broken triangles.

ASCII STL and OBJ write each line into the text instead of formatting
a string per line and appending it (same bytes).

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

* Fix compile after the layer split

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 21:54:19 +00:00
PeppaWutz 1444801d96 Agents and scripts: the canvas commands describe their exact parameters and reply (#12275) (#12338)
canvas.insert, canvas.decal, canvas.edit, canvas.calibrate and canvas.delete
now publish typed input and output schemas. Each parameter is read the way
the handler reads it today and refused with the handler's own message, and
the replies are built from the same types the output schemas describe, so the
JSON they return does not change. Their lines leave unconverted.txt.

The plane check of sketch.create's plane reader is split out so the canvas
contract can use it without changing what it accepts.

Part of #2829.

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 21:38:07 +00:00
github-actions[bot] 28dcbbc862 Regenerate generated files and fold pending files [skip ci] 2026-11-05 21:52:00 +00:00
potuzai 7e96aabd6d i18n: catalogue 214 dialog labels; complete Czech terms (#8421)
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 21:16:02 +00:00
github-actions[bot] 52893744a5 Regenerate generated files and fold pending files [skip ci] 2026-11-05 21:11:13 +00:00
Thijs Damsma 4699b9cc89 Sketch library: include the built-in font in vendored sources (#12162) (#12174)
* claim: sketch font is included in vendored sources (#12162)

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

* fix: include the sketch default font in vendored sources

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

---------

Co-authored-by: Codex <noreply@openai.com>
2026-11-05 20:26:05 +00:00
austin62jake 4eb0c6f5ec Agents and scripts: Manage, Assign and List Plastic Rules describe their exact parameters and reply (#12313) (#12314)
* claim: #12313

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

* Plastic rules: input and output schemas for Manage, Assign and List Plastic Rules (#12313)

The three plastic rule commands get typed contracts and replies, in a
new `schema/plastic.rs` laid out like the sheet metal rules', and leave
`schema/unconverted.txt`.

- Each key reads as its handler reads it, with the handler's message:
  the rule name as `plastic.manage_rules` trims and limits it, `bodies`
  through `config::NameList` (which mirrors `params::string_list`), the
  ten rule values as `LengthExpr` and `AngleExpr`.
- `name` and `bodies` are optional in the types and required in the
  schemas (a `require` transform), so a call without them still gets
  the handler's own message.
- Keys of the wrong type that the handlers ignore today (a non-boolean
  `active` or `delete`, a rule value that is neither a number nor text,
  a non-text `from`, `material` or `rule`) are refused; in warn the call
  still works, with a warning. A test pins each one.
- The handlers build their replies from the reply types through a small
  `typed_reply`; the JSON is unchanged.

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

* Assign Plastic Rule: the schema's `bodies` is a name or a non-empty list, not null

The field is `Option<NameList>`, so its published schema allowed `null`
(from the `Option`) and an empty list (from `NameList`), both of which
the handler refuses ("`bodies` must list bodies"). It now has its own
schema: a name, or a list of 1 to 10 000 names. The reader is unchanged,
so strict still gives the handler's message for those calls. The schema
test adds both cases.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 20:00:52 +00:00
PeppaWutz a07b60cd81 Agents and scripts: the linked-component commands describe their exact parameters and reply (#12277) (#12351)
component.insert_design, update_links, relink, break_link, links, extract,
copies and replace_with_link now publish typed input and output schemas.
Each parameter is read as its handler reads it today, with the same error
messages, and each reply is built from the typed value and serializes to the
same JSON as before. Their lines leave unconverted.txt.

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 20:00:28 +00:00
thocsmith bd3053f57b Insert SVG: shapes a file only defines or hides are not imported (#11039) (#11050)
* claim: #11039

* Insert SVG: shapes a file only defines or hides are not imported (#11039)

read_svg drew every shape it met, whatever its parents were, so a circle
inside defs, clipPath, mask, symbol, marker or pattern, or one hidden by
display: none, became a sketch curve a browser never shows (and could
punch a hole in an extrude). Those elements and their contents are now
skipped; the stack still follows the end tags, so what comes after reads
as before.

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-05 19:52:26 +00:00
Homero Thompson 49ab9179a7 The command reference: the parameters as a table, with their type and whether they are required (#5237) (#11074)
* The command reference: the parameters as a table, with their type and whether they are required (#5237)

The command reference shows each command's parameters as one raw line of
registry notation, so a reader has to read it as code to learn what a
command takes. The generated page now lists the same parameters as a table:
the name, the type, whether the command needs it, and what the registry
says about it. The complete parameter text stays in the automation details,
so nothing is lost for the scripts that read it.

The table is generated from the command registry, like the rest of the page,
so it cannot drift from the commands. The notation is read by a small parser
that knows what the registry writes: names written apart share the type
that follows them, a question mark marks a parameter optional, a pipe
between names offers alternative names for one parameter, a pipe after the
colon lists the types it accepts, a parenthesis says what the parameter
does, and the text after an arrow is the reply the command gives, not a
parameter.

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

* test: the parameter table keeps its description literal

The parameter table shows registry text, so a description that carries
inline Markdown must be shown literally: backticks, emphasis and links
are characters, not syntax.

The type of a parameter ends where its sentence ends, so the sentence
that follows it is not part of the type.

Both tests fail on the current code.

* fix: render the parameter description as prose

The description cell of the parameter table is registry text, and the
rest of the file already renders registry text with prose(): backticks,
emphasis and links are characters, not syntax. table_cell() only kept
the table and the page intact, so a description like `#name = expression`
came out as a code span and a description with `*bold*` came out as
emphasis.

The name and the type keep table_cell(): they are identifiers and
notation, and they are not Markdown prose.

* fix: cut the parameter type at the end of the sentence

A type runs to the end of the clause, so the sentence that follows it
belongs to the command, not to the type: `construction?: bool. Returns
sides {bottom, right, top, left}` showed the whole sentence as the type
of `construction`, and the description of `sides` with it.

The type now ends at a full stop followed by a space and a capital
letter. A dotted or multiword type such as `sketch.rectangle` or
`number or expression` does not match that pattern, so it keeps its
current handling.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 19:52:16 +00:00
thocsmith 8c4caf9372 Insert Part help: say which way point and direction place the part (#11729) (#11755)
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 19:51:56 +00:00
austin62jake 202b775de4 Agents and scripts: Add, Rename, Delete, Comment, Favorite and Move Parameter describe their exact parameters and reply (#11941) (#11943)
* claim: #11941

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

* User parameters: input and output schemas for Add, Rename, Delete, Comment, Favorite and Move (#11941)

describe_command now gives the exact parameters and reply of the six
commands that manage a design's user parameters by name, and the warn
and strict parameter checks use them. The handlers read their
parameters from the raw JSON, so the contracts in the new
schema/parameters.rs read each key as its handler does, with its
message; `value` stays as parameters.add's other name for `expression`,
and `comment` is required in the schema but left to the handler's
message in the type. The replies are built from typed values instead of
json! literals, with the same JSON; parameters.add's reply flattens an
untagged AddedValue (a number's value or a text parameter's text).

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

* Parameters: the schemas count a `null` expression and Move's neighbour as left out

`parameters.add` reads a `null` `expression` or `value` as left out
(`expr_arg`), so the schema's "expression or value" alternatives now
also need the key's type (number or text): `{"expression": null}` alone
no longer matches, while `{"expression": null, "value": 3}` does.

`parameters.move` needs exactly one of `before` and `after`. The schema
now says so with a `oneOf` whose alternatives each need their key as
text, so a `null` neighbour (read as left out) counts as neither, and
both or neither is refused. `conforms` doesn't read `oneOf`, so the test
pins it and counts the matching alternatives itself.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 19:51:46 +00:00
P'tite Tête 2c35a027f5 fix: Edit Feature of a surface revolve maps a new axis into a moved component (#12298)
- timeline.redefine maps a surface revolve's {origin, dir} axis through an edit-only table entry
- a new surface revolve still goes whole through to_active_frame (picked edge and face axes)
- tests: made and edited in a moved and a turned component against the solid revolve; a picked edge axis

Co-authored-by: P'tite Tête <asso@ptitetete.com>
2026-11-05 19:51:18 +00:00
austin62jake 146a43f38e Agents and scripts: Motion Study, List and Delete describe their exact parameters and reply (#12155) (#12156)
* claim: #12155

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

* Motion studies: input and output schemas for Motion Study, List and Delete (#12155)

describe_command now gives the exact parameters and reply of
motion.study, motion.list and motion.delete, and the warn and strict
parameter checks use them. The handler reads its parameters from the
raw JSON, so the contracts in schema/motion.rs read each key as it
does, with its message (a study by id or name, steps, and keys of
[step, value] points); whether the study, joint and value exist stays
the handler's to check. The replies are built from typed values
instead of json! literals, with the same JSON, through `typed_reply`
(the contact commands' helper, renamed now that it serves both);
motion.list's traces stay as motion_trace.rs builds them.

The parameter audit found two tests in cmd/motion_tests.rs sending
`delete: true` to motion.delete, a key only Edit Contact Set takes; a
`deletion` helper now sends it only there.

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

* Motion Study: a point's step must be a number in the schema, as the handler reads it

The schema typed both elements of a key's point as "a number or text",
so `["0", 20]` matched it although the handler refuses a step that isn't
a number ("points are [step, value]"). The two are now typed apart with
`prefixItems`: the step a number, the value a number or an expression,
each under 1e9 in size, as `study_key_problem` and the handler read them.
Elements after those two, which the handler ignores, are left free.

The 1e9 limit, written twice in the key check, is now the named
`MAX_POINT_MAGNITUDE`, used by the check and the schema alike. A new test
checks nine point shapes against both the schema and the key check, so
the two can't drift apart.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 19:51:04 +00:00
thocsmith e04bc060f6 Web app: clippy for wasm passes with -D warnings (#12222) (#12251)
* claim: #12222

* Web app: clippy for wasm passes with -D warnings (#12222)

cargo clippy -p solidcraft-web --target wasm32-unknown-unknown stopped at
drop(file) in safe_write.rs and showed 12 more warnings only that target
has. Each is fixed where it is:

- safe_write::create_atomic and control_auth::write_token_file_with close
  their File by scope (a block; Result::map's closure) instead of drop(),
  which clippy's drop_non_drop flags where File is a stub.
- Native-only imports, the AHEAD constant and the point-cloud worker's
  Condvar are behind cfg(not(target_arch = "wasm32")); Exported::bodies
  and Start::Later, read or built only natively, allow dead_code there.
- home::ask_present uses ctx in its browser branch; the browser blur stub's
  begin returns a Scope, as the native one does.
- The web app drops three map_err(JsValue::from) on dyn_into's error,
  which is a JsValue already.

Native builds behave the same.

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>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 19:50:25 +00:00
PeppaWutz 464da90238 Agents and scripts: the Browser folder commands and Rename Body describe their exact parameters and reply (#12276) (#12339)
browser.collapse_all, browser.expand_all, browser.group, browser.move,
browser.order, browser.rename_group, browser.ungroup, browser.visibility
and body.rename now publish input and output schemas, so agents and
scripts can read exactly which parameters they take and what they
return, and the warn and strict parameter checks cover them.

Each parameter is read the way the handler reads it today, with the same
error messages. The replies are built from typed values and serialize to
the same JSON as before. Part of #2829.

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 19:49:12 +00:00
SS-EN 0b32d3619d Extract a component whose body was built in another component (#12153)
* Extract a component whose body was built in another component

component.extract now takes along the outside features that built, changed or moved
in a body the component owns, when they touch nothing that stays outside. Otherwise
it names the feature that blocks it. Fixes #12142.

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

* Kernel case: extracting a component with a body moved in now succeeds

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:48:19 +00:00
austin62jake eb10552c61 Agents and scripts: the native studio and quality profile commands describe their exact parameters and reply (#11766) (#11768)
* claim: #11766

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

* Render presets: input and output schemas for the native studio and quality profile commands (#11766)

describe_command now gives the exact parameters and reply of
render.preset.resolve and render.preset.apply (review and apply a
native studio composition) and render.quality.prepare (review a fixed
sampling budget), and the warn and strict parameter checks use them.
The handlers already read their parameters with strict serde types;
those types move to the new schema/render_presets.rs, gain descriptions
and JsonSchema, and become the contracts. The replies are built from
typed StudioComposition and QualityPlan values instead of json!
literals, with the same JSON.

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

* Render presets schema: `set` names the setup's fields

As on #11762 and #11742: `patched_settings` reads a `set` patch onto
the saved setup as a RenderSetup, which refuses unknown fields, so the
schema now names the setup's 14 fields with additionalProperties false
(still at most 13 at once). A new test covers it.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 19:45:18 +00:00
Homero Thompson e95f65fd54 IO: the STEP import limit is the import limit, not the design limit (#2721) (#11851) 2026-11-05 19:43:45 +00:00
austin62jake 1fdc56835b Agents and scripts: New, Edit, Inspect and Delete Physical Material describe their exact parameters and reply (#11862) (#11865)
* claim: #11862

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

* Physical materials: input and output schemas for New, Edit, Inspect and Delete Physical Material (#11862)

describe_command now gives the exact parameters and reply of
material.create, material.edit, material.inspect and material.delete,
and the warn and strict parameter checks use them. The handlers read
their parameters from the raw JSON, so the contracts in the new
schema/materials.rs read each key as its handler does, with its
message: `null` keeps its meaning (`color: null` and `physical_card:
null` clear), the look keys reuse the appearance commands' types, and
the card keeps the handler's own check, with its schema from
schema/material_properties.rs (whose card_schema becomes pub(super)).
The replies are built from typed values instead of json! literals, with
the same JSON.

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

* Colour schema: a colour's text form allows what color_param reads

inspect::color_param trims the text and drops any number of leading
`#`, so "  #ff00ff  " and "##ff00ff" are colours to appearance.assign
and the material commands, but ColorParam's published pattern refused
them. The pattern is now built from schema::types' whitespace class (as
AxisDir's is), which becomes pub(crate), and a test pins it next to the
reader's answers.

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

* Colour pattern: a byte may be `+` and one hex digit, as the reader takes it

`inspect::color_param` parses each of the three bytes with
`u8::from_str_radix`, which accepts a leading `+`, so "+fff00" is read as
[15, 255, 0] today. The schema's pattern asked for six hex digits and
would have made strict refuse a colour the handler accepts. The pattern
now allows either two hex digits or `+` and one digit per byte, and the
test pins both the reader's answer and the pattern's text, since
`conforms` doesn't read patterns.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 19:42:20 +00:00
austin62jake 3fde538320 Agents and scripts: Inspect HDR Source and Save Render Settings with HDR describe their exact parameters and reply (#11761) (#11762)
* claim: #11761

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

* Render HDR: input and output schemas for Inspect HDR Source and Save Render Settings with HDR (#11761)

describe_command now gives render.hdr.inspect's and
render.settings.capture_hdr's exact parameters and reply, and the warn
and strict parameter checks use them. The handlers already read their
parameters with strict serde types; those types move to the new
schema/render_hdr.rs, gain descriptions and JsonSchema, and become the
contracts, so the check is no stricter than the handlers. The replies
are built from typed HdrInspected and HdrCaptured values instead of
json! literals, with the same JSON. `expected_sha256` is the doc crate's
HdrId, whose schema is written by hand (64 lowercase hex digits or null).

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

* Render HDR schema: `set` names the setup's fields, and its job may be the saved one's

`patched_settings` puts a `set` patch's keys onto the saved setup and
reads the result as a RenderSetup, which refuses unknown fields. The
schema now names the setup's 14 fields with additionalProperties false
(still at most 13 at once), so `set: {"widht": 10}` is refused, as the
handler refuses it; the values stay the handler's to check. The
description now says the setup the changes make (a saved one keeps the
fields left out) needs a cpu_raytrace or gpu_path job, not that every
patch must give one. A new test covers the field names.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 19:41:27 +00:00
SilentWolf75 283ccd0b21 Web: tab title follows a renamed design (#11375) (#11381)
* claim: #11375

Co-authored-by: Cursor <cursoragent@cursor.com>

* Web: tab title follows a renamed design (#11375).

When an OPFS design is renamed, open tabs keep the new path and a borrowed design name so the tab matches the file list.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-05 19:41:04 +00:00
erman 6b222aedf7 test(ui): cover #11088 Paste New parent context (#11110)
* claim: #11088

* test(ui): cover Paste New into a selected parent

* test(ui): use SolidCore Vec3 in clipboard regression

* test(ui): verify copied face attachment through menu

* style(ui): apply clipboard test formatting

---------

Co-authored-by: ermanyop-stack <278786764+ermanyop-stack@users.noreply.github.com>
2026-11-05 19:39:38 +00:00
CamWight bcdbb91f26 Assemblies: one children-by-parent index for the occurrence walk (#12173)
Document::placements scanned every occurrence for each component it visited,
so its cost was placements times occurrences, on every world placement. The
new OccurrenceTree (crates/doc/src/occurrence_tree.rs) lists each component's
children once, in one pass and in document order; placements walks it with
the same order, caps and stop behaviour, through placements_with, which takes
each occurrence's transform from the caller. inside_component reads the same
index instead of scanning per component.

Tests compare the walk with the scanning one on 13 shapes and on hostile
generated documents, at its caps, in document order and with a given
transform. Release, 97,540 placements: about 120 ms -> 15.5 ms, the same in
either run order (docs/perf.md).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:39:35 +00:00
cronos 21a1269d5c Sketch Trim: keep the stored offset distance after deleting its dimension (#12186) 2026-11-05 19:39:21 +00:00
Alastair D'Silva d580c4256c Evaluation: add --validation to solidcraft-cli eval and skip largest-fit search when validation is off (#12136) 2026-11-05 19:39:16 +00:00
SS-EN 1b52186524 Timeline: reordering a feature says when nothing moved and returns its new index (#12171)
* timeline.reorder: say when nothing moved, and return the new index (#12140)

A position past the end was capped to the last slot; when the feature was
already there the command reported success with no sign nothing moved. The
reply now gives position (index now), from and moved, with a note that says
why nothing moved or that the last slot was used. A move that puts a feature
ahead of what it uses says so, and the command refuses before changing the
design if the feature would not land at the asked position.

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

* timeline.reorder: word a refused move by its direction; note a marker-only change

A feature moved later can fail for reasons other than order, such as a cut that
removes its body, so the move-earlier hint is given only when it moved earlier.
With `active`, a feature left in place gets a note saying only the history
marker moved, or that nothing moved.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:38:38 +00:00
Thijs Damsma 3e6eadc118 Offline web test timeouts show which build each script ran (#3956) (#12206)
* claim: offline script marker diagnostics for #3956

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

* Report script build markers in offline web test timeouts

Expose the existing started and shared dataset markers in diagnostic state. Preserve missing markers as null without changing readiness or retry behavior.

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

---------

Co-authored-by: Codex <noreply@openai.com>
2026-11-05 19:37:59 +00:00
ABDULLAH 87358ef724 Arabic: component spelling, tab-close tip, MCP compact note, surface grain angle, Output names, mouse word, Hole bridging, intersection curve help, ground shadow tip, pan term, Move names and newer-file notices (#12151)
* Arabic: one spelling of component in the Browser rows start closed note, dialog wording in the tab-close tip

* Arabic: no direction marks in the MCP compact output note

* Arabic: general term for the surface grain angle, Output name in the image import note and the Output inspector header

* Arabic: one word for the mouse in the right-click notes of the intersection curve pick and the Play History button

* Arabic: bridging term in the Hole dialog, intersection curve help pronoun, ground shadow tip wording

* Arabic: pan term in the drag-keeps-mode help and the vertical pan direction option

* Arabic: Move Sketch Points name, Move tool name in the drag highlight preference, file format wording in the newer-file notices
2026-11-05 19:37:36 +00:00
austin62jake 3d73822442 Agents and scripts: Parameter Sweep's schema requires its parameter, as text (#12312)
* claim: Parameter Sweep's schema requires parameter

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

* Parameter Sweep: the schema requires `parameter`, as text

`inspect.parameter_sweep` refuses a call without `parameter`, or with a
`null` or numeric one ("`parameter` is required (parameters.list)"), but
its published schema (#10978) neither required the key nor ruled out
`null`: the field's `#[schemars(required)]` has no effect on a key with
`serde(default)`, and `Option<String>` publishes `["string", "null"]`.

The contract keeps the key optional in its type, so the handler, not the
check, gives its own message when it's left out; the schema now requires
it through a struct-level transform, as the contact commands do, and
types it as a string. A new test checks the schema against a call
without the key, with `null` and with a number; it fails without this
change.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 19:37:22 +00:00
Homero Thompson 51f4074506 Split and Trim errors name the command a script can run (#4712) (#11205)
* Sketch modify: name the public command in the split and trim errors (#4712)

Part of #4712.

The split inside the sketch modify tools refused in the name of the
internal `split` step, and the free-form trim in the name of the
internal `trim` one: `invalid parameters for `split`: a circle needs
two points to split at` names a command nobody can write, so an agent
or script reading the message has nowhere to go.

Both now name the public command the caller used: `sketch.modify` for
the split shared by trim and break, `sketch.trim` for the trim. The
descriptions are unchanged.

Co-authored-by: Hermes Agent <noreply@anthropic.com>

* Sketch modify: the split names the command the caller used (#4712)

`sketch.modify` is not a command a caller can write: the registered
sketch commands are `sketch.trim`, `sketch.trim.path` and `sketch.break`.
The split shared by trim and break therefore refused in the name of a
command that does not exist, and a script reading the message had
nowhere to go.

`split_at` takes the command of its caller and refuses in that name:
`sketch.trim` when the trim splits the curve, `sketch.break` when the
break does. Both callers already had the command in hand.

The test now states the decision: the refusal of `sketch.break` carries
`sketch.break`, and the rendered text names no other command.

Co-authored-by: Hermes Agent <noreply@anthropic.com>

---------

Co-authored-by: Hermes Agent <noreply@anthropic.com>
2026-11-05 19:28:22 +00:00
github-actions[bot] 796b7c40d3 Regenerate generated files and fold pending files [skip ci] 2026-11-05 19:17:37 +00:00
Frank 9cdee588f2 Extrude Two Sides: fix the side and missing value box of Distance 2 (#11203)
* Extrude: Two Sides keeps each distance on the side Direction gives it

Distance 2 stays on the side Direction gives it, whatever the sign of Distance 1, and its value box shows on the canvas. Rebased onto main as one change.

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

* Two Sides extrude: keep older designs' sides by a marker, and the full profile search

- A saved two-sided extrude is marked `second_follows_first` instead of having a literal
  negative distance rewritten: expressions such as `-width` keep the old sides when their
  parameters change, `-0 mm` keeps its span, and a feature's named inputs keep their values.
- Live sketch drags and the restored model cache use the full profile search evaluation uses,
  so a sketch whose only closed boundary is projected keeps its profiles.
- The canvas Distance 2 box stays while its text does not evaluate.

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

* Tests: give the extrude added on main the second_follows_first field

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 18:39:09 +00:00
Nathan Dane 90d9c6488a Panels: add columns, stacks and tabs with exact drag previews (#11305) (#11608)
* claim: #11305

* Panels: add columns, stacks and tabs with exact drag previews (#11305)
2026-11-05 18:38:54 +00:00
Nathan Dane edb7882815 Appearance: browse themes in a carousel or grid, filter them, and set Day and Night themes (#12120)
* Appearance: theme picker with carousel, grid, filters and Day/Night slots

* Appearance: theme picker arrows move a screenful of themes

* Theme picker: translations, token metrics, wheel helper in navigation, reveal tolerance

* Theme picker: keep both new Appearance preferences after the rebase

* Appearance: adapt theme picker to egui 0.37
2026-11-05 18:38:42 +00:00
PaddleStroke db3558d820 Extrude: the distance arrow snaps to a parallel face and outlines it (#2398) (#9688)
* claim: #2398

* Extrude: the distance arrow stops at a parallel face and outlines it (#2398)

While Extrude's distance arrow is dragged, a flat face parallel to the
profile and lying over it takes the distance exactly once the tip comes
within 8 screen points of its plane, and the face is outlined as a hovered
face is. A cut dragged through a block so stops at its far side. Faces
beside the profile don't catch the arrow; Alt/Ctrl (free drag) turns it off.
The distance stays a number in the existing parameter.

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

* Extrude face stop: clippy (test-only current, +=)

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

* Extrude face stops: a preference, on by default, keeps the old round steps (#2398)

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

* Extrude face stops: follow world_state returning a Result (#2398)

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

* Extrude face stops: import Vec/Plane from solidcore_record after the layer split

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 18:31:55 +00:00
Jens b2f5da6ca7 joints: support custom names and joint type-dependent default names (#10340) (#10165)
* joints: support custom names in dialog and type-based default names

Allow users to specify a custom name in the Joint dialog and generate
type-prefixed default names (e.g. "Planar Joint1", "Revolute Joint1")
instead of generic "Joint{n}".

- Add `name` field to `JointForm` and display a text row in the Joint
  dialog with a dynamic placeholder matching the chosen type.
- Update `new_joint_name` in `cmd/joints.rs` to take `JointKind` and
  prefix auto-generated names with the joint kind label.
- Prioritize non-empty custom names and pass them through `joint.create`,
  `joint.as_built`, and `joint.edit`.
- Pre-populate the existing joint name in `edit_joint` to allow renaming
  directly from the Edit Joint dialog.

* joints: add tests for custom and type-based joint naming

Verify that the joint dialog and engine command layer correctly generate
type-prefixed default names and respect user-specified custom names.

- Add engine-layer test `new_joints_generate_type_prefixed_names_or_keep_custom_name`
  to verify `joint.create` and `joint.as_built` naming logic.
- Add UI-layer test `joint_dialog_applies_custom_name_or_falls_back_to_type_default`
  to ensure the `JointForm` captures and submits names correctly.

* Format dialogs_assembly_tests.rs (trailing blank line)

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

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 18:31:43 +00:00
Steven Waters f1159a5d51 Added mesh import units for STL and OBJ (#10406)
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 18:31:26 +00:00
github-actions[bot] ffc84dbe2e Regenerate generated files and fold pending files [skip ci] 2026-11-05 17:28:40 +00:00
Yasen-55 942e1540db Bulgarian localization (#8256) (#8303)
* claim: #8256

* Add initial Bulgarian translation (114 keys)

* Delete claim.txt

* Delete translate.py

* Delete assets/locales/bg.json

* Restore the bg catalog the locale list needs, fix indent

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

* Bulgarian: translate the strings the catalog tests require, drop ids that no longer exist

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

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 16:28:09 +00:00
austin62jake 6500c42c9f Agents and scripts: sketch Copy, Cut and Paste describe their exact parameters and reply (#10963) (#10964)
* claim: #10963

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

* Sketch Copy, Cut and Paste: input and output schemas (#10963)

sketch.copy, sketch.cut and sketch.paste get typed contracts and reply
types in schema/sketch_clipboard.rs and leave unconverted.txt. `at` and
`translate` read as the paste reads them, with its message; the replies
are built from Copied and Pasted, with the same JSON as before.

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

* Sketch clipboard: import Vec2 from solidcore_record after the layer split

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 16:14:13 +00:00
github-actions[bot] 655c1f3336 Regenerate generated files and fold pending files [skip ci] 2026-11-05 16:21:12 +00:00
SamD98 9f2e117934 Revolve follows the highlighted sketch edge (#7452) (#7479)
* Revolve follows the highlighted sketch edge (#7452)

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

* Attribute the #7452 screenshots and recording

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

* Fix needless borrow in the revolve axis test

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

---------

Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 15:31:53 +00:00
github-actions[bot] c6fe613d32 Regenerate generated files and fold pending files [skip ci] 2026-11-05 15:50:37 +00:00
Leo d5e953871b Sketch Mirror: use the preselected construction line (#10486) 2026-11-05 15:09:19 +00:00
kaltenbrunnermarkus c7dcab172f Viewport: no dark patch between nearby bodies (#10442) (#10513)
* claim: #10442

* Viewport: no dark patch between nearby bodies (#10442)

The ground shadow was one ellipse under the box around all shown bodies,
darkest in its middle, which for two bodies side by side is the empty
floor between them. Bodies whose footprints meet now share one ellipse
(as before) and bodies apart get one each, on the same ground level and
with the same rings; more than 64 groups fall back to the single ellipse.

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

---------

Co-authored-by: Markus Kaltenbrunner <kaltenbrunnermarkus@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:38:01 +00:00
yhamil04 8312bf0cb8 Create Sketch: pick an origin plane through a body in front of it (#5431) (#6597)
* claim: #5431

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

* Create Sketch: pick an origin plane through a body in front of it (#5431)

While a dialog waits for a plane, the origin and construction planes are
drawn over the bodies, but picking sorted them by depth, so the face of a
body in front always took the click. When the nearest face hides the
nearest plane under the pointer, the planes now sort just ahead of that
face (in their own depth order, still behind a profile on it). A face at
the same depth as a plane still wins the tie (#31), and nothing changes
when no dialog is waiting for a plane.

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

* view_confirm_corner: draw the line where the view shows it

Create Sketch now picks the origin XY plane through the extruded box, so the
sketch is flipped to face the view and (50, 0) -> (70, 10) fell outside it.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 13:11:52 +00:00
github-actions[bot] 8f20ad4532 Regenerate generated files and fold pending files [skip ci] 2026-11-05 13:17:29 +00:00
DuBearte abdf195132 Sketch: sketch.move_points moves several points, each to its own target (#5961) (#5978)
* claim: #5961

* Sketch: sketch.move_points moves several points, each to its own target (#5961)

A script editing a traced outline could move one sketch point per call,
and only by its id: an agent that had to move two points of a
490-segment polyline redrew the whole sketch instead, breaking every
dimension and feature built on it.

sketch.move_points {moves: [{point | near, to}], tolerance?} drags each
point to its own target in one edit (one undo step), as sketch.move_point
drags one, and the sketch is solved. `near` picks the sketch point
closest to a coordinate, refused when none lies within `tolerance`
(default 0.1 mm) or two are as close. Every point is found before any
moves. The reply gives each point's id, its target, where it ended up and
whether it got there, so a fixed or constrained point is reported rather
than silently left in place.

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

* Move the new command label to a pending locale file

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

* Fix the new command for the sketch store and geometry split

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

* Carry the new command label in every complete catalog

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

* sketch.move_points reads the sketch through sketch_store

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 12:20:00 +00:00
bherbruck 7e002f182d Opening a design from a newer SolidCraft: it opens with a notice instead of being refused (#12166)
* Open a design from a newer SolidCraft with a warning instead of refusing it

A newer format number or an unknown change no longer blocks opening. What
this version can read opens; a feature it can't read stays on the timeline
with an error, and fields, sections and container parts it doesn't know are
named in the reply and written back by Save, under the file's own number.

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

* Saving a newer design from the CLI, and editing a feature this version can't read

`run --save` writes a design holding a feature only a newer build can build;
`--out` still stops, since it would export the part without that feature.
Edit Feature on such a feature says why instead of opening the palette.

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

* Translate the newer-design notice for the complete catalogs; clippy

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:18:25 +00:00
JK3D f0d305a783 Move triad: dragging in large designs does less work per step (#7273) (#7276)
* claim: #7273

* Viewport: drag a component as a GPU layer of its own

Each step of a Move triad drag placed the component anew, and the
viewport then rebuilt the model scene and uploaded it again. The dragged
bodies are now drawn from the scene built where the drag found them,
moved on the GPU by the drag's motion; the rest of the model stays as it
was. In the viewport a step meshes, builds and uploads no geometry;
only the transform (and the ground shadow) changes.

- gpu: Frame::moving draws a second scene with its own model matrix
  (U.model, applied in every vertex entry, instanced parts included);
  blocks, evaluated chunks and instanced triangles pass between the
  model scene and the layer instead of being uploaded again; glass is
  sorted in the layer's frame; the AO prepass and see-through pass
  cover it; the frame key includes the layer.
- doc: ModelBody::display_moved_from gives the rigid motion between two
  worlds' copies of one solid.
- ui-egui: the model scene without the dragged bodies is built once;
  dragged bodies are matched by name; the step's body boxes are the
  start boxes moved; selected or hovered dragged bodies light where they
  stand. A drag back where it began keeps its layer. A section, an
  analysis, continuity seams or no GPU draw the drag as before;
  capturing the move makes the scene whole again.

* feat(ui): a setting to keep the highlight under the pointer while Move drags

A Move triad drag drawn as a GPU layer picks nothing under the pointer, which keeps a step from
meshing the dragged bodies where they stand and from looking up the Browser row a highlight
follows. Preferences > Tools > Assembly Move > "Highlight what is under the pointer while dragging
a component" (`move_drag_highlights`, off by default) picks and highlights as before.

Also: the drag layer test takes `as_chunks` (clippy 1.99's `chunks_exact_to_as_chunks`).

* fix(ui): say when the Move drag highlight setting applies

The label names Move's arrows, and the tooltip says that with a section or an analysis shown the drag highlights all the same, and that a part dragged along its joints never does.
2026-11-05 12:12:06 +00:00
kaltenbrunnermarkus dc33c4a24d Saving: designs with many threaded holes keep all saved states (#10601)
* claim: tap marking records once in the model cache

* Model cache: write each tap marking record once and share it between states

Problem: every state of a saved model wrote the cosmetic tap markings of all the features
before it, so the records grew with the square of the features. A design of 400 marked
cylinders wrote 34 of its 37 MB manifest that way: past the 32 MiB limit the save thinned the
cache (590 of 806 states left out, opening evaluates them again) and wrote the manifest
several times while choosing what to keep.

Solution: the records keep a list of markings, each written once (keyed by its text, as the
sheet bodies are); a state names its markings as runs of places, like its bodies and
sketches. A marking at the same place in the state written just before, equal to the bit, is
found without writing it as text. A thinned model keeps the whole list and counts it once;
the reader counts the markings with what a state holds. The cache format is now /6: an older
cache is a miss and the design is evaluated as before. The design document is unchanged.

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

* Saved model: count each tap marking by its text against the held limit

A state clones every marking it lists, so a run repeating one large marking could hold far more than MAX_HELD items of memory.

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

---------

Co-authored-by: Markus Kaltenbrunner <kaltenbrunnermarkus@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 12:11:07 +00:00
GreG Petersen 2405f75c38 Viewport: shade the selected face fill, so a selected STL keeps its shape (#3761)
A selected face was filled flat in `sel_face`. An imported mesh (STL, OBJ)
is a single face, so clicking it in the viewport painted the whole part as
one flat blue silhouette and hid every wall, pocket and edge. The fill is
now lit like the hover fill, which already was.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:42:56 +00:00
semmelrinde de07905f78 Sketch Offset: an inward offset past a narrow neck is refused, not looped (#11055)
* Sketch: an outline drawn inside a shape past its neck is refused, not looped

An inward offset of a closed outline wider than half a neck of the
shape would pinch it into two; one chain can't be that, and its pieces,
each joined only to its neighbours, ran back over each other in a loop.
When the outline itself doesn't cross itself and its offset would, the
offset is refused like other offsets the shape can't take. An outline
that already crosses itself (a bow tie) keeps its crossing offset.

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

* Loop guard: the arc's direction comes with its source, not with the offset piece

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

* Loop guard: a touch counts, lines along each other count, tolerances from the outline's size

An outline split where it crosses itself only touches itself there and
was taken for simple, so its offset was refused: between pieces that
aren't neighbours a touch now counts as crossing. A neck exactly twice
the distance gives two lines lying along each other, which cross at no
point: such an overlap now counts too. The tolerances come from the
outline's own size plus the coordinates' rounding, not from how far it
lies from the origin.

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

* Sketch offset: pass the arc direction from the outline after the dog bone change

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 11:34:02 +00:00
sommerper 1cf7ae8e5c Sketch: dragging one of several selected sides no longer runs ahead of the pointer (#11324)
* Sketch: a selection held back in part follows the pointer, not past it

Dragging a selection part of which cannot move (a rectangle with a corner
on the origin, all four sides selected) took the dragged side nearly twice
as far as the pointer. `sketch.drag` reported the grab where the average of
all dragged points went; the held corner kept that behind the side, and the
next frame's catch-up overshot. It now reports how the dragged point that
got furthest toward the pointer moved, so what can follow moves 1:1.

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

* Sketch drag test: unwrap the world state after the engine change

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 11:33:48 +00:00
PaddleStroke e9efcf4c0b Sketch: scale profiles symmetric about a sketch axis (#11625) (#11708)
* claim: #11625

* Sketch: scale profiles symmetric about a sketch axis
2026-11-05 11:33:32 +00:00
NOWN-DEV 7546e84ef4 Sheet metal: a corner torn between flanges of two features closes (#7126) (#7136)
* claim: #7126

* Sheet metal: a corner torn between flanges of two features closes (#7126)

With the rule's corner relief `tear`, a flange made after another,
meeting it at a corner of the base, left the corner open: its setback
stopped the earlier bend at the corner while that panel ran on R + T
past it (an (R + T) x BA rectangle missing in the flat), and the new
panel stopped at the corner, R from the earlier panel's inner face
rather than the rule's gap. Folded, a hole about R + T across showed at
the base corner. A corner between the flanges of one feature is torn
(#809); one between two features was not.

Such a butt corner is now closed and torn: the new panel ends the gap
from the earlier panel's inner face, and both bends run on to where
their panels' ends start, each end on the plane through its start at
the corner (on the bend's outer face) and the outer edge of its panel's
end. In the flat that end is (cos(th - phi) - cos th)/(1 - cos th) of
the way along at the turn phi (sin phi at 90 degrees), one Bezier of
degree 9 (`tear_curved`). Folded, the corner closes but for a sliver.

In a thick sheet the bends' inner faces would cross beside the corner
(at 90 degrees where R^2 < (R + T)(R - g): with the gap 0.8 from about
2 mm). There the new bend's end eases toward (1 - cos phi)/(1 - cos th)
of the way along (`tear_ease`, still one Bezier), as little as keeps the
bends apart; the earlier bend and both panels' ends stay as they are.
A corner that can't be torn so (opposite or over-90-degree bends, a gap
wider than the radius, overlap in the flat) keeps what it had, with a
note.

The test that pinned a two-feature corner as never torn keeps its
open-corner half; the two-feature corner moves to the new tests, which
cover sheets from 0.9 to 3 mm.

Fixes #7126.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:26:40 +00:00
semmelrinde 278ab40a0f Sketch Dimension: a slanted line gets an aligned dimension by default (#8582)
* Sketch Dimension: aligned across the line, horizontal or vertical by the pull past an end

Review on #7355: the aligned length must stay the default, and the box
rule shrank its zone to a thin strip on a shallow line. Now `auto` is
the distance between the two points everywhere across from them
(between the perpendiculars through them, and a tenth of their distance
past), and only a clear pull past an end changes it: up or down from
that end gives the horizontal distance, sideways the vertical one. The
two meet on the diagonals through the end, so both zones stay wide on a
shallow or steep line. Midpoint pairs keep main's box rule.

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

* Sketch Dimension: two midpoints keep the distance between them past their box's corners

As before #7355 and on main: text above or below the midpoints' bounding box
measures horizontally, beside it vertically, and anywhere else (inside it or
past its corners) the distance between them. The corners fell through to the
line rule and became horizontal or vertical (found in review).

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:26:03 +00:00
github-actions[bot] ed7206cc0d Regenerate generated files and fold pending files [skip ci] 2026-11-05 11:14:17 +00:00
JIJINBEI 16f3b939b3 Update egui/eframe to 0.37 (#9933)
* Update egui/eframe to 0.37 (WIP)

egui, eframe and egui-wgpu 0.36 -> 0.37. SolidCraft's egui-wgpu patch is
rebased onto 0.37.0; the vendored accesskit_macos is dropped (0.27.2 has
the #7535 fix).

Not finished: 36 solidcraft-ui-egui lib tests fail, and the full lib run
crashes with SIGSEGV when tests run in parallel.

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

* Tests: clear texture deltas that egui 0.37 refuses to drop

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

* Drop non-finite pointer input before egui; keep test time monotonic

egui 0.37 debug-asserts on NaN wheel deltas, on time moving backwards in the
pointer history, and on add_space inside a Grid.

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

* Hold a click that follows typing in the same frame until the next frame

egui 0.37 drops a field's focus on a click elsewhere when the field first
reads its style, before it reads the frame's typing, so text typed in the
frame of a click was lost.

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

* Name a document tab's close button "Close tab"

egui 0.37 names an unnamed widget after its tooltip, so the tab's × became a
second control named Close beside a dialog's. The space mouse guard test now
clicks where each button was: by name it found nothing behind the guard.

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

* Turn on egui's default_fonts: 0.37 no longer does

The built-in Hack is the UI's symbol fallback (#2955). The app got it through
eframe, but solidcraft-ui-egui on its own (its tests) did not.

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

* Text menu: act on the selection the menu click took the focus from

egui 0.37 drops a field's focus on a click elsewhere before the field draws,
and an unfocused field loses its selection, so Copy, Cut and Paste from the
right-click menu saw no selection.

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

* Placement field: keep its native height under egui 0.37's interact floor

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

* Tests: pin the theme's 2/3 point radii; measure Japanese ribbon labels with a Japanese face

egui 0.37 rounds widgets 4 points by default, which the theme deliberately
does not follow. The ribbon test measured Japanese with missing glyphs, whose
width changed in 0.37; with BIZ UDPGothic, 駆動 wraps after its particle like
変換 does.

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

* Tests: click the render inspector's Perspective checkbox by position

egui 0.37 orders the accessibility tree differently, so the name found the
stage's Perspective segment first.

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

* Translate "Close tab" for the complete catalogs

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

* Point the focus workarounds at emilk/egui#8763

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

* Cargo.lock: update only what egui 0.37 needs

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

* Web: Id::new -> Id::unique for the wasm-only windows

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

* Command search: keep its hint centred under egui 0.37's interact floor

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

* egui 0.37 renames in code main added since the branch

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

* egui 0.37 renames in code main added since the last rebase

Id::new to Id::unique, ui.id() to ui.scope_id(), WidgetType to Role, the
wheel events' source, and the button stroke read from the widget visuals.

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

* Review: disclosures report expanded, late screenshots drained, chat width reset on both sides

A disclosure's node says whether it is open as expanded, as egui's own
collapsing header does. The screenshot channel is drained every frame, so a
shot whose request was cancelled is dropped. Resetting the chat panel's width
forgets both sides' state, as before 0.37, and the request stays with its
window when tabs switch. Tests main added since the last rebase clear their
texture deltas.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 10:31:50 +00:00
CaRLymx ad230eb4a4 Catalan (ca): retranslate the catalog from English (2026-11-05) (#10896)
* i18n: register the Catalan catalog

Add `ca` to the locale list, between Bosnian and Czech, and attribute
assets/locales/ca.json.

* Catalan (ca): translate preferences and the 61 new messages

- preferences: every prefs.* message is now Catalan (355 strings).
- the 61 messages added upstream since the last catch-up: the layout page,
  sketch options, navigation options and the custom navbar anchors.
- drop the four keys upstream no longer has: thread.direction,
  thread.left_hand, thread.right_hand and ui.print_face_one_body.

Work in progress: ui.*, cmd.*, render.*, the loose sentences and help.*
still mix Spanish and Catalan.

* Catalan (ca): translate the first half of ui.*

400 messages: the 3D mouse settings and calibration, the agent chat and the
AI preferences.

* Catalan (ca): translate ui.* up to the equation and edit-in-place messages

200 more messages: the toolbar and browser controls, colour vision, design
properties, the details panels and editing a linked part in place.

* Catalan (ca): translate ui.* up to the navigation bridge

200 more messages: the ribbon headings, the history panel, the graphics
presets, the physical material review and the mesh formats.

* Catalan (ca): finish ui.*, 1,284 messages

The ribbon headings, the properties, the slicer and point cloud panels, the
view angles and the workspace descriptions are now Catalan. ui.* has no
Spanish left.

* Catalan (ca): translate the command names, 508 messages

Every cmd.* entry, including the render library, the sheet metal tools, the
sketch tools and the named views.

* Catalan (ca): translate the CPU render settings and the environment panel

200 more messages: the CPU light rigs, the reflection targets, the resource
profiles, the preflight details and the stage and HDR environments.

* Catalan (ca): translate the render errors, the shot framing and the inspector

200 more messages: every render error, the frame presets and guides, the image
status, the HDR source details and the appearance inspector.

* Catalan (ca): translate the render library, the lights and the looks

200 more messages: the resource catalog, the physical light editor, the colour
looks and the GPU material and glass overrides.

* Catalan (ca): translate the render output, results and ribbon

200 more messages: the output editor and its size limits, the presentation
filters, the completed-image results, the aging and physical references and
the render ribbon.

* Catalan (ca): finish render.*, 2,392 messages

The saved shots, the stage panels, the studio lights, the subsurface and volume
transport, the wear layers and the render browser. render.* has no Spanish left.

* Catalan (ca): translate the standalone labels, 200 messages

The browser and panel labels, the sheet metal bends and reliefs, the boss, rib,
rest and snap fit drag hints and the issue report steps.

* Catalan (ca): translate the export, folder and material labels, 200 more

The export menu, the sheet metal bend table and reliefs, the font and history
options, the joint labels and the issue report help.

* Catalan (ca): translate the remaining panel labels, 200 more

The report and recovery messages, the profile and edge pickers, the rules
editor, the screenshot steps and the sketch selection prompts.

* Catalan (ca): translate the sheet metal, AI preferences and browser strings

200 more: the standing-up offer for Y-up files, the trim and stitch tools, the
AI availability and permission settings and the browser node names.

* Catalan (ca): translate the crash reports and a large part of help.*

200 more: the copies, the crash reporter, the DXF export progress, the file
loading statuses and the help texts for the sketch and solid tools.

* Catalan (ca): translate the home page, the hole presets and the material editor

200 more: the start page and its dates, the install steps, the issue report
notices, the assembly move handles, the material property card and the motion
keys.

* Catalan (ca): translate the navigation bar and the input presets

200 more: the navigation modes, the navbar customiser and its descriptions,
the network share warning, the fastener dimensions and the picking prompts.

* Catalan (ca): finish the catalog, 5,591 messages

The search box, the settings notes, the sheet metal personal rules, the sketch
report and text tools, the timeline menus, the updater and the web file
prompts. The catalog now has no Spanish left.

* Catalan (ca): translate the 634 messages the pending script had missed

The script only flagged strings identical to the Spanish or English catalog, so
every untouched string that differed from es.json stayed in Spanish: the whole
help.* reference, the import report, the joint limits, most preferences and the
fillet and continuity tips. They are now Catalan, and the script counts a
message as done only when a block file contains it.

* Catalan (ca): keep the sketch hints and stop splitting l·l

The sketch tool hints and engine errors are not in en.json, so they live in a
pending file: add the Catalan messages there instead of letting them fall back
to English. The new asset gets its attribution row under attribution/pending,
so this branch no longer edits ATTRIBUTION.md directly.

The painted-text sweep split labels on the bare middle dot, which is Catalan's
l·l inside a word: "Cancel·la" became "Cancel" and the test reported English
where the catalog is translated. Split only on the spaced middle dot.

* i18n: carry the complete catalogs in the pending sketch hints

A pending file that adds English messages also adds them for the catalogs
delivered complete (ar, he, ja, vi, zh), or i18n --check fails. They keep the
English text, as in the Spanish catch-up branch.

* i18n: attribute the pending hints and fix the break message

The pending sketch hints add an asset, so they get the same attribution row as
in the Spanish catch-up branch (same file, so the two merges without a
conflict). The engine has nothing to break, so say so in English.

* Catalan (ca): translate the 30 new messages

The blur preferences, the dimension step settings and the fillet turn modes
arrived upstream after this branch was opened; merge main and translate them.

* i18n: use US spelling in the pending hints and add en-GB

The English catalog is US-spelled, so the English fallbacks say center; en-GB
keeps centre for the four messages that differ.

* Catalan (ca): fold the pending hints and catch up with main

`main` folded `sketch-tool-hints.json` into every catalog when #10895 merged
and deleted the pending file. This branch still carried it, so the merged tree
failed `cargo xtask lists` with 186 duplicate ids and one repeated attribution
row. The 26 hints now live in `ca.json` and the two pending files go; the
catalog row in `attribution/pending/catalan-catalog.md` stays.

The 118 messages `en.json` gained since this branch opened are translated: the
26 hints and 92 new ones (AI HTTP and instructions preferences, surface-map
import, the ribbon-tabs-only view, hidden-edge selection, recovery, the custom
view navigator and a handful of dialog tips). The obsolete
`cmd.inspect_colored_components_disable` is gone, so `ca.json` matches
`en.json` key for key.

The shaded-with-hidden-edges label said `Sombreado`, which is Spanish.

---------

Co-authored-by: CaRLymx <24634598+carlymx@users.noreply.github.com>
2026-11-05 10:31:17 +00:00
Mario Geiger c1760d4857 Point clouds: draw a PLY file's edges and faces (#8817) (#8820)
* Point clouds: a PLY file's edges and faces as beads and triangles (#5151)

A PLY file's `edge` and `face` elements become segments and triangles
between the cloud's points (a face as a fan), each with its own properties;
a file with them is read whole, since thinning would cut them. A point's
numbers vary along the segments and across the triangles that meet there,
an element's are constant on it.

Segments with `width` and `height` are drawn as beads of that stadium
cross-section, meeting mitred where one runs into the next, from one
indexed template; without them, as lines. Points no segment or triangle
ends on stay dots. A range filter cuts an element where its value crosses
an end, on the GPU and in the tracks alike: each element weighs its
measure (a dot 1, a segment its length, a triangle its area, each kind
over its own total) and spreads it exactly over the values it covers, a
segment's evenly and a triangle's as the tent its corners make.

Columns saved without the element they are on are on the points, so
designs saved with point properties alone still open.

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

* Point clouds: past max_points a PLY is thinned again; the near plane cuts elements exactly

A PLY with edges or faces and more vertices than `max_points` was refused, where it used to be
thinned. It is thinned again: thinning would cut its edges and faces, so they are left out, with
a warning, and raising `max_points` keeps them.

A segment or triangle crossing the near plane moved its corners behind the eye to a made-up
place, which pulled a wedge across the view. A triangle now keeps its true clip-space corners,
which the rasteriser clips exactly. A bead is cut where its axis crosses the plane, a crossing
exact because clip-space coordinates are affine along a line, and its numbers are exact there.

A ramp accepts MAX_BINS bands but an element was split into 4097, so a ramp finer than that lost
measure: half of a segment at 8192. Only the whole numbers have more bands than MAX_BINS.

`xtask mesh-decisions` reads any field named `triangles` as a mesh; a cloud's own complex holds
none, so its three modules are skipped with that reason.

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

* Point clouds: a ramp's measure is whole past both its ends; a column on the points says nothing

A ramp of MAX_BINS bands has one band below it and one above it, so an element running past both
ends crosses MAX_BINS + 1 bands past its first. The limit was one short, and such an element lost
what lay above the ramp.

A column on the points now leaves `on` out when saved, so a design holding only points keeps the
form it had, as the field's comment and the pending format note already say.

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

* Point clouds: a set filter keeps part of a bead whose ends differ; an unreadable point takes only what ends on it

The set filter's whole-element test read the first corner alone, so a bead whose
first end was not kept vanished, while the range tracks counted the part kept. It
now drops a bead only when one value at every corner is not kept; otherwise the
fragments decide, as for triangles.

A PLY with edges or faces and one unreadable vertex was refused whole. It now
keeps the subcomplex the readable points span, renumbered, with its numbers, and
warns about what it left out. A file with numbers on its points gains the same.

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

* Point clouds: build the triangle corner weights without a dynamic vector write

The Windows D3D12 shader compiler rejected w[vi] = 1.0 (error X3500).

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
2026-11-05 10:23:20 +00:00
github-actions[bot] 4d69d8c87a Regenerate generated files and fold pending files [skip ci] 2026-11-05 10:35:00 +00:00
Frank fa2faf99e2 Dialogs: an opt-in setting to remember values and options for this app session (#11135)
* Dialogs: remember values and options for this app session (off by default)

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

* Dialogs: translate the remember-values help text again

The help text changed to say the setting is off by default, and the
complete catalogs (ar, he, ja, vi, zh) lost their translation of it.

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

* Dialogs: recall gives a new face a fresh thread suggestion and rebuilds Move/Hole mode inputs

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

* Dialogs: format recall

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 09:48:28 +00:00
github-actions[bot] 20467e39e2 Regenerate generated files and fold pending files [skip ci] 2026-11-05 09:56:27 +00:00
Christian Hammacher 020e3bebe3 Status line: say which design an Open or Insert brought in (#7858) (#7869)
* Status line: say which file an Open or Insert brought in, and whether it got a new tab

"Open done" and "Insert done" were English text built in code, so they stayed English in every
language and didn't say what was opened. They now read "Opened <file> in a new tab", "Opened
<file>" when a blank design was replaced, or "Inserted <file>", from the message catalogs.

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

* Status line: an opened design is named as its tab names it

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

* Status line: an Open's test and Korean strings

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

* Status line: an Open's message in the chosen language, and none for a design that found no tab

The message is built outside the window's language scope, so it takes the locale from the preference as the other statuses of the file loader do
An opened design is named as its tab shows it (a default name translated), an inserted one as its component is named
An open that finds no tab left keeps the error and answers it, instead of naming the design shown as opened
The test injects the finished open instead of running and polling a worker

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

* Status line: a design to recover that finds no tab stays offered

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

* Status line: a design to recover that hits the tab limit stays offered too

An Open or recovery with every tab taken was refused before the design
was read, and a design to recover was dropped from the list on that path.
It goes back in the list, as when its read fails. The staged-open test
reads the new status.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 09:18:10 +00:00
Sain2d 6029a38ea0 Korean: translate the remaining messages, so nothing shows in English (#6413)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 08:12:27 +00:00
NOWN-DEV 9c93a6c340 Sheet metal convert: a bend split by cut-outs across it is one bend (#7530) (#7581)
A bend that cut-outs across it split into several cylinder faces came out slit, silently: only
the picked piece was bent, the rest of the bend was cut away with the cut-out, and the volume came
out short. Picking the other pieces too was refused ("two faces of the sheet that meet along more
than one edge"). A picked bend cylinder now takes every coaxial piece of the same radius between
the same two faces, on both skins; in the flat, a face that meets its bend neighbour along several
collinear runs gets one bend edge, and the notches between them and the bend zone's pieces there
become holes of the sheet.

Test: a_bend_split_by_slots_across_it_converts_as_one_bend (slots cut through a tray's unfolded
bends, one piece picked or every piece): the volume, flat size, outline area, bends and the three
cut-outs are the source's.

Fixes #7530.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 07:37:58 +00:00
github-actions[bot] 9fdb7fdefc Regenerate generated files and fold pending files [skip ci] 2026-11-05 07:53:13 +00:00
lewis2e 718d5a4383 Intersection Curve: take two sketch curves, no helper surfaces (#11048) (#11049)
* claim: #11048

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

* Intersection Curve: take two sketch curves, no helper surfaces (#11048)

Intersection Curve now also takes curves of other sketches. Each curve
stands in for the surface you would get by extruding it along its own
sketch's normal, both ways and as far as needed, so two sketch curves
(or a curve and a face) give their 3D crossing without the two Surface >
Extrude features it used to take. The surface is never added to the
model. Sketches on parallel planes are refused with an error saying why.

The result stays a linked 3D wire that follows edits to either curve.
In the tool, a curve of another sketch fills a side like a face does;
after the first pick the status bar asks for the second, a right-click
starts the picks over, and the hint returns once the curve is made.

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

* Intersection Curve: keep other tools' right-click, update the tooltip, add a UI scenario (#11048)

The right-click change now applies to Intersection Curve only: Project to
Surface and Spun Profile behave as on main again.

The toolbar tooltip now says Intersection Curve also takes curves of other
sketches, in every catalog that has it, using each language's wording from
the Project to Surface tooltip.

New UI scenario intersection_curve_from_two_sketch_curves: a line on XY and
a line on YZ give one linked 3D wire along X at y = 0, z = 5; it also checks
the second-pick prompt and that a right-click starts the picks over.

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

* Intersection Curve: a picked spline wall meets whole, in one curve (#11048, #9009)

On the SMLib kernel a fit-point spline's wall is one face per span, and
Mesh::surface_patch keeps smooth-joined faces apart, so a face pick met
only the span under the pick and gave part of the crossing (#9009 again,
for faces as well as for sketch curves). A face pick now takes the faces
joined across seams and smooth joins, never across a crease.

The imprint also splits a crossing at every face boundary of either
side, so a crossing came as one wire per span. The pieces are now joined
end to end into one wire, keeping their exact curves; a piece that runs
the other way is reversed as a record curve.

A curve side's sweep is sized from the other body's exact bounds, not
its display mesh. The #9009 test's premise that the spans are one
surface_patch no longer holds and is removed; its checks are unchanged.

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

* Intersection Curve: a picked face joins only tangent spline faces, from exact geometry (#11048)

Which faces a face pick means is now decided on the exact surfaces, not the
display mesh: the picked face and the spline faces joined to it at least
tangentially (the kernel's seam check), so a spline wall's spans still meet
as one (#9009) while a plane, a round or any analytic face is that face
alone. The pieces of a crossing are joined within ten times the kernel's
intersection tolerance instead of a fixed 1e-4 mm.

Tests: a flat face beside a round and the round itself each give their own
crossing; two sketch curves give one curve at 1/100 and 100 times the size.

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

* Known-failing tests: the picked spline wall's intersection curve passes now (#11048, #9009)

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 06:52:54 +00:00
github-actions[bot] 1c10f82b34 Regenerate generated files and fold pending files [skip ci] 2026-11-05 07:16:32 +00:00
Jackson Oursland ca4f3ed1a0 Book: getting started, sheet metal and import/export get pictures (#10732)
* Book: sketching step by step, with three clips and a numbered screenshot

The sketching page now opens with a first sketch in four steps: start a sketch on the Top
plane, draw a 60 x 40 rectangle and a 12 mm circle with typed values, dimension the circle
until the sketch is fully constrained, and finish. Each step has a short clip, and the last a
screenshot numbering the Sketch tools, a constraint, a dimension, the sketch's state and
Finish Sketch.

doc_shots.py gains what these needed: a setup that runs before recording, so a clip starts
where the last one ended; sketch framing; Enter sent as two input frames; and clips that keep
their pauses (hovering a plane).

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

* Book: the sketching page's general notes get a heading after Step by step

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

* Book: sketching adds Offset and Trim; the sketching figures again on 0.29.0

Two more clips after the sketching walkthrough: Offset draws the rectangle's outline 4 mm inside
it with one click (Chain), and Trim cuts a notch where a circle crosses the top side. All the
sketching figures are made again on SolidCraft 0.29.0, with the clips keeping a moment on each
result.

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

* Book: solid features step by step, with four clips

The solid features page now opens with the sketch from the sketching page made into an open
box in four steps, each with a short clip: extrude it 12 mm, shell it with the top open,
round its outer top edges, then make it 20 mm tall from the timeline while the shell and the
fillet rebuild. The panel table and what follows get a heading of their own.

doc_shots.py: the feature shots share their steps with the setups that lead up to the next
shot, and fail when a feature on the timeline carries a warning or an error, so no figure
shows one. Shell comes before Fillet for that reason: shelling through the rounds needed the
kernel's boolean retry. trim_idle.py takes --hold, the seconds of each idle stretch to keep
(default 0.1 as before); the doc clips keep 0.8 s, so a reader sees each result. The app gets
up to three minutes to answer on a busy machine.

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

* Book: features add Hole and Circular Pattern; the Parameters dialog, numbered

The features walkthrough gains two steps before the timeline edit: a 4 mm hole on the box's
floor, then Circular Pattern repeating it four times around the tube. The edit at the end now
rebuilds all of it. The parameters page gets a screenshot of the Parameters dialog numbering
apply as you go, user parameters, model parameters by feature, an expression and its value.
The features clips are made again on SolidCraft 0.29.0.

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

* Book: components and joints step by step, with three clips

The components and joints page now opens with a two-leaf hinge in three steps, each with a
short clip: the two bodies made into components from the Bodies folder's menu (the first one
grounded), a revolute joint on their barrel ends with Flip turning Leaf B the right way round,
and a drag that swings Leaf B about the hinge while grounded Leaf A stays put. What follows
gets a heading of its own.

doc_shots.py builds the leaves from commands, with Leaf B lifted and set back so the joint
visibly brings it into place.

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

* Book: assemblies add Drive Joints; the assembly clips again on 0.29.0

A fourth step drives the hinge with Drive Joints: the slider swings Leaf B while a ghost shows
where it started, and OK keeps the new angle. The assembly clips are made again on SolidCraft
0.29.0.

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

* Book: getting started, sheet metal and import/export get pictures

Getting started gains a section on the start page: a numbered screenshot (new design, open,
import, recent, samples, the File menu) and a clip opening a sample from it. Sheet metal opens
with a tray in three steps, each with a clip: a base flange from a sketched rectangle, edge
flanges from two top edges, and the flat pattern with its bends. Import and export opens with
the File menu, numbered.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 06:31:44 +00:00
SS-EN a1d66c238e MCP: batch runs the steps of a script file (path) (#5957) (#5959)
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 06:02:13 +00:00
thocsmith 70603de654 Emboss: an emboss or deboss that changes nothing says so (#10940) (#10944)
* claim: #10940

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

* Emboss: an emboss or deboss that changes nothing says so (#10940)

solid.emboss on a body its tool missed (a sketch on the far side of the
material, a depth that stops short) was recorded as a success with no
warning, so a sheet metal part looked embossed when it was not. The
evaluation now compares the bodies before and after and adds a warning
when none changed. A working emboss or deboss is silent.

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

* Emboss: the changed-nothing warning names what to check, not a cause it can't know (#10940)

CodeRabbit pointed out that an emboss can change nothing for other reasons
than missing the body (for example a profile that lies inside material that
is already there), so the warning no longer claims the profile misses the
body. It says the operation changed nothing and suggests checking where the
profile lies, which side of the face the sketch is on, and the depth.

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

* Emboss test: put the missing sketch below the sheet, since main's sheet metal emboss now cuts from its underside (#10940)

On current main a deboss from the XY plane reaches the sheet (it is changed and gets
the sheet metal flat-pattern warning), so the test no longer showed an emboss that
changes nothing. A sketch 5 mm below the sheet misses it on both bases.

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

---------

Co-authored-by: thocsmith <193096300+thocsmith@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 05:59:00 +00:00
Bartosz Błachut db20c8be23 Timeline: deleting a sketch entity reuses the results it replaced (#3923) (#11283)
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 05:46:56 +00:00
github-actions[bot] 8f4fe740c7 Regenerate generated files and fold pending files [skip ci] 2026-11-05 06:00:07 +00:00
thocsmith aae4282f1e Polygon: By side shows the Length and Sides boxes (#11271) (#11287)
* claim: #11271

* Polygon By side: Length and Sides boxes, the typed length a side dimension (#11271)

The edge polygon tool showed no value boxes after its first click. It now
shows Length (the side from the first click) and Sides, as the inscribed
and circumscribed modes show Radius and Sides. A typed length places the
second corner and becomes a Length dimension on the first side:
sketch.draw.dimensioned takes a `length` role for sketch.polygon.edge,
an alternative to its radius (as_drawn still adds the radius when no
length is given; both together are refused).

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

* Polygon By side test: read the design's own state so it compiles against main (#11271)

Main's Session::world_state() now returns a Result, so the new test failed
Quick compile on the merge. The sketch is in no component, so the design's
own state shows the same sketch on both the old and new bases.

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

* Polygon By side test: take Vec2 from solidcore_record, where main moved it (#11271)

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-05 05:35:52 +00:00
Colin Faulkingham 18b698ffa8 Keep raised models’ ground shadows on the ground (#9838) (#10257)
* claim: #9838

* fix: anchor raised ground shadows to the origin plane (#9838)

* docs: attribute ground shadow preference messages
2026-11-05 05:14:38 +00:00
github-actions[bot] 051e6236c3 Regenerate generated files and fold pending files [skip ci] 2026-11-05 05:26:55 +00:00
selune 8691cefbbf Render: save wood images with physical grain controls (#1599)
* Render: save wood images with physical grain controls

* Render: prepare plain glass before marking the GPU host ready
2026-11-05 04:49:46 +00:00
NOWN-DEV 6d2465b52d Sketch: a fillet whose lines already leave it is not swapped against a mirrored reference (#10401)
The fillet keeping of #5677 swaps an arc's ends when its sweep jumps by more
than half a turn with both its lines turned. Judged against a reference that
shows the corner mirrored (positions before a move, or a mirrored start), a
fillet the solve left exactly where it was looks turned, and the swap made it
its long complement: a 45-degree fillet on a 135-degree corner became a
315-degree arc with both lines cutting back through it, while the solve
reported ok.

The swap is now decided by the lines: an arc whose tangent lines all leave it
after the solve already rounds its corner and keeps its ends. A swap still
gives a corner its arc back when its lines cut back through it. A second test
keeps a real fillet over three quarters of a turn whose corner mirrored as the
long arc its lines leave (a narrower fix, letting a swap only shorten an arc,
would break it).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 04:28:39 +00:00
semmelrinde c517ca0393 Lip and groove: the rim face follows a parameter change (#11209) (#11425)
A lip kept its rim face as a plain point, so it got no persistent face
name. When a parameter made the box taller, the point stayed below the new
rim and the lip failed ("the plastic feature's placement is no longer on
its body face"). The face is now a face pick, as a boss's is, and the lip
names its body like the other placed plastic features. Both are saved as
the same [x, y, z], so files don't change.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 04:04:17 +00:00
github-actions[bot] ee1bdea97b Regenerate generated files and fold pending files [skip ci] 2026-11-05 04:28:35 +00:00
github-actions[bot] dc54d2f229 Regenerate generated files and fold pending files [skip ci] 2026-11-05 04:16:48 +00:00
raykholo b916f9bf33 Ribbon: an option to fold it to its tab row (#10112) (#10214)
* Ribbon: an option to fold it to its tab row (#10112)

Preferences > Layout > "Show only the ribbon's tabs" (off by default), the
Ribbon Tabs Only command (view.ribbon_tabs_only), and its settings-profile key.
Rebuilt on main's redesigned Layout page.

* Ribbon Tabs Only: switching tabs with a panel menu open no longer keeps the overlay open (#10112)

A tab click now forgets the open panel drop-down of the previous tab, so the pointer leaving or Escape still closes the overlay.

* Ribbon Tabs Only: count its settings-profile key in the profile membership test (#10112)
2026-11-05 03:42:58 +00:00
SS-EN 733f0b2254 MCP: opt-in compact inspect_design and tool output (split from #2901) (#3144)
* MCP: compact inspect_design and tool JSON, off by default (--compact / SOLIDCRAFT_MCP_COMPACT)

Split out of #2901 per review: the smaller inspect_design changed the default
for everyone, so it is now an MCP server option that is off unless asked for.

- solidcraft-cli mcp --compact, or SOLIDCRAFT_MCP_COMPACT=1 (true/yes/on;
  0/false/no/off/empty leave it off; anything else is an error at start-up).
  solidcraft_mcp::Options::resolve is the one place that decides, so an app
  Preferences setting can feed it later.
- With it on, inspect_design summarises sketches (id, name, plane, counts of
  points, curves, constraints and profiles, dof, status), returns full contents
  only for the sketches named in `sketches` (names/ids, true, false or
  "summary"), takes a `bodies` filter and measures only those; unknown names
  list the existing ones. Tool JSON is compact rather than pretty-printed.
- Off, tools/list, argument checks, inspect_design and tool JSON are exactly
  as before.
- document.inspect gains an opt-in `sketch_counts` (plane, points,
  constraints); without it its reply is unchanged.

Tests: both modes in the MCP suite, Options parsing, and the CLI flag and
variable end to end.

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

* MCP compact output: a Preferences setting too (AI › Agents through MCP)

The desktop app's Preferences › AI gets "Compact output" under a new "Agents
through MCP" section, off by default and shown with the chat off too. The app
reports it on the control channel as `mcp.options` ({"compact": bool}); the
agent chat lets its own MCP server read it.

A bridged MCP server (`solidcraft-cli mcp --connect`) asks the app when an
agent first lists or calls a tool and keeps the answer for the session, so the
tools it listed keep their shape. An app not running yet, or busy past 2 s, is
asked again on the next call; an app from before the setting counts as off.
`--compact` and SOLIDCRAFT_MCP_COMPACT=1 still turn it on whatever the app says.

Tests: the server follows the app's answer (waits for it, keeps it, the flag
still wins); the checkbox reaches `mcp.options` and Restore Defaults clears it;
the chat gate allows `mcp.options`. docs/mcp.md and docs/control-protocol.md.

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

* MCP compact output: review fixes (mcp.options never blocks, headless test, locales, prefs doc)

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

* MCP compact output: the setting is a section of the AI page; the bridged test answers mcp.options

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

* MCP compact output: the preference test sets it through ui.prefs; rustfmt

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

* MCP compact output: look for a newly started app before asking its options; counts from sketch.inspect for an older app

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 03:33:33 +00:00
Alexander Puzynia ee02080a25 Two-distance chamfers of free-form rims: a test on the SMLib kernel (#4332) (#4333)
* claim: #4332

* Two-distance and distance-angle chamfers of free-form rims: a test on the SMLib kernel (#4332)

A spline, Bézier or text outline's rim used to be refused by the two-distance and
distance-angle chamfers. The SMLib kernel (#11351) chamfers it along the rim; this test pins
that down on a four-Bézier oval, picked as its tangent chain the way a pick takes it: the
volume taken off is the analytic one for two distances (both ways round) and for a distance
and an angle.
2026-11-05 03:25:50 +00:00
Homero Thompson 99d96482af Sketch: groundwork for pierce constraints, no UI yet (#3599) (#11388)
* Sketch: the geometry of a pierce, a point where another sketch's curve crosses this plane (#3599)

* Sketch: the Pierce constraint, a point on a curve of another sketch (#3599)

* Engine: draw a Pierce constraint at the point it holds (#3599)

* Engine: the pierce tests wait for the command that is not written yet

* style: rustfmt, the imports of the pierce geometry in the order rustfmt wants

The rebase onto the current main resolved the rename of Plane, Vec2 and Vec3
from solidcraft_geom to solidcore_record and left the two use lines in the
order the resolution wrote them. rustfmt wants them the other way round, and
the fmt phase of the gate reads the whole tree.

No token of the file changed: the same 2983 tokens before and after, only the
order of the two use lines moved.

---------

Co-authored-by: bherbruck <bherbruck@gmail.com>
Co-authored-by: vdirienzo <vdirienzo@users.noreply.github.com>
2026-11-05 03:20:41 +00:00
github-actions[bot] a5be592b7d Regenerate generated files and fold pending files [skip ci] 2026-11-05 03:32:27 +00:00
aiapienthusiast d92923a964 Agent chat: a Cheaper Inference preset for OpenAI-compatible endpoints (#11174) 2026-11-05 02:58:56 +00:00
froglemonade2 71598c0354 Agent control: ui.menu refuses items the design doesn't have, reports the History bar's right-click menu, and gives Edit Joint Limits its own id (#10745) (#10746)
* claim: #10745

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

* Control channel: ui.menu refuses missing targets, reports the History item menu, and tells the joint menu items apart (#10745)

- ui.menu looks a target up and refuses one the design doesn't have ("no body `NoSuchBody`").
- The History bar's feature menu is the shared context menu (Target::Timeline), so ui.menu
  reports it, ui.menuPick runs its items and {"type":"timeline","feature":id} opens it.
  Its Show All toggle moves to TreeState so the menu can list Delete after the marker.
- Edit Joint Limits is ui.editJointLimits and opens Edit Joint with Limits expanded.

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

* Icon audit: open the section and canvas menus on a real section and canvas; a hidden section has a menu too

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

* ui.menu: check a group's or folder's scope and folder name; Delete after the marker gets its own id

A group or folder target is refused unless its scope is a row of its component (`c<id>` or a
placement of it) and the folder is bodies, sketches or construction. The History item menu's
delete of everything after the marker is ui.deleteAfterMarker, so ui.menuPick can tell it from
Delete (review on #10746).

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

* ui.menu: a component's own c<id> scope is the design root's only; test that Delete after the marker deletes

The browser draws a part's folders and groups under its placements (o:<path>), so a c<id> scope
for any component but the root names a row that isn't there (review on #10746). The History test
now picks ui.deleteAfterMarker and checks the features are gone.

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

* ui.menu: a placement scope must be spelt as the browser keys it

o:012 parses to placement 12 but isn't the row's key (o:12), so Show/Hide would store a key no
row reads (review on #10746).

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

* History item menu: no Delete after the marker when nothing shown is after it

A timeline target for a feature the bar's component filter leaves out listed no features, so the
item did nothing (review on #10746).

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

* ui.menu: a plane target must be construction geometry

The plane menu's Show/Hide keys the feature's name as an origin item, so any other feature got a
menu whose actions don't fit it (review on #10746).

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

* ui.menu: accept the view navigator's and selection filter's menus, which main added

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 02:35:55 +00:00
Homero Thompson 06a8a9b7d2 AGENTS.md and the contributing skill: say how to work as an agent (#8059)
* AGENTS.md and the contributing skill: say how to work as an agent

Two rules that the loop's own agents follow but the repository never
wrote down, so every agent that reads it had to rediscover them:

* The code, the comments, the commit messages and the docs are in English,
  always. A comment in another language is a defect: the people who
  maintain the code cannot review it. A user-visible string is not inline
  in the code either; it goes to the message catalogs, and the UI text
  skill says how to name and translate it.
* Parallel work runs in parallel, and dependent work stays sequential.
  One subagent per independent part, with a self-contained brief, and no
  two subagents writing the same file. A fix and the test that proves it,
  a refactor and the callers it breaks: those stay in order.

AGENTS.md is the router, so it gets the two rules in one line each, and
skills/solidcraft-contributing/SKILL.md gets the "Working as an agent"
section with the detail.

* AGENTS.md: fit the two agent rules under the router cap

`cargo xtask skills` reads the router as a router: one line per rule,
with the detail in the skill the line points at. The two new lines
broke that contract twice over. They carried their own detail (a
comment in another language is a defect; one subagent per part, no two
writing the same file) instead of pointing at the "Working as an
agent" section that already holds it, and the file grew to 5361
characters, over the 5000 a router may have.

So the two lines shrink to what a router line is, and five clauses
that repeated a rule the pointed-at skill already states in full give
up their place:

* "Act when the code, docs and rules settle a question" is in the
  contributing skill, in more detail.
* The unsafe allowlist is the crash-safety skill's own list.
* "No second PR for an issue a lower-numbered one closes" and "never
  force-push main, no pushes just to catch up with main" are the
  contributing skill's claim and push rules.
* "Do not switch branches while the gate runs" is in the contributing
  skill too.

No rule is lost: each one still has exactly one place that states it,
and that place is a skill. The router is 4970 characters.
2026-11-05 02:25:46 +00:00
Colin Faulkingham 4d2691e636 Assistant: opt-in HTTP authentication for private endpoints (#5341) (#10674)
* claim: #5341

* Allow per-endpoint HTTP authentication with explicit consent

* fix: discard model listings after HTTP consent revocation
2026-11-05 02:12:56 +00:00
Nathalie Schönwetter 6e17874cb9 A Move that copies can be patterned or mirrored (#5931) (#6018)
Co-authored-by: Nathalie Schönwetter <nathalie@cfw-ag.ch>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 02:04:01 +00:00
NAX LAB bf22dad8e8 Fix: flake build fails on git dependencies in Cargo.lock (#12146)
* Set `allowBuiltinFetchGit = true` in `cargoLock`:

* Remove comment
2026-11-05 01:26:31 +00:00
semmelrinde 731029cd87 Report a bug: put the whole report in the GitHub link whenever GitHub keeps it (#7103) (#7104)
Open GitHub issue form filled the issue through the link only up to
2,000 characters, with every space and line break encoded as three, so
most reports opened GitHub with the title alone and their text on the
clipboard, and many arrived empty (#10556, #10654).

The link now encodes only what a query value can't carry (a space is
`+`) and is limited by what GitHub keeps: 6,000 characters, and 7,000
once its sign-in page encodes it again. A report too long for that still
goes through the clipboard, whole.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 01:09:37 +00:00
Raymond Thurman 6b5c5dc6e8 Sketch on a thickened surface's face (#7641) (#7703)
* claim: #7641

* Sketch on a thickened surface follows the face (#7641)

Thicken dropped the kernel's face history, so Create Sketch refused
every face of the solid. Carry that history through, the same way
Shell and Trim do.

The regression covers the offset face and an end wall, and checks
that a boss on the offset face follows a thickness change and reopens.
2026-11-05 01:09:18 +00:00
github-actions[bot] e7ce6c282a Regenerate generated files and fold pending files [skip ci] 2026-11-05 02:47:03 +00:00
rugbymauri 67c58cbd28 Sheet metal rules: a design parameter named Thickness no longer overrides it (#9623) (#9633)
* claim: #9623

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

* Sheet metal and plastic rules: Thickness in a rule's expressions is the rule's thickness

A rule's expressions read `Thickness` as the rule's thickness only while the
design had no parameter of that name; with one, the default gap, reliefs and
a `Thickness` bend radius took the parameter instead (a 2 mm rule beside
Thickness = 10 mm closed corners to a 10 mm gap). Now `Thickness` is always
the rule's, as documented; the rule's own thickness still reads the design's
parameters, so `thickness: Thickness` keeps naming the design parameter.

Renaming a parameter called Thickness, its users and what it drives follow
the same reading: only a rule's thickness field refers to it. Renaming a
parameter to Thickness is refused while another rule field uses it, since
that field would then read the rule's thickness instead.

Fixes #9623

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

---------

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
2026-11-05 01:07:30 +00:00
austin62jake 7c89f7445f Assembly: moving a component without capturing its position marks the design unsaved (#9736) (#9851)
* Claim #9736

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

* Assembly: a move not captured yet is an unsaved change (#9736)

A component moved without capturing its position left the design reading
as saved: file.save wrote the file without the move and said nothing, and
closing the tab didn't ask. Now:

- Session::is_dirty is true while a move is pending, so closing a tab or
  quitting asks "save changes?".
- file.save and file.save_as refuse while a move is pending, naming the
  component and the capture and revert commands.
- In the app, Save As (and Save As JSON, Save a copy, Download design)
  asks the Capture Position question first, as Save already did; a tab
  closing after "Save" waits for that answer, and Cancel keeps it open.

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

* Close: the save-changes card waits behind the Capture Position question (#9736)

Saving a tab that closes asks the Capture Position question first; the
"save changes?" card stayed drawn over it and took a second answer. It
now hides and ignores answers until the question is answered. The design
container doc says a save stops for a move not captured.

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

* Assembly: an exploded view shown is not a move to save (#9736)

explode.show displays a view through the pending moves, as an uncaptured
move does. Those placements last only while the view is shown, so they
don't make the design unsaved and don't stop a save
(Session::moved_uncaptured). A move on top of a shown view still does.

The relink test saved with a move pending; it captures it first now.

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

* Assembly: the pending-move save test reads the world state as main now gives it

world_state() returns a Result since the kernel merge; the test unwraps it.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 01:06:46 +00:00
ShawnMarx 26adcfa997 Docs: add BoxInsertDesigner to the showcase (#10095)
* Docs: add BoxInsertDesigner to the showcase

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

* Docs: attribution rows for the BoxInsertDesigner showcase recording

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 01:06:36 +00:00
github-actions[bot] 1e41dddae2 Regenerate generated files and fold pending files [skip ci] 2026-11-05 02:11:35 +00:00
PapaEcho a9b219bc9f joint: let the origin be the design origin or a sketch point (#10290) (#10584)
The joint origin input only accepted faces, edges and vertices, so the world origin and sketch points could not be picked to place a joint. Extend the origin input's snap mask with ORIGIN and POINTS and resolve a sketch point (and the empty-body world-origin vertex) to a world snap in snap_of, so a joint can be placed on the design origin or a hole centre like Fusion.
2026-11-05 01:06:11 +00:00
semmelrinde 32dc8750df Sketch Project: faces and edges of a part's second copy now project (#9957) (#10721)
* Sketch Project: a face or edge of a part's second placement projects where that placement is (#9957)

Projecting the face of `Block (Part:2)` failed with "face of Block: the
face no longer exists". The pick's body name was turned into the
definition's own name, and the model a sketch reads holds only each
component's first placement, so the face was looked for on the first
placement, somewhere else.

Sketch picks now keep the name the browser shows, and the further
placements a sketch's links name are placed into the model it reads
(`with_placed_copies`), when the sketch is evaluated and when a link is
added or refreshed. Only the named ones are placed. A link to a body
the model lacks also makes the sketch follow every placement, so moving
the copy moves what was projected from it.

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

* Sketch Project: a projection from a second placement follows renames of its part and body (#9957)

The link keeps the copy by the name the browser shows (`Block (Part:2)`),
which a rename of the component or of the body changes. component.rename
and body.rename now rename it in the sketches' links as well.

The copies a sketch reads are found through their component's bodies,
not by going through every body for every placement.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 01:05:40 +00:00
semmelrinde ceeff58a7f Scale: X, Y and Z factors from the dialog (#10782) (#10983)
The Scale dialog gets a Type row, Uniform or Per axis. Per axis shows
X, Y and Z rows and sends factors, which solid.scale already takes. A
Scale made with factors opens per axis with its three values; before,
they rode along as an extra and the dialog's factor did nothing.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 01:05:10 +00:00
github-actions[bot] a55286953a Regenerate generated files and fold pending files [skip ci] 2026-11-05 01:37:26 +00:00
github-actions[bot] 9a0846ef68 Regenerate generated files and fold pending files [skip ci] 2026-11-05 01:28:10 +00:00
raykholo 06749ac464 Add the Fair Surface and Match Surface dialogs (#4644) (#4653)
* claim: #4644

* Add the Fair Surface and Match Surface dialogs (#4644)

Neither command had a dialog, so the toolbar and command search ran them
with no parameters and they failed with "`body` is required".

Fair Surface picks the surface or some of its faces and sets the
strength, the iterations, whether the edges are kept and an optional
tolerance (blank: 0.001 of the body's size). Match Surface picks the
surface or face to rebuild, the target and an edge chain of the target,
and the continuity (G1, G2 or G3, default G2). Both preview, and Edit
Feature restores the saved picks and settings. New labels go through
the catalogs with English, Japanese, Chinese, German and Korean text.

* Keep surface-dialog strings pending with complete translations (#4644)

* Fair tolerance is a length; Fair and Match picks reopen on their saved bodies

The Fair dialog's tolerance now goes through the same design-unit length
conversion as the other surface lengths, on OK and when an edit is refilled.
Editing a Fair or Match feature looks its face and edge picks up on the body
they were saved on, so a coincident face or edge of another body cannot take
their place.

* Surface dialogs: strings stay in the pending catalog only (#4644)

* Surface dialogs: edge picks use the session world, as main's edge_sel now does (#4644)

* Surface dialogs: refuse to refill when a saved pick no longer resolves, and pass body names by reference (#4644)

* Surface dialogs: Fair and Match now open dialogs, so the refused-command tab test no longer lists them (#4644)
2026-11-05 00:05:53 +00:00
semmelrinde a6e7126bf1 Closed stderr pipes no longer crash the app, CLI or MCP server (#10111) (#10126)
* Stderr: a closed stderr no longer stops the app, the CLI or the MCP server (#10111)

`eprintln!` panics with "failed printing to stderr" when stderr is a
pipe its reader has closed. A process another program starts writes
into such a pipe: `solidcraft mcp` under an agent, and the app that
one starts, which inherits it. #10111 is the app stopping that way
while an agent (Codex) connected. `solidcraft_geom::note!` (re-exported
as `solidcraft_engine::note!`) writes the same line and ignores a
failed write, as the CLI's logger already does; the app, the CLI, the
MCP server, the crash hook and the crates they run use it instead of
`eprintln!` outside tests.

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

* Stderr: test that a closed stderr leaves the CLI's exit code as it is (#10111)

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

* Stderr: the old name's alias and the fuzz command don't stop on a closed stderr either (#10111)

`solvecraft-cli` writes its deprecation notice before it starts
`solidcraft-cli`, so an agent still configured with the old name got the
panic before the MCP server started (found in review). It and the fuzz
command now write through `note!` too, and the test covers the alias.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 23:29:07 +00:00
Christian Hammacher 4a906699ee Browser: the component menu keeps its everyday actions and groups the rest in flyouts (#8769) (#8770)
* Browser: the component menu keeps its everyday actions and groups the rest in flyouts

A component's or placement's right-click menu had grown to about thirty entries in seven
blocks. Activate, Edit in Place, Open Linked Design, Move/Copy, Show/Hide, Isolate, the
clipboard, Delete, Rename, Appearance, Physical Material and Properties stay on the menu;
Ground, Capture and Revert Position, Unlock Contents and Turn Up Axis move to a Position
flyout, Relink Source or Extract to File and the exports to File, New Component, New Group
and Paste New to New, and Show All Bodies, Cycle Component Color, Expand All and Collapse
All to Display. context_menu::entries lists a menu with its flyouts, as ui.menuPick reads it.

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

* Browser: the component menu nests its flyouts by topic, and flyouts no longer scroll

Position (Ground, Capture and Revert Position, Unlock Contents, Turn Up Axis), Component
(New Component, Rename, Appearance, Physical Material, Cycle Component Color, Relink Source
or Extract to File, Properties; Design on the design's row), Export (Export, Save As Mesh,
Send to Slicer) and Browser (New Group, Expand All, Collapse All) each open a flyout; Paste
New stays with the clipboard and Show All Bodies with Show/Hide. Flyouts open inside flyouts,
so Appearance keeps its quick choices inside Component; the keys walk in and out of them.

A flyout no longer scrolls or sits away from its row: every flyout has its own area, measured
whole, where a short one used to squeeze every later one into its height. A component's only
body is no longer offered as a component of its own on a folded Bodies folder's entries.

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

* Browser: the component menu starts with what a double-click does, and keeps the old order of its sections

A linked component's menu starts with Edit in Place and Open Linked Design when a double-click
edits it in place (double_click_components), and with Activate otherwise. Position, Component
and Export follow Move/Copy, then the clipboard, then Show/Hide and Isolate, with Browser last,
as the sections came before the flyouts.

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

* Browser: Show All Bodies is on a component's menu only while a body is hidden

It is listed while a body is hidden itself, in a hidden placement, or in a hidden Bodies folder or
group of bodies, anywhere in the design, since that is what it shows.

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

* Browser: Relink Source and Extract to File sit right below Rename in the Component flyout

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

* Browser: Placement and Organize flyouts, Turn Up Axis back as a flyout, and flyout fixes

Placement (Ground, Turn Up Axis, Capture and Revert Position, Unlock Contents) follows
Move/Copy above the first separator, Turn Up Axis opens its two turns in a flyout again, and
the Browser flyout is called Organize. The Component flyout has three blocks: New Component
with Relink Source or Extract to File, then Appearance, Physical Material and Cycle Component
Color, then Rename and Properties.

A flyout of a flyout that opened to the left opens to the left too instead of covering the
menu, Left back to the menu chooses the row that opened the flyout, ui.menuPick refuses a row
that only opens a flyout, and the icon audit checks every level. The guides and the control
protocol describe the new menu paths.

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

* Browser: ui.menu gives a flyout's rows their placeholder flag too

ui.menu set placeholder only on the top-level rows, so a client reading
a flyout row's placeholder got nothing. The icon audit now reads the flag
of the flyout rows instead of resolving their icons itself.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 23:05:26 +00:00
github-actions[bot] a2a7102859 Regenerate generated files and fold pending files [skip ci] 2026-11-05 00:53:06 +00:00
780 changed files with 99888 additions and 15006 deletions
+7 -5
View File
@@ -3,13 +3,13 @@
SolidCraft is a clean-room, pure-Rust parametric 3D CAD app (sketch solver, feature timeline, B-rep kernel, an egui UI that agents drive). This file is a router: the hard rules, then the skill to read for your task. Humans: CONTRIBUTING.md. SolidCraft is a clean-room, pure-Rust parametric 3D CAD app (sketch solver, feature timeline, B-rep kernel, an egui UI that agents drive). This file is a router: the hard rules, then the skill to read for your task. Humans: CONTRIBUTING.md.
## Start here ## Start here
Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelled `help wanted`, `good first issue`, `needs-triage`; architecture in `docs/architecture.md`. Act when the code, docs and rules settle a question; ask only when it changes what users see. Local `plan/` notes are optional. Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelled `help wanted`, `good first issue`, `needs-triage`; architecture in `docs/architecture.md`. Local `plan/` notes are optional.
## Hard rules (what enforces each) ## Hard rules (what enforces each)
- Independent: never copy another product's code, icons, text or templates; never drive or take data from commercial CAD. `skills/solidcraft-ground-rules/SKILL.md`. - Independent: never copy another product's code, icons, text or templates; never drive or take data from commercial CAD. `skills/solidcraft-ground-rules/SKILL.md`.
- No GPL/LGPL/AGPL code, not even reading it (OpenCASCADE, FreeCAD, SolveSpace, CadQuery, LibreCAD, QCAD): `cargo xtask licences --check`. - No GPL/LGPL/AGPL code, not even reading it (OpenCASCADE, FreeCAD, SolveSpace, CadQuery, LibreCAD, QCAD): `cargo xtask licences --check`.
- Every asset is original or openly licensed with a row in ATTRIBUTION.md; read `assets/AGENTS.md` before icon work: `cargo xtask assets`, `cargo xtask icons`. - Every asset is original or openly licensed with a row in ATTRIBUTION.md; read `assets/AGENTS.md` before icon work: `cargo xtask assets`, `cargo xtask icons`.
- Never crash: no unwrap/expect/panic/unsafe in non-test code (unsafe allowlist in crash-safety), errors are `Result`, input is hostile: clippy `-D warnings`, `hostile_params_never_panic`. - Never crash: no unwrap/expect/panic/unsafe in non-test code, errors are `Result`, input is hostile: clippy `-D warnings`, `hostile_params_never_panic`.
- Model decisions (what an operation does, which bodies it touches, which face or edge a point or name means, depths, nearness) use exact geometry; a mesh is for display, export, previews and mesh bodies (`xtask/mesh-decisions.txt` only shrinks): `cargo xtask mesh-decisions`. - Model decisions (what an operation does, which bodies it touches, which face or edge a point or name means, depths, nearness) use exact geometry; a mesh is for display, export, previews and mesh bodies (`xtask/mesh-decisions.txt` only shrinks): `cargo xtask mesh-decisions`.
- New kernel cases go to solidcore: `cargo xtask lists`. - New kernel cases go to solidcore: `cargo xtask lists`.
- Everything is a command and programmatic calls never open dialogs: `skills/solidcraft-commands/SKILL.md`. - Everything is a command and programmatic calls never open dialogs: `skills/solidcraft-commands/SKILL.md`.
@@ -21,12 +21,14 @@ Work: ROADMAP.md, "Where help is wanted most" in CONTRIBUTING.md, issues labelle
- A design-format change is ONE new file in `crates/doc/src/format/pending/`: `scripts/test-format-pending.sh`. - A design-format change is ONE new file in `crates/doc/src/format/pending/`: `scripts/test-format-pending.sh`.
- A command has input and output schemas (will become required; `schema/unconverted.txt` only shrinks): `skills/solidcraft-commands/SKILL.md`. - A command has input and output schemas (will become required; `schema/unconverted.txt` only shrinks): `skills/solidcraft-commands/SKILL.md`.
- New UI strings go in `assets/locales/pending/<slug>.json`, ATTRIBUTION rows in `attribution/pending/<slug>.md`: `cargo xtask lists`. - New UI strings go in `assets/locales/pending/<slug>.json`, ATTRIBUTION rows in `attribution/pending/<slug>.md`: `cargo xtask lists`.
- A changed default keeps the old behaviour behind a preference and fills the PR's `Changes a default:` line, and no second PR for an issue a lower-numbered one closes: `pr-checks.yml`. - A changed default keeps the old behaviour behind a preference and fills the PR's `Changes a default:` line: `pr-checks.yml`.
- A regression test goes in the area's existing test file, never a per-bug file (#3226). - A regression test goes in the area's existing test file, never a per-bug file (#3226).
- Look at open PRs first, claim with a draft PR (lowest number wins), one topic per PR, never force-push `main`, no pushes just to catch up with `main`: `skills/solidcraft-contributing/SKILL.md`. - Look at open PRs first, claim with a draft PR (lowest number wins), one topic per PR: `skills/solidcraft-contributing/SKILL.md`.
- A PR's title and first sentence make sense to someone who never saw your chat or the issue: `skills/solidcraft-contributing/SKILL.md`. - A PR's title and first sentence make sense to someone who never saw your chat or the issue: `skills/solidcraft-contributing/SKILL.md`.
- Code, comments, commit messages and docs are in English, always: `skills/solidcraft-contributing/SKILL.md` ("Working as an agent").
- Independent work runs in parallel, dependent work stays sequential: `skills/solidcraft-contributing/SKILL.md` ("Working as an agent").
- Show observable changes with real screenshots or a recording, captured yourself. - Show observable changes with real screenshots or a recording, captured yourself.
- Run `cargo xtask ci` before every commit, without switching branches while it runs. `cargo xtask skills` keeps this file and `skills/` honest. - Run `cargo xtask ci` before every commit. `cargo xtask skills` keeps this file and `skills/` honest.
## Working on X: read the skill first ## Working on X: read the skill first
| Working on | Read | | Working on | Read |
+46 -4
View File
@@ -82,7 +82,6 @@ Editable drawing code, native projects and shipped exports are collected under `
| 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-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 | | 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 |
| 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 | | 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/liberation-sans/LiberationSans-Regular.ttf | Red Hat, Inc. (Liberation Fonts 2.x; digitized data Google) | https://github.com/liberationfonts (Debian fonts-liberation), unmodified; licence text in assets/fonts/liberation-sans/OFL.txt; used for sketch Text outlines | SIL OFL 1.1 |
| 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/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 | | 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 |
| assets/fonts/craft-ui-tc/CraftUI-TC.otf | Adobe / Google Inc. (Noto Sans TC); SolidCraft subset | https://github.com/notofonts/noto-cjk Sans/SubsetOTF/TC Regular, glyph-subset for assets/locales/zh-TW.json and renamed Craft UI TC (OFL reserved-name); licence text in assets/fonts/craft-ui-tc/OFL.txt; web UI Traditional Chinese | SIL OFL 1.1 | | assets/fonts/craft-ui-tc/CraftUI-TC.otf | Adobe / Google Inc. (Noto Sans TC); SolidCraft subset | https://github.com/notofonts/noto-cjk Sans/SubsetOTF/TC Regular, glyph-subset for assets/locales/zh-TW.json and renamed Craft UI TC (OFL reserved-name); licence text in assets/fonts/craft-ui-tc/OFL.txt; web UI Traditional Chinese | SIL OFL 1.1 |
@@ -147,7 +146,6 @@ Editable drawing code, native projects and shipped exports are collected under `
| 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/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-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/fonts/ibm-plex-sans/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/fonts/liberation-sans/OFL.txt | Red Hat, Inc.; Liberation Fonts contributors | 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/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/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/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 |
@@ -215,6 +213,7 @@ Editable drawing code, native projects and shipped exports are collected under `
| 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/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/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-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/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/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/graphite.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
@@ -799,6 +798,50 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
| 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 | | 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 | | assets/locales/pending/sketch-tool-hints.json | carlymx | Original sketch tool hints and engine error translations | MIT OR Apache-2.0 |
| assets/locales/pending/primitive-pick-field-tips.json | SolidCraft contributors | Original primitive pick-field tooltip translations | MIT OR Apache-2.0 | | assets/locales/pending/primitive-pick-field-tips.json | SolidCraft contributors | Original primitive pick-field tooltip translations | MIT OR Apache-2.0 |
| assets/locales/pending/ribbon-panel-hover.json | SolidCraft contributors | Original ribbon panel menu preference labels and translations | MIT OR Apache-2.0 |
| docs/screenshots/box-insert-designer.gif | Shawn Marx | original recording made with BoxInsertDesigner's own Motion export (its three.js viewer) of its example game `examples/ccg-example` (https://github.com/ShawnMarx/BoxInsertDesigner): a card game box insert whose trays were built by SolidCraft through `solidcraft-cli`; the published card, board and box art in it is pixelated beyond recognition, and no logos or game names are shown (2.5× playback, 800 px wide) | MIT OR Apache-2.0 |
| docs/screenshots/box-insert-designer.mp4 | Shawn Marx | original recording made with BoxInsertDesigner's own Motion export (its three.js viewer) of its example game `examples/ccg-example` (https://github.com/ShawnMarx/BoxInsertDesigner): a card game box insert whose trays were built by SolidCraft through `solidcraft-cli`; the published card, board and box art in it is pixelated beyond recognition, and no logos or game names are shown (1280×720) | MIT OR Apache-2.0 |
| assets/locales/pending/agent-http-consent.json | SolidCraft contributors | Original endpoint-specific HTTP consent messages and translations | MIT OR Apache-2.0 |
| assets/locales/pending/ground-shadow-placement.json | SolidCraft contributors | Original ground-shadow placement preference messages and translations | MIT OR Apache-2.0 |
| docs/book/src/media/assemblies/components.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) making components from two original hinge-leaf bodies, 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 |
| docs/book/src/media/assemblies/joint.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) creating a revolute joint between two hinge leaves, 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 |
| docs/book/src/media/assemblies/drag.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) dragging a jointed hinge leaf, 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 |
| docs/book/src/media/assemblies/drive.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) driving a revolute joint between two hinge leaves, 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 |
| docs/book/src/media/features/extrude.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) extruding a sketch's profile, 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 |
| docs/book/src/media/features/shell.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) shelling a block, 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 |
| docs/book/src/media/features/fillet.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) filleting four edges, 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 |
| docs/book/src/media/features/edit.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) editing a feature from the timeline, 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 |
| docs/book/src/media/features/hole.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) placing a hole, 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 |
| docs/book/src/media/features/pattern.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) patterning a hole around an axis, 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 |
| docs/book/src/media/parameters/dialog.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (default dark theme, software renderer) showing the Parameters dialog, 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/files/menu.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (`--sample`, default dark theme, software renderer) showing the File menu, 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/getting-started/start.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (default dark 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 | MIT OR Apache-2.0 |
| docs/book/src/media/getting-started/sample.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) opening the built-in Sample Plate from the start page, 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 |
| docs/book/src/media/sheet-metal/base.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) making a sheet metal base flange, 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 |
| docs/book/src/media/sheet-metal/flange.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) adding sheet metal edge flanges, 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 |
| docs/book/src/media/sheet-metal/flat.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) showing a sheet metal flat pattern, 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 |
| docs/book/src/media/sketching/create.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) starting a sketch on the Top plane, 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 |
| docs/book/src/media/sketching/draw.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) drawing a rectangle and a circle with typed values, 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 |
| docs/book/src/media/sketching/dimension.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) dimensioning a sketch until it is fully constrained, 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 |
| docs/book/src/media/sketching/parts.png | SolidCraft contributors | screenshot of SolidCraft 0.29.0 itself (default dark 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 | MIT OR Apache-2.0 |
| docs/book/src/media/sketching/offset.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) offsetting a sketch outline, 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 |
| docs/book/src/media/sketching/trim.mp4 | SolidCraft contributors | original screen recording of the actual SolidCraft 0.29.0 English desktop UI (default dark theme, software renderer) trimming a notch in a sketch, 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/ca.json | carlymx | Catalan translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
| assets/locales/pending/sketch-mirror-auto-line.json | SolidCraft contributors | Original Mirror preference label and translations | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-01-extrude5-edge-frame.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-04-preview-outer-l11.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-05-preview-inner-l8.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-06-result-outer-120.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-07-preview-360.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-08-cancelled.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-13-colliding-id.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-14-surface-l1.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/demo-15-surface-result.png | SamD98 | screenshot of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| docs/screenshots/7452/revolve-selected-edge.mp4 | SamD98 | screen recording of the actual SolidCraft desktop UI showing the revolve axis pick on the Cat Post Topper repro design (docs/screenshots/7452/revolve-edge-frame.solidcraft), for #7452 | MIT OR Apache-2.0 |
| assets/locales/bg.json | Yasen-55 | Original translation | MIT OR Apache-2.0 |
| crates/sketch/assets/fonts/liberation-sans/LiberationSans-Regular.ttf | Red Hat, Inc. (Liberation Fonts 2.x; digitized data Google) | https://github.com/liberationfonts (Debian fonts-liberation), unmodified; licence text in crates/sketch/assets/fonts/liberation-sans/OFL.txt; used for sketch Text outlines | SIL OFL 1.1 |
| crates/sketch/assets/fonts/liberation-sans/OFL.txt | Red Hat, Inc.; Liberation Fonts contributors | Unmodified accompanying font licence | SIL OFL 1.1 |
| assets/locales/pending/drag-to-zoom.json | SolidCraft contributors | Original drag-to-zoom labels and translations | MIT OR Apache-2.0 |
## Code adapted from sibling projects ## Code adapted from sibling projects
@@ -868,11 +911,10 @@ copied into SolidCraft.
| Directory | Source | Licence | Changes | | Directory | Source | Licence | Changes |
|---|---|---|---| |---|---|---|---|
| vendor/accesskit_macos | accesskit_macos 0.26.3, https://github.com/AccessKit/accesskit (The AccessKit contributors) | MIT OR Apache-2.0 | the subclassing adapter and its tests from 0.27.2: dropping the adapter keeps AppKit's key-value observers (vendor/README.md) |
## Vendored renderer compatibility fix ## Vendored renderer compatibility fix
`vendor/egui-wgpu` is egui-wgpu 0.36.2 from https://github.com/emilk/egui `vendor/egui-wgpu` is egui-wgpu 0.37.0 from https://github.com/emilk/egui
(MIT OR Apache-2.0; both original licence texts are included). Rust sources and (MIT OR Apache-2.0; both original licence texts are included). Rust sources and
its original `egui.wgsl` shader are retained; no images or other artwork are copied. its original `egui.wgsl` shader are retained; no images or other artwork are copied.
SolidCraft's narrow patch selects a safe 1x MSAA path on the chosen OpenGL adapter SolidCraft's narrow patch selects a safe 1x MSAA path on the chosen OpenGL adapter
+1 -1
View File
@@ -279,7 +279,7 @@ mean something else, it needs a format change. **Add one file, and edit nothing
change's file, or any `v<N>/` folder: those are fixed once released. change's file, or any `v<N>/` folder: those are fixed once released.
That's all. The build counts the files: while any are pending it writes the next format number, That's all. The build counts the files: while any are pending it writes the next format number,
which no release reads, so a release refuses a design that has your change instead of losing it. which no release reads, so a release warns about a design that has your change and keeps what it can't read of it.
A file also lists the pending changes it has (`format_pending`), so a later development build A file also lists the pending changes it has (`format_pending`), so a later development build
runs only the steps that file is missing. Two pull requests that each add a change merge without runs only the steps that file is missing. Two pull requests that each add a change merge without
a conflict. `crates/doc/src/format/pending/README.md` has an example. a conflict. `crates/doc/src/format/pending/README.md` has an example.
Generated
+168 -163
View File
@@ -4,9 +4,9 @@ version = 4
[[package]] [[package]]
name = "accesskit" name = "accesskit"
version = "0.24.1" version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3b7f7f85a7e5f68090000ed7622545829afd484d210358702ae4cb97dd0c320" checksum = "4e883d1d28c5fd5568c79ed2d2bd48d9f2fd3945c8974ed0f53690ceddb051be"
dependencies = [ dependencies = [
"enumn", "enumn",
"serde", "serde",
@@ -15,12 +15,12 @@ dependencies = [
[[package]] [[package]]
name = "accesskit_atspi_common" name = "accesskit_atspi_common"
version = "0.18.1" version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e8c61bee90b42a772d39d06a740207dc71a4e780004ace1db8d99fb1baaa954" checksum = "24f5baf62e34a4a6c30e3d697e4782f821a7337049c44c3b40576a27dfbb580d"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_consumer 0.36.0", "accesskit_consumer",
"atspi-common", "atspi-common",
"phf", "phf",
"serde", "serde",
@@ -29,41 +29,37 @@ dependencies = [
[[package]] [[package]]
name = "accesskit_consumer" name = "accesskit_consumer"
version = "0.35.0" version = "0.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cf47daed85312e763fbf85ceca136e0d7abc68e0a7e12abe11f48172bc3b10" checksum = "f3da8f27636015191b2264ee1df681503170a632cafd832fdc1edfdd4e3a2fd3"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"hashbrown 0.16.1", "hashbrown 0.17.1",
] ]
[[package]] [[package]]
name = "accesskit_consumer" name = "accesskit_ios"
version = "0.36.0" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25e0d7e25d06f4dc21d1774d67146e9e80d6789216cbd4d1e88185b0095dba60" checksum = "a5280724673bbfa8b30a838c013500b719392989be3b97c5a9964062c252c232"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"hashbrown 0.16.1", "accesskit_consumer",
] "hashbrown 0.17.1",
"objc2 0.5.3",
[[package]] "objc2-foundation 0.2.2",
name = "accesskit_consumer" "objc2-ui-kit 0.2.2",
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d10a236f96f87d70732e44520046785431ef01d5bcd6b041317bfadd2f88245"
dependencies = [
"accesskit",
"hashbrown 0.16.1",
] ]
[[package]] [[package]]
name = "accesskit_macos" name = "accesskit_macos"
version = "0.26.3" version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "123828ceeec755b05255e3976cb0852993202de98a0626c97dd8d34246991f84"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_consumer 0.38.0", "accesskit_consumer",
"hashbrown 0.16.1", "hashbrown 0.17.1",
"objc2 0.5.3", "objc2 0.5.3",
"objc2-app-kit 0.2.2", "objc2-app-kit 0.2.2",
"objc2-foundation 0.2.2", "objc2-foundation 0.2.2",
@@ -71,9 +67,9 @@ dependencies = [
[[package]] [[package]]
name = "accesskit_unix" name = "accesskit_unix"
version = "0.21.1" version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b016ca8db0ea0ea2ceff29a9d6240391492d960716aa471967c00e8cc8cb197c" checksum = "30d5192871228c54f1b0fb4a85cef000e11a3804f25d2165f14afa0daa67f3f6"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_atspi_common", "accesskit_atspi_common",
@@ -89,13 +85,13 @@ dependencies = [
[[package]] [[package]]
name = "accesskit_windows" name = "accesskit_windows"
version = "0.32.1" version = "0.35.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff7009f1a532e917d66970a1e80c965140c6cfbbabbdde3d64e5431e6c78e21" checksum = "498668b90da9995302a0055aaecad4756932333da2ddef6baee1c00844c430fc"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_consumer 0.35.0", "accesskit_consumer",
"hashbrown 0.16.1", "hashbrown 0.17.1",
"static_assertions", "static_assertions",
"windows", "windows",
"windows-core", "windows-core",
@@ -103,11 +99,12 @@ dependencies = [
[[package]] [[package]]
name = "accesskit_winit" name = "accesskit_winit"
version = "0.32.2" version = "0.34.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fe9a94394896352cc4660ca2288bd4ef883d83238853c038b44070c8f134313" checksum = "cd4ab4437b520ff03088fbe48676a11e7d44a929535e64b31432c1073e48dbcc"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_ios",
"accesskit_macos", "accesskit_macos",
"accesskit_unix", "accesskit_unix",
"accesskit_windows", "accesskit_windows",
@@ -203,6 +200,7 @@ dependencies = [
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"windows-sys 0.60.2", "windows-sys 0.60.2",
"wl-clipboard-rs",
"x11rb", "x11rb",
] ]
@@ -687,42 +685,18 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
[[package]]
name = "calloop"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b32313e937c8721c9d17ee9bf60699a6402b4b7c2cb6ac1bee0ffcaa4b4e5e"
dependencies = [
"bitflags 2.13.2",
"polling",
"rustix 1.1.5",
"tracing",
]
[[package]] [[package]]
name = "calloop-wayland-source" name = "calloop-wayland-source"
version = "0.3.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
dependencies = [ dependencies = [
"calloop 0.13.0", "calloop",
"rustix 0.38.44", "rustix 0.38.44",
"wayland-backend", "wayland-backend",
"wayland-client", "wayland-client",
] ]
[[package]]
name = "calloop-wayland-source"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
dependencies = [
"calloop 0.14.5",
"rustix 1.1.5",
"wayland-backend",
"wayland-client",
]
[[package]] [[package]]
name = "cbc" name = "cbc"
version = "0.1.2" version = "0.1.2"
@@ -1123,9 +1097,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]] [[package]]
name = "ecolor" name = "ecolor"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0656a7530b9e2841ee7a5f983965bdd9840c32f4012f759cfd44b912cced6b34" checksum = "31bcbef0d4263a63eb32c4834e5d711613035ce1333468e107d928923e21e6e2"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"emath", "emath",
@@ -1134,9 +1108,9 @@ dependencies = [
[[package]] [[package]]
name = "eframe" name = "eframe"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ad41fac6e3149abb4866e93df37dbd33baa95db525c3368c944584e95a5dc2" checksum = "9c5642501a65ca657d05f00c643a5c14ff2346cb3818032bfe23d58e1f8e5f84"
dependencies = [ dependencies = [
"ahash", "ahash",
"bytemuck", "bytemuck",
@@ -1159,6 +1133,7 @@ dependencies = [
"profiling", "profiling",
"raw-window-handle", "raw-window-handle",
"ron", "ron",
"send_wrapper",
"serde", "serde",
"static_assertions", "static_assertions",
"wasm-bindgen", "wasm-bindgen",
@@ -1171,9 +1146,9 @@ dependencies = [
[[package]] [[package]]
name = "egui" name = "egui"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc938cc27cd911415e1e4d151bc56ff9df063d8db081374e87aeb805ea74b2ba" checksum = "bec9144f49b7a28b5f395d3147e325b4fe3e77ba686eac11d1bdf0a7da3f375f"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"ahash", "ahash",
@@ -1193,7 +1168,7 @@ dependencies = [
[[package]] [[package]]
name = "egui-wgpu" name = "egui-wgpu"
version = "0.36.2" version = "0.37.0"
dependencies = [ dependencies = [
"ahash", "ahash",
"bytemuck", "bytemuck",
@@ -1211,32 +1186,34 @@ dependencies = [
[[package]] [[package]]
name = "egui-winit" name = "egui-winit"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc" checksum = "e4e449f4c4a2a60c7ccb4ba7fa4078417bfe1f9ddc03b5e05ce75748e33a70de"
dependencies = [ dependencies = [
"accesskit_winit", "accesskit_winit",
"arboard", "arboard",
"block2 0.6.2",
"bytemuck", "bytemuck",
"egui", "egui",
"log", "log",
"objc2 0.6.5", "objc2 0.6.5",
"objc2-app-kit 0.3.2",
"objc2-foundation 0.3.2", "objc2-foundation 0.3.2",
"objc2-ui-kit 0.3.2", "objc2-ui-kit 0.3.2",
"profiling", "profiling",
"raw-window-handle", "raw-window-handle",
"serde", "serde",
"smithay-clipboard",
"web-time", "web-time",
"webbrowser", "webbrowser",
"windows-sys 0.61.2",
"winit", "winit",
] ]
[[package]] [[package]]
name = "egui_glow" name = "egui_glow"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "606ed4167daf341e5753d703285c4c1d562324b2c07aa8f405cd7d066fe58f3b" checksum = "9275ca5cc35a6b7c94e0e8cedf22542f66cb0cf45ed8ab2657c78ff49fec7268"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"egui", "egui",
@@ -1254,9 +1231,9 @@ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
[[package]] [[package]]
name = "emath" name = "emath"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52c8d4141cf0f60fb2f7aefaf352d3ffa5171ef0ab09731c64391801e95e48f1" checksum = "e73ce90f54750be8672c02be0743fe47530e6f251e066f0ee2869b59eb297af5"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"serde", "serde",
@@ -1330,9 +1307,9 @@ dependencies = [
[[package]] [[package]]
name = "epaint" name = "epaint"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0ec0308dc23130fc1a7d4623a8534c2ed069c6dc84e258ee4f3de99615aa1a3" checksum = "97bac86ae3dde93fc3951e790951caea739ff39a6c89d909cdaf1d9278dbb1bd"
dependencies = [ dependencies = [
"ahash", "ahash",
"bytemuck", "bytemuck",
@@ -1350,15 +1327,16 @@ dependencies = [
"skrifa", "skrifa",
"smallvec", "smallvec",
"unicode-general-category", "unicode-general-category",
"unicode-properties",
"unicode-segmentation", "unicode-segmentation",
"vello_cpu", "vello_cpu",
] ]
[[package]] [[package]]
name = "epaint_default_fonts" name = "epaint_default_fonts"
version = "0.36.2" version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773fa9c96dd0dbef887e39d0ed6177f141cce4d68e6041df77570aa3702dfa13" checksum = "cfc1cc505827f4c23eedc297975a0fd038268d41293f389dd8ff3b574aefab19"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
@@ -1444,6 +1422,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.1.10" version = "1.1.10"
@@ -1455,6 +1439,12 @@ dependencies = [
"zlib-rs", "zlib-rs",
] ]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]] [[package]]
name = "foldhash" name = "foldhash"
version = "0.2.0" version = "0.2.0"
@@ -1651,12 +1641,12 @@ dependencies = [
[[package]] [[package]]
name = "glifo" name = "glifo"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a" checksum = "282a26c1e23de04bdab3e34a21b6f877a479b96737792516b9b8b8f69b6661be"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"foldhash", "foldhash 0.2.0",
"hashbrown 0.17.1", "hashbrown 0.17.1",
"log", "log",
"peniko", "peniko",
@@ -1826,6 +1816,15 @@ dependencies = [
"smallvec", "smallvec",
] ]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash 0.1.5",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.1" version = "0.16.1"
@@ -1834,7 +1833,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [ dependencies = [
"allocator-api2", "allocator-api2",
"equivalent", "equivalent",
"foldhash", "foldhash 0.2.0",
] ]
[[package]] [[package]]
@@ -1843,7 +1842,7 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [ dependencies = [
"foldhash", "foldhash 0.2.0",
] ]
[[package]] [[package]]
@@ -2500,6 +2499,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "num" name = "num"
version = "0.4.3" version = "0.4.3"
@@ -2956,6 +2964,16 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "os_pipe"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@@ -3005,10 +3023,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "phf" name = "petgraph"
version = "0.13.1" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap",
]
[[package]]
name = "phf"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6"
dependencies = [ dependencies = [
"phf_macros", "phf_macros",
"phf_shared", "phf_shared",
@@ -3017,9 +3046,9 @@ dependencies = [
[[package]] [[package]]
name = "phf_generator" name = "phf_generator"
version = "0.13.1" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"phf_shared", "phf_shared",
@@ -3027,9 +3056,9 @@ dependencies = [
[[package]] [[package]]
name = "phf_macros" name = "phf_macros"
version = "0.13.1" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085"
dependencies = [ dependencies = [
"phf_generator", "phf_generator",
"phf_shared", "phf_shared",
@@ -3040,9 +3069,9 @@ dependencies = [
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.13.1" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89"
dependencies = [ dependencies = [
"siphasher", "siphasher",
] ]
@@ -3762,6 +3791,12 @@ version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "send_wrapper"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.229" version = "1.0.229"
@@ -3986,8 +4021,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"calloop 0.13.0", "calloop",
"calloop-wayland-source 0.3.0", "calloop-wayland-source",
"cursor-icon", "cursor-icon",
"libc", "libc",
"log", "log",
@@ -4004,44 +4039,6 @@ dependencies = [
"xkeysym", "xkeysym",
] ]
[[package]]
name = "smithay-client-toolkit"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0"
dependencies = [
"bitflags 2.13.2",
"calloop 0.14.5",
"calloop-wayland-source 0.4.1",
"cursor-icon",
"libc",
"log",
"memmap2",
"rustix 1.1.5",
"thiserror 2.0.21",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
"wayland-cursor",
"wayland-protocols",
"wayland-protocols-experimental",
"wayland-protocols-misc",
"wayland-protocols-wlr",
"wayland-scanner",
"xkeysym",
]
[[package]]
name = "smithay-clipboard"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226"
dependencies = [
"libc",
"smithay-client-toolkit 0.20.0",
"wayland-backend",
]
[[package]] [[package]]
name = "smol_str" name = "smol_str"
version = "0.2.2" version = "0.2.2"
@@ -4665,7 +4662,6 @@ version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [ dependencies = [
"log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@@ -4691,6 +4687,17 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tree_magic_mini"
version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
dependencies = [
"memchr",
"nom",
"petgraph",
]
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.25.1" version = "0.25.1"
@@ -4765,6 +4772,12 @@ version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
[[package]]
name = "unicode-properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993ad287eb20e8ba755312801cfe1413e0f25d604075863acaddca10b04c1833"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.13.3" version = "1.13.3"
@@ -4848,9 +4861,9 @@ dependencies = [
[[package]] [[package]]
name = "vello_common" name = "vello_common"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e9aed918117e8152c9eddfd8362d73c465c23f26c44786aa331707b8a64fa2" checksum = "bbb2141a2bca6e6d598e471fd4d1d7eed8e020aad6a28187edda07f091a325dd"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"fearless_simd", "fearless_simd",
@@ -4863,9 +4876,9 @@ dependencies = [
[[package]] [[package]]
name = "vello_cpu" name = "vello_cpu"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac7349e1f55f6b801c7c277958df4ea53e7f20f21e8014910ad888b2ecda93ea" checksum = "ace506ca414548966fcf3c283be94eb1cad8254de488791ee698bf438b0890a9"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"glifo", "glifo",
@@ -5040,32 +5053,6 @@ dependencies = [
"wayland-scanner", "wayland-scanner",
] ]
[[package]]
name = "wayland-protocols-experimental"
version = "20250721.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1"
dependencies = [
"bitflags 2.13.2",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols-misc"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8"
dependencies = [
"bitflags 2.13.2",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-scanner",
]
[[package]] [[package]]
name = "wayland-protocols-plasma" name = "wayland-protocols-plasma"
version = "0.3.12" version = "0.3.12"
@@ -5643,7 +5630,7 @@ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"block2 0.5.1", "block2 0.5.1",
"bytemuck", "bytemuck",
"calloop 0.13.0", "calloop",
"cfg_aliases", "cfg_aliases",
"concurrent-queue", "concurrent-queue",
"core-foundation 0.9.4", "core-foundation 0.9.4",
@@ -5664,7 +5651,7 @@ dependencies = [
"raw-window-handle", "raw-window-handle",
"redox_syscall 0.4.1", "redox_syscall 0.4.1",
"rustix 0.38.44", "rustix 0.38.44",
"smithay-client-toolkit 0.19.2", "smithay-client-toolkit",
"smol_str", "smol_str",
"tracing", "tracing",
"unicode-segmentation", "unicode-segmentation",
@@ -5707,6 +5694,24 @@ version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wl-clipboard-rs"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "959c7ac3b8afde864f7a7448ac16f29b2b83350b7eccbf77fb781c3999aa6848"
dependencies = [
"libc",
"log",
"os_pipe",
"rustix 1.1.5",
"thiserror 2.0.21",
"tree_magic_mini",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-protocols-wlr",
]
[[package]] [[package]]
name = "writeable" name = "writeable"
version = "0.6.4" version = "0.6.4"
+5 -7
View File
@@ -103,11 +103,12 @@ tiny-skia = { version = "0.12", default-features = false, features = ["std", "si
toml = "1" toml = "1"
# ui # ui
egui = "0.36" # default_fonts: the built-in Hack is the UI's symbol fallback (#2955); 0.37 no longer turns it on.
eframe = { version = "0.36", default-features = false, features = ["persistence"] } egui = { version = "0.37", features = ["default_fonts"] }
eframe = { version = "0.37", default-features = false, features = ["persistence"] }
# Instant/SystemTime that also work in the browser (std panics on wasm32-unknown-unknown). # Instant/SystemTime that also work in the browser (std panics on wasm32-unknown-unknown).
web-time = "1" web-time = "1"
egui-wgpu = "0.36" egui-wgpu = "0.37"
# the wgpu egui-wgpu uses, for compute (crates/gpu); backends come from the apps' features # the wgpu egui-wgpu uses, for compute (crates/gpu); backends come from the apps' features
wgpu = { version = "30", default-features = false, features = ["std", "wgsl"] } wgpu = { version = "30", default-features = false, features = ["std", "wgsl"] }
naga = { version = "30", default-features = false } naga = { version = "30", default-features = false }
@@ -162,12 +163,9 @@ debug = "line-tables-only"
egui-wgpu = { path = "vendor/egui-wgpu" } egui-wgpu = { path = "vendor/egui-wgpu" }
# Deliver trackpad pinch and rotation gestures on Wayland (zwp_pointer_gestures_v1), which # Deliver trackpad pinch and rotation gestures on Wayland (zwp_pointer_gestures_v1), which
# winit 0.30 never binds and eframe 0.36 still requires winit 0.30. # winit 0.30 never binds and eframe 0.37 still requires winit 0.30.
winit = { path = "vendor/winit" } winit = { path = "vendor/winit" }
# macOS: dropping the accessibility adapter leaves AppKit's key-value observers intact (#7535).
accesskit_macos = { path = "vendor/accesskit_macos" }
# Mutation testing (cargo-mutants, docs/mutation-testing.md): the ci profile with incremental # Mutation testing (cargo-mutants, docs/mutation-testing.md): the ci profile with incremental
# builds, since every mutant rebuilds the crates above the one it changes. # builds, since every mutant rebuilds the crates above the one it changes.
[profile.mutants] [profile.mutants]
+6
View File
@@ -225,6 +225,12 @@ completed drawings publish atomically. The browser still exports synchronously.
## Render foundation ## Render foundation
- Wood surface images (#1345): native CPU and GPU opaque rendering share physical
repeat frames and filtered mip chains. Imported maps retain exact bytes and
declared provenance in the design, reopen offline, and expose grain-angle
controls. Scalar face appearances suppress body maps. Planar projection and
CPU encoding/optical limits remain explicit; see [portable surfaces](docs/render-portable-surfaces-and-stages.md).
- Original starter appearances (#1722): 34 opaque recipes through existing commands, with six explicitly unavailable glass recipes and preserved legacy looks; see [the contract](docs/render-starter-appearances.md). - Original starter appearances (#1722): 34 opaque recipes through existing commands, with six explicitly unavailable glass recipes and preserved legacy looks; see [the contract](docs/render-starter-appearances.md).
- Bounded linear film accumulation (#1696) supplies caller-admitted mean/variance storage and complete-pass views; actual progressive consumers remain separate. See [the film contract](docs/render-film.md). - Bounded linear film accumulation (#1696) supplies caller-admitted mean/variance storage and complete-pass views; actual progressive consumers remain separate. See [the film contract](docs/render-film.md).
+275 -116
View File
@@ -1,18 +1,17 @@
Third-party software in SolidCraft Third-party software in SolidCraft
SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 537 crates below. SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 540 crates below.
Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files. Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files.
SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE. SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE.
accesskit 0.24.1 (MIT OR Apache-2.0) accesskit 0.25.2 (MIT OR Apache-2.0)
accesskit_atspi_common 0.18.1 (MIT OR Apache-2.0) accesskit_atspi_common 0.21.1 (MIT OR Apache-2.0)
accesskit_consumer 0.35.0 (MIT OR Apache-2.0) accesskit_consumer 0.39.2 (MIT OR Apache-2.0)
accesskit_consumer 0.36.0 (MIT OR Apache-2.0) accesskit_ios 0.2.2 (MIT OR Apache-2.0)
accesskit_consumer 0.38.0 (MIT OR Apache-2.0) accesskit_macos 0.27.2 (MIT OR Apache-2.0)
accesskit_macos 0.26.3 (MIT OR Apache-2.0) accesskit_unix 0.24.1 (MIT OR Apache-2.0)
accesskit_unix 0.21.1 (MIT OR Apache-2.0) accesskit_windows 0.35.2 (MIT OR Apache-2.0)
accesskit_windows 0.32.1 (MIT OR Apache-2.0) accesskit_winit 0.34.2 (Apache-2.0)
accesskit_winit 0.32.2 (Apache-2.0)
adler2 2.0.1 (0BSD OR MIT OR Apache-2.0) adler2 2.0.1 (0BSD OR MIT OR Apache-2.0)
aes 0.8.4 (MIT OR Apache-2.0) aes 0.8.4 (MIT OR Apache-2.0)
ahash 0.8.12 (MIT OR Apache-2.0) ahash 0.8.12 (MIT OR Apache-2.0)
@@ -65,9 +64,7 @@ cadmpeg-core 0.6.7 (Apache-2.0)
cadmpeg-ir 0.6.7 (Apache-2.0) cadmpeg-ir 0.6.7 (Apache-2.0)
cadmpeg-registry 0.6.7 (Apache-2.0) cadmpeg-registry 0.6.7 (Apache-2.0)
calloop 0.13.0 (MIT) calloop 0.13.0 (MIT)
calloop 0.14.5 (MIT)
calloop-wayland-source 0.3.0 (MIT) calloop-wayland-source 0.3.0 (MIT)
calloop-wayland-source 0.4.1 (MIT)
cbc 0.1.2 (MIT OR Apache-2.0) cbc 0.1.2 (MIT OR Apache-2.0)
cfg-if 1.0.5 (MIT OR Apache-2.0) cfg-if 1.0.5 (MIT OR Apache-2.0)
cgl 0.3.2 (MIT / Apache-2.0) cgl 0.3.2 (MIT / Apache-2.0)
@@ -109,21 +106,21 @@ document-features 0.2.12 (MIT OR Apache-2.0)
downcast-rs 1.2.1 (MIT/Apache-2.0) downcast-rs 1.2.1 (MIT/Apache-2.0)
dpi 0.1.2 (Apache-2.0 AND MIT) dpi 0.1.2 (Apache-2.0 AND MIT)
dyn-clone 1.0.20 (MIT OR Apache-2.0) dyn-clone 1.0.20 (MIT OR Apache-2.0)
ecolor 0.36.2 (MIT OR Apache-2.0) ecolor 0.37.0 (MIT OR Apache-2.0)
eframe 0.36.2 (MIT OR Apache-2.0) eframe 0.37.0 (MIT OR Apache-2.0)
egui 0.36.2 (MIT OR Apache-2.0) egui 0.37.0 (MIT OR Apache-2.0)
egui-wgpu 0.36.2 (MIT OR Apache-2.0) egui-wgpu 0.37.0 (MIT OR Apache-2.0)
egui-winit 0.36.2 (MIT OR Apache-2.0) egui-winit 0.37.0 (MIT OR Apache-2.0)
egui_glow 0.36.2 (MIT OR Apache-2.0) egui_glow 0.37.0 (MIT OR Apache-2.0)
either 1.19.0 (MIT OR Apache-2.0) either 1.19.0 (MIT OR Apache-2.0)
emath 0.36.2 (MIT OR Apache-2.0) emath 0.37.0 (MIT OR Apache-2.0)
encoding_rs 0.8.42 ((Apache-2.0 OR MIT) AND BSD-3-Clause) encoding_rs 0.8.42 ((Apache-2.0 OR MIT) AND BSD-3-Clause)
endi 1.1.1 (MIT) endi 1.1.1 (MIT)
enumflags2 0.7.12 (MIT OR Apache-2.0) enumflags2 0.7.12 (MIT OR Apache-2.0)
enumflags2_derive 0.7.12 (MIT OR Apache-2.0) enumflags2_derive 0.7.12 (MIT OR Apache-2.0)
enumn 0.1.14 (MIT OR Apache-2.0) enumn 0.1.14 (MIT OR Apache-2.0)
epaint 0.36.2 (MIT OR Apache-2.0) epaint 0.37.0 (MIT OR Apache-2.0)
epaint_default_fonts 0.36.2 ((MIT OR Apache-2.0) AND OFL-1.1 AND Ubuntu-font-1.0) epaint_default_fonts 0.37.0 ((MIT OR Apache-2.0) AND OFL-1.1 AND Ubuntu-font-1.0)
equivalent 1.0.2 (Apache-2.0 OR MIT) equivalent 1.0.2 (Apache-2.0 OR MIT)
errno 0.3.14 (MIT OR Apache-2.0) errno 0.3.14 (MIT OR Apache-2.0)
error-code 3.4.0 (BSL-1.0) error-code 3.4.0 (BSL-1.0)
@@ -134,7 +131,9 @@ fastrand 2.5.0 (Apache-2.0 OR MIT)
fax 0.2.7 (MIT) fax 0.2.7 (MIT)
fdeflate 0.3.7 (MIT OR Apache-2.0) fdeflate 0.3.7 (MIT OR Apache-2.0)
fearless_simd 0.4.1 (Apache-2.0 OR MIT) fearless_simd 0.4.1 (Apache-2.0 OR MIT)
fixedbitset 0.5.7 (MIT OR Apache-2.0)
flate2 1.1.10 (MIT OR Apache-2.0) flate2 1.1.10 (MIT OR Apache-2.0)
foldhash 0.1.5 (Zlib)
foldhash 0.2.0 (Zlib) foldhash 0.2.0 (Zlib)
font-types 0.12.6 (MIT OR Apache-2.0) font-types 0.12.6 (MIT OR Apache-2.0)
foreign-types 0.5.0 (MIT/Apache-2.0) foreign-types 0.5.0 (MIT/Apache-2.0)
@@ -154,7 +153,7 @@ getrandom 0.2.17 (MIT OR Apache-2.0)
getrandom 0.3.4 (MIT OR Apache-2.0) getrandom 0.3.4 (MIT OR Apache-2.0)
getrandom 0.4.3 (MIT OR Apache-2.0) getrandom 0.4.3 (MIT OR Apache-2.0)
gif 0.14.2 (MIT OR Apache-2.0) gif 0.14.2 (MIT OR Apache-2.0)
glifo 0.2.0 (Apache-2.0 OR MIT) glifo 0.3.0 (Apache-2.0 OR MIT)
glow 0.17.0 (MIT OR Apache-2.0 OR Zlib) glow 0.17.0 (MIT OR Apache-2.0 OR Zlib)
gltf 1.4.1 (MIT OR Apache-2.0) gltf 1.4.1 (MIT OR Apache-2.0)
gltf-derive 1.4.1 (MIT OR Apache-2.0) gltf-derive 1.4.1 (MIT OR Apache-2.0)
@@ -168,6 +167,7 @@ gpu-allocator 0.28.0 (MIT OR Apache-2.0)
guillotiere 0.7.0 (MIT/Apache-2.0) guillotiere 0.7.0 (MIT/Apache-2.0)
half 2.7.1 (MIT OR Apache-2.0) half 2.7.1 (MIT OR Apache-2.0)
harfrust 0.12.0 (MIT) harfrust 0.12.0 (MIT)
hashbrown 0.15.5 (MIT OR Apache-2.0)
hashbrown 0.16.1 (MIT OR Apache-2.0) hashbrown 0.16.1 (MIT OR Apache-2.0)
hashbrown 0.17.1 (MIT OR Apache-2.0) hashbrown 0.17.1 (MIT OR Apache-2.0)
hermit-abi 0.5.3 (MIT OR Apache-2.0) hermit-abi 0.5.3 (MIT OR Apache-2.0)
@@ -234,6 +234,7 @@ ndk-sys 0.6.0+11769913 (MIT OR Apache-2.0)
nix 0.29.0 (MIT) nix 0.29.0 (MIT)
nix 0.31.3 (MIT) nix 0.31.3 (MIT)
nohash-hasher 0.2.0 (Apache-2.0 OR MIT) nohash-hasher 0.2.0 (Apache-2.0 OR MIT)
nom 8.0.0 (MIT)
num 0.4.3 (MIT OR Apache-2.0) num 0.4.3 (MIT OR Apache-2.0)
num-bigint 0.4.8 (MIT OR Apache-2.0) num-bigint 0.4.8 (MIT OR Apache-2.0)
num-complex 0.4.6 (MIT OR Apache-2.0) num-complex 0.4.6 (MIT OR Apache-2.0)
@@ -275,15 +276,17 @@ orbclient 0.3.55 (MIT)
ordered-float 2.10.1 (MIT) ordered-float 2.10.1 (MIT)
ordered-float 5.5.0 (MIT) ordered-float 5.5.0 (MIT)
ordered-stream 0.2.0 (MIT OR Apache-2.0) ordered-stream 0.2.0 (MIT OR Apache-2.0)
os_pipe 1.2.3 (MIT)
parking 2.2.1 (Apache-2.0 OR MIT) parking 2.2.1 (Apache-2.0 OR MIT)
parking_lot 0.12.5 (MIT OR Apache-2.0) parking_lot 0.12.5 (MIT OR Apache-2.0)
parking_lot_core 0.9.12 (MIT OR Apache-2.0) parking_lot_core 0.9.12 (MIT OR Apache-2.0)
peniko 0.6.1 (Apache-2.0 OR MIT) peniko 0.6.1 (Apache-2.0 OR MIT)
percent-encoding 2.3.2 (MIT OR Apache-2.0) percent-encoding 2.3.2 (MIT OR Apache-2.0)
phf 0.13.1 (MIT) petgraph 0.8.3 (MIT OR Apache-2.0)
phf_generator 0.13.1 (MIT) phf 0.14.0 (MIT)
phf_macros 0.13.1 (MIT) phf_generator 0.14.0 (MIT)
phf_shared 0.13.1 (MIT) phf_macros 0.14.0 (MIT)
phf_shared 0.14.0 (MIT)
pin-project 1.1.13 (Apache-2.0 OR MIT) pin-project 1.1.13 (Apache-2.0 OR MIT)
pin-project-internal 1.1.13 (Apache-2.0 OR MIT) pin-project-internal 1.1.13 (Apache-2.0 OR MIT)
pin-project-lite 0.2.17 (Apache-2.0 OR MIT) pin-project-lite 0.2.17 (Apache-2.0 OR MIT)
@@ -352,6 +355,7 @@ security-framework 3.7.0 (MIT OR Apache-2.0)
security-framework-sys 2.17.0 (MIT OR Apache-2.0) security-framework-sys 2.17.0 (MIT OR Apache-2.0)
self_cell 1.3.0 (Apache-2.0 OR GPL-2.0-only) self_cell 1.3.0 (Apache-2.0 OR GPL-2.0-only)
semver 1.0.28 (MIT OR Apache-2.0) semver 1.0.28 (MIT OR Apache-2.0)
send_wrapper 0.6.0 (MIT/Apache-2.0)
serde 1.0.229 (MIT OR Apache-2.0) serde 1.0.229 (MIT OR Apache-2.0)
serde-value 0.7.0 (MIT) serde-value 0.7.0 (MIT)
serde_core 1.0.229 (MIT OR Apache-2.0) serde_core 1.0.229 (MIT OR Apache-2.0)
@@ -375,8 +379,6 @@ slab 0.4.12 (MIT)
slotmap 1.1.1 (Zlib) slotmap 1.1.1 (Zlib)
smallvec 1.16.2 (MIT OR Apache-2.0) smallvec 1.16.2 (MIT OR Apache-2.0)
smithay-client-toolkit 0.19.2 (MIT) smithay-client-toolkit 0.19.2 (MIT)
smithay-client-toolkit 0.20.0 (MIT)
smithay-clipboard 0.7.3 (MIT)
smol_str 0.2.2 (MIT OR Apache-2.0) smol_str 0.2.2 (MIT OR Apache-2.0)
solidcore 1.0.1 (Apache-2.0) solidcore 1.0.1 (Apache-2.0)
solidcore-record 0.1.0 (Apache-2.0) solidcore-record 0.1.0 (Apache-2.0)
@@ -409,6 +411,7 @@ toml_writer 1.1.3+spec-1.1.0 (MIT OR Apache-2.0)
tracing 0.1.44 (MIT) tracing 0.1.44 (MIT)
tracing-attributes 0.1.31 (MIT) tracing-attributes 0.1.31 (MIT)
tracing-core 0.1.36 (MIT) tracing-core 0.1.36 (MIT)
tree_magic_mini 3.2.2 (MIT)
ttf-parser 0.25.1 (MIT OR Apache-2.0) ttf-parser 0.25.1 (MIT OR Apache-2.0)
twox-hash 2.1.5 (MIT) twox-hash 2.1.5 (MIT)
type-map 0.5.1 (MIT/Apache-2.0) type-map 0.5.1 (MIT/Apache-2.0)
@@ -419,6 +422,7 @@ uds_windows 1.2.1 (MIT)
unicode-bidi 0.3.18 (MIT OR Apache-2.0) unicode-bidi 0.3.18 (MIT OR Apache-2.0)
unicode-general-category 1.1.0 (Apache-2.0) unicode-general-category 1.1.0 (Apache-2.0)
unicode-ident 1.0.26 ((MIT OR Apache-2.0) AND Unicode-3.0) unicode-ident 1.0.26 ((MIT OR Apache-2.0) AND Unicode-3.0)
unicode-properties 0.1.5 ((MIT OR Apache-2.0) AND Unicode-3.0)
unicode-segmentation 1.13.3 (MIT OR Apache-2.0) unicode-segmentation 1.13.3 (MIT OR Apache-2.0)
unicode-width 0.2.2 (MIT OR Apache-2.0) unicode-width 0.2.2 (MIT OR Apache-2.0)
untrusted 0.9.0 (ISC) untrusted 0.9.0 (ISC)
@@ -428,8 +432,8 @@ url 2.5.8 (MIT OR Apache-2.0)
utf8-zero 0.8.1 (MIT OR Apache-2.0) utf8-zero 0.8.1 (MIT OR Apache-2.0)
utf8_iter 1.0.4 (Apache-2.0 OR MIT) utf8_iter 1.0.4 (Apache-2.0 OR MIT)
uuid 1.27.0 (Apache-2.0 OR MIT) uuid 1.27.0 (Apache-2.0 OR MIT)
vello_common 0.1.0 (Apache-2.0 OR MIT) vello_common 0.2.0 (Apache-2.0 OR MIT)
vello_cpu 0.1.0 (Apache-2.0 OR MIT) vello_cpu 0.2.0 (Apache-2.0 OR MIT)
wasi 0.11.1+wasi-snapshot-preview1 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) wasi 0.11.1+wasi-snapshot-preview1 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT)
wasip2 1.0.4+wasi-0.2.12 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) wasip2 1.0.4+wasi-0.2.12 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT)
wasm-bindgen 0.2.129 (MIT OR Apache-2.0) wasm-bindgen 0.2.129 (MIT OR Apache-2.0)
@@ -442,8 +446,6 @@ wayland-client 0.31.15 (MIT)
wayland-csd-frame 0.3.0 (MIT) wayland-csd-frame 0.3.0 (MIT)
wayland-cursor 0.31.14 (MIT) wayland-cursor 0.31.14 (MIT)
wayland-protocols 0.32.13 (MIT) wayland-protocols 0.32.13 (MIT)
wayland-protocols-experimental 20250721.0.1 (MIT)
wayland-protocols-misc 0.3.12 (MIT)
wayland-protocols-plasma 0.3.12 (MIT) wayland-protocols-plasma 0.3.12 (MIT)
wayland-protocols-wlr 0.3.12 (MIT) wayland-protocols-wlr 0.3.12 (MIT)
wayland-scanner 0.31.11 (MIT) wayland-scanner 0.31.11 (MIT)
@@ -500,6 +502,7 @@ winit 0.30.13 (Apache-2.0)
winnow 1.0.4 (MIT) winnow 1.0.4 (MIT)
winreg 0.56.0 (MIT) winreg 0.56.0 (MIT)
wit-bindgen 0.57.1 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) wit-bindgen 0.57.1 (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT)
wl-clipboard-rs 0.9.5 (MIT OR Apache-2.0)
writeable 0.6.4 (Unicode-3.0) writeable 0.6.4 (Unicode-3.0)
x11-dl 2.21.0 (MIT) x11-dl 2.21.0 (MIT)
x11rb 0.13.2 (MIT OR Apache-2.0) x11rb 0.13.2 (MIT OR Apache-2.0)
@@ -570,13 +573,14 @@ num_enum 0.7.6, num_enum_derive 0.7.6, once_cell 1.21.4, ordered-stream 0.2.0, p
pin-project 1.1.13, pin-project-internal 1.1.13, pin-project-lite 0.2.17, piper 0.2.5, polling pin-project 1.1.13, pin-project-internal 1.1.13, pin-project-lite 0.2.17, piper 0.2.5, polling
3.11.0, portable-atomic 1.15.0, portable-atomic-util 0.2.8, proc-macro-crate 3.5.0, proc-macro2 3.11.0, portable-atomic 1.15.0, portable-atomic-util 0.2.8, proc-macro-crate 3.5.0, proc-macro2
1.0.107, quote 1.0.47, ref-cast 1.0.27, ref-cast-impl 1.0.27, rustc-hash 1.1.0, rustc-hash 2.1.3, 1.0.107, quote 1.0.47, ref-cast 1.0.27, ref-cast-impl 1.0.27, rustc-hash 1.1.0, rustc-hash 2.1.3,
rustix 0.38.44, rustix 1.1.5, rustversion 1.0.23, semver 1.0.28, serde 1.0.229, serde_core 1.0.229, rustix 0.38.44, rustix 1.1.5, rustversion 1.0.23, semver 1.0.28, send_wrapper 0.6.0, serde 1.0.229,
serde_derive 1.0.229, serde_derive_internals 0.30.0, serde_json 1.0.151, serde_path_to_error 0.1.20, serde_core 1.0.229, serde_derive 1.0.229, serde_derive_internals 0.30.0, serde_json 1.0.151,
serde_repr 0.1.21, simd_cesu8 1.2.0, smol_str 0.2.2, syn 2.0.119, syn 3.0.6, thiserror 1.0.69, serde_path_to_error 0.1.20, serde_repr 0.1.21, simd_cesu8 1.2.0, smol_str 0.2.2, syn 2.0.119, syn
thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.13.0, typeid 1.0.3, 3.0.6, thiserror 1.0.69, thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path
unicode-ident 1.0.26, utf8-zero 0.8.1, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, 0.13.0, typeid 1.0.3, unicode-ident 1.0.26, utf8-zero 0.8.1, wasi 0.11.1+wasi-snapshot-preview1,
wit-bindgen 0.57.1, x11-dl 2.21.0, xdg-home 1.3.0, zbus-lockstep 0.5.2, zbus-lockstep-macros 0.5.2, wasip2 1.0.4+wasi-0.2.12, wit-bindgen 0.57.1, x11-dl 2.21.0, xdg-home 1.3.0, zbus-lockstep 0.5.2,
zbus_names 3.0.0, zmij 1.0.23, zvariant_utils 2.1.0, zvariant_utils 4.2.0 zbus-lockstep-macros 0.5.2, zbus_names 3.0.0, zmij 1.0.23, zvariant_utils 2.1.0, zvariant_utils
4.2.0
================================================================================ ================================================================================
Permission is hereby granted, free of charge, to any Permission is hereby granted, free of charge, to any
@@ -1086,25 +1090,26 @@ ahash 0.8.12, arrayvec 0.7.8, async-channel 2.5.0, async-executor 1.14.0, async-
0.9.4, core-foundation-sys 0.8.7, core-graphics 0.23.2, core-graphics-types 0.1.3, core_detect 0.9.4, core-foundation-sys 0.8.7, core-graphics 0.23.2, core-graphics-types 0.1.3, core_detect
1.0.0, crossbeam-channel 0.5.17, crossbeam-deque 0.8.8, crossbeam-epoch 0.9.21, crossbeam-utils 1.0.0, crossbeam-channel 0.5.17, crossbeam-deque 0.8.8, crossbeam-epoch 0.9.21, crossbeam-utils
0.8.23, dbus-secret-service 4.1.0, displaydoc 0.2.7, either 1.19.0, equivalent 1.0.2, errno 0.3.14, 0.8.23, dbus-secret-service 4.1.0, displaydoc 0.2.7, either 1.19.0, equivalent 1.0.2, errno 0.3.14,
euclid 0.22.14, event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand 2.5.0, flate2 1.1.10, euclid 0.22.14, event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand 2.5.0, fixedbitset
form_urlencoded 1.2.2, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glow 0.17.0, gltf 1.4.1, 0.5.7, flate2 1.1.10, form_urlencoded 1.2.2, futures-lite 2.6.1, gethostname 1.1.0, gif 0.14.2, glow
gltf-derive 1.4.1, gltf-json 1.4.1, hashbrown 0.16.1, hashbrown 0.17.1, hermit-abi 0.5.3, httparse 0.17.0, gltf 1.4.1, gltf-derive 1.4.1, gltf-json 1.4.1, hashbrown 0.15.5, hashbrown 0.16.1,
1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap 2.14.2, itertools 0.15.0, js-sys 0.3.106, hashbrown 0.17.1, hermit-abi 0.5.3, httparse 1.10.1, idna 1.1.0, idna_adapter 1.2.2, indexmap
keyboard-types 0.8.3, khronos-egl 6.0.0, lazy_static 1.5.1, linux-raw-sys 0.12.1, linux-raw-sys 2.14.2, itertools 0.15.0, js-sys 0.3.106, keyboard-types 0.8.3, khronos-egl 6.0.0, lazy_static
0.4.15, lock_api 0.4.14, log 0.4.34, muda 0.21.2, num 0.4.3, num-bigint 0.4.8, num-complex 0.4.6, 1.5.1, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, lock_api 0.4.14, log 0.4.34, muda 0.21.2, num
num-integer 0.1.47, num-iter 0.1.46, num-rational 0.4.2, num-traits 0.2.19, once_cell 1.21.4, 0.4.3, num-bigint 0.4.8, num-complex 0.4.6, num-integer 0.1.47, num-iter 0.1.46, num-rational 0.4.2,
openssl-probe 0.2.1, ordered-stream 0.2.0, parking 2.2.1, parking_lot 0.12.5, parking_lot_core num-traits 0.2.19, once_cell 1.21.4, openssl-probe 0.2.1, ordered-stream 0.2.0, parking 2.2.1,
0.9.12, percent-encoding 2.3.2, piper 0.2.5, plain 0.2.3, png 0.18.1, polling 3.11.0, pollster parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, petgraph 0.8.3, piper 0.2.5,
0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core 1.13.0, renderdoc-sys 1.1.0, robust 1.2.0, ron plain 0.2.3, png 0.18.1, polling 3.11.0, pollster 0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core
0.12.2, roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, rustix 1.1.5, rustls 0.23.46, 1.13.0, renderdoc-sys 1.1.0, robust 1.2.0, ron 0.12.2, roxmltree 0.21.1, rustc-hash 1.1.0, rustix
rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard 1.2.0, secret-service 4.0.0, 0.38.44, rustix 1.1.5, rustls 0.23.46, rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard
security-framework 2.11.1, security-framework 3.7.0, security-framework-sys 2.17.0, 1.2.0, secret-service 4.0.0, security-framework 2.11.1, security-framework 3.7.0,
signal-hook-registry 1.4.8, simd_cesu8 1.2.0, smallvec 1.16.2, smol_str 0.2.2, stable_deref_trait security-framework-sys 2.17.0, send_wrapper 0.6.0, signal-hook-registry 1.4.8, simd_cesu8 1.2.0,
1.2.1, tempfile 3.27.0, ttf-parser 0.25.1, unicode-bidi 0.3.18, unicode-segmentation 1.13.3, smallvec 1.16.2, smol_str 0.2.2, stable_deref_trait 1.2.1, tempfile 3.27.0, ttf-parser 0.25.1,
unicode-width 0.2.2, url 2.5.8, uuid 1.27.0, wasi 0.11.1+wasi-snapshot-preview1, wasip2 unicode-bidi 0.3.18, unicode-properties 0.1.5, unicode-segmentation 1.13.3, unicode-width 0.2.2, url
1.0.4+wasi-0.2.12, wasm-bindgen 0.2.129, wasm-bindgen-futures 0.4.79, wasm-bindgen-macro 0.2.129, 2.5.8, uuid 1.27.0, wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen
wasm-bindgen-macro-support 0.2.129, wasm-bindgen-shared 0.2.129, web-sys 0.3.106, weezl 0.1.12, 0.2.129, wasm-bindgen-futures 0.4.79, wasm-bindgen-macro 0.2.129, wasm-bindgen-macro-support
wit-bindgen 0.57.1 0.2.129, wasm-bindgen-shared 0.2.129, web-sys 0.3.106, weezl 0.1.12, wit-bindgen 0.57.1,
wl-clipboard-rs 0.9.5
================================================================================ ================================================================================
Apache License Apache License
@@ -1310,7 +1315,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
================================================================================ ================================================================================
allocator-api2 0.2.21, async-trait 0.1.92, dyn-clone 1.0.20, enumn 0.1.14, glifo 0.2.0, itoa 1.0.18, allocator-api2 0.2.21, async-trait 0.1.92, dyn-clone 1.0.20, enumn 0.1.14, glifo 0.3.0, itoa 1.0.18,
libc 0.2.190, litrs 1.0.0, num_enum 0.7.6, num_enum_derive 0.7.6, proc-macro2 1.0.107, quote 1.0.47, libc 0.2.190, litrs 1.0.0, num_enum 0.7.6, num_enum_derive 0.7.6, proc-macro2 1.0.107, quote 1.0.47,
ref-cast 1.0.27, ref-cast-impl 1.0.27, rustc-hash 2.1.3, rustversion 1.0.23, semver 1.0.28, serde ref-cast 1.0.27, ref-cast-impl 1.0.27, rustc-hash 2.1.3, rustversion 1.0.23, semver 1.0.28, serde
1.0.229, serde_core 1.0.229, serde_derive 1.0.229, serde_derive_internals 0.30.0, serde_json 1.0.229, serde_core 1.0.229, serde_derive 1.0.229, serde_derive_internals 0.30.0, serde_json
@@ -1530,7 +1535,7 @@ android-activity 0.6.1, arboard 3.6.1, color 0.3.3, fdeflate 0.3.7, fearless_sim
image 0.25.10, image-webp 0.2.4, linebender_resource_handle 0.1.1, miniz_oxide 0.8.9, miniz_oxide image 0.25.10, image-webp 0.2.4, linebender_resource_handle 0.1.1, miniz_oxide 0.8.9, miniz_oxide
0.9.1, naga 30.0.1, naga-types 30.0.1, pin-project 1.1.13, pin-project-internal 1.1.13, 0.9.1, naga 30.0.1, naga-types 30.0.1, pin-project 1.1.13, pin-project-internal 1.1.13,
pin-project-lite 0.2.17, portable-atomic 1.15.0, portable-atomic-util 0.2.8, range-alloc 0.1.5, pin-project-lite 0.2.17, portable-atomic 1.15.0, portable-atomic-util 0.2.8, range-alloc 0.1.5,
raw-window-handle 0.6.2, simdutf8 0.1.5, vello_common 0.1.0, vello_cpu 0.1.0, wgpu 30.0.1, wgpu-core raw-window-handle 0.6.2, simdutf8 0.1.5, vello_common 0.2.0, vello_cpu 0.2.0, wgpu 30.0.1, wgpu-core
30.0.1, wgpu-core-deps-apple 30.0.1, wgpu-core-deps-emscripten 30.0.1, wgpu-core-deps-wasm 30.0.1, 30.0.1, wgpu-core-deps-apple 30.0.1, wgpu-core-deps-emscripten 30.0.1, wgpu-core-deps-wasm 30.0.1,
wgpu-core-deps-windows-linux-android 30.0.1, wgpu-hal 30.0.1, wgpu-naga-bridge 30.0.1, wgpu-types wgpu-core-deps-windows-linux-android 30.0.1, wgpu-hal 30.0.1, wgpu-naga-bridge 30.0.1, wgpu-types
30.0.1 30.0.1
@@ -2588,7 +2593,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
bit-set 0.10.0, bit-vec 0.9.1, downcast-rs 1.2.1, egui-wgpu 0.36.2, presser 0.3.1 bit-set 0.10.0, bit-vec 0.9.1, downcast-rs 1.2.1, egui-wgpu 0.37.0, presser 0.3.1
================================================================================ ================================================================================
Apache License Apache License
@@ -3134,7 +3139,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
calloop 0.13.0, calloop 0.14.5, smithay-client-toolkit 0.19.2, smithay-client-toolkit 0.20.0 calloop 0.13.0, smithay-client-toolkit 0.19.2
================================================================================ ================================================================================
Copyright (c) 2018 Victor Berger Copyright (c) 2018 Victor Berger
@@ -3158,7 +3163,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
================================================================================ ================================================================================
calloop-wayland-source 0.3.0, calloop-wayland-source 0.4.1 calloop-wayland-source 0.3.0
================================================================================ ================================================================================
Copyright (c) 2023 Kirill Chibisov Copyright (c) 2023 Kirill Chibisov
@@ -5231,7 +5236,7 @@ have been licensed under extremely permissive terms.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
================================================================================ ================================================================================
egui-wgpu 0.36.2 egui-wgpu 0.37.0
================================================================================ ================================================================================
Copyright (c) 2018-2021 Emil Ernerfeldt <emil.ernerfeldt@gmail.com> Copyright (c) 2018-2021 Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
@@ -5261,7 +5266,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
either 1.19.0, itertools 0.15.0 either 1.19.0, itertools 0.15.0, petgraph 0.8.3
================================================================================ ================================================================================
Copyright (c) 2015 Copyright (c) 2015
@@ -5709,6 +5714,36 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================
fixedbitset 0.5.7
================================================================================
Copyright (c) 2015-2017
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
flate2 1.1.10 flate2 1.1.10
================================================================================ ================================================================================
@@ -5740,7 +5775,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
foldhash 0.2.0 foldhash 0.1.5, foldhash 0.2.0
================================================================================ ================================================================================
Copyright (c) 2024 Orson Peters Copyright (c) 2024 Orson Peters
@@ -6511,7 +6546,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
================================================================================ ================================================================================
glifo 0.2.0 glifo 0.3.0
================================================================================ ================================================================================
Copyright 2025 the Vello Authors Copyright 2025 the Vello Authors
@@ -7138,7 +7173,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
================================================================================ ================================================================================
hashbrown 0.16.1, hashbrown 0.17.1 hashbrown 0.15.5, hashbrown 0.16.1, hashbrown 0.17.1
================================================================================ ================================================================================
Copyright (c) 2016 Amanieu d'Antras Copyright (c) 2016 Amanieu d'Antras
@@ -9459,6 +9494,31 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================================================
nom 8.0.0
================================================================================
Copyright (c) 2014-2019 Geoffroy Couprie
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
num_enum 0.7.6, num_enum_derive 0.7.6 num_enum 0.7.6, num_enum_derive 0.7.6
================================================================================ ================================================================================
@@ -9547,6 +9607,30 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================
os_pipe 1.2.3
================================================================================
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================================================ ================================================================================
parking 2.2.1 parking 2.2.1
================================================================================ ================================================================================
@@ -9562,7 +9646,7 @@ option. All files in the project carrying such notice may not be
copied, modified, or distributed except according to those terms. copied, modified, or distributed except according to those terms.
================================================================================ ================================================================================
phf 0.13.1, phf_generator 0.13.1, phf_macros 0.13.1, phf_shared 0.13.1 phf 0.14.0, phf_generator 0.14.0, phf_macros 0.14.0, phf_shared 0.14.0
================================================================================ ================================================================================
The MIT License (MIT) The MIT License (MIT)
@@ -12377,30 +12461,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================
smithay-clipboard 0.7.3
================================================================================
Copyright (c) 2018 Lucas Timmins & Victor Berger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================================================ ================================================================================
solidcore 1.0.1 solidcore 1.0.1
================================================================================ ================================================================================
@@ -12973,6 +13033,32 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================
tree_magic_mini 3.2.2
================================================================================
MIT License
Copyright (c) 2017 Aaron Hancock
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================================================ ================================================================================
ttf-parser 0.25.1 ttf-parser 0.25.1
================================================================================ ================================================================================
@@ -13795,7 +13881,7 @@ carrying such notice may not be copied, modified, or distributed except
according to those terms. according to those terms.
================================================================================ ================================================================================
unicode-bidi 0.3.18, unicode-segmentation 1.13.3, unicode-width 0.2.2 unicode-bidi 0.3.18, unicode-properties 0.1.5, unicode-segmentation 1.13.3, unicode-width 0.2.2
================================================================================ ================================================================================
Copyright (c) 2015 The Rust Project Developers Copyright (c) 2015 The Rust Project Developers
@@ -13869,7 +13955,51 @@ dealings in these Data Files or Software without prior written
authorization of the copyright holder. authorization of the copyright holder.
================================================================================ ================================================================================
unicode-segmentation 1.13.3, unicode-width 0.2.2 unicode-properties 0.1.5
================================================================================
UNICODE LICENSE V3
COPYRIGHT AND PERMISSION NOTICE
Copyright © 1991-2026 Unicode, Inc.
NOTICE TO USER: Carefully read the following legal agreement. BY
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining a
copy of data files and any associated documentation (the "Data Files") or
software and any associated documentation (the "Software") to deal in the
Data Files or Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Data Files or Software, and to permit persons to whom the
Data Files or Software are furnished to do so, provided that either (a)
this copyright and permission notice appear with all copies of the Data
Files or Software, or (b) this copyright and permission notice appear in
associated Documentation.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall
not be used in advertising or otherwise to promote the sale, use or other
dealings in these Data Files or Software without prior written
authorization of the copyright holder.
================================================================================
unicode-properties 0.1.5, unicode-segmentation 1.13.3, unicode-width 0.2.2
================================================================================ ================================================================================
Licensed under the Apache License, Version 2.0 Licensed under the Apache License, Version 2.0
@@ -14015,7 +14145,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
vello_common 0.1.0, vello_cpu 0.1.0 vello_common 0.2.0, vello_cpu 0.2.0
================================================================================ ================================================================================
Copyright 2020 the Vello Authors Copyright 2020 the Vello Authors
@@ -14046,8 +14176,8 @@ DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
wayland-backend 0.3.17, wayland-client 0.31.15, wayland-cursor 0.31.14, wayland-protocols 0.32.13, wayland-backend 0.3.17, wayland-client 0.31.15, wayland-cursor 0.31.14, wayland-protocols 0.32.13,
wayland-protocols-experimental 20250721.0.1, wayland-protocols-misc 0.3.12, wayland-protocols-plasma wayland-protocols-plasma 0.3.12, wayland-protocols-wlr 0.3.12, wayland-scanner 0.31.11, wayland-sys
0.3.12, wayland-protocols-wlr 0.3.12, wayland-scanner 0.31.11, wayland-sys 0.31.11 0.31.11
================================================================================ ================================================================================
Copyright (c) 2015 Elinor Berger Copyright (c) 2015 Elinor Berger
@@ -14942,6 +15072,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
================================================================================
wl-clipboard-rs 0.9.5
================================================================================
Copyright (c) 2019 Ivan Molodetskikh
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================================================ ================================================================================
x11rb 0.13.2, x11rb-protocol 0.13.2 x11rb 0.13.2, x11rb-protocol 0.13.2
================================================================================ ================================================================================
@@ -15967,15 +16127,14 @@ Crates whose package carries no licence file (their licence is named in Cargo.to
texts are as in SolidCraft's own LICENSE-MIT and LICENSE-APACHE) texts are as in SolidCraft's own LICENSE-MIT and LICENSE-APACHE)
================================================================================ ================================================================================
accesskit 0.24.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit 0.25.2: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_atspi_common 0.18.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_atspi_common 0.21.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_consumer 0.35.0: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_consumer 0.39.2: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_consumer 0.36.0: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_ios 0.2.2: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_consumer 0.38.0: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_macos 0.27.2: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_macos 0.26.3: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_unix 0.24.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_unix 0.21.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_windows 0.35.2: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_windows 0.32.1: MIT OR Apache-2.0 (https://github.com/AccessKit/accesskit) accesskit_winit 0.34.2: Apache-2.0 (https://github.com/AccessKit/accesskit)
accesskit_winit 0.32.2: Apache-2.0 (https://github.com/AccessKit/accesskit)
block2 0.5.1: MIT (https://github.com/madsmtm/objc2) block2 0.5.1: MIT (https://github.com/madsmtm/objc2)
block2 0.6.2: MIT (https://github.com/madsmtm/objc2) block2 0.6.2: MIT (https://github.com/madsmtm/objc2)
cadmpeg-codec-freecad 0.6.7: Apache-2.0 (https://github.com/cadmpeg/cadmpeg) cadmpeg-codec-freecad 0.6.7: Apache-2.0 (https://github.com/cadmpeg/cadmpeg)
@@ -15988,14 +16147,14 @@ cadmpeg-registry 0.6.7: Apache-2.0 (https://github.com/cadmpeg/cadmpeg)
clipboard-win 5.4.1: BSL-1.0 (https://github.com/DoumanAsh/clipboard-win) clipboard-win 5.4.1: BSL-1.0 (https://github.com/DoumanAsh/clipboard-win)
dispatch 0.2.0: MIT (http://github.com/SSheldon/rust-dispatch) dispatch 0.2.0: MIT (http://github.com/SSheldon/rust-dispatch)
dispatch2 0.3.1: Zlib OR Apache-2.0 OR MIT (https://github.com/madsmtm/objc2) dispatch2 0.3.1: Zlib OR Apache-2.0 OR MIT (https://github.com/madsmtm/objc2)
ecolor 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui) ecolor 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui)
eframe 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/eframe) eframe 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/eframe)
egui 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui) egui 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui)
egui-winit 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/egui-winit) egui-winit 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/egui-winit)
egui_glow 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/egui_glow) egui_glow 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/egui_glow)
emath 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/emath) emath 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/emath)
epaint 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/epaint) epaint 0.37.0: MIT OR Apache-2.0 (https://github.com/emilk/egui/tree/main/crates/epaint)
epaint_default_fonts 0.36.2: (MIT OR Apache-2.0) AND OFL-1.1 AND Ubuntu-font-1.0 (https://github.com/emilk/egui/tree/main/crates/epaint_default_fonts) epaint_default_fonts 0.37.0: (MIT OR Apache-2.0) AND OFL-1.1 AND Ubuntu-font-1.0 (https://github.com/emilk/egui/tree/main/crates/epaint_default_fonts)
jni 0.22.4: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-rs) jni 0.22.4: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-rs)
jni-macros 0.22.4: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-rs) jni-macros 0.22.4: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-rs)
jni-sys-macros 0.4.1: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-sys) jni-sys-macros 0.4.1: MIT OR Apache-2.0 (https://github.com/jni-rs/jni-sys)
@@ -16039,7 +16198,7 @@ spirv 0.4.0+sdk-1.4.341.0: Apache-2.0 (https://github.com/gfx-rs/rspirv)
Bundled fonts (SIL Open Font License, Version 1.1) Bundled fonts (SIL Open Font License, Version 1.1)
================================================================================ ================================================================================
- LiberationSans-Regular.ttf (assets/fonts/liberation-sans/LiberationSans-Regular.ttf) - LiberationSans-Regular.ttf (crates/sketch/assets/fonts/liberation-sans/LiberationSans-Regular.ttf)
Copyright 2012 Red Hat, Inc. (Liberation Fonts 2.x; digitized data Google) Copyright 2012 Red Hat, Inc. (Liberation Fonts 2.x; digitized data Google)
Source: https://github.com/liberationfonts Source: https://github.com/liberationfonts
+2 -2
View File
@@ -11,7 +11,7 @@ use std::process::{Command, ExitCode};
const TARGET: &str = "solidcraft-cli"; const TARGET: &str = "solidcraft-cli";
fn main() -> ExitCode { fn main() -> ExitCode {
eprintln!("solvecraft-cli is deprecated and will be removed in a later release: use solidcraft-cli"); solidcraft_engine::note!("solvecraft-cli is deprecated and will be removed in a later release: use solidcraft-cli");
let sibling = std::env::current_exe() let sibling = std::env::current_exe()
.ok() .ok()
.and_then(|exe| exe.parent().map(|dir| dir.join(format!("{TARGET}{}", std::env::consts::EXE_SUFFIX)))) .and_then(|exe| exe.parent().map(|dir| dir.join(format!("{TARGET}{}", std::env::consts::EXE_SUFFIX))))
@@ -23,7 +23,7 @@ fn main() -> ExitCode {
None => ExitCode::FAILURE, None => ExitCode::FAILURE,
}, },
Err(e) => { Err(e) => {
eprintln!("solvecraft-cli: could not run {}: {e}", program.to_string_lossy()); solidcraft_engine::note!("solvecraft-cli: could not run {}: {e}", program.to_string_lossy());
ExitCode::FAILURE ExitCode::FAILURE
} }
} }
+9 -6
View File
@@ -33,8 +33,8 @@ pub fn one(args: &[String]) -> Result<(), String> {
std::panic::set_hook(Box::new(|_| { std::panic::set_hook(Box::new(|_| {
PANICS.fetch_add(1, std::sync::atomic::Ordering::SeqCst); PANICS.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
})); }));
eprintln!("design {seed}"); solidcraft_engine::note!("design {seed}");
let run = fuzz::run_with(seed, steps, &mut |st| eprintln!("step {}", serde_json::to_string(st).unwrap_or_default())); let run = fuzz::run_with(seed, steps, &mut |st| solidcraft_engine::note!("step {}", serde_json::to_string(st).unwrap_or_default()));
let mut design = json!({ let mut design = json!({
"outcome": run.outcome, "outcome": run.outcome,
"steps": run.steps.iter().map(|s| s.kind).collect::<Vec<_>>(), "steps": run.steps.iter().map(|s| s.kind).collect::<Vec<_>>(),
@@ -45,13 +45,13 @@ pub fn one(args: &[String]) -> Result<(), String> {
if run.outcome.is_bug() { if run.outcome.is_bug() {
design["script"] = run.script(); design["script"] = run.script();
if minimise { if minimise {
eprintln!("minimise"); solidcraft_engine::note!("minimise");
let m = fuzz::minimise(&run); let m = fuzz::minimise(&run);
design["minimal"] = json!({"outcome": m.outcome, "steps": m.steps.iter().map(|s| s.kind).collect::<Vec<_>>(), "script": m.script()}); design["minimal"] = json!({"outcome": m.outcome, "steps": m.steps.iter().map(|s| s.kind).collect::<Vec<_>>(), "script": m.script()});
} }
} }
let (a, b) = solidcraft_engine::fuzz::boolean_shapes(seed); let (a, b) = solidcraft_engine::fuzz::boolean_shapes(seed);
eprintln!("boolean {seed} {} {}", serde_json::to_string(&a).unwrap_or_default(), serde_json::to_string(&b).unwrap_or_default()); solidcraft_engine::note!("boolean {seed} {} {}", serde_json::to_string(&a).unwrap_or_default(), serde_json::to_string(&b).unwrap_or_default());
let b = boolean_case(seed); let b = boolean_case(seed);
let bp = PANICS.swap(0, std::sync::atomic::Ordering::SeqCst); let bp = PANICS.swap(0, std::sync::atomic::Ordering::SeqCst);
println!("{}", json!({"seed": seed, "design": design, "boolean": b, "boolean_panics": bp})); println!("{}", json!({"seed": seed, "design": design, "boolean": b, "boolean_panics": bp}));
@@ -162,11 +162,14 @@ fn record(v: &Value, out_dir: Option<&str>) {
let d = &v["design"]; let d = &v["design"];
let bug = matches!(d["outcome"]["kind"].as_str(), Some("failed" | "panic" | "invalid" | "volume")); let bug = matches!(d["outcome"]["kind"].as_str(), Some("failed" | "panic" | "invalid" | "volume"));
if bug || v.get("timeout").is_some() || v.get("crash").is_some() { if bug || v.get("timeout").is_some() || v.get("crash").is_some() {
eprintln!("seed {seed}: {}", if bug { format!("{} {}", d["outcome"]["kind"], d["outcome"]["detail"]) } else { format!("{v}") }); solidcraft_engine::note!(
"seed {seed}: {}",
if bug { format!("{} {}", d["outcome"]["kind"], d["outcome"]["detail"]) } else { format!("{v}") }
);
} }
let bk = v["boolean"]["outcome"].as_str().unwrap_or("ok"); let bk = v["boolean"]["outcome"].as_str().unwrap_or("ok");
if bk != "ok" { if bk != "ok" {
eprintln!("seed {seed}: boolean {bk} {}", v["boolean"]["detail"]); solidcraft_engine::note!("seed {seed}: boolean {bk} {}", v["boolean"]["detail"]);
} }
if let Some(dir) = out_dir { if let Some(dir) = out_dir {
use std::io::Write; use std::io::Write;
+148 -35
View File
@@ -1,7 +1,7 @@
//! `kernel-cases --export=DIR`: one kernel rig case as a corpus entry for solidcore's rig. The //! `kernel-cases --export=DIR`: one kernel rig case as a corpus entry for solidcore's rig. The
//! case's commands run as the rig runs them while the kernel's operations are traced //! case's commands run as the rig runs them while the kernel's operations are traced
//! (`smlib_trace`); the entry holds the operation (or the chain of operations) that made the //! (`smlib_trace`); the entry holds every operation in execution order, including discarded
//! bodies the case ends with, each operand that came in as a record given as that record (the //! tool construction and handled refusals, each operand that came in as a record (the
//! B-rep record, solidcore-record's JSON), the fix set, the case's expected values and the rig's //! B-rep record, solidcore-record's JSON), the fix set, the case's expected values and the rig's
//! own result. A case whose result no kernel operation alone accounts for is written too, with //! own result. A case whose result no kernel operation alone accounts for is written too, with
//! the reasons, so nothing is dropped silently. //! the reasons, so nothing is dropped silently.
@@ -98,32 +98,6 @@ impl<'a> Trace<'a> {
} }
} }
/// The operations `ends` need, in the order they ran: each body's maker, and its operands' makers
/// in turn, back to bodies made from records. Operands made by nothing traced are listed in
/// `unknown`.
fn chain(t: &Trace<'_>, ends: &[u64], unknown: &mut BTreeSet<u64>) -> Vec<usize> {
let mut need = BTreeSet::new();
let mut todo: Vec<u64> = ends.to_vec();
while let Some(id) = todo.pop() {
if t.imports.contains_key(&id) {
continue;
}
match t.producer.get(&id) {
Some(&i) => {
if need.insert(i)
&& let Some(c) = t.calls.get(i)
{
todo.extend(c.1.iter().copied());
}
}
None => {
unknown.insert(id);
}
}
}
need.into_iter().collect()
}
/// The entry of case `dir`, run with result `out`, into `root/<area>/<id>.json`, and the fix set /// The entry of case `dir`, run with result `out`, into `root/<area>/<id>.json`, and the fix set
/// into `root/fixes.json`. /// into `root/fixes.json`.
pub fn write(root: &Path, dir: &str, out: &Value, capture: Capture) -> Result<(), String> { pub fn write(root: &Path, dir: &str, out: &Value, capture: Capture) -> Result<(), String> {
@@ -220,14 +194,18 @@ pub fn write(root: &Path, dir: &str, out: &Value, capture: Capture) -> Result<()
} }
let mut unknown = BTreeSet::new(); let mut unknown = BTreeSet::new();
let mut order = chain(&t, &ends, &mut unknown); let mut available: BTreeSet<u64> = t.imports.keys().copied().collect();
for (_, inputs, _, outputs) in &t.calls {
unknown.extend(inputs.iter().filter(|id| !available.contains(id)).copied());
if let Ok(made) = outputs {
available.extend(made.iter().copied());
}
}
unknown.extend(ends.iter().filter(|id| !available.contains(id)).copied());
if !unknown.is_empty() { if !unknown.is_empty() {
why_not.push(format!("operands made by nothing traced: {unknown:?}")); why_not.push(format!("operands made by nothing traced: {unknown:?}"));
} }
if let Some(i) = failed_call.filter(|i| !order.contains(i)) { // Operand records: every body a call takes, or the case ends with, that came in as a record.
order.push(i);
}
// Operand records: every body the chain takes, or the case ends with, that came in as a record.
let mut bodies = BTreeMap::new(); let mut bodies = BTreeMap::new();
let given = |id: u64, bodies: &mut BTreeMap<String, Value>| { let given = |id: u64, bodies: &mut BTreeMap<String, Value>| {
if let Some((record, trusted, splines)) = t.imports.get(&id) { if let Some((record, trusted, splines)) = t.imports.get(&id) {
@@ -235,14 +213,21 @@ pub fn write(root: &Path, dir: &str, out: &Value, capture: Capture) -> Result<()
} }
}; };
let mut calls: Vec<Value> = Vec::new(); let mut calls: Vec<Value> = Vec::new();
for (op, inputs, params, outputs) in order.iter().filter_map(|&i| t.calls.get(i)) { for (i, (op, inputs, params, outputs)) in t.calls.iter().enumerate() {
for &id in inputs.iter() { for &id in inputs.iter() {
given(id, &mut bodies); given(id, &mut bodies);
} }
let mut c = json!({"op": op, "inputs": inputs.iter().map(|i| format!("b{i}")).collect::<Vec<_>>(), "params": params}); let mut c = json!({"op": op, "inputs": inputs.iter().map(|i| format!("b{i}")).collect::<Vec<_>>(), "params": params});
match outputs { match outputs {
Ok(made) => c["outputs"] = json!(made.iter().map(|i| format!("b{i}")).collect::<Vec<_>>()), Ok(made) => c["outputs"] = json!(made.iter().map(|i| format!("b{i}")).collect::<Vec<_>>()),
Err(e) => c["error"] = json!(e), Err(e) => {
c["error"] = json!(e);
// The application handled this refusal. Replay must continue to any later
// calls and grade the final bodies, even when this was the last attempt.
if failed_call != Some(i) {
c["continued"] = json!(true);
}
}
} }
calls.push(c); calls.push(c);
} }
@@ -290,6 +275,134 @@ pub fn write(root: &Path, dir: &str, out: &Value, capture: Capture) -> Result<()
mod tests { mod tests {
use super::*; use super::*;
fn empty_record() -> Brep {
Brep { version: 4, tolerance: 1e-6, regions: Vec::new(), shells: Vec::new(), faces: Vec::new(), edges: Vec::new(), vertices: Vec::new() }
}
fn call(op: &'static str, inputs: &[u64], outputs: Result<Vec<u64>, String>) -> Event {
Event::Call { op, inputs: inputs.to_vec(), params: json!({}), outputs }
}
fn exported_case(name: &str, events: Vec<Event>, ran: Result<Vec<(String, Brep)>, String>) -> Value {
let root = std::env::temp_dir().join(format!("solidcraft-export-{}-{name}", std::process::id()));
let dir = root.join("tests/kernel-cases/traces").join(name);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("expected.json"), "{}").unwrap();
let output = root.join("export");
write(&output, dir.to_str().unwrap(), &json!({"status": "pass"}), Capture { events, ran: Some(ran) }).unwrap();
let entry = output.join("traces").join(format!("{name}.json"));
serde_json::from_str(&std::fs::read_to_string(entry).unwrap()).unwrap()
}
#[test]
fn discarded_tool_construction_is_exported_in_execution_order() {
let record = empty_record();
let e = exported_case(
"discarded-tool",
vec![call("extrude", &[], Ok(vec![1])), call("extrude", &[], Ok(vec![2])), Event::Export { id: 1, record: Box::new(record.clone()) }],
Ok(vec![("Part".into(), record)]),
);
assert_eq!(e["calls"].as_array().unwrap().len(), 2);
assert_eq!(e["calls"][0]["outputs"], json!(["b1"]));
assert_eq!(e["calls"][1]["outputs"], json!(["b2"]));
assert_eq!(e["traced_ops"], json!(["extrude", "extrude"]));
}
#[test]
fn handled_refusals_are_exported_without_becoming_terminal() {
let record = empty_record();
let e = exported_case(
"handled-refusal",
vec![
call("extrude", &[], Ok(vec![1])),
call("fillet", &[1], Err("too large".into())),
call("fillet", &[1], Ok(vec![2])),
Event::Export { id: 2, record: Box::new(record.clone()) },
],
Ok(vec![("Part".into(), record)]),
);
assert_eq!(e["calls"].as_array().unwrap().len(), 3);
assert_eq!(e["calls"][1]["error"], "too large");
assert_eq!(e["calls"][1]["continued"], true);
}
#[test]
fn a_handled_last_attempt_keeps_the_retained_body_as_the_result() {
let record = empty_record();
let e = exported_case(
"handled-last-attempt",
vec![
call("extrude", &[], Ok(vec![1])),
call("fillet", &[1], Err("too large".into())),
Event::Export { id: 1, record: Box::new(record.clone()) },
],
Ok(vec![("Part".into(), record)]),
);
assert_eq!(e["calls"][1]["continued"], true);
assert_eq!(e["result"], json!([{"body": "Part", "made": "b1"}]));
assert_eq!(e["operation_expressible"], true);
}
#[test]
fn the_final_refusal_still_ends_replay() {
let e = exported_case(
"terminal-refusal",
vec![
call("extrude", &[], Ok(vec![1])),
call("fillet", &[1], Err("too large".into())),
call("fillet", &[1], Err("no room".into())),
call("copy", &[1], Ok(vec![2])),
],
Err("no room".into()),
);
assert_eq!(e["calls"].as_array().unwrap().len(), 4);
assert_eq!(e["calls"][1]["continued"], true);
assert!(e["calls"][2].get("continued").is_none());
assert_eq!(e["outcome"]["kernel_error"], "no room");
}
#[test]
fn discarded_operations_still_require_their_operand_records() {
let record = empty_record();
let e = exported_case(
"missing-tool-operand",
vec![call("extrude", &[], Ok(vec![1])), call("copy", &[99], Ok(vec![2])), Event::Export { id: 1, record: Box::new(record.clone()) }],
Ok(vec![("Part".into(), record)]),
);
assert_eq!(e["operation_expressible"], false);
assert!(e["why_not"].as_array().unwrap().iter().any(|why| why.as_str().unwrap().contains("99")));
}
#[test]
fn discarded_operations_keep_their_imported_operands() {
let record = empty_record();
let e = exported_case(
"imported-tool-operand",
vec![
call("extrude", &[], Ok(vec![1])),
Event::Import { id: 9, record: Box::new(record.clone()), trusted: false, keeping_splines: true },
call("copy", &[9], Ok(vec![2])),
Event::Export { id: 1, record: Box::new(record.clone()) },
],
Ok(vec![("Part".into(), record.clone())]),
);
assert_eq!(e["bodies"]["b9"], json!({"record": record, "trusted": false, "keeping_splines": true}));
assert_eq!(e["calls"][1]["inputs"], json!(["b9"]));
assert_eq!(e["operation_expressible"], true);
}
#[test]
fn a_later_output_cannot_supply_an_earlier_discarded_operation() {
let record = empty_record();
let e = exported_case(
"future-tool-operand",
vec![call("copy", &[9], Ok(vec![2])), call("extrude", &[], Ok(vec![9])), Event::Export { id: 9, record: Box::new(record.clone()) }],
Ok(vec![("Part".into(), record)]),
);
assert_eq!(e["operation_expressible"], false);
assert!(e["why_not"].as_array().unwrap().iter().any(|why| why.as_str().unwrap().contains("9")));
}
#[test] #[test]
fn the_area_is_the_path_under_kernel_cases() { fn the_area_is_the_path_under_kernel_cases() {
assert_eq!(area_and_id("tests/kernel-cases/booleans/1894-x").unwrap(), ("booleans".into(), "1894-x".into())); assert_eq!(area_and_id("tests/kernel-cases/booleans/1894-x").unwrap(), ("booleans".into(), "1894-x".into()));
+79 -27
View File
@@ -18,7 +18,7 @@
//! solidcraft-cli oracle <case-dir>... replay recipes and compare with expected.json //! solidcraft-cli oracle <case-dir>... replay recipes and compare with expected.json
//! solidcraft-cli kernel-cases [--json] [--dumps=DIR] [--validation=MODE] <case-dir>... the kernel regression rig (tests/kernel-cases) //! solidcraft-cli kernel-cases [--json] [--dumps=DIR] [--validation=MODE] <case-dir>... the kernel regression rig (tests/kernel-cases)
//! solidcraft-cli mcp [--headless] [--in design|script] [--connect HOST:PORT [--token T]] [--allow-path DIR]... [--allow-any-path] //! solidcraft-cli mcp [--headless] [--in design|script] [--connect HOST:PORT [--token T]] [--allow-path DIR]... [--allow-any-path]
//! [--param-check off|warn|strict] //! [--param-check off|warn|strict] [--compact]
//! MCP server on stdio (docs/mcp.md) //! MCP server on stdio (docs/mcp.md)
//! solidcraft-cli mcp setup [--dry-run] [--client NAME] [--live] (alias: mcp install) add it to OpenCode, Claude Desktop, Claude Code, Cursor //! solidcraft-cli mcp setup [--dry-run] [--client NAME] [--live] (alias: mcp install) add it to OpenCode, Claude Desktop, Claude Code, Cursor
//! solidcraft-cli licences SolidCraft's licence and the third-party licences //! solidcraft-cli licences SolidCraft's licence and the third-party licences
@@ -62,9 +62,9 @@ struct Command {
} }
/// `run`'s lines in the usage. /// `run`'s lines in the usage.
const USAGE_RUN: &str = " solidcraft-cli run <script.json|design.sc|part.step> [--in design.sc|part.step] [--out FILE]... [--save FILE] [--quiet] [--results] [--timings] [--profile] [--profile-out trace.json] [--json-out FILE] [--allow-errors] [--validation each_step|each_feature|off]\n [--param-check off|warn|strict]\n solidcraft-cli run --in <design.sc|part.step> [--out FILE]...\n (a timeline feature that fails fails the run and nothing is written; --allow-errors writes anyway)\n (--validation: when SMLib's full check runs on the features computed (diagnostics.validation), default each_feature)\n (--param-check checks each step against its command's contract: warn reports on stderr, strict stops the run)\n (--timings prints {timings: [{index, command, ms}], total_ms} for a script, with --results its results too;\n --profile adds each command's profile: {boolean_ms, tessellate_ms, other_ms}, the kernel's share)\n (--profile also records where the time goes, SMLib's calls, kernel operations, features, commands and import stages,\n and prints the table to stderr: count, total, self time and longest per span; --profile-out FILE writes the spans\n as a Chrome trace for chrome://tracing or ui.perfetto.dev; SOLIDCRAFT_PROFILE=1 does the same for any command)\n"; const USAGE_RUN: &str = " solidcraft-cli run <script.json|design.sc|part.step> [--in design.sc|part.step] [--out FILE]... [--save FILE] [--quiet] [--results] [--timings] [--profile] [--profile-out trace.json] [--json-out FILE] [--allow-errors] [--validation each_step|each_feature|off]\n [--param-check off|warn|strict] [--quality standard|fine|finest]\n solidcraft-cli run --in <design.sc|part.step> [--out FILE]...\n (a timeline feature that fails fails the run and nothing is written; --allow-errors writes anyway)\n (--quality: how closely an STL, OBJ or 3MF --out follows curved faces, as file.export's quality: a chord of\n 2e-4, 5e-5 or 1e-5 of each body's size, never under 1 µm, default standard)\n (--validation: when SMLib's full check runs on the features computed (diagnostics.validation), default each_feature)\n (--param-check checks each step against its command's contract: warn reports on stderr, strict stops the run)\n (--timings prints {timings: [{index, command, ms}], total_ms} for a script, with --results its results too;\n --profile adds each command's profile: {boolean_ms, tessellate_ms, other_ms}, the kernel's share)\n (--profile also records where the time goes, SMLib's calls, kernel operations, features, commands and import stages,\n and prints the table to stderr: count, total, self time and longest per span; --profile-out FILE writes the spans\n as a Chrome trace for chrome://tracing or ui.perfetto.dev; SOLIDCRAFT_PROFILE=1 does the same for any command)\n";
/// `eval`'s lines in the usage. /// `eval`'s lines in the usage.
const USAGE_EVAL: &str = " solidcraft-cli eval <script.json|design.sc|part.step> [--in design.sc|part.step] [--json-out FILE] [--profile] [--profile-out trace.json] (alias: inspect)\n solidcraft-cli eval --in <script.json|design.sc|part.step> [--json-out FILE]\n (with both inputs, runs the positional script on --in before measuring; does not automatically save the modified design)\n (--json-out FILE writes the JSON that run (with --results, else the measurement) and eval print to FILE instead of stdout,\n as plain UTF-8: a shell's > can re-encode it, e.g. Windows PowerShell adds a byte-order mark)\n (--profile and --profile-out as for run)\n"; const USAGE_EVAL: &str = " solidcraft-cli eval <script.json|design.sc|part.step> [--in design.sc|part.step] [--json-out FILE] [--profile] [--profile-out trace.json] [--validation each_step|each_feature|off] (alias: inspect)\n solidcraft-cli eval --in <script.json|design.sc|part.step> [--json-out FILE]\n (with both inputs, runs the positional script on --in before measuring; does not automatically save the modified design)\n (--json-out FILE writes the JSON that run (with --results, else the measurement) and eval print to FILE instead of stdout,\n as plain UTF-8: a shell's > can re-encode it, e.g. Windows PowerShell adds a byte-order mark)\n (--profile, --profile-out and --validation as for run)\n";
/// `script`'s lines in the usage. /// `script`'s lines in the usage.
const USAGE_SCRIPT: &str = " solidcraft-cli script <design.sc|script.json> [--out script.json]\n (the design's history as a command script that eval and run replay)\n"; const USAGE_SCRIPT: &str = " solidcraft-cli script <design.sc|script.json> [--out script.json]\n (the design's history as a command script that eval and run replay)\n";
/// `bench-open`'s lines in the usage. /// `bench-open`'s lines in the usage.
@@ -91,7 +91,7 @@ const USAGE_KERNEL_CASES: &str = " solidcraft-cli kernel-cases <case-dir>... [-
const USAGE_FUZZ: &str = const USAGE_FUZZ: &str =
" solidcraft-cli fuzz [--from N] [--count N] [--jobs J] [--timeout S] [--steps N] [--minimise] [--out DIR] [--report FILE]\n"; " solidcraft-cli fuzz [--from N] [--count N] [--jobs J] [--timeout S] [--steps N] [--minimise] [--out DIR] [--report FILE]\n";
/// `mcp`'s lines in the usage. /// `mcp`'s lines in the usage.
const USAGE_MCP: &str = " solidcraft-cli mcp [--headless] [--in design.sc|script.json] [--connect 127.0.0.1:PORT [--token T]] [--allow-path DIR]... [--allow-any-path]\n [--param-check off|warn|strict] [--render-gpu]\n solidcraft-cli mcp setup [--dry-run] [--client opencode|claude-desktop|claude-code|cursor] [--live]\n (adds a `solidcraft` server, with this program's path, to each installed AI client; --live adds `solidcraft-live` for the running app; alias: mcp install)\n"; const USAGE_MCP: &str = " solidcraft-cli mcp [--headless] [--in design.sc|script.json] [--connect 127.0.0.1:PORT [--token T]] [--allow-path DIR]... [--allow-any-path]\n [--param-check off|warn|strict] [--render-gpu] [--compact]\n (--compact, SOLIDCRAFT_MCP_COMPACT=1 or the app's Preferences › AI (with --connect): compact tool output for\n agents: inspect_design summarises sketches and takes `sketches` by name and a `bodies` filter, and tool JSON\n is not pretty-printed; off by default)\n solidcraft-cli mcp setup [--dry-run] [--client opencode|claude-desktop|claude-code|cursor] [--live]\n (adds a `solidcraft` server, with this program's path, to each installed AI client; --live adds `solidcraft-live` for the running app; alias: mcp install)\n";
/// `crashes`'s lines in the usage. /// `crashes`'s lines in the usage.
const USAGE_CRASHES: &str = " solidcraft-cli crashes [list [--json] | show <id> | replay <id> | dir | clear [<id>]]\n"; const USAGE_CRASHES: &str = " solidcraft-cli crashes [list [--json] | show <id> | replay <id> | dir | clear [<id>]]\n";
/// `licences`'s lines in the usage. /// `licences`'s lines in the usage.
@@ -154,7 +154,7 @@ fn main() -> ExitCode {
} }
}; };
if let Err(e) = max_file_size(&mut args) { if let Err(e) = max_file_size(&mut args) {
eprintln!("error: {e}"); solidcraft_engine::note!("error: {e}");
return ExitCode::FAILURE; return ExitCode::FAILURE;
} }
let r = match args.first().map(String::as_str) { let r = match args.first().map(String::as_str) {
@@ -235,7 +235,7 @@ fn main() -> ExitCode {
match r { match r {
Ok(()) => ExitCode::SUCCESS, Ok(()) => ExitCode::SUCCESS,
Err(e) => { Err(e) => {
eprintln!("error: {e}"); solidcraft_engine::note!("error: {e}");
ExitCode::FAILURE ExitCode::FAILURE
} }
} }
@@ -318,6 +318,19 @@ fn load_checked(path: &str, check: solidcraft_engine::schema::ParamCheck) -> Res
/// `load_checked`, the features computed under `validation` (`diagnostics.validation`), which /// `load_checked`, the features computed under `validation` (`diagnostics.validation`), which
/// the session keeps. /// the session keeps.
fn load_with(path: &str, check: solidcraft_engine::schema::ParamCheck, validation: solidcraft_engine::kernel::Validation) -> Result<Session, String> { fn load_with(path: &str, check: solidcraft_engine::schema::ParamCheck, validation: solidcraft_engine::kernel::Validation) -> Result<Session, String> {
let s = read_session(path, check, validation)?;
// A newer SolidCraft's file opens all the same; stderr says so, stdout stays the caller's.
for warning in s.doc.newer_file.iter().flat_map(|file| file.warnings()) {
eprintln!("{path}: warning: {warning}");
}
Ok(s)
}
fn read_session(
path: &str,
check: solidcraft_engine::schema::ParamCheck,
validation: solidcraft_engine::kernel::Validation,
) -> Result<Session, String> {
let mut s = Session::default(); let mut s = Session::default();
s.param_check = check; s.param_check = check;
s.set_validation(validation); s.set_validation(validation);
@@ -351,7 +364,7 @@ fn run_script_warning(s: &mut Session, path: &str, script: &Value) -> Result<Vec
/// Step `step`'s `param_warnings` on stderr, one per line, named after the script at `path`. /// Step `step`'s `param_warnings` on stderr, one per line, named after the script at `path`.
fn print_param_warnings(path: &str, step: usize, r: &Value) { fn print_param_warnings(path: &str, step: usize, r: &Value) {
for w in r.get("param_warnings").and_then(Value::as_array).into_iter().flatten() { for w in r.get("param_warnings").and_then(Value::as_array).into_iter().flatten() {
eprintln!("{path}: step {}: {}", step + 1, w.as_str().unwrap_or_default()); solidcraft_engine::note!("{path}: step {}: {}", step + 1, w.as_str().unwrap_or_default());
} }
} }
@@ -438,11 +451,12 @@ fn cmd_run(args: &[String]) -> Result<(), String> {
known_args( known_args(
"run", "run",
args, args,
&["--in", "--out", "--save", "--json-out", "--param-check", "--profile-out", "--validation"], &["--in", "--out", "--save", "--json-out", "--param-check", "--profile-out", "--validation", "--quality"],
&["--quiet", "--results", "--timings", "--profile", "--allow-errors"], &["--quiet", "--results", "--timings", "--profile", "--allow-errors"],
true, true,
)?; )?;
let validation = validation_flag("run", args)?; let validation = validation_flag("run", args)?;
let quality = export_quality("run", args)?;
let base = flag(args, "--in"); let base = flag(args, "--in");
let path = positional(args); let path = positional(args);
if path.is_none() && base.is_none() { if path.is_none() && base.is_none() {
@@ -484,11 +498,17 @@ fn cmd_run(args: &[String]) -> Result<(), String> {
// A feature that fails leaves the bodies as they were before it (a parameter change can // A feature that fails leaves the bodies as they were before it (a parameter change can
// break a feature without failing the command that made it): writing them would hand out // break a feature without failing the command that made it): writing them would hand out
// the wrong part with success, so fail the run unless asked to write it anyway. // the wrong part with success, so fail the run unless asked to write it anyway.
// A feature only a newer SolidCraft can build isn't a broken design: saving the design keeps it
// and hands out no part. Exporting bodies without it would, so that still stops.
if !args.iter().any(|a| a == "--allow-errors") { if !args.iter().any(|a| a == "--allow-errors") {
timeline_ok(&s)?; timeline_ok(&s, flags(args, "--out").is_empty())?;
} }
for out in flags(args, "--out") { for out in flags(args, "--out") {
s.execute("file.export", &json!({"path": out})).map_err(|e| e.to_string())?; let mut params = json!({"path": out});
if let Some(q) = quality {
params["quality"] = json!(q);
}
s.execute("file.export", &params).map_err(|e| e.to_string())?;
} }
if let Some(p) = flag(args, "--save") { if let Some(p) = flag(args, "--save") {
s.execute("file.save_as", &json!({"path": p})).map_err(|e| e.to_string())?; s.execute("file.save_as", &json!({"path": p})).map_err(|e| e.to_string())?;
@@ -529,6 +549,20 @@ fn open_validating(
} }
} }
/// `--quality standard|fine|finest`: how closely the meshes `--out` writes (STL, OBJ, 3MF)
/// follow curved faces, as `file.export`'s `quality` (#12270). Checked before anything runs;
/// given twice it is refused, since only one quality can apply.
fn export_quality<'a>(cmd: &str, args: &'a [String]) -> Result<Option<&'a str>, String> {
if flags(args, "--quality").len() > 1 {
return Err(format!("{cmd}: --quality is given more than once"));
}
match flag(args, "--quality") {
Some(q) if solidcraft_engine::io::MeshQuality::from_name(q).is_some() => Ok(Some(q)),
Some(q) => Err(format!("{cmd}: --quality must be standard, fine or finest, not `{q}`")),
None => Ok(None),
}
}
/// `--validation MODE` (`diagnostics.validation`): the default, each_feature, when not given. /// `--validation MODE` (`diagnostics.validation`): the default, each_feature, when not given.
fn validation_flag(cmd: &str, args: &[String]) -> Result<solidcraft_engine::kernel::Validation, String> { fn validation_flag(cmd: &str, args: &[String]) -> Result<solidcraft_engine::kernel::Validation, String> {
match flag(args, "--validation") { match flag(args, "--validation") {
@@ -561,8 +595,12 @@ fn known_args(cmd: &str, args: &[String], valued: &[&str], switches: &[&str], po
} }
/// Every failing timeline feature, one per line, as an error; Ok when none fails. /// Every failing timeline feature, one per line, as an error; Ok when none fails.
fn timeline_ok(s: &Session) -> Result<(), String> { fn timeline_ok(s: &Session, skip_newer_features: bool) -> Result<(), String> {
let failed: Vec<String> = s.model.results.iter().filter_map(|r| r.error.as_ref().map(|e| format!(" {}: {e}", r.name))).collect(); let newer = |id: u64| {
skip_newer_features && s.doc.feature(id).is_some_and(|f| matches!(f.kind, solidcraft_engine::doc::FeatureKind::NewerFileFeature { .. }))
};
let failed: Vec<String> =
s.model.results.iter().filter(|r| !newer(r.id)).filter_map(|r| r.error.as_ref().map(|e| format!(" {}: {e}", r.name))).collect();
if failed.is_empty() { if failed.is_empty() {
return Ok(()); return Ok(());
} }
@@ -573,13 +611,15 @@ fn timeline_ok(s: &Session) -> Result<(), String> {
)) ))
} }
/// Runs `solidcraft-cli eval` (and its `inspect` alias), opening the input design or script with the requested `--validation` mode and reporting both `inspect.measure` and `document.inspect`.
fn cmd_eval(args: &[String]) -> Result<(), String> { fn cmd_eval(args: &[String]) -> Result<(), String> {
let json_out = json_out(args)?; let json_out = json_out(args)?;
known_args("eval", args, &["--in", "--json-out", "--profile-out"], &["--profile"], true)?; known_args("eval", args, &["--in", "--json-out", "--profile-out", "--validation"], &["--profile"], true)?;
let mut s = open(flag(args, "--in"), positional(args), solidcraft_engine::schema::ParamCheck::Off)?; let validation = validation_flag("eval", args)?;
let mut s = open_validating(flag(args, "--in"), positional(args), solidcraft_engine::schema::ParamCheck::Off, validation)?;
let m = s.execute("inspect.measure", &json!({})).map_err(|e| e.to_string())?; let m = s.execute("inspect.measure", &json!({})).map_err(|e| e.to_string())?;
let d = s.execute("document.inspect", &json!({})).map_err(|e| e.to_string())?; let d = s.execute("document.inspect", &json!({})).map_err(|e| e.to_string())?;
let out = json!({ let mut out = json!({
"body_count": m["body_count"], "body_count": m["body_count"],
"bodies": m["bodies"], "bodies": m["bodies"],
"total": m["total"], "total": m["total"],
@@ -587,6 +627,10 @@ fn cmd_eval(args: &[String]) -> Result<(), String> {
"params": d["params"], "params": d["params"],
"sketches": d["sketches"], "sketches": d["sketches"],
}); });
if let Some(file) = &s.doc.newer_file {
out["newer_file"] = file.report();
out["warnings"] = json!(file.warnings());
}
print_json(&out, json_out) print_json(&out, json_out)
} }
@@ -598,10 +642,10 @@ fn cmd_script(args: &[String]) -> Result<(), String> {
let out = flag(args, "--out"); let out = flag(args, "--out");
let r = s.execute("timeline.export_script", &json!({"path": out})).map_err(|e| e.to_string())?; let r = s.execute("timeline.export_script", &json!({"path": out})).map_err(|e| e.to_string())?;
for what in r["omitted"].as_array().into_iter().flatten().filter_map(Value::as_str) { for what in r["omitted"].as_array().into_iter().flatten().filter_map(Value::as_str) {
eprintln!("note: the script leaves out {what}"); solidcraft_engine::note!("note: the script leaves out {what}");
} }
match out { match out {
Some(out) => eprintln!("{out}: {} steps", r["steps"]), Some(out) => solidcraft_engine::note!("{out}: {} steps", r["steps"]),
None => println!("{}", pretty(&r["script"])), None => println!("{}", pretty(&r["script"])),
} }
Ok(()) Ok(())
@@ -632,7 +676,7 @@ fn cmd_gpu(args: &[String]) -> Result<(), String> {
); );
match s.lands_on { match s.lands_on {
Some(solidcraft_gpu::select::Landing::Cpu) => { Some(solidcraft_gpu::select::Landing::Cpu) => {
eprintln!("warning: {}", solidcraft_engine::capture::CPU_WARNING); solidcraft_engine::note!("warning: {}", solidcraft_engine::capture::CPU_WARNING);
Ok(()) Ok(())
} }
Some(_) => Ok(()), Some(_) => Ok(()),
@@ -709,7 +753,7 @@ fn cmd_snapshot(args: &[String]) -> Result<(), String> {
std::fs::write(out, &png.bytes).map_err(|e| format!("{out}: {e}"))?; std::fs::write(out, &png.bytes).map_err(|e| format!("{out}: {e}"))?;
let mut reply = json!({"path": out, "width": w, "height": h, "bytes": png.bytes.len(), "renderer": png.renderer}); let mut reply = json!({"path": out, "width": w, "height": h, "bytes": png.bytes.len(), "renderer": png.renderer});
if let Some(w) = solidcraft_engine::capture::warning(png.renderer) { if let Some(w) = solidcraft_engine::capture::warning(png.renderer) {
eprintln!("warning: {w}"); solidcraft_engine::note!("warning: {w}");
reply["warning"] = json!(w); reply["warning"] = json!(w);
} }
println!("{}", pretty(&reply)); println!("{}", pretty(&reply));
@@ -792,11 +836,15 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
return Err("mcp: --render-gpu installs a headless image host; a connected application owns its own device".into()); return Err("mcp: --render-gpu installs a headless image host; a connected application owns its own device".into());
} }
install_renderer(); install_renderer();
let options = solidcraft_mcp::Options::from_args_and_env(args).map_err(|e| format!("mcp: {e}"))?;
if options.compact {
eprintln!("solidcraft mcp: compact output (inspect_design summarises sketches; tool JSON is not pretty-printed)");
}
let scope = (!args.iter().any(|a| a == "--allow-any-path")) let scope = (!args.iter().any(|a| a == "--allow-any-path"))
.then(|| solidcraft_mcp::agent_scope(flags(args, "--allow-path").into_iter().map(std::path::PathBuf::from))); .then(|| solidcraft_mcp::agent_scope(flags(args, "--allow-path").into_iter().map(std::path::PathBuf::from)));
if let Some(s) = &scope { if let Some(s) = &scope {
let roots: Vec<String> = s.roots().iter().map(|r| r.display().to_string()).collect(); let roots: Vec<String> = s.roots().iter().map(|r| r.display().to_string()).collect();
eprintln!( solidcraft_engine::note!(
"solidcraft mcp: files limited to {} and the folders of designs opened or saved here (--allow-path DIR adds one, --allow-any-path lifts the limit)", "solidcraft mcp: files limited to {} and the folders of designs opened or saved here (--allow-path DIR adds one, --allow-any-path lifts the limit)",
roots.join(", ") roots.join(", ")
); );
@@ -804,7 +852,7 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
.and_then(|p| std::path::Path::new(p).parent()) .and_then(|p| std::path::Path::new(p).parent())
.map(|d| if d.as_os_str().is_empty() { std::path::Path::new(".") } else { d }); .map(|d| if d.as_os_str().is_empty() { std::path::Path::new(".") } else { d });
if let Some(why) = design_dir.and_then(solidcraft_engine::io::vfs::design_folder_refusal) { if let Some(why) = design_dir.and_then(solidcraft_engine::io::vfs::design_folder_refusal) {
eprintln!("solidcraft mcp: the design's folder is left out because {why}; add it with --allow-path if you mean it"); solidcraft_engine::note!("solidcraft mcp: the design's folder is left out because {why}; add it with --allow-path if you mean it");
} }
} }
// How calls that break a command's parameter contract are treated, headless or bridged. // How calls that break a command's parameter contract are treated, headless or bridged.
@@ -818,7 +866,7 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
// Serve without the app too: the tools connect once it runs, and say it isn't until then. // Serve without the app too: the tools connect once it runs, and say it isn't until then.
let mut remote = solidcraft_mcp::Remote::new(addr, flag(args, "--token")).with_param_check(param_check); let mut remote = solidcraft_mcp::Remote::new(addr, flag(args, "--token")).with_param_check(param_check);
if let Err(e) = remote.try_connect() { if let Err(e) = remote.try_connect() {
eprintln!( solidcraft_engine::note!(
"solidcraft mcp: no SolidCraft app at {addr} yet ({e}); start it with `solidcraft --control {port}` \ "solidcraft mcp: no SolidCraft app at {addr} yet ({e}); start it with `solidcraft --control {port}` \
(or SOLIDCRAFT_CONTROL_PORT={port}), tool calls connect once it runs" (or SOLIDCRAFT_CONTROL_PORT={port}), tool calls connect once it runs"
); );
@@ -835,9 +883,9 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
(None, None) => { (None, None) => {
let auto = !args.iter().any(|a| a == "--headless"); let auto = !args.iter().any(|a| a == "--headless");
if auto && let Some(port) = discover_app() { if auto && let Some(port) = discover_app() {
eprintln!("solidcraft mcp: bridged to the running app at 127.0.0.1:{port} (--headless starts a session of its own)"); solidcraft_engine::note!("solidcraft mcp: bridged to the running app at 127.0.0.1:{port} (--headless starts a session of its own)");
let remote = solidcraft_mcp::Remote::new(&format!("127.0.0.1:{port}"), flag(args, "--token")).with_param_check(param_check); let remote = solidcraft_mcp::Remote::new(&format!("127.0.0.1:{port}"), flag(args, "--token")).with_param_check(param_check);
return serve_mcp(Box::new(remote), scope); return serve_mcp(Box::new(remote), scope, options);
} }
let mut headless = solidcraft_mcp::Headless::default(); let mut headless = solidcraft_mcp::Headless::default();
headless.session.param_check = param_check; headless.session.param_check = param_check;
@@ -852,13 +900,17 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
} }
} }
}; };
serve_mcp(backend, scope) serve_mcp(backend, scope, options)
} }
fn serve_mcp(backend: Box<dyn solidcraft_mcp::Backend>, scope: Option<solidcraft_engine::io::vfs::PathScope>) -> Result<(), String> { fn serve_mcp(
backend: Box<dyn solidcraft_mcp::Backend>,
scope: Option<solidcraft_engine::io::vfs::PathScope>,
options: solidcraft_mcp::Options,
) -> Result<(), String> {
let stdin = std::io::stdin(); let stdin = std::io::stdin();
let stdout = std::io::stdout(); let stdout = std::io::stdout();
solidcraft_mcp::Server::new(backend).with_path_scope(scope).serve(stdin.lock(), stdout.lock()).map_err(|e| e.to_string()) solidcraft_mcp::Server::new(backend).with_path_scope(scope).with_options(options).serve(stdin.lock(), stdout.lock()).map_err(|e| e.to_string())
} }
/// The port of the running desktop app: the one its discovery file names, if something listens /// The port of the running desktop app: the one its discovery file names, if something listens
+23
View File
@@ -188,3 +188,26 @@ fn max_file_size_raises_the_limit_and_refuses_bad_sizes() {
assert!(!output.status.success() && !stderr.contains("too large"), "{stderr}"); assert!(!output.status.success() && !stderr.contains("too large"), "{stderr}");
let _ = std::fs::remove_dir_all(&dir); let _ = std::fs::remove_dir_all(&dir);
} }
/// #10111: a line for a stderr whose reader has gone (the pipe closed before it, as an agent may
/// leave the MCP server's, and the app that one starts) is dropped, and the command ends as it
/// would with stderr open: here a script that isn't there fails with 1, where `eprintln!`
/// panicked with "failed printing to stderr" (101).
#[test]
fn a_closed_stderr_does_not_stop_the_cli() {
for _ in 0..5 {
let mut child = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"))
.args(["run", "no-such-script.json"])
.stdout(Stdio::null())
.stderr(Stdio::piped())
.spawn()
.unwrap();
drop(child.stderr.take());
assert_eq!(child.wait().unwrap().code(), Some(1));
}
// The old name's alias writes its deprecation notice first: an agent still configured with
// `solvecraft-cli mcp` must get the server, not that panic.
let mut child = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).arg("--help").stdout(Stdio::null()).stderr(Stdio::piped()).spawn().unwrap();
drop(child.stderr.take());
assert_eq!(child.wait().unwrap().code(), Some(0));
}
+48
View File
@@ -0,0 +1,48 @@
//! `mcp --compact` and `SOLIDCRAFT_MCP_COMPACT` turn on compact tool output; without them the
//! server's tools are as they always were.
use std::io::Write;
use std::process::{Command, Stdio};
use serde_json::{Value, json};
/// `inspect_design`'s input schema as `solidcraft-cli mcp` with `args` and `env` lists it, or
/// the server's stderr when it does not start.
fn inspect_schema(args: &[&str], env: Option<&str>) -> Result<Value, String> {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"));
// --headless: never bridge to (and read the preference of) an app the developer has running.
cmd.args(["mcp", "--headless", "--allow-any-path"]).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped());
match env {
Some(v) => cmd.env("SOLIDCRAFT_MCP_COMPACT", v),
None => cmd.env_remove("SOLIDCRAFT_MCP_COMPACT"),
};
let mut child = cmd.spawn().unwrap();
{
let mut stdin = child.stdin.take().unwrap();
// The server may refuse to start and close stdin first.
let _ = writeln!(stdin, "{}", json!({"jsonrpc": "2.0", "id": 1, "method": "tools/list"}));
}
let out = child.wait_with_output().unwrap();
if !out.status.success() {
return Err(String::from_utf8_lossy(&out.stderr).into_owned());
}
let reply: Value = serde_json::from_slice(&out.stdout).unwrap();
let tools = reply["result"]["tools"].as_array().cloned().unwrap_or_default();
Ok(tools.into_iter().find(|t| t["name"] == "inspect_design").map(|t| t["inputSchema"].clone()).unwrap_or(Value::Null))
}
#[test]
fn compact_output_is_off_unless_asked() {
let plain = inspect_schema(&[], None).unwrap();
assert_eq!(plain["properties"]["sketches"]["type"], "boolean", "{plain}");
assert!(plain["properties"].get("bodies").is_none(), "{plain}");
assert_eq!(inspect_schema(&[], Some("0")).unwrap(), plain);
for (args, env) in [(&["--compact"][..], None), (&[][..], Some("1")), (&[][..], Some("true"))] {
let compact = inspect_schema(args, env).unwrap();
assert!(compact["properties"]["bodies"].is_object(), "{args:?} {env:?}: {compact}");
}
let e = inspect_schema(&[], Some("maybe")).unwrap_err();
assert!(e.contains("SOLIDCRAFT_MCP_COMPACT"), "{e}");
}
+34 -13
View File
@@ -60,15 +60,25 @@ fn mcp_connect_serves_before_the_app_runs_and_reaches_it_once_it_does() {
let listener = TcpListener::bind(&addr).unwrap(); let listener = TcpListener::bind(&addr).unwrap();
let app = std::thread::spawn(move || { let app = std::thread::spawn(move || {
let (stream, _) = listener.accept().unwrap(); let (stream, _) = listener.accept().unwrap();
let mut line = String::new(); let mut lines = BufReader::new(stream.try_clone().unwrap());
BufReader::new(stream.try_clone().unwrap()).read_line(&mut line).unwrap(); loop {
let req: Value = serde_json::from_str(&line).unwrap(); let mut line = String::new();
let reply = if req["token"] == json!(token) { lines.read_line(&mut line).unwrap();
json!({"id": req["id"], "ok": true, "result": {"bodies": [], "method": req["method"]}}) let req: Value = serde_json::from_str(&line).unwrap();
} else { // The server first asks for the agents' output options (the compact preference: off).
json!({"id": req["id"], "ok": false, "error": format!("unauthorized: token {}", req["token"])}) let options = req["method"] == "mcp.options";
}; let reply = if req["token"] != json!(token) {
writeln!(&stream, "{reply}").unwrap(); json!({"id": req["id"], "ok": false, "error": format!("unauthorized: token {}", req["token"])})
} else if options {
json!({"id": req["id"], "ok": true, "result": {"compact": false}})
} else {
json!({"id": req["id"], "ok": true, "result": {"bodies": [], "method": req["method"]}})
};
writeln!(&stream, "{reply}").unwrap();
if !options {
break;
}
}
}); });
let r = ask(4, "tools/call", measure); let r = ask(4, "tools/call", measure);
assert_ne!(r["result"]["isError"], true, "{r}"); assert_ne!(r["result"]["isError"], true, "{r}");
@@ -111,10 +121,21 @@ fn mcp_without_arguments_finds_the_running_app() {
break (stream, line); break (stream, line);
} }
}; };
let req: Value = serde_json::from_str(&line).unwrap(); let mut lines = BufReader::new(stream.try_clone().unwrap());
let ok = req["token"] == json!(token); let mut line = line;
let reply = json!({"id": req["id"], "ok": ok, "result": {"bodies": [], "method": req["method"]}, "error": "unauthorized"}); // The server first asks for the agents' output options (the compact preference: off).
writeln!(&stream, "{reply}").unwrap(); loop {
let req: Value = serde_json::from_str(&line).unwrap();
let ok = req["token"] == json!(token);
let options = req["method"] == "mcp.options";
let result = if options { json!({"compact": false}) } else { json!({"bodies": [], "method": req["method"]}) };
writeln!(&stream, "{}", json!({"id": req["id"], "ok": ok, "result": result, "error": "unauthorized"})).unwrap();
if !options {
break;
}
line.clear();
lines.read_line(&mut line).unwrap();
}
}); });
let mut child = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")) let mut child = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"))
.args(["mcp", "--allow-any-path"]) .args(["mcp", "--allow-any-path"])
+86 -19
View File
@@ -67,6 +67,9 @@ fn run_rejects_invalid_options_before_script_execution_or_output_writes() {
(&["--out", "--quiet"][..], "--out needs a value"), (&["--out", "--quiet"][..], "--out needs a value"),
(&["--ouut", "part.step"][..], "doesn't take --ouut"), (&["--ouut", "part.step"][..], "doesn't take --ouut"),
(&["--unknown"][..], "doesn't take --unknown"), (&["--unknown"][..], "doesn't take --unknown"),
(&["--quality"][..], "--quality needs a value"),
(&["--quality", "best"][..], "--quality must be standard, fine or finest, not `best`"),
(&["--quality", "standard", "--quality", "best"][..], "--quality is given more than once"),
]; ];
for existing in [false, true] { for existing in [false, true] {
let saved = dir.0.join(format!("{existing}.solidcraft")); let saved = dir.0.join(format!("{existing}.solidcraft"));
@@ -159,7 +162,7 @@ fn cli_loads_both_design_encodings_by_contents() {
} }
/// #1369: a pending concept that did not land in the numbered release must not be silently /// #1369: a pending concept that did not land in the numbered release must not be silently
/// dropped on open/resave, in either encoding or before replacing an existing destination. /// dropped on open/resave, in either encoding: it opens with a warning, and saving keeps it.
#[test] #[test]
fn unknown_pending_concepts_preserve_the_open_design_and_output_files() { fn unknown_pending_concepts_preserve_the_open_design_and_output_files() {
use solidcraft_engine::{Session, doc, io}; use solidcraft_engine::{Session, doc, io};
@@ -173,34 +176,29 @@ fn unknown_pending_concepts_preserve_the_open_design_and_output_files() {
let source = dir.0.join(format!("experimental-{version}.{extension}")); let source = dir.0.join(format!("experimental-{version}.{extension}"));
std::fs::write(&source, &bytes).unwrap(); std::fs::write(&source, &bytes).unwrap();
let mut session = Session::default(); let mut session = Session::default();
session.execute("solid.box", &json!({"length": 2, "width": 3, "height": 4})).unwrap(); // It opens, and the reply says what it is.
let original = session.doc.clone(); let reply = session.execute("doc.open", &json!({"path": source})).unwrap();
let original_path = session.path.clone(); let notice = reply["newer_file"]["notice"].as_str().unwrap().to_string();
let undo = session.undo.len(); assert!(notice.contains("experimental-card") && notice.starts_with("Saved by a newer SolidCraft"), "{notice}");
let dirty = session.is_dirty(); assert_eq!(reply["warnings"][0], notice.as_str());
let err = session.execute("doc.open", &json!({"path": source})).unwrap_err().to_string(); assert_eq!(session.doc.name, "Experimental");
assert!(err.contains("experimental-card") && err.contains("update SolidCraft"), "{err}");
assert_eq!(session.doc, original);
assert_eq!(session.path, original_path);
assert_eq!(session.undo.len(), undo);
assert_eq!(session.is_dirty(), dirty);
for existing in [false, true] { for existing in [false, true] {
let destination = dir.0.join(format!("output-{version}-{extension}-{existing}.{extension}")); let destination = dir.0.join(format!("output-{version}-{extension}-{existing}.{extension}"));
let backup = io::backup_path(&destination); let backup = io::backup_path(&destination);
if existing { if existing {
std::fs::write(&destination, b"existing design").unwrap(); std::fs::write(&destination, b"existing design").unwrap();
std::fs::write(&backup, b"existing backup").unwrap();
} }
let output = cli().args(["run", "--in"]).arg(&source).arg("--save").arg(&destination).output().unwrap(); let output = cli().args(["run", "--in"]).arg(&source).arg("--save").arg(&destination).output().unwrap();
assert_eq!(output.status.code(), Some(1));
let error = String::from_utf8_lossy(&output.stderr); let error = String::from_utf8_lossy(&output.stderr);
assert!(error.contains("experimental-card") && error.contains("update SolidCraft"), "{error}"); assert_eq!(output.status.code(), Some(0), "{error}");
assert!(error.contains("warning: Saved by a newer SolidCraft") && error.contains("experimental-card"), "{error}");
// Saved, it still says it has the change, and opens the same way.
let saved = io::read_design(&std::fs::read(&destination).unwrap()).unwrap();
assert!(saved.format_pending.iter().any(|name| name == "experimental-card"));
assert!(saved.newer_file.is_some());
if existing { if existing {
assert_eq!(std::fs::read(&destination).unwrap(), b"existing design"); assert_eq!(std::fs::read(&backup).unwrap(), b"existing design");
assert_eq!(std::fs::read(&backup).unwrap(), b"existing backup");
} else {
assert!(!destination.exists() && !backup.exists());
} }
assert_eq!(std::fs::read(&source).unwrap(), bytes); assert_eq!(std::fs::read(&source).unwrap(), bytes);
} }
@@ -208,6 +206,43 @@ fn unknown_pending_concepts_preserve_the_open_design_and_output_files() {
} }
} }
/// `eval` and `run` on a design one format newer, with a feature kind this version doesn't have:
/// the rest builds, the reply names it, and the saved file still holds it, under the file's number.
#[test]
fn the_cli_opens_a_newer_design_and_saving_keeps_what_it_cant_read() {
use solidcraft_engine::{Session, doc, io};
let dir = Scratch::new();
let mut session = Session::default();
session.execute("solid.box", &json!({"length": 2, "width": 3, "height": 4})).unwrap();
let mut file: Value = serde_json::from_slice(&io::write_design(&session.doc)).unwrap();
let newer = doc::format::format_string(doc::format::FORMAT + 1);
file["format"] = json!(newer);
let future = json!({"id": 900, "name": "Lattice1", "type": "gyroid_lattice", "cell": 2.5});
file["features"].as_array_mut().unwrap().push(future.clone());
let source = dir.0.join("newer.json");
std::fs::write(&source, file.to_string()).unwrap();
let output = cli().args(["eval"]).arg(&source).output().unwrap();
let error = String::from_utf8_lossy(&output.stderr);
assert_eq!(output.status.code(), Some(0), "{error}");
assert!(error.contains("warning: Saved by a newer SolidCraft") && error.contains("Lattice1"), "{error}");
let reply: Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(reply["body_count"], 1);
assert!(reply["newer_file"]["not_understood"][0].as_str().unwrap().contains("gyroid_lattice"), "{reply}");
assert!(reply["warnings"][0].as_str().unwrap().starts_with("Saved by a newer SolidCraft"), "{reply}");
for extension in ["json", "sc"] {
let destination = dir.0.join(format!("saved.{extension}"));
let output = cli().args(["run", "--in"]).arg(&source).arg("--save").arg(&destination).output().unwrap();
assert_eq!(output.status.code(), Some(0), "{}", String::from_utf8_lossy(&output.stderr));
let saved = io::read_design(&std::fs::read(&destination).unwrap()).unwrap();
assert_eq!(saved.format, newer, "never a lower number");
let again: Value = serde_json::from_slice(&io::write_design(&saved)).unwrap();
assert_eq!(again["features"].as_array().unwrap().last().unwrap(), &future);
}
}
#[test] #[test]
fn known_pending_concepts_and_released_files_round_trip_with_inert_metadata() { fn known_pending_concepts_and_released_files_round_trip_with_inert_metadata() {
use solidcraft_engine::{doc, io}; use solidcraft_engine::{doc, io};
@@ -256,6 +291,38 @@ fn results_still_save_and_export_the_script_once() {
} }
} }
/// The triangles of a binary STL: the count after its 80-byte header.
fn stl_triangles(path: &Path) -> u32 {
let bytes = std::fs::read(path).unwrap();
u32::from_le_bytes(bytes[80..84].try_into().unwrap())
}
/// #12270: `run --out part.stl --quality fine` writes the mesh at that quality, as
/// `file.export`'s `quality` does, without a script to say so.
#[test]
fn run_exports_meshes_at_the_quality_asked_for() {
let dir = Scratch::new();
let script = dir.0.join("cylinder.json");
std::fs::write(&script, json!({"commands": [{"command": "solid.cylinder", "params": {"diameter": 40, "height": 10}}]}).to_string()).unwrap();
let export = |name: &str, quality: Option<&str>| {
let stl = dir.0.join(name);
let mut command = cli();
command.arg("run").arg(&script).arg("--quiet").arg("--out").arg(&stl);
if let Some(q) = quality {
command.args(["--quality", q]);
}
let output = command.output().unwrap();
assert!(output.status.success(), "{quality:?}: {}", String::from_utf8_lossy(&output.stderr));
stl_triangles(&stl)
};
let default = export("default.stl", None);
let standard = export("standard.stl", Some("standard"));
let fine = export("fine.stl", Some("fine"));
let finest = export("finest.stl", Some("finest"));
assert_eq!(default, standard);
assert!(standard < fine && fine < finest, "standard {standard}, fine {fine}, finest {finest}");
}
#[test] #[test]
fn results_with_base_design_and_quiet_still_report_and_save() { fn results_with_base_design_and_quiet_still_report_and_save() {
let dir = Scratch::new(); let dir = Scratch::new();
+1 -1
View File
@@ -676,7 +676,7 @@ pub fn take_drops(files: &Rc<Files>, raw: &mut egui::RawInput, theme: bool) {
/// any later page. /// any later page.
fn hold_page_lock(page: &str) { fn hold_page_lock(page: &str) {
let Some(locks) = web_locks() else { return }; let Some(locks) = web_locks() else { return };
let Ok(request) = Reflect::get(&locks, &"request".into()).and_then(|f| f.dyn_into::<Function>().map_err(JsValue::from)) else { return }; let Ok(request) = Reflect::get(&locks, &"request".into()).and_then(|f| f.dyn_into::<Function>()) else { return };
// A promise that never settles: the lock is let go only when the page goes. // A promise that never settles: the lock is let go only when the page goes.
let hold = Closure::<dyn FnMut(JsValue) -> js_sys::Promise>::new(|_lock: JsValue| js_sys::Promise::new(&mut |_, _| {})); let hold = Closure::<dyn FnMut(JsValue) -> js_sys::Promise>::new(|_lock: JsValue| js_sys::Promise::new(&mut |_, _| {}));
let name = format!("{}{page}", keep::LOCK_PREFIX); let name = format!("{}{page}", keep::LOCK_PREFIX);
+2 -2
View File
@@ -23,9 +23,9 @@ fn prompt() {
let _ = js_sys::Reflect::set(&window, &OFFER.into(), &JsValue::NULL); let _ = js_sys::Reflect::set(&window, &OFFER.into(), &JsValue::NULL);
} }
let shown = js_sys::Reflect::get(&offer, &"prompt".into()) let shown = js_sys::Reflect::get(&offer, &"prompt".into())
.and_then(|f| f.dyn_into::<js_sys::Function>().map_err(JsValue::from)) .and_then(|f| f.dyn_into::<js_sys::Function>())
.and_then(|f| f.call0(&offer)) .and_then(|f| f.call0(&offer))
.and_then(|p| p.dyn_into::<js_sys::Promise>().map_err(JsValue::from)); .and_then(|p| p.dyn_into::<js_sys::Promise>());
match shown { match shown {
// Accepted or dismissed, the browser handles it; a refusal is only logged. // Accepted or dismissed, the browser handles it; a refusal is only logged.
Ok(p) => wasm_bindgen_futures::spawn_local(async move { Ok(p) => wasm_bindgen_futures::spawn_local(async move {
+1 -1
View File
@@ -48,7 +48,7 @@ impl Download {
} }
if solidcraft_ui_egui::documents::any_dirty(app) { if solidcraft_ui_egui::documents::any_dirty(app) {
let mut answer = None; let mut answer = None;
let closed = ui_kit::Window::new(egui::Id::new("open_link"), "status_warning", solidcraft_ui_egui::i18n::tr("web.open_link")) let closed = ui_kit::Window::new(egui::Id::unique("open_link"), "status_warning", solidcraft_ui_egui::i18n::tr("web.open_link"))
.required() .required()
.show_body(ctx, |ui| { .show_body(ctx, |ui| {
ui.label(solidcraft_ui_egui::i18n::tr("web.open_link_confirm")); ui.label(solidcraft_ui_egui::i18n::tr("web.open_link_confirm"));
+12 -4
View File
@@ -726,7 +726,7 @@ mod web {
return; return;
} }
let mut act: Option<(&'static str, String)> = None; let mut act: Option<(&'static str, String)> = None;
let closed = solidcraft_ui_egui::ui_kit::Window::new(egui::Id::new("sc_browser_files"), "folder", "Files in this browser") let closed = solidcraft_ui_egui::ui_kit::Window::new(egui::Id::unique("sc_browser_files"), "folder", "Files in this browser")
// Room for long names; the kit still caps the window at the browser's width. // Room for long names; the kit still caps the window at the browser's width.
.cards(4.0) .cards(4.0)
.show_body(ctx, |ui| { .show_body(ctx, |ui| {
@@ -828,7 +828,9 @@ mod web {
self.files.panel.set(false); self.files.panel.set(false);
} }
"insert" => { "insert" => {
self.app.insert_path(&path); if !solidcraft_ui_egui::mesh_units::ask(&mut self.app, &path, true) {
self.app.insert_path(&path);
}
self.files.panel.set(false); self.files.panel.set(false);
} }
"download" => match vfs::read(&path, solidcraft_engine::io::MAX_DESIGN_BYTES) { "download" => match vfs::read(&path, solidcraft_engine::io::MAX_DESIGN_BYTES) {
@@ -873,10 +875,16 @@ mod web {
*r = new.clone(); *r = new.clone();
} }
} }
if let Some(at) = self.app.home.opened_at.remove(&old) {
self.app.home.opened_at.insert(new.clone(), at);
}
// A forgotten design follows its new name. // A forgotten design follows its new name.
if self.app.home.forgotten.remove(&old) { if self.app.home.forgotten.remove(&old) {
self.app.home.forgotten.insert(new); self.app.home.forgotten.insert(new.clone());
} }
// An open tab of that file keeps its path and, when the name came
// from the file, the title that matches the file list (#11375).
solidcraft_ui_egui::documents::follow_file_rename(&mut self.app, &old, &new);
} }
Err(e) => self.app.set_status(e, true), Err(e) => self.app.set_status(e, true),
} }
@@ -890,7 +898,7 @@ mod web {
fn recovery_prompt(&mut self, ctx: &egui::Context) { fn recovery_prompt(&mut self, ctx: &egui::Context) {
let Some((name, path)) = self.files.recovery.borrow().clone() else { return }; let Some((name, path)) = self.files.recovery.borrow().clone() else { return };
let mut answer = None; let mut answer = None;
let _ = solidcraft_ui_egui::ui_kit::Window::new(egui::Id::new("sc_browser_recovery"), "restore", "Recover unsaved work?") let _ = solidcraft_ui_egui::ui_kit::Window::new(egui::Id::unique("sc_browser_recovery"), "restore", "Recover unsaved work?")
.required() .required()
.show_body(ctx, |ui| { .show_body(ctx, |ui| {
ui.label(format!("“{name}” had unsaved changes when this page last closed.")); ui.label(format!("“{name}” had unsaved changes when this page last closed."));
+13 -9
View File
@@ -68,7 +68,9 @@ pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<Co
Ok(l) => { Ok(l) => {
if let Some(port) = listen_on_listener(l, token.clone(), tx, ctx, false) { if let Some(port) = listen_on_listener(l, token.clone(), tx, ctx, false) {
if matches!(listen_on, control_auth::Listen::Default) { if matches!(listen_on, control_auth::Listen::Default) {
eprintln!("solidcraft: control channel on the default port 127.0.0.1:{port} (Preferences > Assistant turns it off)"); 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. // The discovery file: where `solidcraft-cli mcp` finds this app with no arguments.
match control_auth::write_current_port(port) { match control_auth::write_current_port(port) {
@@ -77,14 +79,14 @@ pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<Co
*p = Some((port, token)); *p = Some((port, token));
} }
} }
Err(e) => eprintln!("solidcraft: could not write the control discovery file ({e})"), Err(e) => solidcraft_engine::note!("solidcraft: could not write the control discovery file ({e})"),
} }
} }
} }
Err(e) => eprintln!("solidcraft: control server failed to bind 127.0.0.1: {e}"), Err(e) => solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}"),
} }
} }
None => eprintln!("solidcraft: control server not started: no random token available"), None => solidcraft_engine::note!("solidcraft: control server not started: no random token available"),
} }
rx rx
} }
@@ -95,13 +97,13 @@ pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<Co
/// requests go to `tx`, where the chat's gate reads them; one may wait long for the user's Allow. /// requests go to `tx`, where the chat's gate reads them; one may wait long for the user's Allow.
pub fn listen_agent(tx: Sender<ControlRequest>, ctx: egui::Context) -> Option<u16> { pub fn listen_agent(tx: Sender<ControlRequest>, ctx: egui::Context) -> Option<u16> {
let Some(token) = new_token() else { let Some(token) = new_token() else {
eprintln!("solidcraft: agent chat endpoint not started: no random token available"); solidcraft_engine::note!("solidcraft: agent chat endpoint not started: no random token available");
return None; return None;
}; };
let listener = match TcpListener::bind(("127.0.0.1", 0)) { let listener = match TcpListener::bind(("127.0.0.1", 0)) {
Ok(l) => l, Ok(l) => l,
Err(e) => { Err(e) => {
eprintln!("solidcraft: control server failed to bind 127.0.0.1: {e}"); solidcraft_engine::note!("solidcraft: control server failed to bind 127.0.0.1: {e}");
return None; return None;
} }
}; };
@@ -115,19 +117,21 @@ fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRe
match control_auth::token_path(port) { match control_auth::token_path(port) {
Some(path) => match control_auth::write_token_file(&path, &token) { Some(path) => match control_auth::write_token_file(&path, &token) {
Ok(()) => { Ok(()) => {
eprintln!("solidcraft: control server listening on 127.0.0.1:{port} (token in {})", path.display()); solidcraft_engine::note!("solidcraft: control server listening on 127.0.0.1:{port} (token in {})", path.display());
if let Ok(mut files) = TOKEN_FILES.lock() { if let Ok(mut files) = TOKEN_FILES.lock() {
files.push((path, token.clone())); files.push((path, token.clone()));
} }
} }
Err(e) => eprintln!( Err(e) => solidcraft_engine::note!(
"solidcraft: control server listening on 127.0.0.1:{port}, but its token file {} could not be written ({e}); \ "solidcraft: control server listening on 127.0.0.1:{port}, but its token file {} could not be written ({e}); \
clients need SOLIDCRAFT_CONTROL_TOKEN", clients need SOLIDCRAFT_CONTROL_TOKEN",
path.display() path.display()
), ),
}, },
None => { None => {
eprintln!("solidcraft: control server listening on 127.0.0.1:{port}; no data folder for its token, clients need SOLIDCRAFT_CONTROL_TOKEN") solidcraft_engine::note!(
"solidcraft: control server listening on 127.0.0.1:{port}; no data folder for its token, clients need SOLIDCRAFT_CONTROL_TOKEN"
)
} }
} }
let token = std::sync::Arc::new(token); let token = std::sync::Arc::new(token);
+1 -1
View File
@@ -112,7 +112,7 @@ pub fn restart(software: bool, lost_at: u64, reason: &str) {
pub fn end() -> ! { pub fn end() -> ! {
let watchdog = std::thread::Builder::new().name("solidcraft-exit".into()).spawn(|| { let watchdog = std::thread::Builder::new().name("solidcraft-exit".into()).spawn(|| {
std::thread::sleep(END_GRACE); std::thread::sleep(END_GRACE);
eprintln!("SolidCraft graphics: still closing after the device was lost; aborting"); solidcraft_engine::note!("SolidCraft graphics: still closing after the device was lost; aborting");
std::process::abort(); std::process::abort();
}); });
if let Err(e) = watchdog { if let Err(e) = watchdog {
+14 -13
View File
@@ -79,7 +79,7 @@ fn mark(step: &str) {
static START: std::sync::OnceLock<(std::time::Instant, bool)> = std::sync::OnceLock::new(); static START: std::sync::OnceLock<(std::time::Instant, bool)> = std::sync::OnceLock::new();
let (start, on) = START.get_or_init(|| (std::time::Instant::now(), solidcraft_engine::geom::env::var_os("PROFILE_STARTUP").is_some())); let (start, on) = START.get_or_init(|| (std::time::Instant::now(), solidcraft_engine::geom::env::var_os("PROFILE_STARTUP").is_some()));
if *on { if *on {
eprintln!("startup {:>6.0} ms {step}", start.elapsed().as_secs_f64() * 1000.0); solidcraft_engine::note!("startup {:>6.0} ms {step}", start.elapsed().as_secs_f64() * 1000.0);
} }
} }
@@ -368,7 +368,7 @@ impl App {
let Some(gpu) = self.gpu.as_mut().filter(|g| g.lost_at.is_none() && g.lost.is_lost()) else { return }; let Some(gpu) = self.gpu.as_mut().filter(|g| g.lost_at.is_none() && g.lost.is_lost()) else { return };
let reason = gpu.lost.reason().unwrap_or_default(); let reason = gpu.lost.reason().unwrap_or_default();
log::error!("graphics: the device was lost ({reason}); closing to start again"); log::error!("graphics: the device was lost ({reason}); closing to start again");
eprintln!("SolidCraft graphics: the device was lost ({reason}); starting again"); solidcraft_engine::note!("SolidCraft graphics: the device was lost ({reason}); starting again");
solidcraft_engine::crash::phase(&format!("graphics device lost: {reason}")); solidcraft_engine::crash::phase(&format!("graphics device lost: {reason}"));
gpu.lost_at = Some(device_lost::now_secs()); gpu.lost_at = Some(device_lost::now_secs());
gpu.reason = reason; gpu.reason = reason;
@@ -993,7 +993,7 @@ fn main() -> eframe::Result {
if let Some(value) = max_file_size { if let Some(value) = max_file_size {
let applied = startup::max_file_size(value.as_deref()).and_then(|bytes| solidcraft_engine::io::limits::set_override(Some(bytes))); let applied = startup::max_file_size(value.as_deref()).and_then(|bytes| solidcraft_engine::io::limits::set_override(Some(bytes)));
if let Err(error) = applied { if let Err(error) = applied {
eprintln!("SolidCraft: {error}"); solidcraft_engine::note!("SolidCraft: {error}");
return Err(eframe::Error::AppCreation(std::io::Error::other(error).into())); return Err(eframe::Error::AppCreation(std::io::Error::other(error).into()));
} }
} }
@@ -1025,7 +1025,7 @@ fn main() -> eframe::Result {
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>());
if let Some(note) = &fallback_note { if let Some(note) = &fallback_note {
log::warn!("{note}"); log::warn!("{note}");
eprintln!("SolidCraft: {note}"); solidcraft_engine::note!("SolidCraft: {note}");
notes.push(note.clone()); notes.push(note.clone());
} }
let saved_samples = if safe_mode { None } else { msaa() }; let saved_samples = if safe_mode { None } else { msaa() };
@@ -1138,13 +1138,13 @@ fn main() -> eframe::Result {
// Windows: the taskbar button shows the mark even when slow first frames keep the // Windows: the taskbar button shows the mark even when slow first frames keep the
// taskbar waiting for the window's icon. // taskbar waiting for the window's icon.
if !native_frame::set_class_icon(cc) { if !native_frame::set_class_icon(cc) {
eprintln!("SolidCraft window: no class icon; the taskbar may show a generic one"); solidcraft_engine::note!("SolidCraft window: no class icon; the taskbar may show a generic one");
} }
// The OS hit test offers the resize border, at the window's DPI, from the first // The OS hit test offers the resize border, at the window's DPI, from the first
// message (#1381). // message (#1381).
app.native_resize_border = custom_titlebar && native_frame::install(cc); app.native_resize_border = custom_titlebar && native_frame::install(cc);
if custom_titlebar && !app.native_resize_border { if custom_titlebar && !app.native_resize_border {
eprintln!("SolidCraft window: no native resize border; egui edge zones instead"); solidcraft_engine::note!("SolidCraft window: no native resize border; egui edge zones instead");
} }
} }
app.integrated_titlebar = cfg!(target_os = "macos"); app.integrated_titlebar = cfg!(target_os = "macos");
@@ -1175,9 +1175,10 @@ fn main() -> eframe::Result {
.collect(); .collect();
let info = rs.adapter.get_info(); let info = rs.adapter.get_info();
if !app.preferences.graphics_adapter.is_empty() && !info.name.eq_ignore_ascii_case(app.preferences.graphics_adapter.as_str()) { if !app.preferences.graphics_adapter.is_empty() && !info.name.eq_ignore_ascii_case(app.preferences.graphics_adapter.as_str()) {
eprintln!( solidcraft_engine::note!(
"SolidCraft graphics: preferred adapter {:?} was not used; using {:?} instead", "SolidCraft graphics: preferred adapter {:?} was not used; using {:?} instead",
app.preferences.graphics_adapter, info.name app.preferences.graphics_adapter,
info.name
); );
} }
let samples = scene_msaa_request(saved_samples); let samples = scene_msaa_request(saved_samples);
@@ -1185,7 +1186,7 @@ fn main() -> eframe::Result {
eframe::egui_wgpu::supported_msaa_samples(&rs.adapter, &rs.device, rs.target_format, depth) eframe::egui_wgpu::supported_msaa_samples(&rs.adapter, &rs.device, rs.target_format, depth)
}); });
let scene_samples = scene_samples(info.backend, u32::from(samples), &supported); let scene_samples = scene_samples(info.backend, u32::from(samples), &supported);
eprintln!("SolidCraft graphics: {:?}, MSAA {scene_samples}x (requested {}x)", rs.adapter.get_info().backend, samples); solidcraft_engine::note!("SolidCraft graphics: {:?}, MSAA {scene_samples}x (requested {}x)", rs.adapter.get_info().backend, samples);
solidcraft_engine::crash::phase("viewport pipelines (shader compile)"); solidcraft_engine::crash::phase("viewport pipelines (shader compile)");
let scene_samples = app.set_wgpu_split(rs, depth_bits, STENCIL_BITS, scene_samples); let scene_samples = app.set_wgpu_split(rs, depth_bits, STENCIL_BITS, scene_samples);
app.msaa_supported = supported; app.msaa_supported = supported;
@@ -1346,7 +1347,7 @@ fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuC
let retry = std::env::var(startup::RETRY_BACKEND_ENV).ok(); let retry = std::env::var(startup::RETRY_BACKEND_ENV).ok();
let preference = if cpu { preference } else { retry.as_deref().or(preference) }; let preference = if cpu { preference } else { retry.as_deref().or(preference) };
if let Some(backends) = startup::choose_backends(cfg!(target_os = "windows"), env_set, cpu, preference, startup::has_hardware_adapter) { if let Some(backends) = startup::choose_backends(cfg!(target_os = "windows"), env_set, cpu, preference, startup::has_hardware_adapter) {
eprintln!("SolidCraft graphics: starting {backends:?}"); solidcraft_engine::note!("SolidCraft graphics: starting {backends:?}");
setup.instance_descriptor.backends = backends; setup.instance_descriptor.backends = backends;
} }
let intel_mac = cfg!(all(target_os = "macos", target_arch = "x86_64")); let intel_mac = cfg!(all(target_os = "macos", target_arch = "x86_64"));
@@ -1372,7 +1373,7 @@ fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuC
/// event loop or a failed device; each retry advances through the APIs, then software once. /// 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>) -> eframe::Result {
log::error!("the window could not open: {error}"); log::error!("the window could not open: {error}");
eprintln!("SolidCraft: 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. // This failure was handled, so neither the marker nor the journal should call it a crash.
if let Some(dir) = settings { if let Some(dir) = settings {
startup::started(dir); startup::started(dir);
@@ -1385,7 +1386,7 @@ fn no_window(error: eframe::Error, tried_cpu: bool, failed: eframe::wgpu::Backen
let previous = std::env::var(startup::FALLBACK_NOTE_ENV).unwrap_or_default(); let previous = std::env::var(startup::FALLBACK_NOTE_ENV).unwrap_or_default();
let note = startup::fallback_note(&previous, failed, next, &error.to_string()); let note = startup::fallback_note(&previous, failed, next, &error.to_string());
log::warn!("{note}"); log::warn!("{note}");
eprintln!("SolidCraft: {note}"); solidcraft_engine::note!("SolidCraft: {note}");
let mut command = std::process::Command::new(exe); let mut command = std::process::Command::new(exe);
command.args(std::env::args_os().skip(1)).env(startup::FALLBACK_NOTE_ENV, note); command.args(std::env::args_os().skip(1)).env(startup::FALLBACK_NOTE_ENV, note);
if next == "cpu" { if next == "cpu" {
@@ -1791,7 +1792,7 @@ mod viewport_tests {
viewport.fullscreen = Some(fullscreen); viewport.fullscreen = Some(fullscreen);
viewport.native_pixels_per_point = Some(retina); viewport.native_pixels_per_point = Some(retina);
super::fullscreen_content_insets(&mut raw, 32.0, zoom); super::fullscreen_content_insets(&mut raw, 32.0, zoom);
let _ = ctx.run_ui(raw, |ui| super::content_ui(app, ui)); ctx.run_ui(raw, |ui| super::content_ui(app, ui)).textures_delta.clear();
}; };
// Enter, leave, and enter again: no stale inset when returning to a normal window. // Enter, leave, and enter again: no stale inset when returning to a normal window.
for fullscreen in [false, true, false, true] { for fullscreen in [false, true, false, true] {
+1 -1
View File
@@ -434,7 +434,7 @@ mod tests {
let mut app = SolveApp::new(solidcraft_engine::Session::default(), solidcraft_ui_egui::Services::default()); let mut app = SolveApp::new(solidcraft_engine::Session::default(), solidcraft_ui_egui::Services::default());
app.home.open = false; app.home.open = false;
let ctx = Context::default(); let ctx = Context::default();
let _ = ctx.run_ui(egui::RawInput { focused: true, ..Default::default() }, |_| {}); ctx.run_ui(egui::RawInput { focused: true, ..Default::default() }, |_| {}).textures_delta.clear();
let mut bridge = NavBridge { shared: Arc::new(Mutex::new(Shared::default())) }; let mut bridge = NavBridge { shared: Arc::new(Mutex::new(Shared::default())) };
let queue = |bridge: &NavBridge| { let queue = |bridge: &NavBridge| {
let mut shared = bridge.shared.lock().unwrap(); let mut shared = bridge.shared.lock().unwrap();
+1
View File
@@ -1914,6 +1914,7 @@ mod tests {
fn wheel() -> egui::Event { fn wheel() -> egui::Event {
egui::Event::MouseWheel { egui::Event::MouseWheel {
source: egui::MouseWheelSource::Unknown,
unit: egui::MouseWheelUnit::Line, unit: egui::MouseWheelUnit::Line,
delta: egui::vec2(0.0, -1.0), delta: egui::vec2(0.0, -1.0),
modifiers: Default::default(), modifiers: Default::default(),
+1 -1
View File
@@ -357,7 +357,7 @@ pub fn relaunch_with_version_compat() -> Result<bool, String> {
return Ok(false); return Ok(false);
} }
log::info!("startup: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV); log::info!("startup: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV);
eprintln!("SolidCraft: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV); solidcraft_engine::note!("SolidCraft: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV);
let exe = std::env::current_exe().map_err(|e| format!("could not find own executable: {e}"))?; let exe = std::env::current_exe().map_err(|e| format!("could not find own executable: {e}"))?;
let status = std::process::Command::new(&exe) let status = std::process::Command::new(&exe)
.args(std::env::args_os().skip(1)) .args(std::env::args_os().skip(1))
+4 -2
View File
@@ -23,7 +23,7 @@ assets/
appearances/library.rs # built-in visual presets appearances/library.rs # built-in visual presets
materials/library.rs # physical defaults and colours materials/library.rs # physical defaults and colours
shaders/viewport.wgsl # original viewport shader shaders/viewport.wgsl # original viewport shader
fonts/{liberation-sans,biz-udp-gothic}/ # unmodified fonts and OFL licences fonts/biz-udp-gothic/ # unmodified font and OFL licence
locales/{en,de,ja,ko}.json # shared offline catalogs locales/{en,de,ja,ko}.json # shared offline catalogs
platforms/{macos,linux,windows}/ # bundle, freedesktop and WiX templates platforms/{macos,linux,windows}/ # bundle, freedesktop and WiX templates
platforms/macos/dmg/ # disk image window: layout, dmgbuild settings, background art platforms/macos/dmg/ # disk image window: layout, dmgbuild settings, background art
@@ -87,7 +87,9 @@ The CLI still supports arbitrary PNG/ICO exports with `solidcraft-cli icon`.
Resources remain compiled by their owning layer through existing APIs: Resources remain compiled by their owning layer through existing APIs:
`ui-egui::icons::paint_icon` and `Tokens` at L5, model presets in L2 `doc`, and sketch `ui-egui::icons::paint_icon` and `Tokens` at L5, model presets in L2 `doc`, and sketch
fonts at L1. State, projection, interaction, commands and GPU bindings stay in fonts at L1. The sketch crate owns its built-in Liberation Sans font and OFL
licence under `crates/sketch/assets/fonts/liberation-sans/`, so Cargo source
packages and vendored builds include both files. State, projection, interaction, commands and GPU bindings stay in
their current modules. Embedded data uses `CARGO_MANIFEST_DIR`; application code their current modules. Embedded data uses `CARGO_MANIFEST_DIR`; application code
needs no runtime resource registry or repository lookup. needs no runtime resource registry or repository lookup.
+1 -1
View File
@@ -89,7 +89,7 @@ pub(crate) fn glyph_icon(name: &str) -> Option<&'static str> {
"Smooth" => "c_smooth", "Smooth" => "c_smooth",
"Equal" => "c_equal", "Equal" => "c_equal",
"Concentric" => "c_concentric", "Concentric" => "c_concentric",
"MidPoint" => "c_midpoint", "MidPoint" | "PointAlong" => "c_midpoint",
"Symmetry" => "c_symmetry", "Symmetry" => "c_symmetry",
"Fix" => "c_fix", "Fix" => "c_fix",
_ => return None, _ => return None,
+1 -2
View File
@@ -55,8 +55,7 @@ pub(crate) fn face_text(painter: &egui::Painter, face: &Facet, ink: Color32, fon
painter.ctx().add_plugin(LabelAtlas); painter.ctx().add_plugin(LabelAtlas);
let text = Shape::Text(egui::epaint::TextShape::new(Pos2::ZERO, galley, ink)); let text = Shape::Text(egui::epaint::TextShape::new(Pos2::ZERO, galley, ink));
let atlas = painter.ctx().fonts(|f| f.font_image_size()); let atlas = painter.ctx().fonts(|f| f.font_image_size());
let primitives = let primitives = painter.ctx().tessellate(vec![egui::epaint::ClippedShape::new(Rect::EVERYTHING, text)], painter.ctx().pixels_per_point());
painter.ctx().tessellate(vec![egui::epaint::ClippedShape { clip_rect: Rect::EVERYTHING, shape: text }], painter.ctx().pixels_per_point());
for primitive in primitives { for primitive in primitives {
if let egui::epaint::Primitive::Mesh(mut mesh) = primitive.primitive { if let egui::epaint::Primitive::Mesh(mut mesh) = primitive.primitive {
mesh.texture_id = LABEL_PIXELS; mesh.texture_id = LABEL_PIXELS;
+486 -8
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Učitava putanje SVG crteža u skicu, skalirane, zakrenute i postavljene gdje zadate. Koristite ga da logotip ili vektorski obris pretvorite u krive koje možete ekstrudirati.", "help.sketch.insert_svg": "Učitava putanje SVG crteža u skicu, skalirane, zakrenute i postavljene gdje zadate. Koristite ga da logotip ili vektorski obris pretvorite u krive koje možete ekstrudirati.",
"help.sketch.inspect": "Otvara izvještaj o otvorenoj skici: koliko je stepeni slobode preostalo i je li potpuno ograničena. Koristite ga da saznate šta se još pomjera prije nego što završite skicu.", "help.sketch.inspect": "Otvara izvještaj o otvorenoj skici: koliko je stepeni slobode preostalo i je li potpuno ograničena. Koristite ga da saznate šta se još pomjera prije nego što završite skicu.",
"help.sketch.intersect": "Dodaje krive ili tačke gdje tijela, lica, ivice ili druge skice sijeku ravan skice. Ostaju povezane i prate model kada se promijeni.", "help.sketch.intersect": "Dodaje krive ili tačke gdje tijela, lica, ivice ili druge skice sijeku ravan skice. Ostaju povezane i prate model kada se promijeni.",
"help.sketch.intersection_curve": "Pravi 3D krive tamo gdje se dva tijela ili lica sastaju, povezane s njima. Koristite ih kao putanje ili vodilice koje prate model.", "help.sketch.intersection_curve": "Pravi 3D krive tamo gdje se dva tijela, lica ili krive drugih skica sastaju, povezane s njima. Koristite ih kao putanje ili vodilice koje prate model.",
"help.sketch.isoparametric_curve": "Pravi 3D krivu u smjeru U ili V lica kroz tačku koju izaberete, povezanu s licem. Koristite je kao putanju ili liniju razdvajanja koja prati površ.", "help.sketch.isoparametric_curve": "Pravi 3D krivu u smjeru U ili V lica kroz tačku koju izaberete, povezanu s licem. Koristite je kao putanju ili liniju razdvajanja koja prati površ.",
"help.sketch.line": "Crta povezane linije tačku po tačku, kao otvoreni lanac ili zatvoren obris. To je osnovni alat za većinu profila.", "help.sketch.line": "Crta povezane linije tačku po tačku, kao otvoreni lanac ili zatvoren obris. To je osnovni alat za većinu profila.",
"help.sketch.line.midpoint": "Crta liniju od njene središnje tačke do jednog kraja, a drugi kraj se preslikava. Koristite je za linije centrirane na tački, npr. simetričnu ivicu.", "help.sketch.line.midpoint": "Crta liniju od njene središnje tačke do jednog kraja, a drugi kraj se preslikava. Koristite je za linije centrirane na tački, npr. simetričnu ivicu.",
File diff suppressed because it is too large Load Diff
+354 -176
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Læser stierne i en SVG-tegning ind i en skitse, skaleret, drejet og placeret, som du angiver. Brug den til at gøre et logo eller en vektorkontur til kurver, du kan ekstrudere.", "help.sketch.insert_svg": "Læser stierne i en SVG-tegning ind i en skitse, skaleret, drejet og placeret, som du angiver. Brug den til at gøre et logo eller en vektorkontur til kurver, du kan ekstrudere.",
"help.sketch.inspect": "Åbner en rapport om den åbne skitse: hvor mange frihedsgrader der er tilbage, og om den er fuldt bundet. Brug den til at finde ud af, hvad der stadig kan bevæge sig, før du afslutter skitsen.", "help.sketch.inspect": "Åbner en rapport om den åbne skitse: hvor mange frihedsgrader der er tilbage, og om den er fuldt bundet. Brug den til at finde ud af, hvad der stadig kan bevæge sig, før du afslutter skitsen.",
"help.sketch.intersect": "Tilføjer de kurver eller punkter, hvor emner, flader, kanter eller andre skitser krydser skitseplanet. De forbliver linkede og følger modellen, når den ændres.", "help.sketch.intersect": "Tilføjer de kurver eller punkter, hvor emner, flader, kanter eller andre skitser krydser skitseplanet. De forbliver linkede og følger modellen, når den ændres.",
"help.sketch.intersection_curve": "Opretter 3D-kurver, hvor to emner eller flader mødes, linket til dem. Brug dem som baner eller styrekurver, der følger modellen.", "help.sketch.intersection_curve": "Opretter 3D-kurver, hvor to emner, flader eller kurver fra andre skitser mødes, linket til dem. Brug dem som baner eller styrekurver, der følger modellen.",
"help.sketch.isoparametric_curve": "Opretter en 3D-kurve langs en flades U- eller V-retning gennem et punkt, du vælger, linket til fladen. Brug den som bane eller delelinje, der følger overfladen.", "help.sketch.isoparametric_curve": "Opretter en 3D-kurve langs en flades U- eller V-retning gennem et punkt, du vælger, linket til fladen. Brug den som bane eller delelinje, der følger overfladen.",
"help.sketch.line": "Tegner forbundne linjer punkt for punkt som en åben kæde eller en lukket kontur. Det er det grundlæggende værktøj til de fleste profiler.", "help.sketch.line": "Tegner forbundne linjer punkt for punkt som en åben kæde eller en lukket kontur. Det er det grundlæggende værktøj til de fleste profiler.",
"help.sketch.line.midpoint": "Tegner en linje fra dens midtpunkt ud til den ene ende, og den anden ende spejles. Brug den til linjer centreret om et punkt, f.eks. en symmetrisk kant.", "help.sketch.line.midpoint": "Tegner en linje fra dens midtpunkt ud til den ene ende, og den anden ende spejles. Brug den til linjer centreret om et punkt, f.eks. en symmetrisk kant.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Eksempelplade", "sample.plate.name": "Eksempelplade",
"sample.vents.about": "Slidser i et rektangulært mønster: Rækker, kolonner og deling er parametre", "sample.vents.about": "Slidser i et rektangulært mønster: Rækker, kolonner og deling er parametre",
"sample.vents.name": "Ventilationsplade", "sample.vents.name": "Ventilationsplade",
"scale.per_axis": "Per akse",
"scale.uniform": "Ensartet",
"search.command_keys": "Enter kør Shift+Enter kør og hold åben Esc luk", "search.command_keys": "Enter kør Shift+Enter kør og hold åben Esc luk",
"search.commands": "Kommandoer", "search.commands": "Kommandoer",
"search.design": "I dette design", "search.design": "I dette design",
+269 -1
View File
@@ -568,6 +568,7 @@
"Select edges": "Kanten auswählen", "Select edges": "Kanten auswählen",
"Select points of the sketch being edited": "Punkte der bearbeiteten Skizze auswählen", "Select points of the sketch being edited": "Punkte der bearbeiteten Skizze auswählen",
"Select the centre the pattern turns around first": "Zuerst den Mittelpunkt auswählen, um den sich das Muster dreht", "Select the centre the pattern turns around first": "Zuerst den Mittelpunkt auswählen, um den sich das Muster dreht",
"Select the curves to divide first": "Zuerst die zu teilenden Kurven auswählen",
"Select the curves to offset first": "Zuerst die zu versetzenden Kurven auswählen", "Select the curves to offset first": "Zuerst die zu versetzenden Kurven auswählen",
"Select the mirror line": "Die Spiegellinie auswählen", "Select the mirror line": "Die Spiegellinie auswählen",
"Select the sketch curves or points to mirror first": "Zuerst die zu spiegelnden Skizzenkurven oder -punkte auswählen", "Select the sketch curves or points to mirror first": "Zuerst die zu spiegelnden Skizzenkurven oder -punkte auswählen",
@@ -628,6 +629,8 @@
"Suppress Selected Folders": "Ausgewählte Ordner unterdrücken", "Suppress Selected Folders": "Ausgewählte Ordner unterdrücken",
"Suppressed": "Unterdrückt", "Suppressed": "Unterdrückt",
"Surface": "Flächenkörper", "Surface": "Flächenkörper",
"Surface or face": "Flächenkörper oder Fläche",
"Surface or faces": "Flächenkörper oder Flächen",
"Surface, or faces to turn over": "Fläche oder umzudrehende Flächen", "Surface, or faces to turn over": "Fläche oder umzudrehende Flächen",
"Surfaces": "Flächen", "Surfaces": "Flächen",
"Swap Ends": "Enden vertauschen", "Swap Ends": "Enden vertauschen",
@@ -641,6 +644,7 @@
"Target": "Ziel", "Target": "Ziel",
"Target Body": "Zielkörper", "Target Body": "Zielkörper",
"Target Face (optional)": "Zielfläche (optional)", "Target Face (optional)": "Zielfläche (optional)",
"Target edges": "Zielkanten",
"Tear": "Reißen", "Tear": "Reißen",
"Technical details": "Technische Details", "Technical details": "Technische Details",
"The dashed sketch is a saved plane guide. Select a new face to repair the attachment.": "Die gestrichelte Skizze ist eine gespeicherte Ebenenführung. Wählen Sie eine neue Fläche, um die Anbindung zu reparieren.", "The dashed sketch is a saved plane guide. Select a new face to repair the attachment.": "Die gestrichelte Skizze ist eine gespeicherte Ebenenführung. Wählen Sie eine neue Fläche, um die Anbindung zu reparieren.",
@@ -648,6 +652,7 @@
"The direction must be an axis or a straight sketch curve that lies in the sketch plane": "Die Richtung muss eine Achse oder eine gerade Skizzenkurve in der Skizzenebene sein", "The direction must be an axis or a straight sketch curve that lies in the sketch plane": "Die Richtung muss eine Achse oder eine gerade Skizzenkurve in der Skizzenebene sein",
"The mirror line cannot also be mirrored": "Die Spiegellinie kann nicht gleichzeitig gespiegelt werden", "The mirror line cannot also be mirrored": "Die Spiegellinie kann nicht gleichzeitig gespiegelt werden",
"The mirror line must be a straight curve of this sketch, not an origin axis": "Die Spiegellinie muss eine gerade Kurve dieser Skizze sein, keine Ursprungsachse", "The mirror line must be a straight curve of this sketch, not an origin axis": "Die Spiegellinie muss eine gerade Kurve dieser Skizze sein, keine Ursprungsachse",
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "Die Ursprungsachse steht senkrecht auf der Skizzenebene und hat daher keine Linie in ihr",
"The saved author occurrence is missing. Select a valid author placement before rebinding.": "Das gespeicherte Autorvorkommen fehlt. Wählen Sie vor dem erneuten Anbinden eine gültige Autorplatzierung.", "The saved author occurrence is missing. Select a valid author placement before rebinding.": "Das gespeicherte Autorvorkommen fehlt. Wählen Sie vor dem erneuten Anbinden eine gültige Autorplatzierung.",
"Then": "Then", "Then": "Then",
"These features will be deleted:": "Diese Merkmale werden gelöscht:", "These features will be deleted:": "Diese Merkmale werden gelöscht:",
@@ -689,6 +694,7 @@
"Unsuppress Selected Folders": "Unterdrückung der ausgewählten Ordner aufheben", "Unsuppress Selected Folders": "Unterdrückung der ausgewählten Ordner aufheben",
"Updating the preview": "Vorschau wird aktualisiert", "Updating the preview": "Vorschau wird aktualisiert",
"Use active author placement": "Aktive Autorplatzierung verwenden", "Use active author placement": "Aktive Autorplatzierung verwenden",
"Use axis direction only": "Nur Achsenrichtung verwenden",
"Use fixed plane": "Feste Ebene verwenden", "Use fixed plane": "Feste Ebene verwenden",
"Use saved fixed plane": "Gespeicherte feste Ebene verwenden", "Use saved fixed plane": "Gespeicherte feste Ebene verwenden",
"Use selected face as fixed plane": "Ausgewählte Fläche als feste Ebene verwenden", "Use selected face as fixed plane": "Ausgewählte Fläche als feste Ebene verwenden",
@@ -739,6 +745,9 @@
"a picked edge's body is gone": "der Körper einer gewählten Kante existiert nicht mehr", "a picked edge's body is gone": "der Körper einer gewählten Kante existiert nicht mehr",
"add a key for a joint first": "zuerst einen Schlüssel für ein Gelenk hinzufügen", "add a key for a joint first": "zuerst einen Schlüssel für ein Gelenk hinzufügen",
"ai.connected_toast": "SolidCraft ist jetzt in {clients} verfügbar. Starten Sie diese neu, um es zu nutzen (Einstellungen > Assistent).", "ai.connected_toast": "SolidCraft ist jetzt in {clients} verfügbar. Starten Sie diese neu, um es zu nutzen (Einstellungen > Assistent).",
"ai.http.allow": "Unsicheres HTTP erlauben",
"ai.http.confirm": "Für diesen Endpunkt erlauben",
"ai.http.warning": "Der API-Schlüssel und die Unterhaltung werden unverschlüsselt gesendet. Jeder mit Zugriff auf das Netzwerk kann sie lesen oder verändern. Verwenden Sie dies nur in einem vertrauenswürdigen Netzwerk.",
"ai.prefs.allow_control": "KI-Agenten verbinden lassen", "ai.prefs.allow_control": "KI-Agenten verbinden lassen",
"ai.prefs.allow_control_note": "Ein lokaler Kanal (MCP). Nichts verlässt diesen Computer.\n\nÖffnet einen Steuerkanal nur auf diesem Computer (127.0.0.1, Port 27878 oder der nächste freie). Ein verbindendes Programm muss zusätzlich ein geheimes Token vorweisen, das nur Ihr Benutzerkonto lesen kann und bei jedem Start neu erzeugt wird. Wirkt ab dem nächsten Start von SolidCraft. Aus: Es wartet nichts auf Verbindungen, außer Sie starten SolidCraft mit --control.", "ai.prefs.allow_control_note": "Ein lokaler Kanal (MCP). Nichts verlässt diesen Computer.\n\nÖffnet einen Steuerkanal nur auf diesem Computer (127.0.0.1, Port 27878 oder der nächste freie). Ein verbindendes Programm muss zusätzlich ein geheimes Token vorweisen, das nur Ihr Benutzerkonto lesen kann und bei jedem Start neu erzeugt wird. Wirkt ab dem nächsten Start von SolidCraft. Aus: Es wartet nichts auf Verbindungen, außer Sie starten SolidCraft mit --control.",
"ai.prefs.availability": "Verfügbarkeit", "ai.prefs.availability": "Verfügbarkeit",
@@ -1028,6 +1037,7 @@
"cmd.occurrence_move": "Instanz verschieben", "cmd.occurrence_move": "Instanz verschieben",
"cmd.occurrence_properties": "Physikalische Eigenschaften der Instanz", "cmd.occurrence_properties": "Physikalische Eigenschaften der Instanz",
"cmd.occurrence_reparent": "In andere Komponente verschieben", "cmd.occurrence_reparent": "In andere Komponente verschieben",
"cmd.panel.action": "Panelaktion ausführen",
"cmd.panel.activate": "Panel-Registerkarte aktivieren", "cmd.panel.activate": "Panel-Registerkarte aktivieren",
"cmd.panel.close": "Panel schließen", "cmd.panel.close": "Panel schließen",
"cmd.panel.collapse": "Panel-Bereich einklappen", "cmd.panel.collapse": "Panel-Bereich einklappen",
@@ -1071,9 +1081,15 @@
"cmd.pointcloud_edit": "Punktwolke bearbeiten", "cmd.pointcloud_edit": "Punktwolke bearbeiten",
"cmd.pointcloud_insert": "Punktwolke einfügen", "cmd.pointcloud_insert": "Punktwolke einfügen",
"cmd.pointcloud_list": "Punktwolken", "cmd.pointcloud_list": "Punktwolken",
"cmd.pointcloud_reload": "Punktwolke neu laden",
"cmd.render.coat.bind": "Klarlack speichern",
"cmd.render.coat.unbind": "Klarlack entfernen",
"cmd.render.compare.divider": "Render-Vergleichstrenner verschieben", "cmd.render.compare.divider": "Render-Vergleichstrenner verschieben",
"cmd.render.result.discard": "Renderergebnis verwerfen", "cmd.render.result.discard": "Renderergebnis verwerfen",
"cmd.render.result.select": "Renderergebnis auswählen", "cmd.render.result.select": "Renderergebnis auswählen",
"cmd.render.surface.import": "Oberflächentexturen importieren",
"cmd.render.texture.list": "Eingebettete Oberflächenbilder auflisten",
"cmd.render.texture.remove": "Eingebettetes Oberflächenbild entfernen",
"cmd.render_aging_describe": "Mehrschichtige Oberflächenalterung", "cmd.render_aging_describe": "Mehrschichtige Oberflächenalterung",
"cmd.render_backends": "Render-Backends", "cmd.render_backends": "Render-Backends",
"cmd.render_batch": "Alle Aufnahmen rendern", "cmd.render_batch": "Alle Aufnahmen rendern",
@@ -1216,6 +1232,7 @@
"cmd.sketch_options": "Skizzenpalettenoptionen", "cmd.sketch_options": "Skizzenpalettenoptionen",
"cmd.sketch_paste": "Skizzenelemente einfügen", "cmd.sketch_paste": "Skizzenelemente einfügen",
"cmd.sketch_point3d": "3D-Punkt", "cmd.sketch_point3d": "3D-Punkt",
"cmd.sketch_point_divide": "Kurve teilen",
"cmd.sketch_polygon_circumscribed": "Umgeschriebenes Polygon", "cmd.sketch_polygon_circumscribed": "Umgeschriebenes Polygon",
"cmd.sketch_polygon_edge": "Polygon über eine Kante", "cmd.sketch_polygon_edge": "Polygon über eine Kante",
"cmd.sketch_polygon_inscribed": "Eingeschriebenes Polygon", "cmd.sketch_polygon_inscribed": "Eingeschriebenes Polygon",
@@ -1293,6 +1310,7 @@
"cmd.view.render_browser": "Render-Browser", "cmd.view.render_browser": "Render-Browser",
"cmd.view.render_dock": "Render-Panel verschieben", "cmd.view.render_dock": "Render-Panel verschieben",
"cmd.view.render_focus": "Render-Fokusansicht", "cmd.view.render_focus": "Render-Fokusansicht",
"cmd.view.render_live": "Live-Rendering pausieren oder fortsetzen",
"cmd.view.status_details": "Statusdetails des Ansichtsfensters", "cmd.view.status_details": "Statusdetails des Ansichtsfensters",
"cmd.view.status_items": "Ansichtsstatus-Elemente", "cmd.view.status_items": "Ansichtsstatus-Elemente",
"cmd.view_ambient_occlusion": "Umgebungsverdeckung", "cmd.view_ambient_occlusion": "Umgebungsverdeckung",
@@ -1322,6 +1340,7 @@
"cmd.view_shots_strip": "Aufnahmenleiste", "cmd.view_shots_strip": "Aufnahmenleiste",
"cmd.view_spin": "Ansicht kontinuierlich drehen", "cmd.view_spin": "Ansicht kontinuierlich drehen",
"cmd.view_tool": "Navigationswerkzeug", "cmd.view_tool": "Navigationswerkzeug",
"cmd.view_tool_zoom": "Durch Ziehen zoomen",
"cmd.view_top": "Draufsicht", "cmd.view_top": "Draufsicht",
"cmd.view_visual_style": "Darstellungsstil", "cmd.view_visual_style": "Darstellungsstil",
"color.blue": "Blau", "color.blue": "Blau",
@@ -1446,8 +1465,11 @@
"file.open.portal_fallback.xwayland": "Die geöffnete Dateiauswahl ist nicht die des Desktops: Unter XWayland lehnt das Portal das Elternfenster ab.", "file.open.portal_fallback.xwayland": "Die geöffnete Dateiauswahl ist nicht die des Desktops: Unter XWayland lehnt das Portal das Elternfenster ab.",
"file_load.built": "Bisher erstellt: {built} von {total} Merkmalen.", "file_load.built": "Bisher erstellt: {built} von {total} Merkmalen.",
"file_load.converting": "Volumenkörper {done} von {total} wird konvertiert", "file_load.converting": "Volumenkörper {done} von {total} wird konvertiert",
"file_load.inserted": "{name} eingefügt",
"file_load.inserting": "Geometrie wird eingefügt", "file_load.inserting": "Geometrie wird eingefügt",
"file_load.link_item": "{name} ({done} von {total})", "file_load.link_item": "{name} ({done} von {total})",
"file_load.opened": "{name} geöffnet",
"file_load.opened_in_tab": "{name} in neuem Tab geöffnet",
"file_load.opening": "Design wird geöffnet", "file_load.opening": "Design wird geöffnet",
"file_load.preparing_thumbnail": "Vorschaubild wird vorbereitet...", "file_load.preparing_thumbnail": "Vorschaubild wird vorbereitet...",
"file_load.preparing_view": "Ansicht wird vorbereitet...", "file_load.preparing_view": "Ansicht wird vorbereitet...",
@@ -1456,6 +1478,7 @@
"file_load.reading_percent": "Datei wird gelesen... {percent} %", "file_load.reading_percent": "Datei wird gelesen... {percent} %",
"file_load.rebuilding": "Merkmal {done} von {total} wird neu aufgebaut", "file_load.rebuilding": "Merkmal {done} von {total} wird neu aufgebaut",
"file_load.recovering": "Design wird wiederhergestellt", "file_load.recovering": "Design wird wiederhergestellt",
"file_load.reloading_cloud": "Punktwolke wird neu geladen",
"file_load.step_build": "Modell wird aufgebaut", "file_load.step_build": "Modell wird aufgebaut",
"file_load.step_feature": "Merkmal {done} von {total}", "file_load.step_feature": "Merkmal {done} von {total}",
"file_load.step_part": "Teil {done} von {total}", "file_load.step_part": "Teil {done} von {total}",
@@ -1683,7 +1706,7 @@
"help.sketch.insert_svg": "Liest die Pfade einer SVG-Zeichnung in eine Skizze ein, skaliert, gedreht und an der gewünschten Stelle. Damit machen Sie aus einem Logo oder einer Vektorkontur Kurven, die sich extrudieren lassen.", "help.sketch.insert_svg": "Liest die Pfade einer SVG-Zeichnung in eine Skizze ein, skaliert, gedreht und an der gewünschten Stelle. Damit machen Sie aus einem Logo oder einer Vektorkontur Kurven, die sich extrudieren lassen.",
"help.sketch.inspect": "Öffnet einen Bericht zur offenen Skizze: wie viele Freiheitsgrade übrig sind und ob sie vollständig bestimmt ist. Damit sehen Sie, was sich noch bewegt, bevor Sie die Skizze abschließen.", "help.sketch.inspect": "Öffnet einen Bericht zur offenen Skizze: wie viele Freiheitsgrade übrig sind und ob sie vollständig bestimmt ist. Damit sehen Sie, was sich noch bewegt, bevor Sie die Skizze abschließen.",
"help.sketch.intersect": "Fügt die Kurven oder Punkte hinzu, an denen Körper, Flächen, Kanten oder andere Skizzen die Skizzenebene schneiden. Sie bleiben verknüpft und folgen Änderungen am Modell.", "help.sketch.intersect": "Fügt die Kurven oder Punkte hinzu, an denen Körper, Flächen, Kanten oder andere Skizzen die Skizzenebene schneiden. Sie bleiben verknüpft und folgen Änderungen am Modell.",
"help.sketch.intersection_curve": "Erzeugt 3D-Kurven, wo sich zwei Körper oder Flächen treffen, mit diesen verknüpft. Als Pfade oder Leitkurven, die dem Modell folgen.", "help.sketch.intersection_curve": "Erzeugt 3D-Kurven, wo sich zwei Körper, Flächen oder Kurven anderer Skizzen treffen, mit diesen verknüpft. Als Pfade oder Leitkurven, die dem Modell folgen.",
"help.sketch.isoparametric_curve": "Erzeugt eine 3D-Kurve in U- oder V-Richtung einer Fläche durch einen gewählten Punkt, mit der Fläche verknüpft. Als Pfad oder Trennlinie, die der Fläche folgt.", "help.sketch.isoparametric_curve": "Erzeugt eine 3D-Kurve in U- oder V-Richtung einer Fläche durch einen gewählten Punkt, mit der Fläche verknüpft. Als Pfad oder Trennlinie, die der Fläche folgt.",
"help.sketch.line": "Zeichnet verbundene Linien Punkt für Punkt, als offene Kette oder geschlossene Kontur. Das Grundwerkzeug für die meisten Profile.", "help.sketch.line": "Zeichnet verbundene Linien Punkt für Punkt, als offene Kette oder geschlossene Kontur. Das Grundwerkzeug für die meisten Profile.",
"help.sketch.line.midpoint": "Zeichnet eine Linie von ihrem Mittelpunkt zu einem Ende, das andere Ende gespiegelt. Für Linien, die auf einem Punkt mittig liegen, etwa eine symmetrische Kante.", "help.sketch.line.midpoint": "Zeichnet eine Linie von ihrem Mittelpunkt zu einem Ende, das andere Ende gespiegelt. Für Linien, die auf einem Punkt mittig liegen, etwa eine symmetrische Kante.",
@@ -1695,6 +1718,7 @@
"help.sketch.pattern.circular": "Kopiert Skizzengeometrie um einen Mittelpunkt, über einen vollen Kreis oder einen festen Winkel. Für Lochkreise, Speichen und Zähne.", "help.sketch.pattern.circular": "Kopiert Skizzengeometrie um einen Mittelpunkt, über einen vollen Kreis oder einen festen Winkel. Für Lochkreise, Speichen und Zähne.",
"help.sketch.pattern.rectangular": "Kopiert Skizzengeometrie in Reihen und Spalten mit festen Abständen. Für Raster aus Bohrungen, Schlitzen oder Lüftungsöffnungen.", "help.sketch.pattern.rectangular": "Kopiert Skizzengeometrie in Reihen und Spalten mit festen Abständen. Für Raster aus Bohrungen, Schlitzen oder Lüftungsöffnungen.",
"help.sketch.point": "Setzt einen Skizzenpunkt. Als Bezug für Maße, Bedingungen, Bohrungsmitten oder spätere Elemente.", "help.sketch.point": "Setzt einen Skizzenpunkt. Als Bezug für Maße, Bedingungen, Bohrungsmitten oder spätere Elemente.",
"help.sketch.point.divide": "Setzt Punkte, die die gewählten Kurven in gleich lange Abschnitte teilen. Die Punkte bleiben auf jeder Kurve und behalten ihren Abstand, wenn sie sich ändert.",
"help.sketch.point3d": "Setzt bei eingeschalteter 3D-Skizze einen Punkt im Raum. Als Bezug für 3D-Kurven und Pfade.", "help.sketch.point3d": "Setzt bei eingeschalteter 3D-Skizze einen Punkt im Raum. Als Bezug für 3D-Kurven und Pfade.",
"help.sketch.polygon.circumscribed": "Zeichnet ein regelmäßiges Polygon um einen Kreis, bemessen vom Mittelpunkt zur Mitte einer Seite. Wenn die Schlüsselweite bekannt ist, etwa bei einer Sechskantmutter.", "help.sketch.polygon.circumscribed": "Zeichnet ein regelmäßiges Polygon um einen Kreis, bemessen vom Mittelpunkt zur Mitte einer Seite. Wenn die Schlüsselweite bekannt ist, etwa bei einer Sechskantmutter.",
"help.sketch.polygon.edge": "Zeichnet ein regelmäßiges Polygon aus den beiden Enden einer Seite. Wenn Länge und Lage einer Seite bekannt sind.", "help.sketch.polygon.edge": "Zeichnet ein regelmäßiges Polygon aus den beiden Enden einer Seite. Wenn Länge und Lage einer Seite bekannt sind.",
@@ -2143,6 +2167,7 @@
"navbar.value_tip": "{name} · {value}", "navbar.value_tip": "{name} · {value}",
"navbar.visual_style": "Darstellung", "navbar.visual_style": "Darstellung",
"navbar.zoom": "Zoomen", "navbar.zoom": "Zoomen",
"navbar.zoom_hold_tip": "Zoomen (Tastenkürzel gedrückt halten)",
"needs two joints": "benötigt zwei Gelenke", "needs two joints": "benötigt zwei Gelenke",
"network.allow_once": "Einmalig erlauben", "network.allow_once": "Einmalig erlauben",
"network.always_allow": "Diesen Server immer erlauben", "network.always_allow": "Diesen Server immer erlauben",
@@ -2293,6 +2318,7 @@
"prefs.carousel_previous": "Zurück", "prefs.carousel_previous": "Zurück",
"prefs.choose_font": "Schriftdatei auswählen…", "prefs.choose_font": "Schriftdatei auswählen…",
"prefs.click": "Klicken", "prefs.click": "Klicken",
"prefs.command_dialog_values": "Befehlsdialoge",
"prefs.contact_shading": "Weiche Kontaktschattierung", "prefs.contact_shading": "Weiche Kontaktschattierung",
"prefs.contact_shading_note": "Erzeugt weiche Schatten an Stellen, an denen sich Bauteile nahekommen.", "prefs.contact_shading_note": "Erzeugt weiche Schatten an Stellen, an denen sich Bauteile nahekommen.",
"prefs.context_menu": "Kontextmenü", "prefs.context_menu": "Kontextmenü",
@@ -2339,6 +2365,8 @@
"prefs.edges": "Kanten und Schattierung", "prefs.edges": "Kanten und Schattierung",
"prefs.extend": "Erweitern", "prefs.extend": "Erweitern",
"prefs.extra_navigation": "Mit Strg und gedrückter linker Maustaste auf einer freien Fläche drehen. Leertaste gedrückt halten, um die Ansicht zu verschieben.", "prefs.extra_navigation": "Mit Strg und gedrückter linker Maustaste auf einer freien Fläche drehen. Leertaste gedrückt halten, um die Ansicht zu verschieben.",
"prefs.extrude_arrow_face_stops": "Extrusionspfeil hält an Flächen",
"prefs.extrude_arrow_face_stops_note": "Beim Ziehen des Abstandspfeils von Extrusion hält er an ebenen Flächen parallel zum Profil, etwa an der Rückseite eines Blocks, in den geschnitten wird, und hebt die Fläche hervor. Aus: Der Pfeil bewegt sich nur in runden Schritten.",
"prefs.extrude_view_isometric": "Beim Öffnen von Extrudieren isometrisch ausrichten", "prefs.extrude_view_isometric": "Beim Öffnen von Extrudieren isometrisch ausrichten",
"prefs.extrude_view_return": "Beim Schließen von Extrudieren zur vorigen Ansicht zurück", "prefs.extrude_view_return": "Beim Schließen von Extrudieren zur vorigen Ansicht zurück",
"prefs.follows_os": "Wie im Betriebssystem", "prefs.follows_os": "Wie im Betriebssystem",
@@ -2388,9 +2416,15 @@
"prefs.graphics_page.surfaces_edges": "Flächen und Kanten", "prefs.graphics_page.surfaces_edges": "Flächen und Kanten",
"prefs.graphics_page.view_bar": "Auch in der Ansichtsleiste", "prefs.graphics_page.view_bar": "Auch in der Ansichtsleiste",
"prefs.graphics_presets_note": "Mit den Profilen werden die unten aufgeführten Optionen gemeinsam eingestellt.", "prefs.graphics_presets_note": "Mit den Profilen werden die unten aufgeführten Optionen gemeinsam eingestellt.",
"prefs.ground_shadow_follows_model": "Bodenschatten folgt dem Modell",
"prefs.ground_shadow_follows_model_help": "Den Schatten unter dem niedrigsten sichtbaren Körper platzieren. Wenn deaktiviert, bleibt der Schatten angehobener Modelle auf der Bodenebene durch den Ursprung.",
"prefs.hide_constraint_glyphs_zoomed_out": "Bindungssymbole bei starkem Herauszoomen ausblenden", "prefs.hide_constraint_glyphs_zoomed_out": "Bindungssymbole bei starkem Herauszoomen ausblenden",
"prefs.hide_constraint_glyphs_zoomed_out_note": "Bindungssymbole verschwinden, wenn die Skizze so weit herausgezoomt ist, dass sie sie überladen würden. Aus: sie behalten bei jedem Zoom eine feste Bildschirmgröße.", "prefs.hide_constraint_glyphs_zoomed_out_note": "Bindungssymbole verschwinden, wenn die Skizze so weit herausgezoomt ist, dass sie sie überladen würden. Aus: sie behalten bei jedem Zoom eine feste Bildschirmgröße.",
"prefs.history": "Verlauf", "prefs.history": "Verlauf",
"prefs.history_bar_groups": "Verlaufsleiste in Gruppen falten",
"prefs.history_bar_groups_note": "In einem langen Verlauf wird eine Folge von Features einer Komponente zu einem Chip gefaltet, und Merkmalsordner beginnen gefaltet. Eine eingefügte STEP-Baugruppe kommt in einen Group-Ordner. Aus zeigt jedes Feature, öffnet Ordner und legt keinen Ordner an.",
"prefs.history_group_joints": "Gelenke im Verlauf gruppieren",
"prefs.history_group_joints_note": "Zwei oder mehr Gelenke erscheinen als eine Schaltfläche mit ihrer Anzahl; ein Klick zeigt jedes einzeln. Aus zeigt jedes Gelenk einzeln.",
"prefs.history_origin_bodies": "Ursprung und Körper oben zeigen", "prefs.history_origin_bodies": "Ursprung und Körper oben zeigen",
"prefs.history_origin_bodies_note": "Der Verlauf links oder unter dem Browser beginnt mit dem Körper-Ordner der aktiven Komponente und dem Ursprung, mit Augen und Menüs wie im Browser. Der Verlauf unten bleibt unverändert.", "prefs.history_origin_bodies_note": "Der Verlauf links oder unter dem Browser beginnt mit dem Körper-Ordner der aktiven Komponente und dem Ursprung, mit Augen und Menüs wie im Browser. Der Verlauf unten bleibt unverändert.",
"prefs.history_play_button": "Schaltfläche „Verlauf abspielen“ in den Verlaufssteuerelementen", "prefs.history_play_button": "Schaltfläche „Verlauf abspielen“ in den Verlaufssteuerelementen",
@@ -2423,6 +2457,8 @@
"prefs.layout_page.card": "Karte", "prefs.layout_page.card": "Karte",
"prefs.layout_page.column": "Spalte", "prefs.layout_page.column": "Spalte",
"prefs.layout_page.hover": "Bei Mauszeiger", "prefs.layout_page.hover": "Bei Mauszeiger",
"prefs.layout_page.hover_panel_menus": "Bereichsmenüs beim Darüberfahren wechseln",
"prefs.layout_page.hover_panel_menus_help": "Klicken Sie auf einen Bereichsnamen, um das Menü zu öffnen. Bewegen Sie den Zeiger auf einen anderen Bereichsnamen, um das Menü zu wechseln. Außerhalb des Menübands und des geöffneten Menüs schließt es sich.",
"prefs.layout_page.icons_labels": "Symbole + Beschriftungen", "prefs.layout_page.icons_labels": "Symbole + Beschriftungen",
"prefs.layout_page.ok_cancel": "OK und Abbrechen", "prefs.layout_page.ok_cancel": "OK und Abbrechen",
"prefs.layout_page.on_hover": "Bei Mauszeiger", "prefs.layout_page.on_hover": "Bei Mauszeiger",
@@ -2461,6 +2497,8 @@
"prefs.mouse": "Maus und Trackpad", "prefs.mouse": "Maus und Trackpad",
"prefs.mouse_heading": "Maus", "prefs.mouse_heading": "Maus",
"prefs.mouse_mapping": "Mausbelegung", "prefs.mouse_mapping": "Mausbelegung",
"prefs.move_drag_highlights": "Hervorheben, was unter dem Zeiger liegt, während die Pfeile von Verschieben eine Komponente ziehen",
"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": "Navigation",
"prefs.navigation.axes_signed": "Achsen", "prefs.navigation.axes_signed": "Achsen",
"prefs.navigation.cube_compact": "Würfel", "prefs.navigation.cube_compact": "Würfel",
@@ -2525,6 +2563,10 @@
"prefs.quality_smoother": "Stärker geglättet", "prefs.quality_smoother": "Stärker geglättet",
"prefs.quick_measure": "Schnellmessung in der Ecke der Ansicht", "prefs.quick_measure": "Schnellmessung in der Ecke der Ansicht",
"prefs.quick_measure_note": "Zeigt unten rechts in der Ansicht die Größe der Auswahl an: bei einer Kante die Länge, bei einer kreisförmigen Kante zusätzlich Durchmesser (Ø) und Radius (R), bei einer Fläche den Flächeninhalt, bei einem Punkt die Position, bei zwei Elementen Abstand und Winkel sowie bei mehreren Kanten oder Flächen die Gesamtlänge bzw. Gesamtfläche. Ein Klick kopiert den Messwert.", "prefs.quick_measure_note": "Zeigt unten rechts in der Ansicht die Größe der Auswahl an: bei einer Kante die Länge, bei einer kreisförmigen Kante zusätzlich Durchmesser (Ø) und Radius (R), bei einer Fläche den Flächeninhalt, bei einem Punkt die Position, bei zwei Elementen Abstand und Winkel sowie bei mehreren Kanten oder Flächen die Gesamtlänge bzw. Gesamtfläche. Ein Klick kopiert den Messwert.",
"prefs.remember_dialog_values": "Befehlsdialogwerte merken",
"prefs.remember_dialog_values.help": "Standardmäßig aus. Wenn aktiviert, werden nach erfolgreicher Ausführung eines Befehls seine sicheren Werte und Optionen beim nächsten Öffnen desselben Befehls wiederverwendet, bis SolidCraft geschlossen wird.",
"prefs.render_legacy_image_defaults": "Bisherige Render-Bildvorgaben verwenden",
"prefs.render_legacy_image_defaults_help": "Den bisherigen manuellen Ablauf beibehalten: neue Setups mit CPU-Raster, feste Abtastung beim CPU-Raytracing und manuell geöffnete Ergebnisse. Beim Wechsel zu Render die Ansicht neu einpassen, Aufnahmen ohne Wiederherstellung ihrer Kamera wechseln und die bisherige Bildausrichtung und Navigation verwenden. Automatische Live-Bildrückmeldungen deaktivieren. Gespeicherte Setups bleiben unverändert.",
"prefs.render_previous_geometry_budget": "Bisheriges Geometriebudget für die Render-Vorschau verwenden", "prefs.render_previous_geometry_budget": "Bisheriges Geometriebudget für die Render-Vorschau verwenden",
"prefs.render_previous_geometry_budget_help": "Stellt die bisherige feste Obergrenze für die Geometrie wieder her (512 MiB auf 64-Bit-Desktop-Systemen, andernfalls 128 MiB) anstelle des geräteabhängigen Budgets.", "prefs.render_previous_geometry_budget_help": "Stellt die bisherige feste Obergrenze für die Geometrie wieder her (512 MiB auf 64-Bit-Desktop-Systemen, andernfalls 128 MiB) anstelle des geräteabhängigen Budgets.",
"prefs.reports_saved": "{n} gespeichert", "prefs.reports_saved": "{n} gespeichert",
@@ -2601,6 +2643,7 @@
"prefs.sketch_exit_view_note": "Legt fest, zu welcher Ansicht nach „Skizze beenden“, „Abbrechen“ oder zweimaligem Drücken der Esc-Taste gewechselt wird.", "prefs.sketch_exit_view_note": "Legt fest, zu welcher Ansicht nach „Skizze beenden“, „Abbrechen“ oder zweimaligem Drücken der Esc-Taste gewechselt wird.",
"prefs.sketch_face_activates_part": "Skizzieren auf der Fläche eines Teils aktiviert dieses Teil", "prefs.sketch_face_activates_part": "Skizzieren auf der Fläche eines Teils aktiviert dieses Teil",
"prefs.sketch_face_activates_part_note": "Eine Skizze, die auf einer Fläche am Körper einer anderen Komponente begonnen wird, aktiviert zuerst diese Komponente, sodass die Skizze zu ihr gehört und im Browser bei diesem Teil bleibt. Das Teil bleibt danach aktiv. Aus: Die Skizze gehört zur aktiven Komponente.", "prefs.sketch_face_activates_part_note": "Eine Skizze, die auf einer Fläche am Körper einer anderen Komponente begonnen wird, aktiviert zuerst diese Komponente, sodass die Skizze zu ihr gehört und im Browser bei diesem Teil bleibt. Das Teil bleibt danach aktiv. Aus: Die Skizze gehört zur aktiven Komponente.",
"prefs.sketch_mirror_auto_line": "Vorausgewählte Konstruktionslinie zum Spiegeln verwenden",
"prefs.sketch_open_look_at": "Beim Öffnen einer Skizze auf sie ausrichten", "prefs.sketch_open_look_at": "Beim Öffnen einer Skizze auf sie ausrichten",
"prefs.sketch_open_look_at_note": "Aus: Beim Erstellen oder Bearbeiten einer Skizze bleibt die Ansicht, wie sie ist. „Ansehen“ richtet die Ansicht bei Bedarf auf die Skizze aus.", "prefs.sketch_open_look_at_note": "Aus: Beim Erstellen oder Bearbeiten einer Skizze bleibt die Ansicht, wie sie ist. „Ansehen“ richtet die Ansicht bei Bedarf auf die Skizze aus.",
"prefs.sketch_recent_snap": "Automatisch an zuletzt verwendete Mittelpunkte fangen", "prefs.sketch_recent_snap": "Automatisch an zuletzt verwendete Mittelpunkte fangen",
@@ -2652,6 +2695,8 @@
"prefs.structure.work": "Arbeit", "prefs.structure.work": "Arbeit",
"prefs.supersampling_brief": "Rendert die Ansicht größer und verkleinert sie dann: sehr scharf, aber rechenintensiver.", "prefs.supersampling_brief": "Rendert die Ansicht größer und verkleinert sie dann: sehr scharf, aber rechenintensiver.",
"prefs.tab_accent_note": "Die Akzentfarbe richtet sich nach dem aktiven Tab.", "prefs.tab_accent_note": "Die Akzentfarbe richtet sich nach dem aktiven Tab.",
"prefs.tab_double_click_renames": "Entwurfsregisterkarte per Doppelklick umbenennen",
"prefs.tab_double_click_renames_note": "Geben Sie den neuen Namen ein und drücken Sie Enter oder klicken Sie woanders hin, um ihn zu übernehmen, oder Esc zum Abbrechen. Aus: Ein Doppelklick auf eine Registerkarte maximiert das Fenster, wie auf dem leeren Teil der Leiste.",
"prefs.theme_file": "Designdatei", "prefs.theme_file": "Designdatei",
"prefs.theme_file_or_paste": "Datei oder Einfügen", "prefs.theme_file_or_paste": "Datei oder Einfügen",
"prefs.theme_follow": "Einer Designdatei folgen", "prefs.theme_follow": "Einer Designdatei folgen",
@@ -2748,6 +2793,9 @@
"refused.join": "Konnte nicht mit {body} vereinigt werden.", "refused.join": "Konnte nicht mit {body} vereinigt werden.",
"refused.repair": "Teil reparieren", "refused.repair": "Teil reparieren",
"refused.show_face": "Fläche zeigen", "refused.show_face": "Fläche zeigen",
"render.adaptive.pilot_progress": "Adaptive Pilotphase · {current}/{target} Durchgänge",
"render.adaptive.preview_help": "Pilotbilder bestimmen die Verteilung und sind vom Endbild ausgeschlossen. Produktionsiterationen nutzen ein eigenes Budget pro Pixel; die Iterationszahl ist keine einheitliche Samplezahl pro Pixel.",
"render.adaptive.production_progress": "Adaptive Produktion · {current}/{target} Iterationen",
"render.adaptive_absolute": "Absolute RGB-Fehleruntergrenze", "render.adaptive_absolute": "Absolute RGB-Fehleruntergrenze",
"render.adaptive_coverage": "Zielwert für den Abdeckungsfehler", "render.adaptive_coverage": "Zielwert für den Abdeckungsfehler",
"render.adaptive_enable": "Samples mithilfe unabhängiger Pilot-Samples zuteilen", "render.adaptive_enable": "Samples mithilfe unabhängiger Pilot-Samples zuteilen",
@@ -2776,6 +2824,7 @@
"render.aging_metallic": "Metallanteil der Schicht", "render.aging_metallic": "Metallanteil der Schicht",
"render.aging_origin": "Feldursprung · Weltkoordinaten (mm)", "render.aging_origin": "Feldursprung · Weltkoordinaten (mm)",
"render.aging_patina": "Kupfergrüne Patina", "render.aging_patina": "Kupfergrüne Patina",
"render.aging_raytrace_help": "Alterung wird beim CPU-Raytracing und GPU-Pathtracing angewendet. Raster bleibt eine schematische Darstellung.",
"render.aging_refresh_targets": "Aktuelle Körper prüfen", "render.aging_refresh_targets": "Aktuelle Körper prüfen",
"render.aging_roughness": "Rauheit der Schicht", "render.aging_roughness": "Rauheit der Schicht",
"render.aging_rust": "Oxidiertes Eisen / Rost", "render.aging_rust": "Oxidiertes Eisen / Rost",
@@ -2796,6 +2845,7 @@
"render.appearance_editor.closed": "Geschlossener Körper", "render.appearance_editor.closed": "Geschlossener Körper",
"render.appearance_editor.coat": "Klarlack", "render.appearance_editor.coat": "Klarlack",
"render.appearance_editor.cpu_reason": "Benötigt CPU-Strahlverfolgung.", "render.appearance_editor.cpu_reason": "Benötigt CPU-Strahlverfolgung.",
"render.appearance_editor.discard_saved_edit": "Ungespeicherte Optikänderungen verwerfen",
"render.appearance_editor.glass": "Glas und Absorption", "render.appearance_editor.glass": "Glas und Absorption",
"render.appearance_editor.glass_enable": "Physikalisches Glas für diesen Körper verwenden", "render.appearance_editor.glass_enable": "Physikalisches Glas für diesen Körper verwenden",
"render.appearance_editor.glass_note": "Geschlossenes Glas verwendet geometrische Abstände. Es kann nicht mit Klarlack oder Texturen auf demselben Körper kombiniert werden.", "render.appearance_editor.glass_note": "Geschlossenes Glas verwendet geometrische Abstände. Es kann nicht mit Klarlack oder Texturen auf demselben Körper kombiniert werden.",
@@ -2860,9 +2910,13 @@
"render.base_metallic": "Metallanteil", "render.base_metallic": "Metallanteil",
"render.base_opaque_only": "Dieser Editor lässt Körper undurchsichtig. Für optische Transmission verwenden Sie die gesonderten Glaseinstellungen.", "render.base_opaque_only": "Dieser Editor lässt Körper undurchsichtig. Für optische Transmission verwenden Sie die gesonderten Glaseinstellungen.",
"render.batch_all_shots": "Alle Ansichten ({count})", "render.batch_all_shots": "Alle Ansichten ({count})",
"render.batch_current_settings_help": "Verwendet die aktuellen Bildeinstellungen mit jeder gespeicherten Aufnahmekamera, eine Aufnahme nach der anderen.",
"render.batch_empty": "Vor dem Rendern aller Ansichten eine Ansicht speichern.", "render.batch_empty": "Vor dem Rendern aller Ansichten eine Ansicht speichern.",
"render.batch_limit": "Es können höchstens 32 Ansichten gerendert werden.", "render.batch_limit": "Es können höchstens 32 Ansichten gerendert werden.",
"render.batch_owner_limit": "Es können höchstens 32 Dokument-Bildfolgen vorgehalten werden. Schließen Sie zuerst eine vorhandene Folge ab oder brechen Sie sie ab.",
"render.batch_preparing": "Nächste Aufnahme wird vorbereitet",
"render.batch_status": "{running} läuft · {waiting} warten", "render.batch_status": "{running} läuft · {waiting} warten",
"render.batch_waiting_worker": "Warten auf die Rendering-Vorbereitung",
"render.bloom_enable": "Darstellungs-Bloom", "render.bloom_enable": "Darstellungs-Bloom",
"render.bloom_help": "Kreativer Ausgabeglanz aus linearen Glanzlichtern mit drei normierten Durchläufen. Radius in Ausgabepixeln; Addition vor sRGB. Keine Linsen-, Volumen- oder Konvergenzsimulation. Das rohe EXR bleibt unverändert.", "render.bloom_help": "Kreativer Ausgabeglanz aus linearen Glanzlichtern mit drei normierten Durchläufen. Radius in Ausgabepixeln; Addition vor sRGB. Keine Linsen-, Volumen- oder Konvergenzsimulation. Das rohe EXR bleibt unverändert.",
"render.bloom_opaque": "Bloom benötigt eine deckende Ausgabe. Transparentes PNG wird abgelehnt, nicht still abgeflacht.", "render.bloom_opaque": "Bloom benötigt eine deckende Ausgabe. Transparentes PNG wird abgelehnt, nicht still abgeflacht.",
@@ -2892,6 +2946,16 @@
"render.category_paint": "Lack", "render.category_paint": "Lack",
"render.category_plastic": "Kunststoff", "render.category_plastic": "Kunststoff",
"render.category_wood": "Holz", "render.category_wood": "Holz",
"render.caustics_depth": "Kaustik-Pfadtiefe",
"render.caustics_enable": "Glaskaustiken durch Punkt- und Richtungslichter",
"render.caustics_help": "Die Photonenzahl bestimmt Rauschen und Aufwand. Der Sammelradius tauscht scharfe Details gegen eine glattere Schätzung. CPU benötigt indirekte Beleuchtung.",
"render.caustics_path_required": "CPU-Kaustiken benötigen indirekte Beleuchtung.",
"render.caustics_photons": "Photonen",
"render.caustics_radius": "Sammelradius",
"render.check_glass_cpu": "Die CPU unterstützt geprüfte ebene Glasscheiben und achsenparallele Boxen. Allgemeine geschlossene Netze, Verschachtelung und innere Streuung erfordern indirekte Beleuchtung. Durch geschlossenes Glas übertragene Schatten bleiben nicht unterstützt.",
"render.check_glass_gpu": "Die GPU unterstützt geprüfte getrennte Glasmedien oder ausdrücklich aktivierte geprüfte Verschachtelung. Dafür müssen die äußeren Körper konvex und die inneren streng enthalten sein; Grenzen dürfen sich nicht berühren.",
"render.check_media_remaining": "Dichtegitter, Displacement, vollständige spektrale Integration und fortgeführte Polarisation bleiben nicht verfügbar.",
"render.check_media_scope": "Aktive innere Streuung benötigt ein geschlossenes Glasmedium ohne gerade Schattenübertragung und ohne Rauschreduzierung. Die GPU benötigt außerdem eine Fresnel-Schicht. Aktive äußere Atmosphäre kann nicht mit Glas oder Oberflächen-Rauschreduzierung kombiniert werden.",
"render.check_opaque": "Transparenz: nur undurchsichtige Oberflächen; Hintergrund-Alpha wird unterstützt.", "render.check_opaque": "Transparenz: nur undurchsichtige Oberflächen; Hintergrund-Alpha wird unterstützt.",
"render.check_sorted_alpha": "Transparenz: Näherung mit sortiertem Alpha.", "render.check_sorted_alpha": "Transparenz: Näherung mit sortiertem Alpha.",
"render.check_transmission": "Transparenz: physikalische Transmission.", "render.check_transmission": "Transparenz: physikalische Transmission.",
@@ -2973,6 +3037,14 @@
"render.choose_look": "Zuerst einen Look in der Bibliothek wählen", "render.choose_look": "Zuerst einen Look in der Bibliothek wählen",
"render.chromatic_offset": "Chromatischer Kantenversatz", "render.chromatic_offset": "Chromatischer Kantenversatz",
"render.clear_stage": "Remove saved stage", "render.clear_stage": "Remove saved stage",
"render.coat_discard": "Klarlackänderung verwerfen",
"render.coat_pending_edit": "Diese Klarlackänderung ist ungespeichert. Mit der Aufnahme speichern oder verwerfen.",
"render.coat_remove": "Gespeicherten Klarlack entfernen",
"render.coat_remove_note": "Entfernt den Klarlack dieses Ziels aus der Aufnahme. Geometrie, Aussehen und physikalische Materialien bleiben unverändert.",
"render.coat_remove_title": "Gespeicherten Klarlack entfernen?",
"render.coat_revalidate_saved": "Der gespeicherte Klarlack wurde geändert. Diese Änderung verwerfen und das Ziel vor der nächsten Bearbeitung erneut öffnen.",
"render.coat_save": "Klarlack in Aufnahme speichern",
"render.coat_saved_help": "Klarlack fügt undurchsichtigen Flächen eine glänzende Schicht hinzu. Mit der Aufnahme speichern. Glas kann nicht dasselbe Ziel verwenden. Auf der CPU dürfen auch benutzerdefinierte Reflexions- und Anisotropieüberschreibungen dieses Ziel nicht verwenden.",
"render.compare_divider": "Vergleichstrenner", "render.compare_divider": "Vergleichstrenner",
"render.compare_live": "Live", "render.compare_live": "Live",
"render.compare_live_preview": "Live-Vorschau", "render.compare_live_preview": "Live-Vorschau",
@@ -3006,10 +3078,18 @@
"render.cpu_budget_triangles": "Dreiecksobergrenze", "render.cpu_budget_triangles": "Dreiecksobergrenze",
"render.cpu_budget_workstation": "Workstation (komplexe Szenen)", "render.cpu_budget_workstation": "Workstation (komplexe Szenen)",
"render.cpu_captured_hdr": "Für dieses Bild erfasstes HDR", "render.cpu_captured_hdr": "Für dieses Bild erfasstes HDR",
"render.cpu_celestial_adopt": "CPU-Raytracing mit indirekter Beleuchtung · Pfadtiefe {depth} · {spp} SPP · verfolgte Schatten · Seed {seed} · 1 Primärsample",
"render.cpu_celestial_adopt_label": "CPU-Raytracing mit indirekter Beleuchtung",
"render.cpu_celestial_path_required": "Endliche Sonne und Verlaufshimmel verwenden indirekte CPU-Beleuchtung.",
"render.cpu_celestial_switch": "Wähle CPU-Raytracing mit indirekter Beleuchtung, um diese Sonne oder diesen Himmel beizubehalten.",
"render.cpu_celestial_unportable": "Behalte GPU-Pathtracing für die aktuellen Transmissions-Sample-Einstellungen bei.",
"render.cpu_check_capture_help": "Prüfen und Starten verifizieren dieselbe Datei-Prüfsumme oder verwenden das eingebettete HDR. Jedes Bild behält seine erfasste Quelle.", "render.cpu_check_capture_help": "Prüfen und Starten verifizieren dieselbe Datei-Prüfsumme oder verwenden das eingebettete HDR. Jedes Bild behält seine erfasste Quelle.",
"render.cpu_check_changed": "Die Einstellungen oder das Modell haben sich nach dieser Prüfung geändert. Prüfen Sie erneut, bevor Sie rendern.", "render.cpu_check_changed": "Die Einstellungen oder das Modell haben sich nach dieser Prüfung geändert. Prüfen Sie erneut, bevor Sie rendern.",
"render.cpu_constant_direct_help": "Ohne indirekte Beleuchtung kann diese konstante Quelle in Reflexionen und durch Glas sichtbar sein. Sie beleuchtet keine undurchsichtigen Flächen. Schalte indirekte Beleuchtung ein, um sie als Szenenlicht zu nutzen.",
"render.cpu_constant_enable_indirect_plan": "Pfadtiefe {depth}; progressives Sampling mit {spp} Samples/Pixel (Seed {seed}); ein Primärstrahl pro Sample; Raytracing-Schatten. Bildgröße, CPU-Budget und andere Einstellungen bleiben erhalten.",
"render.cpu_constant_help": "Konstante Strahldichte ist für reflektierte oder durchgelassene Strahlen sichtbar. Sie liefert keine direkte diffuse Beleuchtung.", "render.cpu_constant_help": "Konstante Strahldichte ist für reflektierte oder durchgelassene Strahlen sichtbar. Sie liefert keine direkte diffuse Beleuchtung.",
"render.cpu_custom_directions": "Vorgabe durch eigene Richtungslichter ersetzen", "render.cpu_custom_directions": "Vorgabe durch eigene Richtungslichter ersetzen",
"render.cpu_denoise_help": "Verringert das Rauschen bei jeder Bildaktualisierung. Feine Details und Übergänge der Tiefenschärfe können weicher werden. Die EXR-Rohdaten bleiben unverändert. Nachträgliche Anpassungen eines fertigen Bildes verwenden dessen Rohbild und wenden die Rauschreduzierung nicht erneut an.",
"render.cpu_direction": "Richtung zum Licht (X, Y, Z)", "render.cpu_direction": "Richtung zum Licht (X, Y, Z)",
"render.cpu_directional": "Richtungslicht", "render.cpu_directional": "Richtungslicht",
"render.cpu_directional_add": "Richtungslicht hinzufügen", "render.cpu_directional_add": "Richtungslicht hinzufügen",
@@ -3021,8 +3101,11 @@
"render.cpu_environment_samples": "HDR-Beleuchtungs-Samples", "render.cpu_environment_samples": "HDR-Beleuchtungs-Samples",
"render.cpu_exposure_help": "Die CPU-Belichtung muss zwischen −16 und 16 EV liegen. Eine GPU-Belichtung außerhalb dieses Bereichs bleibt erhalten, bis Sie sie ändern.", "render.cpu_exposure_help": "Die CPU-Belichtung muss zwischen −16 und 16 EV liegen. Eine GPU-Belichtung außerhalb dieses Bereichs bleibt erhalten, bis Sie sie ändern.",
"render.cpu_fixed": "Einzelbild", "render.cpu_fixed": "Einzelbild",
"render.cpu_fixed_retained": "Feste Abtastung beibehalten",
"render.cpu_glass_enable_path": "Indirekte Beleuchtung einschalten",
"render.cpu_hdr_help": "Radiance-HDR-Datei (.hdr), Panorama im Format 2:1, bis zu 2048 × 1024 Pixel und 16 MiB. Für die CPU müssen die sRGB/D65-Primärfarben ausdrücklich in der Datei angegeben sein. Dateien ohne Angabe der Primärfarben sowie EXR-Dateien werden abgelehnt.", "render.cpu_hdr_help": "Radiance-HDR-Datei (.hdr), Panorama im Format 2:1, bis zu 2048 × 1024 Pixel und 16 MiB. Für die CPU müssen die sRGB/D65-Primärfarben ausdrücklich in der Datei angegeben sein. Dateien ohne Angabe der Primärfarben sowie EXR-Dateien werden abgelehnt.",
"render.cpu_hdr_reflection_help": "Raue HDR-Reflexionen erfordern vollständig metallische Körper- und Flächenoberflächen. Die Prüfung meldet nicht unterstützte Kombinationen.", "render.cpu_hdr_reflection_help": "Raue HDR-Reflexionen erfordern vollständig metallische Körper- und Flächenoberflächen. Die Prüfung meldet nicht unterstützte Kombinationen.",
"render.cpu_indirect_method_required": "Wähle CPU-Raytracing, um diesen Modus für indirekte Beleuchtung einzuschalten.",
"render.cpu_key_rim": "Haupt- und Konturlicht", "render.cpu_key_rim": "Haupt- und Konturlicht",
"render.cpu_last_check": "Letzte CPU-Prüfung", "render.cpu_last_check": "Letzte CPU-Prüfung",
"render.cpu_light_help": "Bis zu acht Richtungslichter. Eine leere eigene Liste schaltet sie aus; die Wahl einer Vorgabe stellt deren Lichter wieder her. Farben sind lineares RGB, und die Intensität ist ein relativer Wert, keine Leistungsangabe in Watt.", "render.cpu_light_help": "Bis zu acht Richtungslichter. Eine leere eigene Liste schaltet sie aus; die Wahl einer Vorgabe stellt deren Lichter wieder her. Farben sind lineares RGB, und die Intensität ist ein relativer Wert, keine Leistungsangabe in Watt.",
@@ -3034,18 +3117,32 @@
"render.cpu_lighting": "Beleuchtungsvorgabe", "render.cpu_lighting": "Beleuchtungsvorgabe",
"render.cpu_lights": "CPU-Lichter", "render.cpu_lights": "CPU-Lichter",
"render.cpu_linear_color": "Lineare Farbe (R, G, B)", "render.cpu_linear_color": "Lineare Farbe (R, G, B)",
"render.cpu_maps_saved_help": "CPU-Renderings können gespeicherte Karten undurchsichtiger Flächen verwenden: Oberfläche wählen und die Karten in der Aufnahme speichern. Mit indirekter Beleuchtung darf ein anderer Körper Glas verwenden; der Körper mit Karten darf kein Glas sein. Ausgewählte Reflexionen, Anisotropie und prozedurale Effekte ausschalten. Temporäre Kartendateipfade verwenden die GPU.",
"render.cpu_material_certification": "Die CPU-Prüfung validiert unterstützte Glasgeometrie vor dem Rendern. Geschlossenes Glas verwendet geometrische Abstände.",
"render.cpu_neutral": "Neutral", "render.cpu_neutral": "Neutral",
"render.cpu_opaque_hint": "CPU-Raytracing verwendet einen undurchsichtigen Hintergrund.",
"render.cpu_opaque_required": "CPU-Raytracing benötigt einen undurchsichtigen Hintergrund. Entfernen Sie das Häkchen bei „Transparenter Hintergrund“, um fortzufahren.", "render.cpu_opaque_required": "CPU-Raytracing benötigt einen undurchsichtigen Hintergrund. Entfernen Sie das Häkchen bei „Transparenter Hintergrund“, um fortzufahren.",
"render.cpu_options_pending": "Dieses CPU-Bedienfeld kann Emission, Oberflächeneffekte, Glas oder Anisotropie noch nicht bearbeiten. Entfernen Sie diese API-Optionen, bevor Sie es verwenden.", "render.cpu_options_pending": "Dieses CPU-Bedienfeld kann Emission, Oberflächeneffekte, Glas oder Anisotropie noch nicht bearbeiten. Entfernen Sie diese API-Optionen, bevor Sie es verwenden.",
"render.cpu_path_depth": "Pfadtiefe",
"render.cpu_path_help": "Berechnet Licht, das zwischen undurchsichtigen Flächen und durch unterstützte Glasformen läuft. Erfordert progressives Rendern und Raytracing-Schatten. Die Pfadtiefe zählt beleuchtete Flächen, Glasgrenzen und Streuereignisse ab dem ersten Treffer (1–16). Tiefe 1 liefert direkte Beleuchtung auf undurchsichtigen Flächen; höhere Werte erlauben mehr Reflexionen oder Glasdurchgänge und können länger dauern. Für eigene Reflexionen oder Anisotropie die indirekte Beleuchtung ausschalten.",
"render.cpu_path_lighting": "Indirekte Beleuchtung",
"render.cpu_path_optics_reason": "Die Einstellungen bleiben erhalten. Für eigene Reflexionen oder Anisotropie die indirekte Beleuchtung ausschalten.",
"render.cpu_point": "Punktlicht", "render.cpu_point": "Punktlicht",
"render.cpu_point_add": "Punktlicht hinzufügen", "render.cpu_point_add": "Punktlicht hinzufügen",
"render.cpu_point_help": "Bis zu acht Punktlichter, zusätzlich zur gewählten Richtungsbeleuchtung. Abstände in mm; der Mindestabstand darf den Referenzabstand nicht überschreiten.", "render.cpu_point_help": "Bis zu acht Punktlichter, zusätzlich zur gewählten Richtungsbeleuchtung. Abstände in mm; der Mindestabstand darf den Referenzabstand nicht überschreiten.",
"render.cpu_primary_samples": "Kanten-Samples pro Pixel", "render.cpu_primary_samples": "Kanten-Samples pro Pixel",
"render.cpu_progressive": "CPU progressiv", "render.cpu_progressive": "CPU progressiv",
"render.cpu_progressive_adopt": "Progressive Abtastung verwenden",
"render.cpu_progressive_adopt_help": "Die progressive Abtastung verwendet ein Kamerasample pro Durchlauf. Bildgröße, Lichtquellen und Reflexionseinstellungen bleiben unverändert.",
"render.cpu_progressive_always": "Progressive Abtastung ist immer aktiv",
"render.cpu_progressive_help": "Neue CPU-Kamerasamples sammeln und jeden vollständigen Durchgang zeigen. Ausgewählte Reflexionen verwenden einen Versuch pro Kamerasample; zertifiziertes Glas und planare Anisotropie behalten ihre bisherigen Grenzen. Adaptive Pilot- und Produktionssamples teilen sich das CPU-Profilbudget.", "render.cpu_progressive_help": "Neue CPU-Kamerasamples sammeln und jeden vollständigen Durchgang zeigen. Ausgewählte Reflexionen verwenden einen Versuch pro Kamerasample; zertifiziertes Glas und planare Anisotropie behalten ihre bisherigen Grenzen. Adaptive Pilot- und Produktionssamples teilen sich das CPU-Profilbudget.",
"render.cpu_progressive_limits": "Höchstens 1.048.576 Pixel und 16.777.216 Auswertungen von Pixel × Sample. Das Ändern der Samples passt die Bildgröße nie automatisch an.", "render.cpu_progressive_limits": "Höchstens 1.048.576 Pixel und 16.777.216 Auswertungen von Pixel × Sample. Das Ändern der Samples passt die Bildgröße nie automatisch an.",
"render.cpu_progressive_reflection_adopt": "Setzen Sie die Reflexionsversuche ausgewählter Körper auf 1, bevor Sie die progressive Abtastung übernehmen.",
"render.cpu_progressive_seed": "Startwert für das CPU-Sampling", "render.cpu_progressive_seed": "Startwert für das CPU-Sampling",
"render.cpu_progressive_spp": "Samples pro Pixel", "render.cpu_progressive_spp": "Samples pro Pixel",
"render.cpu_quality_budget_help": "Ändert Größe, Obergrenze der Produktionssamples, Startwert und CPU-Ressourcenprofil. Kamera, Objektiv, Beleuchtung, GI-Tiefe und Effekte bleiben erhalten.",
"render.cpu_quality_progressive_required": "Aktiviere unten progressive Samples, bevor du ein CPU-Budget auswählst.",
"render.cpu_quality_summary": "{width} × {height} · Sample-Grenze {samples} · Startwert {seed} · {profile}",
"render.cpu_reflection_add": "Raue Reflexion hinzufügen", "render.cpu_reflection_add": "Raue Reflexion hinzufügen",
"render.cpu_reflection_depth": "Reflexionstiefe (1–8)", "render.cpu_reflection_depth": "Reflexionstiefe (1–8)",
"render.cpu_reflection_empty": "Keine Körper ausgewählt: Szenenreflexionen sind aus.", "render.cpu_reflection_empty": "Keine Körper ausgewählt: Szenenreflexionen sind aus.",
@@ -3059,7 +3156,21 @@
"render.cpu_runtime_help": "Numerische Licht- und Umgebungseinstellungen werden mit dem Setup gespeichert. Körperreflexionen und HDR-Dateien bleiben vorübergehend. Vorhandene Werte für Flächenlicht und Spotkegel bleiben erhalten.", "render.cpu_runtime_help": "Numerische Licht- und Umgebungseinstellungen werden mit dem Setup gespeichert. Körperreflexionen und HDR-Dateien bleiben vorübergehend. Vorhandene Werte für Flächenlicht und Spotkegel bleiben erhalten.",
"render.cpu_sampling_mode": "CPU-Sampling-Modus", "render.cpu_sampling_mode": "CPU-Sampling-Modus",
"render.cpu_shadows": "Schatten werfen", "render.cpu_shadows": "Schatten werfen",
"render.cpu_sky_bounds": "Die Himmelsrotation muss endlich innerhalb ±1.000.000 Radiant liegen; die Intensität muss 0–100 sein.",
"render.cpu_studio_enable": "Indirekte Beleuchtung für dieses Lichtset aktivieren",
"render.cpu_studio_enable_apply": "Indirekte Beleuchtung aktivieren und anwenden",
"render.cpu_studio_indirect_help": "Dieses Sonnen-Lichtset benötigt indirekte Beleuchtung mit Tiefe 8, verfolgte Schatten und eine Kamerastichprobe pro Durchlauf. Ist progressives Rendern ausgeschaltet, beginnt es mit 16 Stichproben pro Pixel und Startwert 0. Vorhandene progressive Einstellungen und das Ressourcenprofil bleiben erhalten. Unvereinbare Einstellungen verhindern die Anwendung, ohne sie zu ändern.",
"render.cpu_studio_radiance_limit": "Dieses Lichtset hat eine Flächenstrahldichte von {radiance}, über der CPU-Grenze von 64. Die vorgegebene Beleuchtung bleibt erhalten; wählen Sie ein anderes Lichtset oder GPU.",
"render.cpu_subsurface_denoise_reason": "Streuung im Glas auf der CPU benötigt ausgeschaltete Rauschreduzierung. Die Einstellungen bleiben erhalten.",
"render.cpu_subsurface_help": "Streuung lenkt Licht im Inneren geschlossenen Glases um. Positive Raten benötigen indirekte Beleuchtung ohne Rauschreduzierung. Die Rate zählt Kollisionen pro mm; 0 fügt keine Streuung hinzu. Positive Richtungswerte bevorzugen vorwärts, negative rückwärts.",
"render.cpu_summary": "CPU-Raytracing · Reflexionen · HDR · Richtungs- und Punktlichter", "render.cpu_summary": "CPU-Raytracing · Reflexionen · HDR · Richtungs- und Punktlichter",
"render.cpu_transparent_help": "Transparentes PNG entfernt den Hintergrund und erhält die Kantenabdeckung. Körper- und Flächendeckkraft müssen 100 % bleiben.",
"render.cpu_volume_enable_path": "Indirekte Beleuchtung einschalten",
"render.cpu_volume_enable_path_plan": "CPU-Raytracing · Pfadtiefe {depth} · {spp} Samples/Pixel · Seed {seed} · Raytracing-Schatten. Atmosphäre und Bildbudget bleiben erhalten.",
"render.cpu_volume_help": "CPU-Atmosphäre nutzt indirekte Beleuchtung. Bei Extinktion null bleibt die gespeicherte Box ohne Nebel erhalten.",
"render.cpu_volume_method_adopt": "CPU-Raytracing mit indirekter Beleuchtung",
"render.cpu_volume_method_incompatible": "Diese Licht-, Sampling- oder Atmosphäreinstellungen lassen sich nicht auf diese Methode übertragen. Die Einstellungen bleiben erhalten.",
"render.cpu_volume_path_required": "Indirekte Beleuchtung einschalten, um CPU-Atmosphäre zu nutzen.",
"render.cpu_warm_cool": "Warm und kühl", "render.cpu_warm_cool": "Warm und kühl",
"render.diag_bodies": "Sichtbare Körper", "render.diag_bodies": "Sichtbare Körper",
"render.diag_job_details": "Erfasste Auftragsdetails", "render.diag_job_details": "Erfasste Auftragsdetails",
@@ -3069,6 +3180,7 @@
"render.diag_preflight_details": "Details der Vorabprüfung", "render.diag_preflight_details": "Details der Vorabprüfung",
"render.diag_request": "Aktuelle Anfrage im Wortlaut", "render.diag_request": "Aktuelle Anfrage im Wortlaut",
"render.diag_triangles": "Dreiecke", "render.diag_triangles": "Dreiecke",
"render.directional_sun_limit": "Die GPU unterstützt insgesamt acht gerichtete Lichtquellen, darunter höchstens eine weiche Sonne. Dupliziere ein hartes gerichtetes Licht für eine weitere entfernte Quelle.",
"render.discard_continue": "Entwurf verwerfen und fortfahren", "render.discard_continue": "Entwurf verwerfen und fortfahren",
"render.draft_confirm_help": "Der aktuelle Render-Entwurf enthält nicht angewendete Änderungen. Speichern Sie sie vor dem Wechsel, verwerfen Sie sie ausdrücklich oder bearbeiten Sie weiter.", "render.draft_confirm_help": "Der aktuelle Render-Entwurf enthält nicht angewendete Änderungen. Speichern Sie sie vor dem Wechsel, verwerfen Sie sie ausdrücklich oder bearbeiten Sie weiter.",
"render.draft_confirm_title": "Bearbeitete Rendereinstellungen beibehalten", "render.draft_confirm_title": "Bearbeitete Rendereinstellungen beibehalten",
@@ -3256,11 +3368,20 @@
"render.frame_tall": "9:16 · Vertikal", "render.frame_tall": "9:16 · Vertikal",
"render.frame_thirds": "Drittellinien", "render.frame_thirds": "Drittellinien",
"render.frame_wide": "16:9 · Breitbild", "render.frame_wide": "16:9 · Breitbild",
"render.glass_abbe": "Abbe-Zahl",
"render.glass_dispersion": "Chromatische Dispersion",
"render.glass_film": "Dünnschichtinterferenz",
"render.glass_film_ior": "Brechungsindex der Schicht",
"render.glass_film_thickness": "Schichtdicke",
"render.glass_model_enable": "Erweitertes Glasmodell",
"render.glass_model_help": "Glasrauheit streut durchgelassene Strahlen. Dispersion und Schichtfarbe verwenden drei Wellenlängenbänder. Raue Scheiben benötigen ausgeschaltete gerade Schattenübertragung.",
"render.glass_roughness": "Glasrauheit",
"render.gpu_depth": "Maximale Pfadtiefe", "render.gpu_depth": "Maximale Pfadtiefe",
"render.gpu_options_help": "Samples, Tiefe, Startwert und Belichtung werden mit diesem Setup gespeichert. Es wird nur die aktive Bildmethode gespeichert.", "render.gpu_options_help": "Samples, Tiefe, Startwert und Belichtung werden mit diesem Setup gespeichert. Es wird nur die aktive Bildmethode gespeichert.",
"render.gpu_path_crashed": "SolidCraft wurde beim letzten Einrichten auf diesem Grafikadapter beendet, wahrscheinlich im Grafiktreiber, und richtet ihn deshalb nicht von selbst erneut ein. Verwenden Sie stattdessen Raytracing auf der CPU oder versuchen Sie es erneut (nach einem Treiberupdate wird es ebenfalls erneut versucht).", "render.gpu_path_crashed": "SolidCraft wurde beim letzten Einrichten auf diesem Grafikadapter beendet, wahrscheinlich im Grafiktreiber, und richtet ihn deshalb nicht von selbst erneut ein. Verwenden Sie stattdessen Raytracing auf der CPU oder versuchen Sie es erneut (nach einem Treiberupdate wird es ebenfalls erneut versucht).",
"render.gpu_path_failed": "GPU-Pathtracer nicht verfügbar", "render.gpu_path_failed": "GPU-Pathtracer nicht verfügbar",
"render.gpu_path_first_setup": "Das erste Setup auf dieser GPU kann mehrere Minuten dauern; SolidCraft bleibt währenddessen bedienbar. Spätere Starts verwenden die kompilierten Shader erneut, sofern der Treiber sie behält.", "render.gpu_path_first_setup": "Das erste Setup auf dieser GPU kann mehrere Minuten dauern; SolidCraft bleibt währenddessen bedienbar. Spätere Starts verwenden die kompilierten Shader erneut, sofern der Treiber sie behält.",
"render.gpu_path_not_started": "Die Einrichtung des GPU-Pfadtracers wurde noch nicht gestartet.",
"render.gpu_path_preparing": "GPU-Pathtracer: Shader werden kompiliert…", "render.gpu_path_preparing": "GPU-Pathtracer: Shader werden kompiliert…",
"render.gpu_path_retry": "Erneut versuchen", "render.gpu_path_retry": "Erneut versuchen",
"render.gpu_seed": "Zufallsstartwert", "render.gpu_seed": "Zufallsstartwert",
@@ -3456,6 +3577,8 @@
"render.light_product_centre": "Produktmitte", "render.light_product_centre": "Produktmitte",
"render.light_size": "Größe", "render.light_size": "Größe",
"render.light_softness": "Weichheit", "render.light_softness": "Weichheit",
"render.light_space_world": "Lichter in Weltkoordinaten",
"render.light_space_world_help": "Lichtpositionen und -richtungen verwenden Weltkoordinaten. Beim Umkreisen mit der Kamera bleiben die Lichter an ihrer Position.",
"render.light_temperature": "Farbtemperatur", "render.light_temperature": "Farbtemperatur",
"render.light_temperature_help": "Angenäherte Schwarzkörperfarbe; als lineares RGB gespeichert.", "render.light_temperature_help": "Angenäherte Schwarzkörperfarbe; als lineares RGB gespeichert.",
"render.light_type": "Typ", "render.light_type": "Typ",
@@ -3512,6 +3635,25 @@
"render.linear_help": "Behält ein lineares 32-Bit-Gleitkomma-RGBA-Rohbild vor Entrauschen, Belichtung, Tone-Mapping, Filtern und Hintergrund. Lineares sRGB/D65; Abdeckung vormultipliziert. Zusätzlicher Speicher wird ausdrücklich zugelassen. Keine Komprimierung und keine zusätzlichen Durchgänge.", "render.linear_help": "Behält ein lineares 32-Bit-Gleitkomma-RGBA-Rohbild vor Entrauschen, Belichtung, Tone-Mapping, Filtern und Hintergrund. Lineares sRGB/D65; Abdeckung vormultipliziert. Zusätzlicher Speicher wird ausdrücklich zugelassen. Keine Komprimierung und keine zusätzlichen Durchgänge.",
"render.linear_retain": "Lineares Roh-EXR behalten", "render.linear_retain": "Lineares Roh-EXR behalten",
"render.linear_unavailable": "Für das gewählte fertige Bild wurde kein EXR behalten. Aktivieren Sie das Behalten vor dem Rendern; ein älteres PNG kann die rohe Strahldichte nicht wiederherstellen.", "render.linear_unavailable": "Für das gewählte fertige Bild wurde kein EXR behalten. Aktivieren Sie das Behalten vor dem Rendern; ein älteres PNG kann die rohe Strahldichte nicht wiederherstellen.",
"render.live.adaptive": "Live · {width} × {height} · {progress}",
"render.live.final_changed": "Die Render-Anfrage hat sich beim Anhalten des Live-Renderings geändert. Starten Sie das finale Bild erneut.",
"render.live.final_waiting": "Finales Bild vorbereiten · Live-Render-Ressourcen freigeben",
"render.live.invalid_size": "Live-Rendering benötigt eine positive Ausgabebreite und -höhe.",
"render.live.pause": "Live pausieren",
"render.live.paused": "Live · Pausiert",
"render.live.paused_outdated": "Live · Pausiert · Veraltet",
"render.live.quality_help": "Interaktive Qualität: höchstens 512 Pixel an der längsten Kante. Verwendet den gewählten Renderer und seine unterstützten Effekte. Endauflösung, Einstellungen und Export bleiben getrennt.",
"render.live.refused": "Live nicht verfügbar: {reason}",
"render.live.resume": "Live fortsetzen",
"render.live.samples": "Live · {width} × {height} · {current}/{target} Samples",
"render.live.source_current": "{method} · Live",
"render.live.source_outdated": "{method} · Vorheriges Bild",
"render.live.source_outdated_help": "Zeigt das zuletzt aufgenommene Bild, während das Live-Rendering aktualisiert wird oder nicht verfügbar ist. Es kann von der aktuellen Szene oder den Bildeinstellungen abweichen.",
"render.live.source_settings_help": "Ausgabe öffnen, um Renderer und Bildeinstellungen zu bearbeiten.",
"render.live.stopped": "Live-Rendering angehalten",
"render.live.updating": "Live · Interaktive Qualität (bis 512 px) · Aktualisierung",
"render.live.waiting_canvas": "Warten auf die Render-Ansicht",
"render.live.worker_stopped": "Der Aufnahmeprozess für das Live-Rendering wurde vor der Rückgabe eines Ergebnisses beendet",
"render.look_add": "Farblook hinzufügen", "render.look_add": "Farblook hinzufügen",
"render.look_applied": "{name} angewendet", "render.look_applied": "{name} angewendet",
"render.look_bleach": "Von Bleach-Bypass inspiriert", "render.look_bleach": "Von Bleach-Bypass inspiriert",
@@ -3541,6 +3683,9 @@
"render.material_coat_help": "Illustrative dielektrische Beschichtung über dem vorhandenen undurchsichtigen Erscheinungsbild. Gewicht null lässt das Grundmaterial unverändert.", "render.material_coat_help": "Illustrative dielektrische Beschichtung über dem vorhandenen undurchsichtigen Erscheinungsbild. Gewicht null lässt das Grundmaterial unverändert.",
"render.material_color_map": "Grundfarbentextur (sRGB)", "render.material_color_map": "Grundfarbentextur (sRGB)",
"render.material_color_replace": "Basismap ersetzt Körperfarbe", "render.material_color_replace": "Basismap ersetzt Körperfarbe",
"render.material_cpu_glass_only": "Temporäre Bilddatei-Karten benötigen die GPU. Die CPU kann gespeicherte integrierte Oberflächenkarten verwenden.",
"render.material_cpu_optics_limits": "Indirekte Beleuchtung für unterstützte geschlossene Glasformen, geprüfte Verschachtelung und Streuung im Inneren einschalten. Dünne Scheiben können Licht für Schatten durchlassen. Sonst eine ebene Scheibe oder achsenparallele Box verwenden. Berührende Formen und durch geschlossenes Glas übertragene Schatten werden weiterhin nicht unterstützt. Die Werte bleiben erhalten.",
"render.material_cpu_saved_runtime_conflict": "Gespeicherte CPU-Optik kann nicht mit temporären optischen Bindungen kombiniert werden. Geprüfte Optik speichern oder die temporäre Bindung entfernen.",
"render.material_custom": "Eigene illustrative Optik", "render.material_custom": "Eigene illustrative Optik",
"render.material_enable": "Diese GPU-Materialüberschreibungen verwenden", "render.material_enable": "Diese GPU-Materialüberschreibungen verwenden",
"render.material_filter": "Szenenkörper filtern…", "render.material_filter": "Szenenkörper filtern…",
@@ -3561,6 +3706,7 @@
"render.material_normal_map": "Normalenbild (OpenGL, +Y)", "render.material_normal_map": "Normalenbild (OpenGL, +Y)",
"render.material_normal_strength": "Normalenstärke (0–1)", "render.material_normal_strength": "Normalenstärke (0–1)",
"render.material_origin": "Texturursprung X · Y · Z (mm)", "render.material_origin": "Texturursprung X · Y · Z (mm)",
"render.material_raytrace_required": "Physikalisches Glas benötigt CPU-Raytracing oder GPU-Pathtracing.",
"render.material_refresh": "Szenenkörper aktualisieren", "render.material_refresh": "Szenenkörper aktualisieren",
"render.material_refresh_needed": "Die Szene hat sich geändert. Aktualisieren Sie die Körperliste, bevor Sie ein Ziel hinzufügen.", "render.material_refresh_needed": "Die Szene hat sich geändert. Aktualisieren Sie die Körperliste, bevor Sie ein Ziel hinzufügen.",
"render.material_remove": "Diese Zuweisung entfernen", "render.material_remove": "Diese Zuweisung entfernen",
@@ -3570,6 +3716,7 @@
"render.material_revalidate_needed": "Diese Zuweisung gehört zu einer früheren Szenenrevision. Prüfen Sie die genaue Körperidentität erneut, bevor Sie rendern.", "render.material_revalidate_needed": "Diese Zuweisung gehört zu einer früheren Szenenrevision. Prüfen Sie die genaue Körperidentität erneut, bevor Sie rendern.",
"render.material_roughness": "Rauheit des Klarlacks (0,045–1)", "render.material_roughness": "Rauheit des Klarlacks (0,045–1)",
"render.material_roughness_map": "Rauheitsmap (linear)", "render.material_roughness_map": "Rauheitsmap (linear)",
"render.material_saved_edit_pending": "Diese Optikänderungen sind ungespeichert. Geprüfte Werte speichern, die gespeicherte Zuordnung entfernen oder Änderungen verwerfen. Temporäre Bindungen und nicht unterstützte Effekte können das gespeicherte Ziel nicht überschreiben.",
"render.material_shadow": "Gerade Schattenstrahlen durchlassen", "render.material_shadow": "Gerade Schattenstrahlen durchlassen",
"render.material_target_missing": "Ordnungsnummer und Name des Körpers stimmen nicht mehr überein. Entfernen Sie diese Zuweisung und wählen Sie den gewünschten Körper ausdrücklich erneut.", "render.material_target_missing": "Ordnungsnummer und Name des Körpers stimmen nicht mehr überein. Entfernen Sie diese Zuweisung und wählen Sie den gewünschten Körper ausdrücklich erneut.",
"render.material_thickness": "Dicke der dünnen Schicht (mm)", "render.material_thickness": "Dicke der dünnen Schicht (mm)",
@@ -3614,11 +3761,14 @@
"render.output_image": "Bild", "render.output_image": "Bild",
"render.output_largest": "{width} × {height} max.", "render.output_largest": "{width} × {height} max.",
"render.output_lock_ratio": "Seitenverhältnis sperren", "render.output_lock_ratio": "Seitenverhältnis sperren",
"render.output_master_unavailable": "Zum EXR-Export ein fertiges Bild mit EXR-Rohdaten auswählen. EXR-Rohdaten vor dem Rendern neuer Bilder aktivieren.",
"render.output_over_budget": "Das angeforderte Bild überschreitet den gewählten Ressourcenrahmen. Wählen Sie ausdrücklich eine passende Größe oder ein passendes Profil; es erfolgt keine automatische Herabstufung.", "render.output_over_budget": "Das angeforderte Bild überschreitet den gewählten Ressourcenrahmen. Wählen Sie ausdrücklich eine passende Größe oder ein passendes Profil; es erfolgt keine automatische Herabstufung.",
"render.output_presentation_limits": "CPU-Bildeffekte und EXR-Ausgabe unterstützen Bilder mit bis zu 8192 Pixeln Breite oder Höhe und insgesamt höchstens 16.777.216 Pixeln.",
"render.output_presets_help": "Format, Qualität und Prüfliste befinden sich im Ausgabeeditor.", "render.output_presets_help": "Format, Qualität und Prüfliste befinden sich im Ausgabeeditor.",
"render.output_quality": "Qualität", "render.output_quality": "Qualität",
"render.output_quality_waiting": "Qualitätsdefinition steht noch aus", "render.output_quality_waiting": "Qualitätsdefinition steht noch aus",
"render.output_ratio_refused": "Die verknüpfte Abmessung überschreitet das Größenlimit dieser Methode. Die vorherige Größe bleibt erhalten; entsperren Sie das Verhältnis oder wählen Sie einen kleineren Wert.", "render.output_ratio_refused": "Die verknüpfte Abmessung überschreitet das Größenlimit dieser Methode. Die vorherige Größe bleibt erhalten; entsperren Sie das Verhältnis oder wählen Sie einen kleineren Wert.",
"render.output_raytrace_only": "Bildeffekte erfordern CPU-Raytracing oder GPU-Pathtracing.",
"render.output_ready": "Bereit zum Rendern", "render.output_ready": "Bereit zum Rendern",
"render.output_run_check": "Prüfung starten", "render.output_run_check": "Prüfung starten",
"render.output_size_limit": "{method}: bis zu {dimension} px pro Seite und {pixels} Pixel. Größte passende Größe: {width} × {height}.", "render.output_size_limit": "{method}: bis zu {dimension} px pro Seite und {pixels} Pixel. Größte passende Größe: {width} × {height}.",
@@ -3673,6 +3823,12 @@
"render.post_saturation": "Sättigung", "render.post_saturation": "Sättigung",
"render.post_title": "Darstellungsfilter", "render.post_title": "Darstellungsfilter",
"render.post_vignette": "Vignettierung", "render.post_vignette": "Vignettierung",
"render.preparation_cancelled": "Rendering-Vorbereitung abgebrochen",
"render.preparation_checking": "Rendering wird geprüft",
"render.preparation_retirement_failed": "Die Bereinigung der Rendering-Vorbereitung ist fehlgeschlagen. Dieses Fenster kann kein weiteres Bild vorbereiten.",
"render.preparation_retiring": "Rendering-Vorbereitung wird abgeschlossen",
"render.preparation_unavailable": "Rendering-Vorbereitung nicht verfügbar",
"render.presentation_banner": "Bildeffekte funktionieren mit CPU- und GPU-Raytracing. Das Öffnen dieser Seite ändert die Methode nicht.",
"render.preview": "Integrierte Vorschau", "render.preview": "Integrierte Vorschau",
"render.preview_help": "Rasterdarstellung mit gemischter Transparenz. Brechung, HDRI und finales Rendering sind noch nicht verfügbar.", "render.preview_help": "Rasterdarstellung mit gemischter Transparenz. Brechung, HDRI und finales Rendering sind noch nicht verfügbar.",
"render.preview_image_settings_help": "Die Live-Vorschau behält eine feste Studiobeleuchtung. Belichtung und Bildbeleuchtung gelten für den Bildauftrag, wenn Sie „Prüfen“ oder „Start“ verwenden.", "render.preview_image_settings_help": "Die Live-Vorschau behält eine feste Studiobeleuchtung. Belichtung und Bildbeleuchtung gelten für den Bildauftrag, wenn Sie „Prüfen“ oder „Start“ verwenden.",
@@ -3691,11 +3847,15 @@
"render.quality_ack": "Die Projektion mit festem Budget und ihre Auslassungen bestätigen", "render.quality_ack": "Die Projektion mit festem Budget und ihre Auslassungen bestätigen",
"render.quality_apply": "Dieses feste Sampling-Budget verwenden", "render.quality_apply": "Dieses feste Sampling-Budget verwenden",
"render.quality_balanced": "Ausgewogen", "render.quality_balanced": "Ausgewogen",
"render.quality_budget_help": "Legt Größe, Samples, Tiefe, Startwert und Rauschreduzierung fest. Andere Bildeinstellungen bleiben erhalten.",
"render.quality_custom": "Benutzerdefiniert", "render.quality_custom": "Benutzerdefiniert",
"render.quality_denoise_off": "Rauschreduzierung: Aus",
"render.quality_denoise_on": "Rauschreduzierung: Ein",
"render.quality_draft": "Entwurf", "render.quality_draft": "Entwurf",
"render.quality_high": "Hoch", "render.quality_high": "Hoch",
"render.quality_projection_help": "Diese Prüfung ändert nur Auflösung, Abtastbudget, Pfadtiefe, Startwert und Rauschreduzierung. Andere Einstellungen bleiben erhalten; das Budget garantiert keine Konvergenz.", "render.quality_projection_help": "Diese Prüfung ändert nur Auflösung, Abtastbudget, Pfadtiefe, Startwert und Rauschreduzierung. Andere Einstellungen bleiben erhalten; das Budget garantiert keine Konvergenz.",
"render.quality_review": "Sampling-Budget prüfen", "render.quality_review": "Sampling-Budget prüfen",
"render.quality_summary": "{width} × {height} · {samples} Samples · Tiefe {depth} · Startwert {seed} · {denoise}",
"render.queue_pending": "In dieser Oberfläche gibt es keine automatische Produktionswarteschlange und keinen Animations-Renderer. Fertige Einzelbilder bleiben separat exportierbar.", "render.queue_pending": "In dieser Oberfläche gibt es keine automatische Produktionswarteschlange und keinen Animations-Renderer. Fertige Einzelbilder bleiben separat exportierbar.",
"render.radial_assign": "Erscheinungsbild zuweisen", "render.radial_assign": "Erscheinungsbild zuweisen",
"render.radial_compare": "Vergleichen", "render.radial_compare": "Vergleichen",
@@ -3814,9 +3974,11 @@
"render.shot_frame_subject": "Motiv einpassen", "render.shot_frame_subject": "Motiv einpassen",
"render.shot_invalid_camera": "Kamerawerte müssen endlich und im gültigen Bereich sein.", "render.shot_invalid_camera": "Kamerawerte müssen endlich und im gültigen Bereich sein.",
"render.shot_lens": "Objektiv", "render.shot_lens": "Objektiv",
"render.shot_lens_cpu_progressive_reason": "Vor der CPU-Schärfentiefe unter Sampling die progressive Abtastung übernehmen.",
"render.shot_lens_enable_reason": "Schärfentiefe aktivieren, um Blende und Fokusabstand zu bearbeiten.", "render.shot_lens_enable_reason": "Schärfentiefe aktivieren, um Blende und Fokusabstand zu bearbeiten.",
"render.shot_lens_gpu_reason": "Schärfentiefe benötigt GPU-Pfadverfolgung.", "render.shot_lens_gpu_reason": "Schärfentiefe benötigt GPU-Pfadverfolgung.",
"render.shot_lens_perspective_reason": "Schärfentiefe benötigt perspektivische Projektion.", "render.shot_lens_perspective_reason": "Schärfentiefe benötigt perspektivische Projektion.",
"render.shot_lens_raytrace_reason": "Schärfentiefe ist für CPU-Raytracing und GPU-Pathtracing verfügbar.",
"render.shot_look_selection": "Auswahl anvisieren", "render.shot_look_selection": "Auswahl anvisieren",
"render.shot_manager": "Gespeicherte Aufnahmen", "render.shot_manager": "Gespeicherte Aufnahmen",
"render.shot_new_name": "Neuer Aufnahmename", "render.shot_new_name": "Neuer Aufnahmename",
@@ -3850,7 +4012,12 @@
"render.sky_horizon": "Horizont · lineares RGB", "render.sky_horizon": "Horizont · lineares RGB",
"render.sky_zenith": "Zenit · lineares RGB", "render.sky_zenith": "Zenit · lineares RGB",
"render.soft_focus": "Weichzeichnung", "render.soft_focus": "Weichzeichnung",
"render.spot_axis": "Abstrahlrichtung",
"render.spot_cone": "Spotkegel", "render.spot_cone": "Spotkegel",
"render.spot_gpu_help": "Die Winkel werden von der Abstrahlrichtung aus gemessen. Zwischen innerem und äußerem Winkel wird das Licht schwächer. Sehr schmale Übergänge erfordern CPU-Rendering.",
"render.spot_help": "Die Winkel werden von der Abstrahlrichtung aus gemessen. Zwischen innerem und äußerem Winkel wird das Licht schwächer.",
"render.spot_inner": "Innerer Halbwinkel",
"render.spot_outer": "Äußerer Halbwinkel",
"render.stage_frame": "Bildausschnitt", "render.stage_frame": "Bildausschnitt",
"render.stage_layout.appearance_note": "Zum Anwenden auf die Auswahl klicken.", "render.stage_layout.appearance_note": "Zum Anwenden auf die Auswahl klicken.",
"render.stage_layout.studio_note": "Vor dem Anwenden zur Prüfung klicken.", "render.stage_layout.studio_note": "Vor dem Anwenden zur Prüfung klicken.",
@@ -3876,6 +4043,7 @@
"render.stage_panels.extent": "Ausdehnung", "render.stage_panels.extent": "Ausdehnung",
"render.stage_panels.fit_save": "Einpassen und speichern", "render.stage_panels.fit_save": "Einpassen und speichern",
"render.stage_panels.gpu_required": "Benötigt GPU-Pfadverfolgung", "render.stage_panels.gpu_required": "Benötigt GPU-Pfadverfolgung",
"render.stage_panels.grain_angle": "Maserungswinkel",
"render.stage_panels.keep": "Behalten", "render.stage_panels.keep": "Behalten",
"render.stage_panels.kept": "Beibehalten", "render.stage_panels.kept": "Beibehalten",
"render.stage_panels.kept_fields": "Kamera, Abtastung, Abmessungen, optische Bindungen, CAD-Geometrie und technische Eigenschaften.", "render.stage_panels.kept_fields": "Kamera, Abtastung, Abmessungen, optische Bindungen, CAD-Geometrie und technische Eigenschaften.",
@@ -3994,6 +4162,19 @@
"render.subsurface_enable": "Random Walk für innere Streuung", "render.subsurface_enable": "Random Walk für innere Streuung",
"render.subsurface_help": "Nur für geschlossene Dielektrika. Streuung und RGB-Absorption sind getrennte Koeffizienten pro mm. Pfade streuen innerhalb der tatsächlichen Geometrie und werden dann an der Grenzfläche gebrochen oder reflektiert. Deaktivieren Sie die Transmission gerader Schattenstrahlen, das Entrauschen von Oberflächen und das äußere Volumen; verwenden Sie eine Fresnel-Schicht. Kein Diffusions-Shader, kein Dichtegitter und kein gemessenes Material. Dichte Medien können mehr Samples und Pfadtiefe benötigen.", "render.subsurface_help": "Nur für geschlossene Dielektrika. Streuung und RGB-Absorption sind getrennte Koeffizienten pro mm. Pfade streuen innerhalb der tatsächlichen Geometrie und werden dann an der Grenzfläche gebrochen oder reflektiert. Deaktivieren Sie die Transmission gerader Schattenstrahlen, das Entrauschen von Oberflächen und das äußere Volumen; verwenden Sie eine Fresnel-Schicht. Kein Diffusions-Shader, kein Dichtegitter und kein gemessenes Material. Dichte Medien können mehr Samples und Pfadtiefe benötigen.",
"render.subsurface_rate": "Streukollisionsrate", "render.subsurface_rate": "Streukollisionsrate",
"render.surface_import.author": "Autor",
"render.surface_import.busy": "Bild wird importiert…",
"render.surface_import.complete": "Wählen Sie ein Bild und geben Sie Autor, Quelle und Lizenz an.",
"render.surface_import.embedded": "Importiertes Bild",
"render.surface_import.failed": "Der Bildimport wurde nicht abgeschlossen.",
"render.surface_import.license": "Lizenz / Eigentum",
"render.surface_import.raytrace_required": "Bilder erfordern CPU- oder GPU-Raytracing. Wählen Sie es unter Ausgabe.",
"render.surface_import.repeat_u": "Wiederholung U",
"render.surface_import.repeat_v": "Wiederholung V",
"render.surface_import.save": "Bild am Körper speichern",
"render.surface_import.saved_cpu": "Speichern Sie Texturen für das CPU-Rendering.",
"render.surface_import.source": "Quelle",
"render.surface_import.title": "Bild importieren",
"render.tone_aces_fitted": "ACES angepasst", "render.tone_aces_fitted": "ACES angepasst",
"render.tone_reinhard": "Reinhard", "render.tone_reinhard": "Reinhard",
"render.transmission_scope": "GPU-Glas unterstützt zertifizierte getrennte Medien. Unbeschränkt verschachtelte Medien und ein rauschfreier Transmissionsschätzer werden nicht bereitgestellt.", "render.transmission_scope": "GPU-Glas unterstützt zertifizierte getrennte Medien. Unbeschränkt verschachtelte Medien und ein rauschfreier Transmissionsschätzer werden nicht bereitgestellt.",
@@ -4038,11 +4219,15 @@
"render.use_preview": "Integrierte Vorschau verwenden", "render.use_preview": "Integrierte Vorschau verwenden",
"render.volume_albedo": "Streualbedo · lineares RGB", "render.volume_albedo": "Streualbedo · lineares RGB",
"render.volume_anisotropy": "Mittlerer Phasenkosinus", "render.volume_anisotropy": "Mittlerer Phasenkosinus",
"render.volume_denoise_required": "Für Atmosphäre die Rauschreduzierung ausschalten.",
"render.volume_enable": "Teilnehmendes Medium aktivieren", "render.volume_enable": "Teilnehmendes Medium aktivieren",
"render.volume_extinction": "Extinktionskoeffizient", "render.volume_extinction": "Extinktionskoeffizient",
"render.volume_glass_required": "Atmosphäre und Glas können in dieser Einstellung nicht kombiniert werden.",
"render.volume_help": "GPU-Transport innerhalb einer endlichen Box, mit Beer-Lambert-Abschwächung und HG-Streuung auf Kamera- und indirekten Pfaden. Verwendet ausdrückliche Studio-, HDR- und Himmelsbeleuchtung einschließlich Schattenabschwächung. Ein positiver Phasenkosinus streut nach vorn. Glasgrenzflächen und Oberflächenentrauschen müssen ausdrücklich deaktiviert werden. Extinktion null lässt den Transport unverändert. Keine physikalische Mondatmosphäre, kein Dichtegitter, keine Volumenemission, kein spektraler Transport und keine zertifizierte Materialeigenschaft.", "render.volume_help": "GPU-Transport innerhalb einer endlichen Box, mit Beer-Lambert-Abschwächung und HG-Streuung auf Kamera- und indirekten Pfaden. Verwendet ausdrückliche Studio-, HDR- und Himmelsbeleuchtung einschließlich Schattenabschwächung. Ein positiver Phasenkosinus streut nach vorn. Glasgrenzflächen und Oberflächenentrauschen müssen ausdrücklich deaktiviert werden. Extinktion null lässt den Transport unverändert. Keine physikalische Mondatmosphäre, kein Dichtegitter, keine Volumenemission, kein spektraler Transport und keine zertifizierte Materialeigenschaft.",
"render.volume_lighting_required": "Für Atmosphäre eine Umgebung oder ein eigenes Lichtrig wählen.",
"render.volume_max": "Obere Grenzen · Weltkoordinaten (mm)", "render.volume_max": "Obere Grenzen · Weltkoordinaten (mm)",
"render.volume_min": "Untere Grenzen · Weltkoordinaten (mm)", "render.volume_min": "Untere Grenzen · Weltkoordinaten (mm)",
"render.volume_single_stratum_required": "Für Atmosphäre ein Transmissionssample verwenden.",
"render.volume_title": "Begrenztes homogenes Volumen", "render.volume_title": "Begrenztes homogenes Volumen",
"render.wait_add_light": "Noch nicht unterstützt: benannte Lichtquellen erstellen", "render.wait_add_light": "Noch nicht unterstützt: benannte Lichtquellen erstellen",
"render.wait_batch": "Noch nicht unterstützt: Renderwarteschlange gespeicherter Aufnahmen", "render.wait_batch": "Noch nicht unterstützt: Renderwarteschlange gespeicherter Aufnahmen",
@@ -4070,6 +4255,8 @@
"sample.plate.name": "Beispielplatte", "sample.plate.name": "Beispielplatte",
"sample.vents.about": "Langlöcher in einem Rechteckmuster: Zeilen, Spalten und Abstand sind Parameter", "sample.vents.about": "Langlöcher in einem Rechteckmuster: Zeilen, Spalten und Abstand sind Parameter",
"sample.vents.name": "Lüftungsplatte", "sample.vents.name": "Lüftungsplatte",
"scale.per_axis": "Je Achse",
"scale.uniform": "Gleichmäßig",
"search.command_keys": "Eingabe ausführen Umschalt+Eingabe ausführen und offen lassen Esc schließen", "search.command_keys": "Eingabe ausführen Umschalt+Eingabe ausführen und offen lassen Esc schließen",
"search.commands": "Befehle", "search.commands": "Befehle",
"search.design": "In diesem Design", "search.design": "In diesem Design",
@@ -4157,6 +4344,7 @@
"sketch.dimension_applied": "Maß angewendet", "sketch.dimension_applied": "Maß angewendet",
"sketch.dimension_applied_defined": "Maß angewendet; Parameter `{name}` definiert", "sketch.dimension_applied_defined": "Maß angewendet; Parameter `{name}` definiert",
"sketch.dimension_applied_renamed": "Maß angewendet; der Parameter heißt jetzt `{name}`", "sketch.dimension_applied_renamed": "Maß angewendet; der Parameter heißt jetzt `{name}`",
"sketch.divide_hint": "Punkte teilen jede Kurve in gleich lange Abschnitte und behalten sie bei, wenn sie sich ändert.",
"sketch.dof_left": "{count} Freiheitsgrade übrig", "sketch.dof_left": "{count} Freiheitsgrade übrig",
"sketch.dof_left_one": "{count} Freiheitsgrad übrig", "sketch.dof_left_one": "{count} Freiheitsgrad übrig",
"sketch.draw_curves": "Als {linetype} zeichnen", "sketch.draw_curves": "Als {linetype} zeichnen",
@@ -4712,6 +4900,7 @@
"ui.click_selects_whole_bodies": "Klick wählt ganze Körper aus", "ui.click_selects_whole_bodies": "Klick wählt ganze Körper aus",
"ui.click_then_press_key": "Klicken, dann die neue Taste drücken", "ui.click_then_press_key": "Klicken, dann die neue Taste drücken",
"ui.close": "Schließen", "ui.close": "Schließen",
"ui.close_tab": "Tab schließen",
"ui.coil": "Schraube", "ui.coil": "Schraube",
"ui.coincident": "Koinzident", "ui.coincident": "Koinzident",
"ui.collapse": "Einklappen", "ui.collapse": "Einklappen",
@@ -4927,6 +5116,11 @@
"ui.factor": "Faktor", "ui.factor": "Faktor",
"ui.fade": "Auslauf", "ui.fade": "Auslauf",
"ui.fade_length": "Auslauflänge", "ui.fade_length": "Auslauflänge",
"ui.fair_iterations": "Iterationen",
"ui.fair_keep_edges": "Kanten behalten",
"ui.fair_strength": "Stärke",
"ui.fair_surface_title": "FLÄCHENBEGRADIGUNG",
"ui.fair_tolerance_default": "0,001 der Körpergröße",
"ui.feature_history": "Feature-Verlauf", "ui.feature_history": "Feature-Verlauf",
"ui.feature_options": "Funktionsoptionen", "ui.feature_options": "Funktionsoptionen",
"ui.features": "Funktionen", "ui.features": "Funktionen",
@@ -5007,6 +5201,7 @@
"ui.heading_custom_view_navigator": "EIGENER ANSICHTSNAVIGATOR", "ui.heading_custom_view_navigator": "EIGENER ANSICHTSNAVIGATOR",
"ui.heading_cylinder": "ZYLINDER", "ui.heading_cylinder": "ZYLINDER",
"ui.heading_design": "DESIGN", "ui.heading_design": "DESIGN",
"ui.heading_divide_curve": "KURVE TEILEN",
"ui.heading_draft": "ABZIEHEN", "ui.heading_draft": "ABZIEHEN",
"ui.heading_edit": "BEARBEITEN", "ui.heading_edit": "BEARBEITEN",
"ui.heading_equation_curve": "GLEICHUNGSKURVE", "ui.heading_equation_curve": "GLEICHUNGSKURVE",
@@ -5087,6 +5282,11 @@
"ui.history_play_button_show": "Wiedergabe-Schaltfläche einblenden", "ui.history_play_button_show": "Wiedergabe-Schaltfläche einblenden",
"ui.history_play_finish_action": "Die aktuelle Aktion abschließen, bevor der Verlauf abgespielt wird", "ui.history_play_finish_action": "Die aktuelle Aktion abschließen, bevor der Verlauf abgespielt wird",
"ui.history_play_roll_back": "Die Verlaufsmarkierung vor dem Abspielen zurücksetzen", "ui.history_play_roll_back": "Die Verlaufsmarkierung vor dem Abspielen zurücksetzen",
"ui.history_scope_all": "Features des ganzen Designs zeigen",
"ui.history_scope_all_shown": "Die Features des ganzen Designs",
"ui.history_scope_pick": "Eine Komponente bearbeiten oder im Browser wählen, um nur ihre Features zu zeigen",
"ui.history_scope_show": "Nur die Features von {name} und der Komponenten darin zeigen",
"ui.history_scope_shown": "Die Features von {name} und der Komponenten darin",
"ui.history_show_names": "Namen anzeigen", "ui.history_show_names": "Namen anzeigen",
"ui.history_sketch_listed_under": "Aufgeführt unter {feature}", "ui.history_sketch_listed_under": "Aufgeführt unter {feature}",
"ui.history_title": "Verlauf", "ui.history_title": "Verlauf",
@@ -5109,6 +5309,7 @@
"ui.inspect": "Prüfen", "ui.inspect": "Prüfen",
"ui.instances": "Instanzen", "ui.instances": "Instanzen",
"ui.intersect": "Schnitt", "ui.intersect": "Schnitt",
"ui.intersection_curve_second_pick": "Schnittkurve: zweite Fläche oder Kurve anklicken (Rechtsklick zum Neubeginn)",
"ui.isolate": "Isolieren", "ui.isolate": "Isolieren",
"ui.join": "Verbinden", "ui.join": "Verbinden",
"ui.joint_play": "▶ Abspielen", "ui.joint_play": "▶ Abspielen",
@@ -5136,6 +5337,7 @@
"ui.manipulator_free_alt": "Freies Ziehen des Manipulators auch mit Alt/Option", "ui.manipulator_free_alt": "Freies Ziehen des Manipulators auch mit Alt/Option",
"ui.manipulator_free_alt_tip": "An: Alt/Option oder Strg/Cmd auf Extrusions-/Gizmo-Pfeilen deaktiviert das Einrasten von Werten. Aus: nur Strg/Cmd.", "ui.manipulator_free_alt_tip": "An: Alt/Option oder Strg/Cmd auf Extrusions-/Gizmo-Pfeilen deaktiviert das Einrasten von Werten. Aus: nur Strg/Cmd.",
"ui.manufacture": "Fertigung", "ui.manufacture": "Fertigung",
"ui.match_surface_title": "FLÄCHENANPASSUNG",
"ui.material_review.axes": "Materiallokale Achsen; keine Körperausrichtung zugewiesen.", "ui.material_review.axes": "Materiallokale Achsen; keine Körperausrichtung zugewiesen.",
"ui.material_review.claims": "Quellen und Lizenzen sind ungeprüfte Angaben. Fehlende Werte bleiben unbekannt.", "ui.material_review.claims": "Quellen und Lizenzen sind ungeprüfte Angaben. Fehlende Werte bleiben unbekannt.",
"ui.material_review.compressive_strength": "Druckfestigkeit", "ui.material_review.compressive_strength": "Druckfestigkeit",
@@ -5158,6 +5360,9 @@
"ui.material_review.title": "Physikalische Materialdaten prüfen", "ui.material_review.title": "Physikalische Materialdaten prüfen",
"ui.material_review.unknown": "Unbekannt", "ui.material_review.unknown": "Unbekannt",
"ui.material_review.yield_strength": "Streckgrenze", "ui.material_review.yield_strength": "Streckgrenze",
"ui.mcp_agents": "Agenten über MCP",
"ui.mcp_compact": "Kompakte Ausgabe",
"ui.mcp_compact_note": "Für Agenten, die über den MCP-Server (solidcraft-cli mcp) verbunden sind: inspect_design fasst Skizzen zusammen und Werkzeugergebnisse werden nicht formatiert, sodass sie weniger Tokens verbrauchen. Gilt für Agentensitzungen, die nach der Änderung beginnen; --compact oder SOLIDCRAFT_MCP_COMPACT=1 schalten es ebenfalls ein.",
"ui.measure": "Messen", "ui.measure": "Messen",
"ui.mesh_format_3mf": "3MF", "ui.mesh_format_3mf": "3MF",
"ui.mesh_format_3mf_tagged": "3MF mit Flächenmarken", "ui.mesh_format_3mf_tagged": "3MF mit Flächenmarken",
@@ -5199,6 +5404,7 @@
"ui.options": "Optionen", "ui.options": "Optionen",
"ui.orbit": "Drehen", "ui.orbit": "Drehen",
"ui.orbit_around": "Umkreisen um", "ui.orbit_around": "Umkreisen um",
"ui.organize": "Organisieren",
"ui.orientation": "Ausrichtung", "ui.orientation": "Ausrichtung",
"ui.origin": "Ursprung", "ui.origin": "Ursprung",
"ui.palette_construction_mode": "Konstruktionsmodus (X)", "ui.palette_construction_mode": "Konstruktionsmodus (X)",
@@ -5206,6 +5412,65 @@
"ui.palette_sketch_options": "Skizzenoptionen", "ui.palette_sketch_options": "Skizzenoptionen",
"ui.pan": "Verschieben", "ui.pan": "Verschieben",
"ui.pan_zoom_orbit": "Verschieben, zoomen, umkreisen", "ui.pan_zoom_orbit": "Verschieben, zoomen, umkreisen",
"ui.panel_fixture.apply": "Anwenden",
"ui.panel_fixture.cancel": "Abbrechen",
"ui.panel_fixture.caption": "Synthetisches Panelmuster",
"ui.panel_fixture.draft": "Beibehaltener Entwurf",
"ui.panel_fixture.editor": "Mustereditor",
"ui.panel_fixture.explanation": "Dieser synthetische Inhalt behält seinen Entwurf beim Ausblenden oder Verschieben.",
"ui.panel_fixture.fill": "Füllendes Muster",
"ui.panel_fixture.finish": "Abschließen",
"ui.panel_fixture.finished": "Synthetische Transaktion beendet",
"ui.panel_fixture.footer": "Musteraktionen lassen den Entwurf unverändert.",
"ui.panel_fixture.guard": "Abbruch bei laufender Transaktion verweigern",
"ui.panel_fixture.inline": "Einzeiliges Muster",
"ui.panel_fixture.live": "Synthetische Transaktion läuft",
"ui.panel_fixture.log": "Musterprotokoll",
"ui.panel_fixture.pin": "Angeheftetes Muster",
"ui.panel_fixture.title": "{title} · {id}",
"ui.panel_fixture.updates": "Dienstaktualisierungen: {count}",
"ui.panel_host.attention": "Aufmerksamkeit erforderlich",
"ui.panel_host.bottom": "Unten",
"ui.panel_host.close": "Panel schließen",
"ui.panel_host.collapse": "Panel einklappen",
"ui.panel_host.expand": "Panel ausklappen",
"ui.panel_host.floating": "Schwebend",
"ui.panel_host.focus": "Panel fokussieren",
"ui.panel_host.focus_target": "{title} fokussieren",
"ui.panel_host.header": "Panelkopf",
"ui.panel_host.join": "Tabs verbinden",
"ui.panel_host.join_target": "Tabs mit {title} verbinden",
"ui.panel_host.left": "Links",
"ui.panel_host.menu": "Panelaktionen",
"ui.panel_host.move": "Verschieben nach",
"ui.panel_host.overflow": "Weitere Panels",
"ui.panel_host.popout": "In einem Fenster öffnen",
"ui.panel_host.resize": "Panelgröße ändern",
"ui.panel_host.right": "Rechts",
"ui.panel_host.rule.availability": "Dieses Panel ist nicht verfügbar.",
"ui.panel_host.rule.bounds": "Die Panels passen nicht in ihre Größenbegrenzungen.",
"ui.panel_host.rule.capability": "Dieser Host unterstützt diese Aktion nicht.",
"ui.panel_host.rule.collection_limit": "Das Panellayout hat seine Grenze erreicht.",
"ui.panel_host.rule.duplicate_id": "Diese Panelkennung wird bereits verwendet.",
"ui.panel_host.rule.exactly_once": "Jedes Panel muss einmal erscheinen.",
"ui.panel_host.rule.feature_disabled": "Diese Aktion ist für dieses Panel deaktiviert.",
"ui.panel_host.rule.id": "Die Panelkennung ist ungültig.",
"ui.panel_host.rule.incompatible_tabs": "Diese Panels können keine Tabgruppe teilen.",
"ui.panel_host.rule.lifecycle": "Das Panel konnte diese Aktion nicht abschließen.",
"ui.panel_host.rule.missing_target": "Dieses Panelziel ist nicht mehr verfügbar.",
"ui.panel_host.rule.no_space": "Für dieses Panellayout ist kein Platz.",
"ui.panel_host.rule.pin_conflict": "An dieser Kante ist bereits ein anderes Panel angeheftet.",
"ui.panel_host.rule.pin_order": "Ein angeheftetes Panel muss an seiner Kante zuerst bleiben.",
"ui.panel_host.rule.placement": "Dieses Panel kann nicht an diese Position verschoben werden.",
"ui.panel_host.rule.revision": "Das Layout wurde geändert. Versuchen Sie die Aktion erneut.",
"ui.panel_host.rule.schema": "Die Panelanfrage ist ungültig.",
"ui.panel_host.rule.version": "Diese Panellayoutversion wird nicht unterstützt.",
"ui.panel_host.sash": "Benachbarte Panels skalieren",
"ui.panel_host.scroll_horizontal": "Panelspalten scrollen",
"ui.panel_host.scroll_vertical": "Panelstapel scrollen",
"ui.panel_host.surface": "Panel",
"ui.panel_host.tab": "Paneltab",
"ui.panel_host.tabs": "Alle Tabs",
"ui.parallel": "Parallel", "ui.parallel": "Parallel",
"ui.parameters": "Parameter", "ui.parameters": "Parameter",
"ui.part_size_needs_a_part": "Wählen Sie ein eingefügtes Standardbauteil (Schraube, Mutter, Scheibe oder Stift) aus, um seine Größe zu ändern. Einen Körper vergrößern oder verkleinern Sie mit Skalieren.", "ui.part_size_needs_a_part": "Wählen Sie ein eingefügtes Standardbauteil (Schraube, Mutter, Scheibe oder Stift) aus, um seine Größe zu ändern. Einen Körper vergrößern oder verkleinern Sie mit Skalieren.",
@@ -5243,6 +5508,7 @@
"ui.point_cloud_add_filter": "Filter hinzufügen…", "ui.point_cloud_add_filter": "Filter hinzufügen…",
"ui.point_cloud_auto_range": "Bereich automatisch", "ui.point_cloud_auto_range": "Bereich automatisch",
"ui.point_cloud_color_by": "Färben nach", "ui.point_cloud_color_by": "Färben nach",
"ui.point_cloud_dots": "Einzelpunkte",
"ui.point_cloud_file_colors": "Farben der Datei", "ui.point_cloud_file_colors": "Farben der Datei",
"ui.point_cloud_filter_by": "Filtern nach", "ui.point_cloud_filter_by": "Filtern nach",
"ui.point_cloud_height_high": "Oberste Höhe", "ui.point_cloud_height_high": "Oberste Höhe",
@@ -5251,6 +5517,7 @@
"ui.point_cloud_no_file_colors": "Die Datei hat keine Farben", "ui.point_cloud_no_file_colors": "Die Datei hat keine Farben",
"ui.point_cloud_pause": "Pause", "ui.point_cloud_pause": "Pause",
"ui.point_cloud_play": "Abspielen", "ui.point_cloud_play": "Abspielen",
"ui.point_cloud_reload": "Aus Datei neu laden",
"ui.point_cloud_single_color": "Einheitliche Farbe", "ui.point_cloud_single_color": "Einheitliche Farbe",
"ui.point_cloud_size": "Punktgröße", "ui.point_cloud_size": "Punktgröße",
"ui.point_cloud_units": "Einheit der Datei", "ui.point_cloud_units": "Einheit der Datei",
@@ -5345,6 +5612,7 @@
"ui.second_rail": "Zweite Leitkurve", "ui.second_rail": "Zweite Leitkurve",
"ui.section_analysis": "Querschnittsanalyse", "ui.section_analysis": "Querschnittsanalyse",
"ui.section_size": "Querschnittsgröße", "ui.section_size": "Querschnittsgröße",
"ui.segments": "Segmente",
"ui.select": "Auswählen", "ui.select": "Auswählen",
"ui.selectOther": "Andere auswählen…", "ui.selectOther": "Andere auswählen…",
"ui.selectTangentChain": "Tangentialkette auswählen", "ui.selectTangentChain": "Tangentialkette auswählen",
+6
View File
@@ -134,6 +134,7 @@
"render.aging_metallic": "Layer metallic fraction", "render.aging_metallic": "Layer metallic fraction",
"render.aging_origin": "Field origin · world mm", "render.aging_origin": "Field origin · world mm",
"render.aging_patina": "Copper-green patina", "render.aging_patina": "Copper-green patina",
"render.aging_raytrace_help": "Ageing is applied by CPU ray tracing and GPU path tracing. Raster keeps schematic rendering.",
"render.aging_refresh_targets": "Inspect current bodies", "render.aging_refresh_targets": "Inspect current bodies",
"render.aging_roughness": "Layer roughness", "render.aging_roughness": "Layer roughness",
"render.aging_rust": "Oxidized iron / rust", "render.aging_rust": "Oxidized iron / rust",
@@ -159,6 +160,7 @@
"render.background_workflow": "Choose the background you intend: a camera-only colour/gradient, a physical stage that receives light, or HDR illumination. They are independent. Live Preview is a modelling view; render a new image or regrade a retained master to see camera finishing.", "render.background_workflow": "Choose the background you intend: a camera-only colour/gradient, a physical stage that receives light, or HDR illumination. They are independent. Live Preview is a modelling view; render a new image or regrade a retained master to see camera finishing.",
"render.base_color": "Base colour · sRGB", "render.base_color": "Base colour · sRGB",
"render.bloom_help": "Creative output-only glow from positive linear highlights, spread with three normalised box passes. Radius is in output pixels. Added in linear display light before sRGB; not a lens, volumetric effect or convergence improvement. The raw EXR is unchanged.", "render.bloom_help": "Creative output-only glow from positive linear highlights, spread with three normalised box passes. Radius is in output pixels. Added in linear display light before sRGB; not a lens, volumetric effect or convergence improvement. The raw EXR is unchanged.",
"render.check_media_remaining": "Density grids, displacement, full spectral integration and propagated polarisation remain unavailable.",
"render.chromatic_offset": "Chromatic edge offset", "render.chromatic_offset": "Chromatic edge offset",
"render.cpu_area_editor_help": "Full side vectors in millimeters; U cross V points towards the emitting side. This differs from GPU half-edge vectors.", "render.cpu_area_editor_help": "Full side vectors in millimeters; U cross V points towards the emitting side. This differs from GPU half-edge vectors.",
"render.cpu_light_help": "Up to eight directional lights. An empty custom list turns them off; selecting a preset restores its lights. Colours are linear RGB and intensity is relative, not watts.", "render.cpu_light_help": "Up to eight directional lights. An empty custom list turns them off; selecting a preset restores its lights. Colours are linear RGB and intensity is relative, not watts.",
@@ -178,6 +180,7 @@
"render.flare_strength": "Highlight flare strength", "render.flare_strength": "Highlight flare strength",
"render.flare_threshold": "Scene-linear flare threshold", "render.flare_threshold": "Scene-linear flare threshold",
"render.frame_centre_mark": "Centre mark", "render.frame_centre_mark": "Centre mark",
"render.glass_model_help": "Glass roughness scatters transmitted rays. Dispersion and film colour use three wavelength bands. Rough sheets require straight transmitted shadows off.",
"render.hdr_primaries_declared": "The source declares its colour primaries.", "render.hdr_primaries_declared": "The source declares its colour primaries.",
"render.hdr_primaries_srgb": "Colour primaries: sRGB/D65", "render.hdr_primaries_srgb": "Colour primaries: sRGB/D65",
"render.hdr_primaries_undeclared": "The source does not declare primaries; review the renderer colour requirements.", "render.hdr_primaries_undeclared": "The source does not declare primaries; review the renderer colour requirements.",
@@ -235,6 +238,8 @@
"render.studio_area_help": "Up to four one-sided rectangles. Orthogonal half-edges U and V define size; U × V faces the lit side. Coordinates are world-space millimetres.", "render.studio_area_help": "Up to four one-sided rectangles. Orthogonal half-edges U and V define size; U × V faces the lit side. Coordinates are world-space millimetres.",
"render.studio_center": "Centre X, Y, Z (mm)", "render.studio_center": "Centre X, Y, Z (mm)",
"render.studio_hdr_help": "Radiance .hdr, 2:1 panorama, up to 2048 × 1024. EXR is unavailable. The colour assumption applies only when primaries are unspecified.", "render.studio_hdr_help": "Radiance .hdr, 2:1 panorama, up to 2048 × 1024. EXR is unavailable. The colour assumption applies only when primaries are unspecified.",
"render.surface_import.complete": "Choose an image and enter its author, source and licence.",
"render.surface_import.license": "Licence / ownership",
"sketch.hint.arc.center_point": "Arc: click centre and start, go round either way and click the end, or type a signed sweep", "sketch.hint.arc.center_point": "Arc: click centre and start, go round either way and click the end, or type a signed sweep",
"sketch.hint.circle.center": "Circle: click the centre, then a point on the circle", "sketch.hint.circle.center": "Circle: click the centre, then a point on the circle",
"sketch.hint.constraint.midpoint": "MidPoint: pick a point and a line, or two lines to centre the second on the first", "sketch.hint.constraint.midpoint": "MidPoint: pick a point and a line, or two lines to centre the second on the first",
@@ -266,6 +271,7 @@
"ui.layout_compact": "Compact", "ui.layout_compact": "Compact",
"ui.layout_floating": "Floating", "ui.layout_floating": "Floating",
"ui.material_review.claims": "Sources and licences are unverified claims. Missing values remain unknown.", "ui.material_review.claims": "Sources and licences are unverified claims. Missing values remain unknown.",
"ui.organize": "Organise",
"ui.point_cloud_color_by": "Colour By", "ui.point_cloud_color_by": "Colour By",
"ui.point_cloud_file_colors": "File Colours", "ui.point_cloud_file_colors": "File Colours",
"ui.point_cloud_no_file_colors": "The file has no colours", "ui.point_cloud_no_file_colors": "The file has no colours",
+480 -2
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -568,6 +568,7 @@
"Select edges": "Selecciona aristas", "Select edges": "Selecciona aristas",
"Select points of the sketch being edited": "Selecciona puntos del boceto que se está editando", "Select points of the sketch being edited": "Selecciona puntos del boceto que se está editando",
"Select the centre the pattern turns around first": "Selecciona primero el centro alrededor del cual gira el patrón", "Select the centre the pattern turns around first": "Selecciona primero el centro alrededor del cual gira el patrón",
"Select the curves to divide first": "Seleccione primero las curvas que desea dividir",
"Select the curves to offset first": "Selecciona primero las curvas que se van a desfasar", "Select the curves to offset first": "Selecciona primero las curvas que se van a desfasar",
"Select the mirror line": "Selecciona la línea de simetría", "Select the mirror line": "Selecciona la línea de simetría",
"Select the sketch curves or points to mirror first": "Selecciona primero las curvas o puntos del boceto que se van a reflejar", "Select the sketch curves or points to mirror first": "Selecciona primero las curvas o puntos del boceto que se van a reflejar",
@@ -1221,6 +1222,7 @@
"cmd.sketch_options": "Opciones de la paleta de bocetos", "cmd.sketch_options": "Opciones de la paleta de bocetos",
"cmd.sketch_paste": "Pegar entidades del boceto", "cmd.sketch_paste": "Pegar entidades del boceto",
"cmd.sketch_point3d": "Punto 3D", "cmd.sketch_point3d": "Punto 3D",
"cmd.sketch_point_divide": "Dividir curva",
"cmd.sketch_polygon_circumscribed": "Polígono circunscrito", "cmd.sketch_polygon_circumscribed": "Polígono circunscrito",
"cmd.sketch_polygon_edge": "Polígono por arista", "cmd.sketch_polygon_edge": "Polígono por arista",
"cmd.sketch_polygon_inscribed": "Polígono inscrito", "cmd.sketch_polygon_inscribed": "Polígono inscrito",
@@ -1697,6 +1699,7 @@
"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.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.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.point": "Places a sketch point. Use it as a reference for dimensions, constraints, hole centres or later features.",
"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.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.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.edge": "Draws a regular polygon from the two ends of one side. Use it when the length and position of a side are known.",
@@ -2349,6 +2352,8 @@
"prefs.edges": "Aristas y sombreado", "prefs.edges": "Aristas y sombreado",
"prefs.extend": "Extensiones", "prefs.extend": "Extensiones",
"prefs.extra_navigation": "Ctrl + arrastrar con el botón izquierdo sobre un espacio vacío orbita; mantén Espacio para desplazar.", "prefs.extra_navigation": "Ctrl + arrastrar con el botón izquierdo sobre un espacio vacío orbita; mantén Espacio para desplazar.",
"prefs.extrude_arrow_face_stops": "La flecha de Extruir se detiene en las caras",
"prefs.extrude_arrow_face_stops_note": "Al arrastrar la flecha de distancia de Extruir, se detiene en las caras planas paralelas al perfil, como el lado opuesto de un bloque que se corta, y resalta la cara. Desactivado: la flecha solo avanza en pasos redondos.",
"prefs.extrude_view_isometric": "Girar la vista a isométrica al abrir Extrusión", "prefs.extrude_view_isometric": "Girar la vista a isométrica al abrir Extrusión",
"prefs.extrude_view_return": "Volver a la vista anterior al cerrar Extrusión", "prefs.extrude_view_return": "Volver a la vista anterior al cerrar Extrusión",
"prefs.follows_os": "Sigue al sistema operativo", "prefs.follows_os": "Sigue al sistema operativo",
@@ -2473,6 +2478,8 @@
"prefs.mouse": "Ratón y panel táctil", "prefs.mouse": "Ratón y panel táctil",
"prefs.mouse_heading": "Ratón", "prefs.mouse_heading": "Ratón",
"prefs.mouse_mapping": "Asignación del ratón", "prefs.mouse_mapping": "Asignación del ratón",
"prefs.move_drag_highlights": "Resaltar lo que hay bajo el puntero mientras las flechas de Mover arrastran un componente",
"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": "Navegación",
"prefs.navigation.axes_signed": "Ejes", "prefs.navigation.axes_signed": "Ejes",
"prefs.navigation.cube_compact": "Cubo", "prefs.navigation.cube_compact": "Cubo",
@@ -3045,6 +3052,8 @@
"render.cpu_lighting": "Preajuste de iluminación", "render.cpu_lighting": "Preajuste de iluminación",
"render.cpu_lights": "Luces CPU", "render.cpu_lights": "Luces CPU",
"render.cpu_linear_color": "Color lineal (R, G, B)", "render.cpu_linear_color": "Color lineal (R, G, B)",
"render.cpu_maps_saved_help": "Los renders CPU pueden usar mapas opacos guardados: elige una superficie y guarda sus mapas en la toma. Con Iluminación indirecta, otro cuerpo puede usar Vidrio; el cuerpo con mapas no puede usar Vidrio. Desactiva los reflejos seleccionados, la anisotropía y los efectos procedurales. Las rutas temporales de archivos de mapas usan GPU.",
"render.cpu_material_certification": "La comprobación de CPU valida la geometría de vidrio admitida antes de renderizar. El vidrio cerrado usa la distancia geométrica.",
"render.cpu_neutral": "Neutro", "render.cpu_neutral": "Neutro",
"render.cpu_opaque_required": "El trazado CPU requiere un fondo opaco. Desactiva Fondo transparente para continuar.", "render.cpu_opaque_required": "El trazado CPU requiere un fondo opaco. Desactiva Fondo transparente para continuar.",
"render.cpu_options_pending": "Este panel CPU todavía no puede editar emisión, efectos de superficie, vidrio ni anisotropía. Borra esas opciones de la API antes de usarlo.", "render.cpu_options_pending": "Este panel CPU todavía no puede editar emisión, efectos de superficie, vidrio ni anisotropía. Borra esas opciones de la API antes de usarlo.",
@@ -4079,6 +4088,8 @@
"sample.plate.name": "Placa de ejemplo", "sample.plate.name": "Placa de ejemplo",
"sample.vents.about": "Ranuras en un patrón rectangular: las filas, las columnas y el paso son parámetros", "sample.vents.about": "Ranuras en un patrón rectangular: las filas, las columnas y el paso son parámetros",
"sample.vents.name": "Placa de ventilación", "sample.vents.name": "Placa de ventilación",
"scale.per_axis": "Por eje",
"scale.uniform": "Uniforme",
"search.command_keys": "Intro ejecutar Mayús+Intro ejecutar y mantener abierto Esc cerrar", "search.command_keys": "Intro ejecutar Mayús+Intro ejecutar y mantener abierto Esc cerrar",
"search.commands": "Comandos", "search.commands": "Comandos",
"search.design": "En este diseño", "search.design": "En este diseño",
@@ -4166,6 +4177,7 @@
"sketch.dimension_applied": "Cota aplicada", "sketch.dimension_applied": "Cota aplicada",
"sketch.dimension_applied_defined": "Cota aplicada; parámetro `{name}` definido", "sketch.dimension_applied_defined": "Cota aplicada; parámetro `{name}` definido",
"sketch.dimension_applied_renamed": "Cota aplicada; parámetro nombrado `{name}`", "sketch.dimension_applied_renamed": "Cota aplicada; parámetro nombrado `{name}`",
"sketch.divide_hint": "Los puntos dividen cada curva en longitudes iguales y las mantienen cuando cambia.",
"sketch.dof_left": "Quedan {count} grados de libertad", "sketch.dof_left": "Quedan {count} grados de libertad",
"sketch.dof_left_one": "Queda {count} grado de libertad", "sketch.dof_left_one": "Queda {count} grado de libertad",
"sketch.draw_curves": "Dibujar como {linetype}", "sketch.draw_curves": "Dibujar como {linetype}",
@@ -4750,6 +4762,7 @@
"ui.click_selects_whole_bodies": "Un clic selecciona cuerpos completos", "ui.click_selects_whole_bodies": "Un clic selecciona cuerpos completos",
"ui.click_then_press_key": "Haz clic y pulsa la nueva tecla", "ui.click_then_press_key": "Haz clic y pulsa la nueva tecla",
"ui.close": "Cerrar", "ui.close": "Cerrar",
"ui.close_tab": "Cerrar pestaña",
"ui.coil": "Hélice", "ui.coil": "Hélice",
"ui.coincident": "Coincidente", "ui.coincident": "Coincidente",
"ui.collapse": "Contraer", "ui.collapse": "Contraer",
@@ -5046,6 +5059,7 @@
"ui.heading_create_sketch": "CREAR BOCETO", "ui.heading_create_sketch": "CREAR BOCETO",
"ui.heading_cylinder": "CILINDRO", "ui.heading_cylinder": "CILINDRO",
"ui.heading_design": "DISEÑO", "ui.heading_design": "DISEÑO",
"ui.heading_divide_curve": "DIVIDIR CURVA",
"ui.heading_draft": "ÁNGULO DE SALIDA", "ui.heading_draft": "ÁNGULO DE SALIDA",
"ui.heading_edit": "EDITAR", "ui.heading_edit": "EDITAR",
"ui.heading_equation_curve": "CURVA ECUACIÓN", "ui.heading_equation_curve": "CURVA ECUACIÓN",
@@ -5386,6 +5400,7 @@
"ui.second_rail": "Segunda línea guía", "ui.second_rail": "Segunda línea guía",
"ui.section_analysis": "Análisis de sección", "ui.section_analysis": "Análisis de sección",
"ui.section_size": "Tamaño de la sección", "ui.section_size": "Tamaño de la sección",
"ui.segments": "Segmentos",
"ui.select": "Seleccionar", "ui.select": "Seleccionar",
"ui.selectOther": "Seleccionar otro…", "ui.selectOther": "Seleccionar otro…",
"ui.selectTangentChain": "Seleccionar cadena tangente", "ui.selectTangentChain": "Seleccionar cadena tangente",
+2
View File
@@ -4077,6 +4077,8 @@
"sample.plate.name": "Esimerkkilevy", "sample.plate.name": "Esimerkkilevy",
"sample.vents.about": "Urat suorakulmaisessa kuviossa: rivit, sarakkeet ja jako ovat parametreja", "sample.vents.about": "Urat suorakulmaisessa kuviossa: rivit, sarakkeet ja jako ovat parametreja",
"sample.vents.name": "Tuuletuslevy", "sample.vents.name": "Tuuletuslevy",
"scale.per_axis": "Akseleittain",
"scale.uniform": "Tasainen",
"search.command_keys": "Enter suorita Shift+Enter suorita ja pidä auki Esc sulje", "search.command_keys": "Enter suorita Shift+Enter suorita ja pidä auki Esc sulje",
"search.commands": "Komennot", "search.commands": "Komennot",
"search.design": "Tässä mallissa", "search.design": "Tässä mallissa",
+20 -1
View File
@@ -566,6 +566,7 @@
"Select edges": "Sélectionner des arêtes", "Select edges": "Sélectionner des arêtes",
"Select points of the sketch being edited": "Sélectionner des points de l'esquisse en cours de modification", "Select points of the sketch being edited": "Sélectionner des points de l'esquisse en cours de modification",
"Select the centre the pattern turns around first": "Sélectionner d'abord le centre autour duquel la répétition pivote", "Select the centre the pattern turns around first": "Sélectionner d'abord le centre autour duquel la répétition pivote",
"Select the curves to divide first": "Sélectionner d'abord les courbes à diviser",
"Select the curves to offset first": "Sélectionner d'abord les courbes à décaler", "Select the curves to offset first": "Sélectionner d'abord les courbes à décaler",
"Select the mirror line": "Sélectionner la ligne de symétrie", "Select the mirror line": "Sélectionner la ligne de symétrie",
"Select the sketch curves or points to mirror first": "Sélectionner d'abord les courbes ou points d'esquisse à symétriser", "Select the sketch curves or points to mirror first": "Sélectionner d'abord les courbes ou points d'esquisse à symétriser",
@@ -1048,6 +1049,7 @@
"cmd.pointcloud_edit": "Modifier le nuage de points", "cmd.pointcloud_edit": "Modifier le nuage de points",
"cmd.pointcloud_insert": "Insérer un nuage de points", "cmd.pointcloud_insert": "Insérer un nuage de points",
"cmd.pointcloud_list": "Nuages de points", "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.compare.divider": "Déplacer le séparateur de comparaison des rendus",
"cmd.render.result.discard": "Écarter le résultat de rendu", "cmd.render.result.discard": "Écarter le résultat de rendu",
"cmd.render.result.select": "Sélectionner le résultat de rendu", "cmd.render.result.select": "Sélectionner le résultat de rendu",
@@ -1193,6 +1195,7 @@
"cmd.sketch_options": "Options de la palette d'esquisse", "cmd.sketch_options": "Options de la palette d'esquisse",
"cmd.sketch_paste": "Coller les entités d'esquisse", "cmd.sketch_paste": "Coller les entités d'esquisse",
"cmd.sketch_point3d": "Point 3D", "cmd.sketch_point3d": "Point 3D",
"cmd.sketch_point_divide": "Diviser la courbe",
"cmd.sketch_polygon_circumscribed": "Polygone circonscrit", "cmd.sketch_polygon_circumscribed": "Polygone circonscrit",
"cmd.sketch_polygon_edge": "Polygone par côté", "cmd.sketch_polygon_edge": "Polygone par côté",
"cmd.sketch_polygon_inscribed": "Polygone inscrit", "cmd.sketch_polygon_inscribed": "Polygone inscrit",
@@ -1425,6 +1428,7 @@
"file_load.reading_percent": "Lecture du fichier... {percent} %", "file_load.reading_percent": "Lecture du fichier... {percent} %",
"file_load.rebuilding": "Reconstruction de l’entité {done} sur {total}", "file_load.rebuilding": "Reconstruction de l’entité {done} sur {total}",
"file_load.recovering": "Récupération de la conception", "file_load.recovering": "Récupération de la conception",
"file_load.reloading_cloud": "Rechargement du nuage de points",
"file_load.stopping": "Attente de l’arrêt de l’opération précédente...", "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.updating_links": "Mise à jour des liens",
"file_load.waiting": "En attente d’une opération sur fichier", "file_load.waiting": "En attente d’une opération sur fichier",
@@ -1624,7 +1628,7 @@
"help.sketch.insert_svg": "Lit les tracés d'un dessin SVG dans une esquisse, mis à l'échelle, tournés et placés comme vous le définissez. À utiliser pour transformer un logo ou un contour vectoriel en courbes que vous pouvez extruder.", "help.sketch.insert_svg": "Lit les tracés d'un dessin SVG dans une esquisse, mis à l'échelle, tournés et placés comme vous le définissez. À utiliser pour transformer un logo ou un contour vectoriel en courbes que vous pouvez extruder.",
"help.sketch.inspect": "Ouvre un rapport sur l'esquisse ouverte : combien de degrés de liberté il reste et si elle est entièrement contrainte. À utiliser pour savoir ce qui bouge encore avant de terminer l'esquisse.", "help.sketch.inspect": "Ouvre un rapport sur l'esquisse ouverte : combien de degrés de liberté il reste et si elle est entièrement contrainte. À utiliser pour savoir ce qui bouge encore avant de terminer l'esquisse.",
"help.sketch.intersect": "Ajoute les courbes ou points où des corps, faces, arêtes ou d'autres esquisses traversent le plan d'esquisse. Ils restent liés et suivent le modèle lorsqu'il change.", "help.sketch.intersect": "Ajoute les courbes ou points où des corps, faces, arêtes ou d'autres esquisses traversent le plan d'esquisse. Ils restent liés et suivent le modèle lorsqu'il change.",
"help.sketch.intersection_curve": "Crée des courbes 3D là où deux corps ou faces se rencontrent, liées à eux. À utiliser comme trajectoires ou rails guides qui suivent le modèle.", "help.sketch.intersection_curve": "Crée des courbes 3D là où deux corps, faces ou courbes d'autres esquisses se rencontrent, liées à eux. À utiliser comme trajectoires ou rails guides qui suivent le modèle.",
"help.sketch.isoparametric_curve": "Crée une courbe 3D le long de la direction U ou V d'une face, par un point que vous choisissez, liée à la face. À utiliser comme trajectoire ou ligne de partage qui suit la surface.", "help.sketch.isoparametric_curve": "Crée une courbe 3D le long de la direction U ou V d'une face, par un point que vous choisissez, liée à la face. À utiliser comme trajectoire ou ligne de partage qui suit la surface.",
"help.sketch.line": "Dessine des lignes connectées point par point, en chaîne ouverte ou en contour fermé. C'est l'outil de base de la plupart des profils.", "help.sketch.line": "Dessine des lignes connectées point par point, en chaîne ouverte ou en contour fermé. C'est l'outil de base de la plupart des profils.",
"help.sketch.line.midpoint": "Dessine une ligne de son milieu vers une extrémité, l'autre extrémité étant son symétrique. À utiliser pour des lignes centrées sur un point, comme une arête symétrique.", "help.sketch.line.midpoint": "Dessine une ligne de son milieu vers une extrémité, l'autre extrémité étant son symétrique. À utiliser pour des lignes centrées sur un point, comme une arête symétrique.",
@@ -1636,6 +1640,7 @@
"help.sketch.pattern.circular": "Copie la géométrie d'esquisse autour d'un centre, sur un cercle complet ou un angle donné. À utiliser pour des cercles de perçages, des rayons et des dents.", "help.sketch.pattern.circular": "Copie la géométrie d'esquisse autour d'un centre, sur un cercle complet ou un angle donné. À utiliser pour des cercles de perçages, des rayons et des dents.",
"help.sketch.pattern.rectangular": "Copie la géométrie d'esquisse en lignes et colonnes à des espacements donnés. À utiliser pour des grilles de trous, de rainures ou d'aérations.", "help.sketch.pattern.rectangular": "Copie la géométrie d'esquisse en lignes et colonnes à des espacements donnés. À utiliser pour des grilles de trous, de rainures ou d'aérations.",
"help.sketch.point": "Place un point d'esquisse. À utiliser comme référence pour des cotes, des contraintes, des centres de perçage ou des fonctions ultérieures.", "help.sketch.point": "Place un point d'esquisse. À utiliser comme référence pour des cotes, des contraintes, des centres de perçage ou des fonctions ultérieures.",
"help.sketch.point.divide": "Place des points qui divisent les courbes choisies en longueurs égales. Les points restent sur chaque courbe et gardent leur espacement quand elle change.",
"help.sketch.point3d": "Place un point dans l'espace, avec Esquisse 3D activée. À utiliser comme référence pour des courbes et trajectoires 3D.", "help.sketch.point3d": "Place un point dans l'espace, avec Esquisse 3D activée. À utiliser comme référence pour des courbes et trajectoires 3D.",
"help.sketch.polygon.circumscribed": "Dessine un polygone régulier autour d'un cercle, dimensionné du centre au milieu d'un côté. À utiliser lorsque la largeur sur plats est connue, comme pour un écrou hexagonal.", "help.sketch.polygon.circumscribed": "Dessine un polygone régulier autour d'un cercle, dimensionné du centre au milieu d'un côté. À utiliser lorsque la largeur sur plats est connue, comme pour un écrou hexagonal.",
"help.sketch.polygon.edge": "Dessine un polygone régulier à partir des deux extrémités d'un côté. À utiliser lorsque la longueur et la position d'un côté sont connues.", "help.sketch.polygon.edge": "Dessine un polygone régulier à partir des deux extrémités d'un côté. À utiliser lorsque la longueur et la position d'un côté sont connues.",
@@ -2201,6 +2206,8 @@
"prefs.edges": "Arêtes et ombrage", "prefs.edges": "Arêtes et ombrage",
"prefs.extend": "Étendre", "prefs.extend": "Étendre",
"prefs.extra_navigation": "Ctrl+glisser gauche dans le vide fait orbiter ; maintenir Espace pour un panoramique.", "prefs.extra_navigation": "Ctrl+glisser gauche dans le vide fait orbiter ; maintenir Espace pour un panoramique.",
"prefs.extrude_arrow_face_stops": "La flèche d'extrusion s'arrête aux faces",
"prefs.extrude_arrow_face_stops_note": "En faisant glisser la flèche de distance d'Extrusion, elle s'arrête aux faces planes parallèles au profil, comme l'autre côté d'un bloc qu'on découpe, et souligne la face. Désactivé : la flèche avance seulement par pas ronds.",
"prefs.extrude_view_isometric": "Passer la vue en isométrique à l'ouverture de l'extrusion", "prefs.extrude_view_isometric": "Passer la vue en isométrique à l'ouverture de l'extrusion",
"prefs.extrude_view_return": "Revenir à la vue précédente à la fermeture de l'extrusion", "prefs.extrude_view_return": "Revenir à la vue précédente à la fermeture de l'extrusion",
"prefs.follows_os": "Suit le système", "prefs.follows_os": "Suit le système",
@@ -2280,6 +2287,8 @@
"prefs.mouse": "Souris et pavé tactile", "prefs.mouse": "Souris et pavé tactile",
"prefs.mouse_heading": "Souris", "prefs.mouse_heading": "Souris",
"prefs.mouse_mapping": "Affectation des boutons de la souris", "prefs.mouse_mapping": "Affectation des boutons de la souris",
"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": "Navigation",
"prefs.navigation_note": "Comment la souris, le pavé tactile et la souris 3D déplacent la vue.", "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": "Cadrer le modèle après un changement de vue du repère de navigation",
@@ -2778,6 +2787,8 @@
"render.cpu_lighting": "Préréglage d'éclairage", "render.cpu_lighting": "Préréglage d'éclairage",
"render.cpu_lights": "Lumières CPU", "render.cpu_lights": "Lumières CPU",
"render.cpu_linear_color": "Couleur linéaire (R, V, B)", "render.cpu_linear_color": "Couleur linéaire (R, V, B)",
"render.cpu_maps_saved_help": "Le rendu CPU accepte les cartes opaques enregistrées : choisissez une surface, puis enregistrez ses cartes dans la vue. Avec l’éclairage indirect, un autre corps peut utiliser Verre ; le corps avec les cartes ne le peut pas. Désactivez les réflexions sélectionnées, l’anisotropie et les effets procéduraux. Les fichiers temporaires de cartes utilisent le GPU.",
"render.cpu_material_certification": "La vérification CPU valide la géométrie de verre prise en charge avant le rendu. Le verre fermé utilise la distance géométrique.",
"render.cpu_neutral": "Neutre", "render.cpu_neutral": "Neutre",
"render.cpu_opaque_required": "Le lancer de rayons CPU nécessite un arrière-plan opaque. Décochez Arrière-plan transparent pour continuer.", "render.cpu_opaque_required": "Le lancer de rayons CPU nécessite un arrière-plan opaque. Décochez Arrière-plan transparent pour continuer.",
"render.cpu_options_pending": "Ce panneau CPU ne peut pas encore modifier l'émission, les effets de surface, le verre ni l'anisotropie. Effacez ces options d'API avant de l'utiliser.", "render.cpu_options_pending": "Ce panneau CPU ne peut pas encore modifier l'émission, les effets de surface, le verre ni l'anisotropie. Effacez ces options d'API avant de l'utiliser.",
@@ -3814,6 +3825,8 @@
"sample.plate.name": "Plaque d'exemple", "sample.plate.name": "Plaque d'exemple",
"sample.vents.about": "Rainures en répétition rectangulaire : lignes, colonnes et pas sont des paramètres", "sample.vents.about": "Rainures en répétition rectangulaire : lignes, colonnes et pas sont des paramètres",
"sample.vents.name": "Plaque d'aération", "sample.vents.name": "Plaque d'aération",
"scale.per_axis": "Par axe",
"scale.uniform": "Uniforme",
"search.command_keys": "Entrée exécuter Maj+Entrée exécuter et garder ouvert Échap fermer", "search.command_keys": "Entrée exécuter Maj+Entrée exécuter et garder ouvert Échap fermer",
"search.commands": "Commandes", "search.commands": "Commandes",
"search.design": "Dans cette conception", "search.design": "Dans cette conception",
@@ -3901,6 +3914,7 @@
"sketch.dimension_applied": "Cote appliquée", "sketch.dimension_applied": "Cote appliquée",
"sketch.dimension_applied_defined": "Cote appliquée ; paramètre `{name}` défini", "sketch.dimension_applied_defined": "Cote appliquée ; paramètre `{name}` défini",
"sketch.dimension_applied_renamed": "Cote appliquée ; paramètre nommé `{name}`", "sketch.dimension_applied_renamed": "Cote appliquée ; paramètre nommé `{name}`",
"sketch.divide_hint": "Les points divisent chaque courbe en longueurs égales et les gardent quand elle change.",
"sketch.dof_left": "{count} degrés de liberté restants", "sketch.dof_left": "{count} degrés de liberté restants",
"sketch.dof_left_one": "{count} degré de liberté restant", "sketch.dof_left_one": "{count} degré de liberté restant",
"sketch.draw_curves": "Dessiner en {linetype}", "sketch.draw_curves": "Dessiner en {linetype}",
@@ -4443,6 +4457,7 @@
"ui.click_selects_whole_bodies": "Un clic sélectionne des corps entiers", "ui.click_selects_whole_bodies": "Un clic sélectionne des corps entiers",
"ui.click_then_press_key": "Cliquer, puis appuyer sur la nouvelle touche", "ui.click_then_press_key": "Cliquer, puis appuyer sur la nouvelle touche",
"ui.close": "Fermer", "ui.close": "Fermer",
"ui.close_tab": "Fermer l’onglet",
"ui.coil": "Hélice", "ui.coil": "Hélice",
"ui.coincident": "Coïncidence", "ui.coincident": "Coïncidence",
"ui.collapse": "Réduire", "ui.collapse": "Réduire",
@@ -4689,6 +4704,7 @@
"ui.heading_create_sketch": "CRÉER UNE ESQUISSE", "ui.heading_create_sketch": "CRÉER UNE ESQUISSE",
"ui.heading_cylinder": "CYLINDRE", "ui.heading_cylinder": "CYLINDRE",
"ui.heading_design": "DESIGN", "ui.heading_design": "DESIGN",
"ui.heading_divide_curve": "DIVISER LA COURBE",
"ui.heading_draft": "DÉPOUILLE", "ui.heading_draft": "DÉPOUILLE",
"ui.heading_edit": "ÉDITION", "ui.heading_edit": "ÉDITION",
"ui.heading_equation_curve": "COURBE PAR ÉQUATION", "ui.heading_equation_curve": "COURBE PAR ÉQUATION",
@@ -4926,6 +4942,7 @@
"ui.point_cloud_add_filter": "Ajouter un filtre…", "ui.point_cloud_add_filter": "Ajouter un filtre…",
"ui.point_cloud_auto_range": "Plage automatique", "ui.point_cloud_auto_range": "Plage automatique",
"ui.point_cloud_color_by": "Colorer par", "ui.point_cloud_color_by": "Colorer par",
"ui.point_cloud_dots": "Points isolés",
"ui.point_cloud_file_colors": "Couleurs du fichier", "ui.point_cloud_file_colors": "Couleurs du fichier",
"ui.point_cloud_filter_by": "Filtrer par", "ui.point_cloud_filter_by": "Filtrer par",
"ui.point_cloud_height_high": "Plus haut", "ui.point_cloud_height_high": "Plus haut",
@@ -4934,6 +4951,7 @@
"ui.point_cloud_no_file_colors": "Le fichier n'a pas de couleurs", "ui.point_cloud_no_file_colors": "Le fichier n'a pas de couleurs",
"ui.point_cloud_pause": "Pause", "ui.point_cloud_pause": "Pause",
"ui.point_cloud_play": "Lire", "ui.point_cloud_play": "Lire",
"ui.point_cloud_reload": "Recharger le fichier",
"ui.point_cloud_single_color": "Couleur unique", "ui.point_cloud_single_color": "Couleur unique",
"ui.point_cloud_size": "Taille des points", "ui.point_cloud_size": "Taille des points",
"ui.point_cloud_units": "Unités du fichier", "ui.point_cloud_units": "Unités du fichier",
@@ -5026,6 +5044,7 @@
"ui.second_rail": "Second rail", "ui.second_rail": "Second rail",
"ui.section_analysis": "Analyse de coupe", "ui.section_analysis": "Analyse de coupe",
"ui.section_size": "Taille de la section", "ui.section_size": "Taille de la section",
"ui.segments": "Segments",
"ui.select": "Sélectionner", "ui.select": "Sélectionner",
"ui.selectOther": "Sélectionner un autre…", "ui.selectOther": "Sélectionner un autre…",
"ui.selectTangentChain": "Sélectionner la chaîne tangente", "ui.selectTangentChain": "Sélectionner la chaîne tangente",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Le os trazados dun debuxo SVG nun bosquexo, escalados, xirados e colocados onde indiques. Úsao para converter un logotipo ou un contorno vectorial en curvas que podes extruír.", "help.sketch.insert_svg": "Le os trazados dun debuxo SVG nun bosquexo, escalados, xirados e colocados onde indiques. Úsao para converter un logotipo ou un contorno vectorial en curvas que podes extruír.",
"help.sketch.inspect": "Abre un informe do bosquexo aberto: cantos graos de liberdade quedan e se está totalmente restrinxido. Úsao para saber o que aínda se move antes de rematar o bosquexo.", "help.sketch.inspect": "Abre un informe do bosquexo aberto: cantos graos de liberdade quedan e se está totalmente restrinxido. Úsao para saber o que aínda se move antes de rematar o bosquexo.",
"help.sketch.intersect": "Engade as curvas ou os puntos onde corpos, caras, arestas ou outros bosquexos cruzan o plano do bosquexo. Quedan ligados e seguen o modelo cando cambia.", "help.sketch.intersect": "Engade as curvas ou os puntos onde corpos, caras, arestas ou outros bosquexos cruzan o plano do bosquexo. Quedan ligados e seguen o modelo cando cambia.",
"help.sketch.intersection_curve": "Crea curvas 3D onde se atopan dous corpos ou caras, ligadas a eles. Úsaas como traxectorias ou guías que seguen o modelo.", "help.sketch.intersection_curve": "Crea curvas 3D onde se atopan dous corpos, caras ou curvas doutros bosquexos, ligadas a eles. Úsaas como traxectorias ou guías que seguen o modelo.",
"help.sketch.isoparametric_curve": "Crea unha curva 3D na dirección U ou V dunha cara por un punto que escollas, ligada á cara. Úsaa como traxectoria ou liña de división que segue a superficie.", "help.sketch.isoparametric_curve": "Crea unha curva 3D na dirección U ou V dunha cara por un punto que escollas, ligada á cara. Úsaa como traxectoria ou liña de división que segue a superficie.",
"help.sketch.line": "Debuxa liñas conectadas punto a punto, como cadea aberta ou como contorno pechado. É a ferramenta básica para a maioría dos perfís.", "help.sketch.line": "Debuxa liñas conectadas punto a punto, como cadea aberta ou como contorno pechado. É a ferramenta básica para a maioría dos perfís.",
"help.sketch.line.midpoint": "Debuxa unha liña desde o seu punto medio ata un extremo, co outro extremo reflectido. Úsao para liñas centradas nun punto, como unha aresta simétrica.", "help.sketch.line.midpoint": "Debuxa unha liña desde o seu punto medio ata un extremo, co outro extremo reflectido. Úsao para liñas centradas nun punto, como unha aresta simétrica.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Placa de exemplo", "sample.plate.name": "Placa de exemplo",
"sample.vents.about": "Ranuras nun patrón rectangular: filas, columnas e paso son parámetros", "sample.vents.about": "Ranuras nun patrón rectangular: filas, columnas e paso son parámetros",
"sample.vents.name": "Placa de ventilación", "sample.vents.name": "Placa de ventilación",
"scale.per_axis": "Por eixo",
"scale.uniform": "Uniforme",
"search.command_keys": "Intro executar Maiús+Intro executar e manter aberto Esc pechar", "search.command_keys": "Intro executar Maiús+Intro executar e manter aberto Esc pechar",
"search.commands": "Ordes", "search.commands": "Ordes",
"search.design": "Neste deseño", "search.design": "Neste deseño",
+479 -1
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Čita putanje SVG crteža u skicu, skalirane, zakrenute i postavljene kako zadate. Upotrijebite ga za pretvaranje logotipa ili vektorskog obrisa u krivulje koje možete ekstrudirati.", "help.sketch.insert_svg": "Čita putanje SVG crteža u skicu, skalirane, zakrenute i postavljene kako zadate. Upotrijebite ga za pretvaranje logotipa ili vektorskog obrisa u krivulje koje možete ekstrudirati.",
"help.sketch.inspect": "Otvara izvješće o otvorenoj skici: koliko je stupnjeva slobode preostalo i je li potpuno ograničena. Upotrijebite ga kako biste saznali što se još pomiče prije dovršetka skice.", "help.sketch.inspect": "Otvara izvješće o otvorenoj skici: koliko je stupnjeva slobode preostalo i je li potpuno ograničena. Upotrijebite ga kako biste saznali što se još pomiče prije dovršetka skice.",
"help.sketch.intersect": "Dodaje krivulje ili točke u kojima tijela, lica, bridovi ili druge skice presijecaju ravninu skice. Ostaju povezane i prate model kad se promijeni.", "help.sketch.intersect": "Dodaje krivulje ili točke u kojima tijela, lica, bridovi ili druge skice presijecaju ravninu skice. Ostaju povezane i prate model kad se promijeni.",
"help.sketch.intersection_curve": "Izrađuje 3D krivulje na mjestu gdje se dva tijela ili lica susreću, povezane s njima. Upotrijebite ih kao putanje ili vodilice koje prate model.", "help.sketch.intersection_curve": "Izrađuje 3D krivulje na mjestu gdje se dva tijela, lica ili krivulje drugih skica susreću, povezane s njima. Upotrijebite ih kao putanje ili vodilice koje prate model.",
"help.sketch.isoparametric_curve": "Izrađuje 3D krivulju u smjeru U ili V lica kroz točku koju odaberete, povezanu s licem. Upotrijebite je kao putanju ili liniju razdvajanja koja prati plohu.", "help.sketch.isoparametric_curve": "Izrađuje 3D krivulju u smjeru U ili V lica kroz točku koju odaberete, povezanu s licem. Upotrijebite je kao putanju ili liniju razdvajanja koja prati plohu.",
"help.sketch.line": "Crta povezane linije točku po točku, kao otvoreni lanac ili zatvoreni obris. To je osnovni alat za većinu profila.", "help.sketch.line": "Crta povezane linije točku po točku, kao otvoreni lanac ili zatvoreni obris. To je osnovni alat za većinu profila.",
"help.sketch.line.midpoint": "Crta liniju od njezine središnje točke do jednog kraja, a drugi kraj zrcali. Upotrijebite ga za linije centrirane na točku, primjerice simetričan brid.", "help.sketch.line.midpoint": "Crta liniju od njezine središnje točke do jednog kraja, a drugi kraj zrcali. Upotrijebite ga za linije centrirane na točku, primjerice simetričan brid.",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Beolvassa egy SVG-rajz útvonalait egy vázlatba, az Ön által megadott léptékkel, elforgatással és helyen. Használja egy logó vagy vektoros körvonal kihúzható görbékké alakítására.", "help.sketch.insert_svg": "Beolvassa egy SVG-rajz útvonalait egy vázlatba, az Ön által megadott léptékkel, elforgatással és helyen. Használja egy logó vagy vektoros körvonal kihúzható görbékké alakítására.",
"help.sketch.inspect": "Jelentést nyit a megnyitott vázlatról: hány szabadságfok maradt, és teljesen kényszerezett-e. Használja annak kiderítésére, mi mozdul még, mielőtt befejezi a vázlatot.", "help.sketch.inspect": "Jelentést nyit a megnyitott vázlatról: hány szabadságfok maradt, és teljesen kényszerezett-e. Használja annak kiderítésére, mi mozdul még, mielőtt befejezi a vázlatot.",
"help.sketch.intersect": "Hozzáadja azokat a görbéket vagy pontokat, ahol testek, lapok, élek vagy más vázlatok metszik a vázlatsíkot. Kapcsoltak maradnak, és követik a modellt, ha az megváltozik.", "help.sketch.intersect": "Hozzáadja azokat a görbéket vagy pontokat, ahol testek, lapok, élek vagy más vázlatok metszik a vázlatsíkot. Kapcsoltak maradnak, és követik a modellt, ha az megváltozik.",
"help.sketch.intersection_curve": "3D görbéket hoz létre ott, ahol két test vagy lap találkozik, hozzájuk kapcsolva. Használja őket útvonalként vagy vezérgörbeként, amely követi a modellt.", "help.sketch.intersection_curve": "3D görbéket hoz létre ott, ahol két test, lap vagy más vázlatok görbéi találkozik, hozzájuk kapcsolva. Használja őket útvonalként vagy vezérgörbeként, amely követi a modellt.",
"help.sketch.isoparametric_curve": "3D görbét hoz létre egy lap U vagy V iránya mentén egy kiválasztott ponton át, a laphoz kapcsolva. Használja útvonalként vagy osztóvonalként, amely követi a felületet.", "help.sketch.isoparametric_curve": "3D görbét hoz létre egy lap U vagy V iránya mentén egy kiválasztott ponton át, a laphoz kapcsolva. Használja útvonalként vagy osztóvonalként, amely követi a felületet.",
"help.sketch.line": "Összefüggő vonalakat rajzol pontról pontra, nyitott láncként vagy zárt körvonalként. Ez a legtöbb profil alapeszköze.", "help.sketch.line": "Összefüggő vonalakat rajzol pontról pontra, nyitott láncként vagy zárt körvonalként. Ez a legtöbb profil alapeszköze.",
"help.sketch.line.midpoint": "Vonalat rajzol a felezőpontjától az egyik végéig, a másik véget tükrözve. Használja egy pontra középen álló vonalakhoz, például szimmetrikus élhez.", "help.sketch.line.midpoint": "Vonalat rajzol a felezőpontjától az egyik végéig, a másik véget tükrözve. Használja egy pontra középen álló vonalakhoz, például szimmetrikus élhez.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Mintalemez", "sample.plate.name": "Mintalemez",
"sample.vents.about": "Hornyok téglalap mintában: a sorok, oszlopok és osztás paraméterek", "sample.vents.about": "Hornyok téglalap mintában: a sorok, oszlopok és osztás paraméterek",
"sample.vents.name": "Szellőzőlemez", "sample.vents.name": "Szellőzőlemez",
"scale.per_axis": "Tengelyenként",
"scale.uniform": "Egyenletes",
"search.command_keys": "Enter futtatás Shift+Enter futtatás és nyitva tartás Esc bezárás", "search.command_keys": "Enter futtatás Shift+Enter futtatás és nyitva tartás Esc bezárás",
"search.commands": "Parancsok", "search.commands": "Parancsok",
"search.design": "Ebben a tervben", "search.design": "Ebben a tervben",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Membaca path gambar SVG ke dalam sketsa, diskalakan, diputar, dan ditempatkan sesuai pengaturan Anda. Gunakan untuk mengubah logo atau kontur vektor menjadi kurva yang dapat diekstrusi.", "help.sketch.insert_svg": "Membaca path gambar SVG ke dalam sketsa, diskalakan, diputar, dan ditempatkan sesuai pengaturan Anda. Gunakan untuk mengubah logo atau kontur vektor menjadi kurva yang dapat diekstrusi.",
"help.sketch.inspect": "Membuka laporan tentang sketsa yang terbuka: berapa derajat kebebasan yang tersisa dan apakah sketsa terbatasi penuh. Gunakan untuk mengetahui apa yang masih bergerak sebelum Anda menyelesaikan sketsa.", "help.sketch.inspect": "Membuka laporan tentang sketsa yang terbuka: berapa derajat kebebasan yang tersisa dan apakah sketsa terbatasi penuh. Gunakan untuk mengetahui apa yang masih bergerak sebelum Anda menyelesaikan sketsa.",
"help.sketch.intersect": "Menambahkan kurva atau titik tempat bodi, muka, tepi, atau sketsa lain memotong bidang sketsa. Semuanya tetap tertaut dan mengikuti model saat model berubah.", "help.sketch.intersect": "Menambahkan kurva atau titik tempat bodi, muka, tepi, atau sketsa lain memotong bidang sketsa. Semuanya tetap tertaut dan mengikuti model saat model berubah.",
"help.sketch.intersection_curve": "Membuat kurva 3D di tempat dua bodi atau muka bertemu, tertaut padanya. Gunakan sebagai jalur atau rel pemandu yang mengikuti model.", "help.sketch.intersection_curve": "Membuat kurva 3D di tempat dua bodi, muka, atau kurva sketsa lain bertemu, tertaut padanya. Gunakan sebagai jalur atau rel pemandu yang mengikuti model.",
"help.sketch.isoparametric_curve": "Membuat kurva 3D sepanjang arah U atau V sebuah muka melalui titik yang Anda pilih, tertaut ke muka itu. Gunakan sebagai jalur atau garis pisah yang mengikuti permukaan.", "help.sketch.isoparametric_curve": "Membuat kurva 3D sepanjang arah U atau V sebuah muka melalui titik yang Anda pilih, tertaut ke muka itu. Gunakan sebagai jalur atau garis pisah yang mengikuti permukaan.",
"help.sketch.line": "Menggambar garis-garis tersambung titik demi titik, sebagai rantai terbuka atau kontur tertutup. Ini alat dasar untuk sebagian besar profil.", "help.sketch.line": "Menggambar garis-garis tersambung titik demi titik, sebagai rantai terbuka atau kontur tertutup. Ini alat dasar untuk sebagian besar profil.",
"help.sketch.line.midpoint": "Menggambar garis dari titik tengahnya ke satu ujung, dengan ujung lainnya dicerminkan. Gunakan untuk garis yang dipusatkan pada sebuah titik, seperti tepi simetris.", "help.sketch.line.midpoint": "Menggambar garis dari titik tengahnya ke satu ujung, dengan ujung lainnya dicerminkan. Gunakan untuk garis yang dipusatkan pada sebuah titik, seperti tepi simetris.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Pelat Contoh", "sample.plate.name": "Pelat Contoh",
"sample.vents.about": "Slot dalam pola persegi panjang: baris, kolom, dan pitch adalah parameter", "sample.vents.about": "Slot dalam pola persegi panjang: baris, kolom, dan pitch adalah parameter",
"sample.vents.name": "Pelat Ventilasi", "sample.vents.name": "Pelat Ventilasi",
"scale.per_axis": "Per sumbu",
"scale.uniform": "Seragam",
"search.command_keys": "Enter jalankan Shift+Enter jalankan dan tetap buka Esc tutup", "search.command_keys": "Enter jalankan Shift+Enter jalankan dan tetap buka Esc tutup",
"search.commands": "Perintah", "search.commands": "Perintah",
"search.design": "Di desain ini", "search.design": "Di desain ini",
+9 -1
View File
@@ -567,6 +567,7 @@
"Select edges": "Seleziona spigoli", "Select edges": "Seleziona spigoli",
"Select points of the sketch being edited": "Seleziona punti dello schizzo in modifica", "Select points of the sketch being edited": "Seleziona punti dello schizzo in modifica",
"Select the centre the pattern turns around first": "Seleziona prima il centro attorno a cui ruota la serie", "Select the centre the pattern turns around first": "Seleziona prima il centro attorno a cui ruota la serie",
"Select the curves to divide first": "Selezionare prima le curve da dividere",
"Select the curves to offset first": "Seleziona prima le curve per l'offset", "Select the curves to offset first": "Seleziona prima le curve per l'offset",
"Select the mirror line": "Seleziona la linea di simmetria", "Select the mirror line": "Seleziona la linea di simmetria",
"Select the sketch curves or points to mirror first": "Seleziona prima le curve o i punti dello schizzo da specchiare", "Select the sketch curves or points to mirror first": "Seleziona prima le curve o i punti dello schizzo da specchiare",
@@ -1194,6 +1195,7 @@
"cmd.sketch_options": "Opzioni della tavolozza schizzo", "cmd.sketch_options": "Opzioni della tavolozza schizzo",
"cmd.sketch_paste": "Incolla entità dello schizzo", "cmd.sketch_paste": "Incolla entità dello schizzo",
"cmd.sketch_point3d": "Punto 3D", "cmd.sketch_point3d": "Punto 3D",
"cmd.sketch_point_divide": "Dividi curva",
"cmd.sketch_polygon_circumscribed": "Poligono circoscritto", "cmd.sketch_polygon_circumscribed": "Poligono circoscritto",
"cmd.sketch_polygon_edge": "Poligono per lato", "cmd.sketch_polygon_edge": "Poligono per lato",
"cmd.sketch_polygon_inscribed": "Poligono inscritto", "cmd.sketch_polygon_inscribed": "Poligono inscritto",
@@ -1625,7 +1627,7 @@
"help.sketch.insert_svg": "Legge i tracciati di un disegno SVG in uno schizzo, scalati, ruotati e posizionati come imposti. Usalo per trasformare un logo o un contorno vettoriale in curve che puoi estrudere.", "help.sketch.insert_svg": "Legge i tracciati di un disegno SVG in uno schizzo, scalati, ruotati e posizionati come imposti. Usalo per trasformare un logo o un contorno vettoriale in curve che puoi estrudere.",
"help.sketch.inspect": "Apre un rapporto sullo schizzo aperto: quanti gradi di libertà restano e se è completamente vincolato. Usalo per scoprire cosa si muove ancora prima di terminare lo schizzo.", "help.sketch.inspect": "Apre un rapporto sullo schizzo aperto: quanti gradi di libertà restano e se è completamente vincolato. Usalo per scoprire cosa si muove ancora prima di terminare lo schizzo.",
"help.sketch.intersect": "Aggiunge le curve o i punti in cui corpi, facce, spigoli o altri schizzi attraversano il piano dello schizzo. Restano collegati e seguono il modello quando cambia.", "help.sketch.intersect": "Aggiunge le curve o i punti in cui corpi, facce, spigoli o altri schizzi attraversano il piano dello schizzo. Restano collegati e seguono il modello quando cambia.",
"help.sketch.intersection_curve": "Crea curve 3D dove si incontrano due corpi o facce, collegate a essi. Usale come percorsi o guide che seguono il modello.", "help.sketch.intersection_curve": "Crea curve 3D dove si incontrano due corpi, facce o curve di altri schizzi, collegate a essi. Usale come percorsi o guide che seguono il modello.",
"help.sketch.isoparametric_curve": "Crea una curva 3D lungo la direzione U o V di una faccia passante per un punto che scegli, collegata alla faccia. Usala come percorso o linea di divisione che segue la superficie.", "help.sketch.isoparametric_curve": "Crea una curva 3D lungo la direzione U o V di una faccia passante per un punto che scegli, collegata alla faccia. Usala come percorso o linea di divisione che segue la superficie.",
"help.sketch.line": "Disegna linee collegate punto per punto, come catena aperta o contorno chiuso. È lo strumento di base per la maggior parte dei profili.", "help.sketch.line": "Disegna linee collegate punto per punto, come catena aperta o contorno chiuso. È lo strumento di base per la maggior parte dei profili.",
"help.sketch.line.midpoint": "Disegna una linea dal suo punto medio fino a un'estremità, con l'altra estremità speculare. Usalo per linee centrate su un punto, come un bordo simmetrico.", "help.sketch.line.midpoint": "Disegna una linea dal suo punto medio fino a un'estremità, con l'altra estremità speculare. Usalo per linee centrate su un punto, come un bordo simmetrico.",
@@ -1637,6 +1639,7 @@
"help.sketch.pattern.circular": "Copia la geometria dello schizzo attorno a un punto centrale, su un cerchio completo o su un angolo stabilito. Usalo per cerchi di bulloni, raggi e denti.", "help.sketch.pattern.circular": "Copia la geometria dello schizzo attorno a un punto centrale, su un cerchio completo o su un angolo stabilito. Usalo per cerchi di bulloni, raggi e denti.",
"help.sketch.pattern.rectangular": "Copia la geometria dello schizzo in righe e colonne con spaziature stabilite. Usalo per griglie di fori, asole o prese d'aria.", "help.sketch.pattern.rectangular": "Copia la geometria dello schizzo in righe e colonne con spaziature stabilite. Usalo per griglie di fori, asole o prese d'aria.",
"help.sketch.point": "Colloca un punto dello schizzo. Usalo come riferimento per quote, vincoli, centri di fori o lavorazioni successive.", "help.sketch.point": "Colloca un punto dello schizzo. Usalo come riferimento per quote, vincoli, centri di fori o lavorazioni successive.",
"help.sketch.point.divide": "Posiziona punti che dividono le curve scelte in lunghezze uguali. I punti restano su ogni curva e ne mantengono la spaziatura quando cambia.",
"help.sketch.point3d": "Colloca un punto nello spazio, con Schizzo 3D attivo. Usalo come riferimento per curve e percorsi 3D.", "help.sketch.point3d": "Colloca un punto nello spazio, con Schizzo 3D attivo. Usalo come riferimento per curve e percorsi 3D.",
"help.sketch.polygon.circumscribed": "Disegna un poligono regolare attorno a un cerchio, dimensionato dal centro al punto medio di un lato. Usalo quando è nota l'apertura chiave, come per un dado esagonale.", "help.sketch.polygon.circumscribed": "Disegna un poligono regolare attorno a un cerchio, dimensionato dal centro al punto medio di un lato. Usalo quando è nota l'apertura chiave, come per un dado esagonale.",
"help.sketch.polygon.edge": "Disegna un poligono regolare a partire dai due estremi di un lato. Usalo quando sono note la lunghezza e la posizione di un lato.", "help.sketch.polygon.edge": "Disegna un poligono regolare a partire dai due estremi di un lato. Usalo quando sono note la lunghezza e la posizione di un lato.",
@@ -3813,6 +3816,8 @@
"sample.plate.name": "Piastra di esempio", "sample.plate.name": "Piastra di esempio",
"sample.vents.about": "Asole in ripetizione rettangolare: righe, colonne e passo sono parametri", "sample.vents.about": "Asole in ripetizione rettangolare: righe, colonne e passo sono parametri",
"sample.vents.name": "Piastra di ventilazione", "sample.vents.name": "Piastra di ventilazione",
"scale.per_axis": "Per asse",
"scale.uniform": "Uniforme",
"search.command_keys": "Invio esegui Maiusc+Invio esegui e tieni aperto Esc chiudi", "search.command_keys": "Invio esegui Maiusc+Invio esegui e tieni aperto Esc chiudi",
"search.commands": "Comandi", "search.commands": "Comandi",
"search.design": "In questo progetto", "search.design": "In questo progetto",
@@ -3900,6 +3905,7 @@
"sketch.dimension_applied": "Quota applicata", "sketch.dimension_applied": "Quota applicata",
"sketch.dimension_applied_defined": "Quota applicata; parametro `{name}` definito", "sketch.dimension_applied_defined": "Quota applicata; parametro `{name}` definito",
"sketch.dimension_applied_renamed": "Quota applicata; parametro denominato `{name}`", "sketch.dimension_applied_renamed": "Quota applicata; parametro denominato `{name}`",
"sketch.divide_hint": "I punti dividono ogni curva in lunghezze uguali e le mantengono quando cambia.",
"sketch.dof_left": "{count} gradi di libertà rimanenti", "sketch.dof_left": "{count} gradi di libertà rimanenti",
"sketch.dof_left_one": "{count} grado di libertà rimanente", "sketch.dof_left_one": "{count} grado di libertà rimanente",
"sketch.draw_curves": "Disegna come {linetype}", "sketch.draw_curves": "Disegna come {linetype}",
@@ -4689,6 +4695,7 @@
"ui.heading_create_sketch": "CREA SCHIZZO", "ui.heading_create_sketch": "CREA SCHIZZO",
"ui.heading_cylinder": "CILINDRO", "ui.heading_cylinder": "CILINDRO",
"ui.heading_design": "PROGETTAZIONE", "ui.heading_design": "PROGETTAZIONE",
"ui.heading_divide_curve": "DIVIDI CURVA",
"ui.heading_draft": "SFORMO", "ui.heading_draft": "SFORMO",
"ui.heading_edit": "MODIFICA", "ui.heading_edit": "MODIFICA",
"ui.heading_equation_curve": "CURVA DA EQUAZIONE", "ui.heading_equation_curve": "CURVA DA EQUAZIONE",
@@ -5027,6 +5034,7 @@
"ui.second_rail": "Seconda guida", "ui.second_rail": "Seconda guida",
"ui.section_analysis": "Analisi in sezione", "ui.section_analysis": "Analisi in sezione",
"ui.section_size": "Dimensione della sezione", "ui.section_size": "Dimensione della sezione",
"ui.segments": "Segmenti",
"ui.select": "Seleziona", "ui.select": "Seleziona",
"ui.selectOther": "Seleziona altro…", "ui.selectOther": "Seleziona altro…",
"ui.selectTangentChain": "Seleziona catena tangente", "ui.selectTangentChain": "Seleziona catena tangente",
+479 -1
View File
File diff suppressed because it is too large Load Diff
+1018 -46
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Membaca laluan lukisan SVG ke dalam lakaran, diskalakan, diputar dan diletakkan mengikut tetapan anda. Gunakan untuk menukar logo atau garis luar vektor kepada lengkung yang boleh disemperit.", "help.sketch.insert_svg": "Membaca laluan lukisan SVG ke dalam lakaran, diskalakan, diputar dan diletakkan mengikut tetapan anda. Gunakan untuk menukar logo atau garis luar vektor kepada lengkung yang boleh disemperit.",
"help.sketch.inspect": "Membuka laporan tentang lakaran yang terbuka: berapa banyak darjah kebebasan yang tinggal dan sama ada ia terkekang sepenuhnya. Gunakan untuk mengetahui apa yang masih bergerak sebelum anda menamatkan lakaran.", "help.sketch.inspect": "Membuka laporan tentang lakaran yang terbuka: berapa banyak darjah kebebasan yang tinggal dan sama ada ia terkekang sepenuhnya. Gunakan untuk mengetahui apa yang masih bergerak sebelum anda menamatkan lakaran.",
"help.sketch.intersect": "Menambah lengkung atau titik tempat jasad, muka, tepi atau lakaran lain melintasi satah lakaran. Ia kekal terpaut dan mengikut model apabila model berubah.", "help.sketch.intersect": "Menambah lengkung atau titik tempat jasad, muka, tepi atau lakaran lain melintasi satah lakaran. Ia kekal terpaut dan mengikut model apabila model berubah.",
"help.sketch.intersection_curve": "Mencipta lengkung 3D tempat dua jasad atau muka bertemu, terpaut kepadanya. Gunakan sebagai laluan atau rel pemandu yang mengikut model.", "help.sketch.intersection_curve": "Mencipta lengkung 3D tempat dua jasad, muka atau lengkung lakaran lain bertemu, terpaut kepadanya. Gunakan sebagai laluan atau rel pemandu yang mengikut model.",
"help.sketch.isoparametric_curve": "Mencipta lengkung 3D di sepanjang arah U atau V muka melalui titik yang anda pilih, terpaut kepada muka itu. Gunakan sebagai laluan atau garis belahan yang mengikut permukaan.", "help.sketch.isoparametric_curve": "Mencipta lengkung 3D di sepanjang arah U atau V muka melalui titik yang anda pilih, terpaut kepada muka itu. Gunakan sebagai laluan atau garis belahan yang mengikut permukaan.",
"help.sketch.line": "Melukis garis bersambung titik demi titik, sebagai rantaian terbuka atau garis luar tertutup. Ia ialah alat asas bagi kebanyakan profil.", "help.sketch.line": "Melukis garis bersambung titik demi titik, sebagai rantaian terbuka atau garis luar tertutup. Ia ialah alat asas bagi kebanyakan profil.",
"help.sketch.line.midpoint": "Melukis garis daripada titik tengahnya ke satu hujung, dengan hujung satu lagi dicerminkan. Gunakan untuk garis yang berpusat pada satu titik, seperti tepi simetri.", "help.sketch.line.midpoint": "Melukis garis daripada titik tengahnya ke satu hujung, dengan hujung satu lagi dicerminkan. Gunakan untuk garis yang berpusat pada satu titik, seperti tepi simetri.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Plat Contoh", "sample.plate.name": "Plat Contoh",
"sample.vents.about": "Corak slot segi empat tepat: baris, lajur dan pic sebagai parameter", "sample.vents.about": "Corak slot segi empat tepat: baris, lajur dan pic sebagai parameter",
"sample.vents.name": "Plat Pengudaraan", "sample.vents.name": "Plat Pengudaraan",
"scale.per_axis": "Mengikut paksi",
"scale.uniform": "Seragam",
"search.command_keys": "Enter jalankan Shift+Enter jalankan dan kekalkan terbuka Esc tutup", "search.command_keys": "Enter jalankan Shift+Enter jalankan dan kekalkan terbuka Esc tutup",
"search.commands": "Arahan", "search.commands": "Arahan",
"search.design": "Dalam reka bentuk ini", "search.design": "Dalam reka bentuk ini",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Leser banene fra en SVG-tegning inn i en skisse, skalert, dreid og plassert slik du angir. Bruk det til å gjøre en logo eller vektorkontur om til kurver du kan ekstrudere.", "help.sketch.insert_svg": "Leser banene fra en SVG-tegning inn i en skisse, skalert, dreid og plassert slik du angir. Bruk det til å gjøre en logo eller vektorkontur om til kurver du kan ekstrudere.",
"help.sketch.inspect": "Åpner en rapport om den åpne skissen: hvor mange frihetsgrader som gjenstår og om den er fullstendig bundet. Bruk det til å finne ut hva som fortsatt beveger seg før du fullfører skissen.", "help.sketch.inspect": "Åpner en rapport om den åpne skissen: hvor mange frihetsgrader som gjenstår og om den er fullstendig bundet. Bruk det til å finne ut hva som fortsatt beveger seg før du fullfører skissen.",
"help.sketch.intersect": "Legger til kurvene eller punktene der kropper, flater, kanter eller andre skisser krysser skisseplanet. De forblir koblet og følger modellen når den endres.", "help.sketch.intersect": "Legger til kurvene eller punktene der kropper, flater, kanter eller andre skisser krysser skisseplanet. De forblir koblet og følger modellen når den endres.",
"help.sketch.intersection_curve": "Oppretter 3D-kurver der to kropper eller flater møtes, koblet til dem. Bruk dem som baner eller føringskurver som følger modellen.", "help.sketch.intersection_curve": "Oppretter 3D-kurver der to kropper, flater eller kurver fra andre skisser møtes, koblet til dem. Bruk dem som baner eller føringskurver som følger modellen.",
"help.sketch.isoparametric_curve": "Oppretter en 3D-kurve langs U- eller V-retningen til en flate gjennom et punkt du velger, koblet til flaten. Bruk den som en bane eller delelinje som følger flaten.", "help.sketch.isoparametric_curve": "Oppretter en 3D-kurve langs U- eller V-retningen til en flate gjennom et punkt du velger, koblet til flaten. Bruk den som en bane eller delelinje som følger flaten.",
"help.sketch.line": "Tegner sammenhengende linjer punkt for punkt, som en åpen kjede eller en lukket kontur. Det er det grunnleggende verktøyet for de fleste profiler.", "help.sketch.line": "Tegner sammenhengende linjer punkt for punkt, som en åpen kjede eller en lukket kontur. Det er det grunnleggende verktøyet for de fleste profiler.",
"help.sketch.line.midpoint": "Tegner en linje fra midtpunktet og ut til den ene enden, med den andre enden speilet. Bruk det til linjer sentrert på et punkt, for eksempel en symmetrisk kant.", "help.sketch.line.midpoint": "Tegner en linje fra midtpunktet og ut til den ene enden, med den andre enden speilet. Bruk det til linjer sentrert på et punkt, for eksempel en symmetrisk kant.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Eksempelplate", "sample.plate.name": "Eksempelplate",
"sample.vents.about": "Spor i et rektangulært mønster: rader, kolonner og stigning er parametere", "sample.vents.about": "Spor i et rektangulært mønster: rader, kolonner og stigning er parametere",
"sample.vents.name": "Ventilasjonsplate", "sample.vents.name": "Ventilasjonsplate",
"scale.per_axis": "Per akse",
"scale.uniform": "Jevn",
"search.command_keys": "Enter kjør Shift+Enter kjør og behold åpen Esc lukk", "search.command_keys": "Enter kjør Shift+Enter kjør og behold åpen Esc lukk",
"search.commands": "Kommandoer", "search.commands": "Kommandoer",
"search.design": "I dette designet", "search.design": "I dette designet",
+3 -1
View File
@@ -1625,7 +1625,7 @@
"help.sketch.insert_svg": "Leest de paden van een SVG-tekening in een schets, geschaald, gedraaid en geplaatst waar je instelt. Gebruik dit om een logo of vectorcontour om te zetten in curven die je kunt extruderen.", "help.sketch.insert_svg": "Leest de paden van een SVG-tekening in een schets, geschaald, gedraaid en geplaatst waar je instelt. Gebruik dit om een logo of vectorcontour om te zetten in curven die je kunt extruderen.",
"help.sketch.inspect": "Opent een rapport over de geopende schets: hoeveel vrijheidsgraden er nog over zijn en of hij volledig beperkt is. Gebruik dit om te zien wat nog beweegt voordat je de schets voltooit.", "help.sketch.inspect": "Opent een rapport over de geopende schets: hoeveel vrijheidsgraden er nog over zijn en of hij volledig beperkt is. Gebruik dit om te zien wat nog beweegt voordat je de schets voltooit.",
"help.sketch.intersect": "Voegt de curven of punten toe waar lichamen, vlakken, randen of andere schetsen het schetsvlak kruisen. Ze blijven gekoppeld en volgen het model wanneer dat verandert.", "help.sketch.intersect": "Voegt de curven of punten toe waar lichamen, vlakken, randen of andere schetsen het schetsvlak kruisen. Ze blijven gekoppeld en volgen het model wanneer dat verandert.",
"help.sketch.intersection_curve": "Maakt 3D-curven waar twee lichamen of vlakken samenkomen, eraan gekoppeld. Gebruik ze als paden of geleiders die het model volgen.", "help.sketch.intersection_curve": "Maakt 3D-curven waar twee lichamen, vlakken of curven van andere schetsen samenkomen, eraan gekoppeld. Gebruik ze als paden of geleiders die het model volgen.",
"help.sketch.isoparametric_curve": "Maakt een 3D-curve langs de U- of V-richting van een vlak door een punt dat je kiest, gekoppeld aan het vlak. Gebruik dit als pad of splitslijn die het oppervlak volgt.", "help.sketch.isoparametric_curve": "Maakt een 3D-curve langs de U- of V-richting van een vlak door een punt dat je kiest, gekoppeld aan het vlak. Gebruik dit als pad of splitslijn die het oppervlak volgt.",
"help.sketch.line": "Tekent verbonden lijnen punt voor punt, als open keten of gesloten contour. Het is het basisgereedschap voor de meeste profielen.", "help.sketch.line": "Tekent verbonden lijnen punt voor punt, als open keten of gesloten contour. Het is het basisgereedschap voor de meeste profielen.",
"help.sketch.line.midpoint": "Tekent een lijn vanuit zijn middelpunt naar één uiteinde, waarbij het andere uiteinde wordt gespiegeld. Gebruik dit voor lijnen die op een punt zijn gecentreerd, zoals een symmetrische rand.", "help.sketch.line.midpoint": "Tekent een lijn vanuit zijn middelpunt naar één uiteinde, waarbij het andere uiteinde wordt gespiegeld. Gebruik dit voor lijnen die op een punt zijn gecentreerd, zoals een symmetrische rand.",
@@ -3818,6 +3818,8 @@
"sample.plate.name": "Voorbeeldplaat", "sample.plate.name": "Voorbeeldplaat",
"sample.vents.about": "Sleuven in een rechthoekig patroon: rijen, kolommen en spoed zijn parameters", "sample.vents.about": "Sleuven in een rechthoekig patroon: rijen, kolommen en spoed zijn parameters",
"sample.vents.name": "Ventilatieplaat", "sample.vents.name": "Ventilatieplaat",
"scale.per_axis": "Per as",
"scale.uniform": "Uniform",
"search.command_keys": "Enter uitvoeren Shift+Enter uitvoeren en open houden Esc sluiten", "search.command_keys": "Enter uitvoeren Shift+Enter uitvoeren en open houden Esc sluiten",
"search.commands": "Opdrachten", "search.commands": "Opdrachten",
"search.design": "In dit ontwerp", "search.design": "In dit ontwerp",
@@ -1,26 +0,0 @@
{
"en": {
"ai.prefs.instructions": "Custom instructions",
"ai.prefs.instructions_note": "Sent to the agent at the start of every chat, after SolidCraft's own instructions: how you like to work, rules to keep to. A change applies from the next chat (Connect or New chat)."
},
"ar": {
"ai.prefs.instructions": "تعليمات مخصصة",
"ai.prefs.instructions_note": "تُرسَل إلى الوكيل في بداية كل محادثة، بعد تعليمات SolidCraft الخاصة: طريقتك المفضلة في العمل والقواعد التي يجب الالتزام بها. يسري أي تغيير من المحادثة التالية (اتصال أو محادثة جديدة)."
},
"he": {
"ai.prefs.instructions": "הוראות מותאמות אישית",
"ai.prefs.instructions_note": "נשלחות לסוכן בתחילת כל צ'אט, אחרי ההוראות של SolidCraft עצמה: דרך העבודה המועדפת עליך וכללים שיש להקפיד עליהם. שינוי חל מהצ'אט הבא (התחברות או צ'אט חדש)."
},
"ja": {
"ai.prefs.instructions": "カスタム指示",
"ai.prefs.instructions_note": "各チャットの開始時に、SolidCraft 自身の指示の後に続けてエージェントへ送られます。作業の進め方や守ってほしいルールを書いてください。変更は次のチャット(接続または新しいチャット)から適用されます。"
},
"vi": {
"ai.prefs.instructions": "Hướng dẫn tùy chỉnh",
"ai.prefs.instructions_note": "Được gửi cho agent khi bắt đầu mỗi cuộc trò chuyện, sau hướng dẫn riêng của SolidCraft: cách bạn muốn làm việc, các quy tắc cần tuân theo. Thay đổi có hiệu lực từ cuộc trò chuyện tiếp theo (Kết nối hoặc Cuộc trò chuyện mới)."
},
"zh": {
"ai.prefs.instructions": "自定义指令",
"ai.prefs.instructions_note": "在每次对话开始时发送给代理,位于 SolidCraft 自身的指令之后:你喜欢的工作方式、需要遵守的规则。更改从下一次对话(连接或新对话)起生效。"
}
}
-29
View File
@@ -1,29 +0,0 @@
{
"ar": {
"render.aging_raytrace_help": "يُطبّق التعتيق في تتبع الأشعة على المعالج وتتبع المسارات على المعالج الرسومي. يبقى التصيير النقطي تخطيطياً."
},
"de": {
"render.aging_raytrace_help": "Alterung wird beim CPU-Raytracing und GPU-Pathtracing angewendet. Raster bleibt eine schematische Darstellung."
},
"en": {
"render.aging_raytrace_help": "Aging is applied by CPU ray tracing and GPU path tracing. Raster keeps schematic rendering."
},
"en-GB": {
"render.aging_raytrace_help": "Ageing is applied by CPU ray tracing and GPU path tracing. Raster keeps schematic rendering."
},
"he": {
"render.aging_raytrace_help": "התיישנות מוחלת במעקב קרניים במעבד ובמעקב מסלולים במעבד הגרפי. רינדור רסטר נשאר סכמטי."
},
"ja": {
"render.aging_raytrace_help": "エイジングはCPUレイトレーシングとGPUパストレーシングで適用されます。ラスタは模式的な描画を維持します。"
},
"ko": {
"render.aging_raytrace_help": "에이징은 CPU 광선 추적과 GPU 경로 추적에 적용됩니다. 래스터는 도식적인 렌더링을 유지합니다."
},
"vi": {
"render.aging_raytrace_help": "Hiệu ứng lão hoá được áp dụng khi dò tia bằng CPU và dò đường đi bằng GPU. Kết xuất raster giữ kiểu sơ đồ."
},
"zh": {
"render.aging_raytrace_help": "老化效果适用于CPU光线追踪和GPU路径追踪。光栅保持示意渲染。"
}
}
@@ -1,98 +0,0 @@
{
"ar": {
"render.cpu_volume_enable_path": "تفعيل الإضاءة غير المباشرة",
"render.cpu_volume_enable_path_plan": "تتبع أشعة CPU · عمق المسار {depth} · {spp} عينة/بكسل · بذرة {seed} · ظلال متتبعة. يحتفظ بالغلاف الجوي وميزانية الصورة المحددين.",
"render.cpu_volume_help": "يستخدم الغلاف الجوي على CPU الإضاءة غير المباشرة. يحافظ الانطفاء الصفري على الصندوق المحفوظ دون ضباب.",
"render.cpu_volume_method_adopt": "تتبع أشعة CPU مع إضاءة غير مباشرة",
"render.cpu_volume_method_incompatible": "لا يمكن نقل إعدادات الإضاءة أو أخذ العينات أو الغلاف الجوي هذه إلى هذه الطريقة. تبقى إعداداتك محفوظة.",
"render.cpu_volume_path_required": "فعّل الإضاءة غير المباشرة لاستخدام الغلاف الجوي على CPU.",
"render.volume_denoise_required": "أوقف تقليل الضوضاء لاستخدام الغلاف الجوي.",
"render.volume_glass_required": "لا يمكن الجمع بين الغلاف الجوي والزجاج في هذا الإعداد.",
"render.volume_lighting_required": "اختر بيئة أو مجموعة إضاءة محددة لتصيير الغلاف الجوي.",
"render.volume_single_stratum_required": "استخدم عينة نفاذ واحدة لتصيير الغلاف الجوي."
},
"de": {
"render.cpu_volume_enable_path": "Indirekte Beleuchtung einschalten",
"render.cpu_volume_enable_path_plan": "CPU-Raytracing · Pfadtiefe {depth} · {spp} Samples/Pixel · Seed {seed} · Raytracing-Schatten. Atmosphäre und Bildbudget bleiben erhalten.",
"render.cpu_volume_help": "CPU-Atmosphäre nutzt indirekte Beleuchtung. Bei Extinktion null bleibt die gespeicherte Box ohne Nebel erhalten.",
"render.cpu_volume_method_adopt": "CPU-Raytracing mit indirekter Beleuchtung",
"render.cpu_volume_method_incompatible": "Diese Licht-, Sampling- oder Atmosphäreinstellungen lassen sich nicht auf diese Methode übertragen. Die Einstellungen bleiben erhalten.",
"render.cpu_volume_path_required": "Indirekte Beleuchtung einschalten, um CPU-Atmosphäre zu nutzen.",
"render.volume_denoise_required": "Für Atmosphäre die Rauschreduzierung ausschalten.",
"render.volume_glass_required": "Atmosphäre und Glas können in dieser Einstellung nicht kombiniert werden.",
"render.volume_lighting_required": "Für Atmosphäre eine Umgebung oder ein eigenes Lichtrig wählen.",
"render.volume_single_stratum_required": "Für Atmosphäre ein Transmissionssample verwenden."
},
"en": {
"render.cpu_volume_enable_path": "Enable Indirect lighting",
"render.cpu_volume_enable_path_plan": "CPU ray tracing · path depth {depth} · {spp} samples/pixel · seed {seed} · traced shadows. Keeps the authored atmosphere and image budget.",
"render.cpu_volume_help": "CPU Atmosphere uses Indirect lighting. Zero extinction keeps the saved box without fog.",
"render.cpu_volume_method_adopt": "CPU ray tracing with indirect lighting",
"render.cpu_volume_method_incompatible": "These light, sampling or atmosphere settings cannot be transferred to this method. Your settings are kept.",
"render.cpu_volume_path_required": "Enable Indirect lighting to use CPU Atmosphere.",
"render.volume_denoise_required": "Turn off noise reduction to use Atmosphere.",
"render.volume_glass_required": "Atmosphere cannot be combined with Glass in this setup.",
"render.volume_lighting_required": "Choose an environment or an explicit light rig to render Atmosphere.",
"render.volume_single_stratum_required": "Use one transmission sample to render Atmosphere."
},
"he": {
"render.cpu_volume_enable_path": "הפעלת תאורה עקיפה",
"render.cpu_volume_enable_path_plan": "מעקב קרניים ב־CPU · עומק מסלול {depth} · {spp} דגימות לפיקסל · זרע {seed} · צללים במעקב קרניים. האטמוספרה ותקציב התמונה שנקבעו נשמרים.",
"render.cpu_volume_help": "אטמוספרה ב־CPU משתמשת בתאורה עקיפה. הכחדה אפסית שומרת את התיבה ללא ערפל.",
"render.cpu_volume_method_adopt": "מעקב קרניים ב־CPU עם תאורה עקיפה",
"render.cpu_volume_method_incompatible": "לא ניתן להעביר הגדרות תאורה, דגימה או אטמוספרה אלה לשיטה זו. ההגדרות שלך נשמרות.",
"render.cpu_volume_path_required": "יש להפעיל תאורה עקיפה כדי להשתמש באטמוספרה ב־CPU.",
"render.volume_denoise_required": "יש לכבות הפחתת רעש כדי להשתמש באטמוספרה.",
"render.volume_glass_required": "לא ניתן לשלב אטמוספרה וזכוכית בהגדרה זו.",
"render.volume_lighting_required": "יש לבחור סביבה או מערך תאורה מפורש כדי לרנדר אטמוספרה.",
"render.volume_single_stratum_required": "יש להשתמש בדגימת מעבר אחת כדי לרנדר אטמוספרה."
},
"ja": {
"render.cpu_volume_enable_path": "間接照明を有効にする",
"render.cpu_volume_enable_path_plan": "CPUレイトレーシング · パス深度{depth} · {spp}サンプル/ピクセル · シード{seed} · レイトレースシャドウ。大気と画像予算の設定を保持します。",
"render.cpu_volume_help": "CPUの大気は間接照明を使用します。消散係数がゼロでも、霧のないボックスとして設定は保存されます。",
"render.cpu_volume_method_adopt": "間接照明を使うCPUレイトレーシング",
"render.cpu_volume_method_incompatible": "この照明、サンプリング、大気の設定はこの方式に引き継げません。設定は保持されます。",
"render.cpu_volume_path_required": "CPUの大気を使うには間接照明を有効にしてください。",
"render.volume_denoise_required": "大気を使うにはノイズ低減をオフにしてください。",
"render.volume_glass_required": "この設定では大気とガラスを併用できません。",
"render.volume_lighting_required": "大気を描画するには環境または明示的なライト構成を選んでください。",
"render.volume_single_stratum_required": "大気を描画するには透過サンプル数を1にしてください。"
},
"ko": {
"render.cpu_volume_enable_path": "간접 조명 켜기",
"render.cpu_volume_enable_path_plan": "CPU 레이 트레이싱 · 경로 깊이 {depth} · 픽셀당 {spp}샘플 · 시드 {seed} · 레이 트레이싱 그림자. 작성한 대기와 이미지 예산을 유지합니다.",
"render.cpu_volume_help": "CPU 대기는 간접 조명을 사용합니다. 소광 계수가 0이면 저장된 상자는 안개 없이 유지됩니다.",
"render.cpu_volume_method_adopt": "간접 조명을 사용하는 CPU 레이 트레이싱",
"render.cpu_volume_method_incompatible": "이 조명, 샘플링 또는 대기 설정을 이 방식으로 옮길 수 없습니다. 설정은 유지됩니다.",
"render.cpu_volume_path_required": "CPU 대기를 사용하려면 간접 조명을 켜세요.",
"render.volume_denoise_required": "대기를 사용하려면 노이즈 감소를 끄세요.",
"render.volume_glass_required": "이 설정에서는 대기와 유리를 함께 사용할 수 없습니다.",
"render.volume_lighting_required": "대기를 렌더링하려면 환경 또는 명시적인 조명 구성을 선택하세요.",
"render.volume_single_stratum_required": "대기를 렌더링하려면 투과 샘플을 1로 설정하세요."
},
"vi": {
"render.cpu_volume_enable_path": "Bật chiếu sáng gián tiếp",
"render.cpu_volume_enable_path_plan": "Dò tia CPU · độ sâu đường đi {depth} · {spp} mẫu/pixel · hạt giống {seed} · bóng dò tia. Giữ nguyên khí quyển và ngân sách ảnh đã đặt.",
"render.cpu_volume_help": "Khí quyển trên CPU dùng chiếu sáng gián tiếp. Hệ số suy giảm bằng không vẫn giữ hộp đã lưu mà không tạo sương.",
"render.cpu_volume_method_adopt": "Dò tia CPU với chiếu sáng gián tiếp",
"render.cpu_volume_method_incompatible": "Không thể chuyển các thiết lập đèn, lấy mẫu hoặc khí quyển này sang phương pháp này. Thiết lập của bạn được giữ nguyên.",
"render.cpu_volume_path_required": "Bật chiếu sáng gián tiếp để dùng Khí quyển trên CPU.",
"render.volume_denoise_required": "Tắt giảm nhiễu để dùng Khí quyển.",
"render.volume_glass_required": "Không thể kết hợp Khí quyển và Kính trong thiết lập này.",
"render.volume_lighting_required": "Chọn môi trường hoặc bộ đèn tường minh để kết xuất Khí quyển.",
"render.volume_single_stratum_required": "Dùng một mẫu truyền sáng để kết xuất Khí quyển."
},
"zh": {
"render.cpu_volume_enable_path": "启用间接照明",
"render.cpu_volume_enable_path_plan": "CPU 光线追踪 · 路径深度 {depth} · 每像素 {spp} 个采样 · 种子 {seed} · 追踪阴影。保留已编写的大气和图像预算。",
"render.cpu_volume_help": "CPU 大气使用间接照明。消光系数为零时,已保存的包围盒仍会保留,但不会产生雾。",
"render.cpu_volume_method_adopt": "使用间接照明的 CPU 光线追踪",
"render.cpu_volume_method_incompatible": "这些灯光、采样或大气设置无法转移到此方式。您的设置会保留。",
"render.cpu_volume_path_required": "启用间接照明以使用 CPU 大气。",
"render.volume_denoise_required": "关闭降噪以使用大气。",
"render.volume_glass_required": "此设置无法同时使用大气和玻璃。",
"render.volume_lighting_required": "选择环境或显式灯光配置以渲染大气。",
"render.volume_single_stratum_required": "将透射采样数设为 1 以渲染大气。"
}
}
@@ -1,42 +0,0 @@
{
"ar": {
"render.cpu_constant_direct_help": "بدون الإضاءة غير المباشرة، يمكن أن يظهر هذا المصدر الثابت في الانعكاسات وعبر الزجاج. لكنه لا يضيء الأسطح المعتمة. فعّل الإضاءة غير المباشرة لاستخدامه في إضاءة المشهد.",
"render.cpu_constant_enable_indirect_plan": "عمق المسار {depth}؛ أخذ عينات تدريجي بمعدل {spp} عينة/بكسل (البذرة {seed})؛ شعاع أولي واحد لكل عينة؛ ظلال متتبعة. يحتفظ بحجم الصورة وميزانية CPU والإعدادات الأخرى.",
"render.cpu_indirect_method_required": "اختر تتبع أشعة CPU لتفعيل وضع الإضاءة غير المباشرة هذا."
},
"de": {
"render.cpu_constant_direct_help": "Ohne indirekte Beleuchtung kann diese konstante Quelle in Reflexionen und durch Glas sichtbar sein. Sie beleuchtet keine undurchsichtigen Flächen. Schalte indirekte Beleuchtung ein, um sie als Szenenlicht zu nutzen.",
"render.cpu_constant_enable_indirect_plan": "Pfadtiefe {depth}; progressives Sampling mit {spp} Samples/Pixel (Seed {seed}); ein Primärstrahl pro Sample; Raytracing-Schatten. Bildgröße, CPU-Budget und andere Einstellungen bleiben erhalten.",
"render.cpu_indirect_method_required": "Wähle CPU-Raytracing, um diesen Modus für indirekte Beleuchtung einzuschalten."
},
"en": {
"render.cpu_constant_direct_help": "Without Indirect lighting, this constant source can appear in reflections and through Glass. It does not light opaque surfaces. Enable Indirect lighting to use it for scene lighting.",
"render.cpu_constant_enable_indirect_plan": "Path depth {depth}; progressive sampling at {spp} samples/pixel (seed {seed}); one primary ray per sample; traced shadows. Keeps your image size, CPU budget and other settings.",
"render.cpu_indirect_method_required": "Choose CPU ray tracing to enable this Indirect lighting mode."
},
"he": {
"render.cpu_constant_direct_help": "ללא תאורה עקיפה, מקור קבוע זה עשוי להופיע בהשתקפויות ודרך זכוכית. הוא אינו מאיר משטחים אטומים. יש להפעיל תאורה עקיפה כדי להשתמש בו לתאורת הסצנה.",
"render.cpu_constant_enable_indirect_plan": "עומק מסלול {depth}; דגימה הדרגתית עם {spp} דגימות לפיקסל (זרע {seed}); קרן ראשית אחת לכל דגימה; צללים במעקב קרניים. גודל התמונה, תקציב ה־CPU וההגדרות האחרות נשמרים.",
"render.cpu_indirect_method_required": "יש לבחור מעקב קרניים ב־CPU כדי להפעיל מצב זה של תאורה עקיפה."
},
"ja": {
"render.cpu_constant_direct_help": "間接照明を使わない場合、この一定の光源は反射やガラス越しに見えることがありますが、不透明な面は照らしません。シーンの照明に使うには、間接照明を有効にしてください。",
"render.cpu_constant_enable_indirect_plan": "パスの深さ {depth}、ピクセルあたり {spp} サンプルのプログレッシブサンプリング(シード {seed})、各サンプルに一次レイ1本、レイトレーシングの影を使用します。画像サイズ、CPU予算、その他の設定は保持します。",
"render.cpu_indirect_method_required": "この間接照明モードを有効にするには、CPUレイトレーシングを選択してください。"
},
"ko": {
"render.cpu_constant_direct_help": "간접 조명이 꺼져 있으면 이 일정한 광원은 반사나 유리를 통해 보일 수 있지만 불투명한 표면을 밝히지는 않습니다. 장면 조명으로 사용하려면 간접 조명을 켜세요.",
"render.cpu_constant_enable_indirect_plan": "경로 깊이 {depth}, 픽셀당 {spp}개 샘플의 점진적 샘플링(시드 {seed}), 샘플당 기본 광선 1개, 추적된 그림자를 사용합니다. 이미지 크기, CPU 예산 및 다른 설정을 유지합니다.",
"render.cpu_indirect_method_required": "이 간접 조명 모드를 켜려면 CPU 레이 트레이싱을 선택하세요."
},
"vi": {
"render.cpu_constant_direct_help": "Khi tắt Chiếu sáng gián tiếp, nguồn sáng đồng nhất này có thể xuất hiện trong phản xạ và qua Kính nhưng không chiếu sáng các bề mặt đục. Bật Chiếu sáng gián tiếp để dùng nguồn này chiếu sáng cảnh.",
"render.cpu_constant_enable_indirect_plan": "Độ sâu đường đi {depth}; lấy mẫu tăng dần với {spp} mẫu/pixel (hạt giống {seed}); một tia sơ cấp cho mỗi mẫu; bóng đổ dò tia. Giữ kích thước ảnh, ngân sách CPU và các cài đặt khác.",
"render.cpu_indirect_method_required": "Chọn dò tia CPU để bật chế độ Chiếu sáng gián tiếp này."
},
"zh": {
"render.cpu_constant_direct_help": "未启用间接照明时,此恒定光源可能出现在反射中或透过玻璃可见,但不会照亮不透明表面。要用它照亮场景,请启用间接照明。",
"render.cpu_constant_enable_indirect_plan": "路径深度 {depth};每像素 {spp} 个样本的渐进采样(种子 {seed});每个样本一条主光线;光线追踪阴影。保留图像尺寸、CPU预算和其他设置。",
"render.cpu_indirect_method_required": "请选择CPU光线追踪以启用此间接照明模式。"
}
}
@@ -1,58 +0,0 @@
{
"ar": {
"render.cpu_glass_enable_path": "تشغيل الإضاءة غير المباشرة",
"render.cpu_path_depth": "عمق المسار",
"render.cpu_path_help": "تحسب الضوء المرتد بين الأسطح المعتمة والمار عبر أشكال الزجاج المدعومة. تتطلب التصيير التدريجي وظلال تتبع الأشعة. يحسب عمق المسار الأسطح المضاءة وحدود الزجاج وأحداث التشتت بدءاً من أول تقاطع (1–16). يقتصر العمق 1 على الإضاءة المباشرة للأسطح المعتمة؛ وتسمح القيم الأعلى بمزيد من الارتدادات أو عبور الزجاج وقد تستغرق وقتاً أطول. أوقف الإضاءة غير المباشرة لاستخدام الانعكاسات المخصصة أو التباين الاتجاهي.",
"render.cpu_path_lighting": "إضاءة غير مباشرة",
"render.cpu_path_optics_reason": "تبقى إعداداتك كما هي. أوقف الإضاءة غير المباشرة لاستخدام الانعكاسات المخصصة أو التباين الاتجاهي."
},
"de": {
"render.cpu_glass_enable_path": "Indirekte Beleuchtung einschalten",
"render.cpu_path_depth": "Pfadtiefe",
"render.cpu_path_help": "Berechnet Licht, das zwischen undurchsichtigen Flächen und durch unterstützte Glasformen läuft. Erfordert progressives Rendern und Raytracing-Schatten. Die Pfadtiefe zählt beleuchtete Flächen, Glasgrenzen und Streuereignisse ab dem ersten Treffer (1–16). Tiefe 1 liefert direkte Beleuchtung auf undurchsichtigen Flächen; höhere Werte erlauben mehr Reflexionen oder Glasdurchgänge und können länger dauern. Für eigene Reflexionen oder Anisotropie die indirekte Beleuchtung ausschalten.",
"render.cpu_path_lighting": "Indirekte Beleuchtung",
"render.cpu_path_optics_reason": "Die Einstellungen bleiben erhalten. Für eigene Reflexionen oder Anisotropie die indirekte Beleuchtung ausschalten."
},
"en": {
"render.cpu_glass_enable_path": "Enable Indirect lighting",
"render.cpu_path_depth": "Path depth",
"render.cpu_path_help": "Adds light bouncing between opaque surfaces and through supported Glass shapes. Requires progressive rendering and traced shadows. Path depth counts shaded surfaces, Glass boundaries and scattering events, starting with the first hit (1–16). Depth 1 gives direct lighting on opaque surfaces; higher values allow more bounces or Glass crossings and may take longer. Turn off Indirect lighting to use custom reflections or anisotropy.",
"render.cpu_path_lighting": "Indirect lighting",
"render.cpu_path_optics_reason": "Your settings are kept. Turn off Indirect lighting to use custom reflections or anisotropy."
},
"he": {
"render.cpu_glass_enable_path": "הפעלת תאורה עקיפה",
"render.cpu_path_depth": "עומק מסלול",
"render.cpu_path_help": "מחשבת אור שמוחזר בין משטחים אטומים ועובר דרך צורות זכוכית נתמכות. נדרשים רינדור הדרגתי וצללים במעקב קרניים. עומק המסלול סופר משטחים מוצללים, גבולות זכוכית ואירועי פיזור החל מהמפגש הראשון (1–16). עומק 1 נותן תאורה ישירה למשטחים אטומים; ערכים גבוהים מאפשרים יותר החזרות או מעברים בזכוכית ועשויים לדרוש יותר זמן. יש לכבות תאורה עקיפה כדי להשתמש בהשתקפויות מותאמות או באנאיזוטרופיה.",
"render.cpu_path_lighting": "תאורה עקיפה",
"render.cpu_path_optics_reason": "ההגדרות שלך נשמרות. יש לכבות תאורה עקיפה כדי להשתמש בהשתקפויות מותאמות או באנאיזוטרופיה."
},
"ja": {
"render.cpu_glass_enable_path": "間接照明を有効にする",
"render.cpu_path_depth": "パス深度",
"render.cpu_path_help": "不透明な面の間で反射し、対応するガラス形状を通る光を計算します。プログレッシブ描画とレイトレーシングの影が必要です。パス深度は最初の交点から、照明を計算する面、ガラス境界、散乱イベントを数えます(1~16)。深度1は不透明面の直接照明のみです。値を上げると反射やガラスの通過を増やせますが、時間がかかる場合があります。独自の反射設定や異方性を使うには間接照明をオフにしてください。",
"render.cpu_path_lighting": "間接照明",
"render.cpu_path_optics_reason": "設定は保持されます。独自の反射設定や異方性を使うには間接照明をオフにしてください。"
},
"ko": {
"render.cpu_glass_enable_path": "간접 조명 켜기",
"render.cpu_path_depth": "경로 깊이",
"render.cpu_path_help": "불투명 표면 사이에서 반사되고 지원되는 유리 형상을 통과하는 빛을 계산합니다. 점진적 렌더링과 레이 추적 그림자가 필요합니다. 경로 깊이는 첫 교점부터 조명이 계산되는 표면, 유리 경계 및 산란 이벤트를 셉니다(1–16). 깊이 1은 불투명 표면의 직접 조명만 계산합니다. 값을 높이면 반사나 유리 통과가 늘어나며 시간이 더 걸릴 수 있습니다. 사용자 반사 설정이나 이방성을 사용하려면 간접 조명을 끄세요.",
"render.cpu_path_lighting": "간접 조명",
"render.cpu_path_optics_reason": "설정은 유지됩니다. 사용자 반사 설정이나 이방성을 사용하려면 간접 조명을 끄세요."
},
"vi": {
"render.cpu_glass_enable_path": "Bật Chiếu sáng gián tiếp",
"render.cpu_path_depth": "Độ sâu đường truyền",
"render.cpu_path_help": "Tính ánh sáng phản xạ giữa các bề mặt đục và truyền qua các hình kính được hỗ trợ. Cần kết xuất lũy tiến và bóng dò tia. Độ sâu đường đi đếm các bề mặt được chiếu sáng, ranh giới kính và các sự kiện tán xạ từ giao điểm đầu tiên (1–16). Độ sâu 1 chỉ chiếu sáng trực tiếp bề mặt đục; giá trị cao hơn cho phép thêm lần phản xạ hoặc xuyên kính và có thể lâu hơn. Tắt Chiếu sáng gián tiếp để dùng phản xạ tùy chỉnh hoặc dị hướng.",
"render.cpu_path_lighting": "Chiếu sáng gián tiếp",
"render.cpu_path_optics_reason": "Các thiết lập được giữ nguyên. Tắt Chiếu sáng gián tiếp để dùng phản xạ tùy chỉnh hoặc dị hướng."
},
"zh": {
"render.cpu_glass_enable_path": "启用间接照明",
"render.cpu_path_depth": "路径深度",
"render.cpu_path_help": "计算在不透明表面之间反射并穿过受支持玻璃形状的光。需要渐进渲染和光线追踪阴影。路径深度从首次相交开始计算着色表面、玻璃边界和散射事件(1–16)。深度 1 只计算不透明表面的直接照明;更高的值允许更多反射或玻璃穿越,也可能耗时更长。使用自定义反射或各向异性时,请关闭间接照明。",
"render.cpu_path_lighting": "间接照明",
"render.cpu_path_optics_reason": "设置会保留。使用自定义反射或各向异性时,请关闭间接照明。"
}
}
@@ -1,42 +0,0 @@
{
"en": {
"render.cpu_quality_budget_help": "Changes size, production sample cap, seed and CPU resource profile. Camera, lens, lighting, GI depth and effects are kept.",
"render.cpu_quality_progressive_required": "Enable progressive sampling below before choosing a CPU budget.",
"render.cpu_quality_summary": "{width} × {height} · {samples} sample cap · seed {seed} · {profile}"
},
"ar": {
"render.cpu_quality_budget_help": "يغير الحجم وحد عينات الإنتاج والبذرة وملف موارد CPU. تُحفظ الكاميرا والعدسة والإضاءة وعمق GI والتأثيرات.",
"render.cpu_quality_progressive_required": "فعّل أخذ العينات التدريجي أدناه قبل اختيار ميزانية CPU.",
"render.cpu_quality_summary": "{width} × {height} · حد العينات {samples} · البذرة {seed} · {profile}"
},
"de": {
"render.cpu_quality_budget_help": "Ändert Größe, Obergrenze der Produktionssamples, Startwert und CPU-Ressourcenprofil. Kamera, Objektiv, Beleuchtung, GI-Tiefe und Effekte bleiben erhalten.",
"render.cpu_quality_progressive_required": "Aktiviere unten progressive Samples, bevor du ein CPU-Budget auswählst.",
"render.cpu_quality_summary": "{width} × {height} · Sample-Grenze {samples} · Startwert {seed} · {profile}"
},
"he": {
"render.cpu_quality_budget_help": "משנה גודל, תקרת דגימות הפקה, זרע ופרופיל משאבי CPU. המצלמה, העדשה, התאורה, עומק GI והאפקטים נשמרים.",
"render.cpu_quality_progressive_required": "יש להפעיל דגימה מתקדמת למטה לפני בחירת תקציב CPU.",
"render.cpu_quality_summary": "{width} × {height} · תקרת דגימות {samples} · זרע {seed} · {profile}"
},
"ja": {
"render.cpu_quality_budget_help": "サイズ、本番サンプル数の上限、シード、CPUリソースプロファイルを変更します。カメラ、レンズ、照明、GI深度、エフェクトは維持されます。",
"render.cpu_quality_progressive_required": "CPU予算を選ぶ前に、下でプログレッシブサンプリングを有効にしてください。",
"render.cpu_quality_summary": "{width} × {height} · サンプル上限 {samples} · シード {seed} · {profile}"
},
"ko": {
"render.cpu_quality_budget_help": "크기, 제작 샘플 상한, 시드와 CPU 리소스 프로필을 변경합니다. 카메라, 렌즈, 조명, GI 깊이와 효과는 유지됩니다.",
"render.cpu_quality_progressive_required": "CPU 예산을 선택하기 전에 아래에서 점진적 샘플링을 활성화하세요.",
"render.cpu_quality_summary": "{width} × {height} · 샘플 상한 {samples} · 시드 {seed} · {profile}"
},
"vi": {
"render.cpu_quality_budget_help": "Thay đổi kích thước, trần mẫu sản xuất, hạt giống và cấu hình tài nguyên CPU. Giữ nguyên máy ảnh, ống kính, ánh sáng, độ sâu GI và hiệu ứng.",
"render.cpu_quality_progressive_required": "Bật lấy mẫu tiến dần bên dưới trước khi chọn ngân sách CPU.",
"render.cpu_quality_summary": "{width} × {height} · trần mẫu {samples} · hạt giống {seed} · {profile}"
},
"zh": {
"render.cpu_quality_budget_help": "更改尺寸、正式样本上限、种子和CPU资源配置。保留相机、镜头、照明、GI深度和效果。",
"render.cpu_quality_progressive_required": "选择CPU预算前,请先在下方启用渐进采样。",
"render.cpu_quality_summary": "{width} × {height} · 样本上限 {samples} · 种子 {seed} · {profile}"
}
}
@@ -1,82 +0,0 @@
{
"ar": {
"render.appearance_editor.discard_saved_edit": "تجاهل التعديلات البصرية غير المحفوظة",
"render.cpu_subsurface_denoise_reason": "يتطلب التشتت داخل الزجاج على CPU إيقاف إزالة الضجيج. تبقى إعداداتك محفوظة.",
"render.cpu_subsurface_help": "يغيّر التشتت اتجاه الضوء داخل الزجاج المغلق. تتطلب المعدلات الموجبة إضاءة غير مباشرة مع إيقاف إزالة الضجيج. المعدل هو عدد التصادمات لكل مم؛ لا يضيف الصفر أي تشتت. يفضّل انحياز الاتجاه الموجب الأمام، والسالب الخلف.",
"render.material_cpu_glass_only": "تتطلب خرائط ملفات الصور المؤقتة GPU. يمكن لـCPU استخدام خرائط الأسطح المضمنة المحفوظة.",
"render.material_cpu_optics_limits": "شغّل الإضاءة غير المباشرة لأشكال الزجاج المغلقة المدعومة والتداخل المتحقق منه والتشتت داخل الزجاج. يمكن للصفائح الرقيقة تمرير الضوء للظلال. وإلا فاستخدم صفيحة مستوية أو صندوقًا محاذيًا للمحاور. تظل الأشكال المتلامسة والظلال النافذة عبر الزجاج المغلق غير مدعومة. تبقى قيمك محفوظة.",
"render.material_cpu_saved_runtime_conflict": "لا يمكن الجمع بين البصريات المحفوظة على CPU والارتباطات البصرية المؤقتة السابقة. احفظ البصريات التي راجعتها أو أزل الارتباط المؤقت المتعارض.",
"render.material_raytrace_required": "يتطلب الزجاج الفيزيائي تتبع الأشعة على CPU أو تتبع المسارات على GPU.",
"render.material_saved_edit_pending": "هذه التعديلات البصرية غير محفوظة. احفظ القيم التي راجعتها، أو أزل التعيين المحفوظ، أو تجاهل التعديلات. لا يمكن للارتباطات المؤقتة السابقة والمؤثرات غير المدعومة تجاوز الهدف المحفوظ."
},
"de": {
"render.appearance_editor.discard_saved_edit": "Ungespeicherte Optikänderungen verwerfen",
"render.cpu_subsurface_denoise_reason": "Streuung im Glas auf der CPU benötigt ausgeschaltete Rauschreduzierung. Die Einstellungen bleiben erhalten.",
"render.cpu_subsurface_help": "Streuung lenkt Licht im Inneren geschlossenen Glases um. Positive Raten benötigen indirekte Beleuchtung ohne Rauschreduzierung. Die Rate zählt Kollisionen pro mm; 0 fügt keine Streuung hinzu. Positive Richtungswerte bevorzugen vorwärts, negative rückwärts.",
"render.material_cpu_glass_only": "Temporäre Bilddatei-Karten benötigen die GPU. Die CPU kann gespeicherte integrierte Oberflächenkarten verwenden.",
"render.material_cpu_optics_limits": "Indirekte Beleuchtung für unterstützte geschlossene Glasformen, geprüfte Verschachtelung und Streuung im Inneren einschalten. Dünne Scheiben können Licht für Schatten durchlassen. Sonst eine ebene Scheibe oder achsenparallele Box verwenden. Berührende Formen und durch geschlossenes Glas übertragene Schatten werden weiterhin nicht unterstützt. Die Werte bleiben erhalten.",
"render.material_cpu_saved_runtime_conflict": "Gespeicherte CPU-Optik kann nicht mit temporären optischen Bindungen kombiniert werden. Geprüfte Optik speichern oder die temporäre Bindung entfernen.",
"render.material_raytrace_required": "Physikalisches Glas benötigt CPU-Raytracing oder GPU-Pathtracing.",
"render.material_saved_edit_pending": "Diese Optikänderungen sind ungespeichert. Geprüfte Werte speichern, die gespeicherte Zuordnung entfernen oder Änderungen verwerfen. Temporäre Bindungen und nicht unterstützte Effekte können das gespeicherte Ziel nicht überschreiben."
},
"en": {
"render.appearance_editor.discard_saved_edit": "Discard unsaved optical edits",
"render.cpu_subsurface_denoise_reason": "CPU subsurface scattering needs Denoise off. Your settings are kept.",
"render.cpu_subsurface_help": "Scattering redirects light inside closed Glass. Positive rates need Indirect lighting with Denoise off. The rate is collisions per mm; 0 adds no scattering. Positive phase bias favors forward directions; negative favors backward.",
"render.material_cpu_glass_only": "Temporary image-file maps require GPU. CPU can use saved built-in surface maps.",
"render.material_cpu_optics_limits": "Turn on Indirect lighting for supported closed Glass shapes, certified nesting and subsurface scattering. Thin sheets can pass shadows. Otherwise use a planar sheet or axis-aligned box. Touching shapes and transmitted shadows through closed Glass remain unsupported. Your values are kept.",
"render.material_cpu_saved_runtime_conflict": "Saved CPU optics cannot combine with legacy temporary optical bindings. Save the reviewed optics or remove the conflicting temporary binding.",
"render.material_raytrace_required": "Physical Glass requires CPU ray tracing or GPU path tracing.",
"render.material_saved_edit_pending": "These optical edits are unsaved. Save reviewed values, remove the saved assignment, or discard the edits. Legacy temporary bindings and unsupported effects cannot override the saved target."
},
"he": {
"render.appearance_editor.discard_saved_edit": "ביטול שינויים אופטיים שלא נשמרו",
"render.cpu_subsurface_denoise_reason": "פיזור בתוך זכוכית ב־CPU דורש הסרת רעש כבויה. ההגדרות נשמרות.",
"render.cpu_subsurface_help": "פיזור משנה את כיוון האור בתוך זכוכית סגורה. קצב חיובי דורש תאורה עקיפה והסרת רעש כבויה. הקצב הוא מספר התנגשויות למ״מ; 0 אינו מוסיף פיזור. הטיית כיוון חיובית מעדיפה קדימה, ושלילית אחורה.",
"render.material_cpu_glass_only": "מפות זמניות מקובצי תמונה דורשות GPU. ב־CPU אפשר להשתמש במפות משטח מובנות שנשמרו.",
"render.material_cpu_optics_limits": "יש להפעיל תאורה עקיפה לצורות זכוכית סגורות נתמכות, לקינון שנבדק ולפיזור בתוך הזכוכית. יריעות דקות יכולות להעביר אור לצללים. אחרת יש להשתמש ביריעה מישורית או בתיבה מקבילה לצירים. צורות נוגעות וצללים העוברים בזכוכית סגורה עדיין אינם נתמכים. הערכים נשמרים.",
"render.material_cpu_saved_runtime_conflict": "אי אפשר לשלב הגדרות אופטיות שמורות ב־CPU עם הקישורים האופטיים הזמניים הישנים. יש לשמור את ההגדרות שנבדקו או להסיר את הקישור הזמני המתנגש.",
"render.material_raytrace_required": "זכוכית פיזיקלית דורשת עקיבת קרניים ב־CPU או עקיבת נתיבים ב־GPU.",
"render.material_saved_edit_pending": "השינויים האופטיים האלה לא נשמרו. יש לשמור את הערכים שנבדקו, להסיר את ההקצאה השמורה או לבטל את השינויים. קישורים זמניים ישנים ואפקטים שאינם נתמכים אינם יכולים לעקוף את היעד השמור."
},
"ja": {
"render.appearance_editor.discard_saved_edit": "未保存の光学設定の変更を破棄",
"render.cpu_subsurface_denoise_reason": "CPUの内部散乱ではノイズ除去をオフにしてください。設定値は保持されます。",
"render.cpu_subsurface_help": "散乱は閉じたガラスの内部で光の方向を変えます。正の値には間接照明を使い、ノイズ除去をオフにします。率は1mmあたりの衝突回数です。0では散乱を加えません。方向の偏りが正なら前方、負なら後方を優先します。",
"render.material_cpu_glass_only": "一時画像ファイルのマップにはGPUが必要です。CPUでは保存済みの組み込み表面マップを使用できます。",
"render.material_cpu_optics_limits": "対応する閉じたガラス形状、検証済みの入れ子形状、内部散乱には間接照明をオンにしてください。薄いシートは影に光を透過できます。それ以外は平面シートか軸平行の箱を使います。接触する形状と閉じたガラスを通る透過影には未対応です。値は保持されます。",
"render.material_cpu_saved_runtime_conflict": "保存済みCPU光学設定と一時的な光学割り当ては併用できません。確認した設定を保存するか、競合する一時割り当てを削除してください。",
"render.material_raytrace_required": "物理ガラスにはCPUレイトレーシングまたはGPUパストレーシングが必要です。",
"render.material_saved_edit_pending": "光学設定の変更は未保存です。確認した値を保存するか、保存済み割り当てを削除するか、変更を破棄してください。一時割り当てや未対応の効果で保存済み対象を上書きできません。"
},
"ko": {
"render.appearance_editor.discard_saved_edit": "저장하지 않은 광학 편집 버리기",
"render.cpu_subsurface_denoise_reason": "CPU 내부 산란을 사용하려면 노이즈 제거를 끄세요. 설정은 유지됩니다.",
"render.cpu_subsurface_help": "산란은 닫힌 유리 내부에서 빛의 방향을 바꿉니다. 양수 비율에는 간접광을 사용하고 노이즈 제거를 끄세요. 비율은 mm당 충돌 횟수이며, 0은 산란을 추가하지 않습니다. 방향 편향이 양수이면 전방, 음수이면 후방을 선호합니다.",
"render.material_cpu_glass_only": "임시 이미지 파일 맵에는 GPU가 필요합니다. CPU는 저장된 내장 표면 맵을 사용할 수 있습니다.",
"render.material_cpu_optics_limits": "지원되는 닫힌 유리 형상, 검증된 중첩 및 내부 산란에는 간접 조명을 켜세요. 얇은 시트는 그림자에 빛을 통과시킬 수 있습니다. 그 외에는 평면 시트나 축 정렬 상자를 사용하세요. 서로 닿는 형상과 닫힌 유리를 통과하는 투과 그림자는 아직 지원하지 않습니다. 값은 유지됩니다.",
"render.material_cpu_saved_runtime_conflict": "저장된 CPU 광학 설정은 임시 광학 바인딩과 함께 사용할 수 없습니다. 검토한 설정을 저장하거나 충돌하는 임시 바인딩을 제거하세요.",
"render.material_raytrace_required": "물리 유리에는 CPU 레이 트레이싱이나 GPU 패스 트레이싱이 필요합니다.",
"render.material_saved_edit_pending": "광학 편집을 아직 저장하지 않았습니다. 검토한 값을 저장하거나 저장된 할당을 제거하거나 편집을 버리세요. 임시 바인딩과 지원하지 않는 효과는 저장된 대상을 덮어쓸 수 없습니다."
},
"vi": {
"render.appearance_editor.discard_saved_edit": "Hủy chỉnh sửa quang học chưa lưu",
"render.cpu_subsurface_denoise_reason": "Tán xạ bên trong kính trên CPU cần tắt Khử nhiễu. Các cài đặt được giữ nguyên.",
"render.cpu_subsurface_help": "Tán xạ đổi hướng ánh sáng bên trong kính kín. Tốc độ dương cần Chiếu sáng gián tiếp và tắt Khử nhiễu. Tốc độ là số va chạm mỗi mm; 0 không thêm tán xạ. Độ lệch hướng dương ưu tiên phía trước, âm ưu tiên phía sau.",
"render.material_cpu_glass_only": "Bản đồ từ tệp ảnh tạm thời yêu cầu GPU. CPU có thể dùng bản đồ bề mặt tích hợp đã lưu.",
"render.material_cpu_optics_limits": "Bật Chiếu sáng gián tiếp cho hình kính kín được hỗ trợ, cấu trúc lồng nhau đã kiểm chứng và tán xạ bên trong kính. Tấm mỏng có thể truyền ánh sáng cho bóng. Nếu không, dùng tấm phẳng hoặc hộp thẳng theo trục. Chưa hỗ trợ hình chạm nhau và bóng truyền qua kính kín. Các giá trị được giữ nguyên.",
"render.material_cpu_saved_runtime_conflict": "Không thể kết hợp quang học CPU đã lưu với các liên kết quang học tạm thời kiểu cũ. Hãy lưu quang học đã xem xét hoặc xóa liên kết tạm thời xung đột.",
"render.material_raytrace_required": "Kính vật lý yêu cầu dò tia trên CPU hoặc dò đường đi trên GPU.",
"render.material_saved_edit_pending": "Các chỉnh sửa quang học này chưa được lưu. Hãy lưu các giá trị đã xem xét, xóa phép gán đã lưu hoặc hủy chỉnh sửa. Liên kết tạm thời kiểu cũ và hiệu ứng chưa được hỗ trợ không thể ghi đè đích đã lưu."
},
"zh": {
"render.appearance_editor.discard_saved_edit": "放弃未保存的光学编辑",
"render.cpu_subsurface_denoise_reason": "CPU 内部散射需要关闭降噪。设置会保留。",
"render.cpu_subsurface_help": "散射会改变闭合玻璃内部的光线方向。正散射率需要开启间接光照并关闭降噪。散射率表示每毫米的碰撞次数;0 不增加散射。方向偏置为正时偏向前方,为负时偏向后方。",
"render.material_cpu_glass_only": "临时图像文件贴图需要GPU。CPU可以使用已保存的内置表面贴图。",
"render.material_cpu_optics_limits": "启用间接光照可使用受支持的闭合玻璃形状、经验证的嵌套结构及内部散射。薄片可以透射阴影。否则请使用平面薄片或轴对齐盒体。仍不支持相互接触的形状及穿过闭合玻璃的透射阴影。设置值会保留。",
"render.material_cpu_saved_runtime_conflict": "已保存的CPU光学设置不能与临时光学绑定组合。请保存已审阅的设置或移除冲突的临时绑定。",
"render.material_raytrace_required": "物理玻璃需要CPU光线追踪或GPU路径追踪。",
"render.material_saved_edit_pending": "这些光学编辑尚未保存。请保存已审阅的值、移除已保存的分配或放弃编辑。临时绑定和不支持的效果不能覆盖已保存的目标。"
}
}
@@ -1,32 +0,0 @@
{
"ar": {
"render.cpu_maps_saved_help": "يمكن لتصيير CPU استخدام خرائط الأسطح المعتمة المحفوظة: اختر سطحًا هنا ثم احفظ خرائطه في اللقطة. مع الإضاءة غير المباشرة، يمكن استخدام الزجاج في جسم آخر؛ لا يمكن استخدام الزجاج في الجسم ذي الخرائط. يجب إيقاف الانعكاسات المختارة والتباين الاتجاهي والتأثيرات الإجرائية. تتطلب مسارات ملفات الخرائط المؤقتة GPU."
},
"de": {
"render.cpu_maps_saved_help": "CPU-Renderings können gespeicherte Karten undurchsichtiger Flächen verwenden: Oberfläche wählen und die Karten in der Aufnahme speichern. Mit indirekter Beleuchtung darf ein anderer Körper Glas verwenden; der Körper mit Karten darf kein Glas sein. Ausgewählte Reflexionen, Anisotropie und prozedurale Effekte ausschalten. Temporäre Kartendateipfade verwenden die GPU."
},
"en": {
"render.cpu_maps_saved_help": "CPU renders can use saved opaque maps: choose a surface here, then Save maps to shot. With Indirect lighting, Glass can be on another body; a mapped body cannot use Glass. Selected reflections, anisotropy and procedural surface effects must be off. Temporary map file paths use GPU."
},
"es": {
"render.cpu_maps_saved_help": "Los renders CPU pueden usar mapas opacos guardados: elige una superficie y guarda sus mapas en la toma. Con Iluminación indirecta, otro cuerpo puede usar Vidrio; el cuerpo con mapas no puede usar Vidrio. Desactiva los reflejos seleccionados, la anisotropía y los efectos procedurales. Las rutas temporales de archivos de mapas usan GPU."
},
"fr": {
"render.cpu_maps_saved_help": "Le rendu CPU accepte les cartes opaques enregistrées : choisissez une surface, puis enregistrez ses cartes dans la vue. Avec l’éclairage indirect, un autre corps peut utiliser Verre ; le corps avec les cartes ne le peut pas. Désactivez les réflexions sélectionnées, l’anisotropie et les effets procéduraux. Les fichiers temporaires de cartes utilisent le GPU."
},
"he": {
"render.cpu_maps_saved_help": "רינדור CPU יכול להשתמש במפות אטומות שמורות: בחרו כאן משטח ושמרו את המפות בתצלום. עם תאורה עקיפה, גוף אחר יכול להשתמש בזכוכית; הגוף בעל המפות אינו יכול להשתמש בזכוכית. יש לכבות החזרות שנבחרו, אנאיזוטרופיה ואפקטים פרוצדורליים. נתיבים זמניים לקובצי מפות משתמשים ב־GPU."
},
"ja": {
"render.cpu_maps_saved_help": "CPUレンダリングは保存された不透明サーフェスマップを使えます。サーフェスを選び、ショットにマップを保存してください。間接光を使う場合、別のボディにはガラスを使えますが、マップを持つボディには使えません。選択した反射、異方性、プロシージャル効果はオフにします。一時的なマップファイルにはGPUを使います。"
},
"ko": {
"render.cpu_maps_saved_help": "CPU 렌더링은 저장한 불투명 표면 맵을 사용할 수 있습니다. 표면을 선택하고 샷에 맵을 저장하세요. 간접광을 사용하면 다른 바디에 유리를 사용할 수 있지만, 맵이 있는 바디에는 유리를 사용할 수 없습니다. 선택 반사, 비등방성 및 절차적 효과는 끄세요. 임시 맵 파일 경로는 GPU를 사용합니다."
},
"vi": {
"render.cpu_maps_saved_help": "Kết xuất CPU hỗ trợ bản đồ bề mặt đục đã lưu: chọn bề mặt rồi lưu bản đồ vào ảnh chụp. Với chiếu sáng gián tiếp, thân khác có thể dùng kính; thân có bản đồ không thể dùng kính. Tắt phản xạ được chọn, dị hướng và hiệu ứng thủ tục. Đường dẫn tạm tới tệp bản đồ dùng GPU."
},
"zh": {
"render.cpu_maps_saved_help": "CPU 渲染可使用已保存的不透明表面贴图:在此选择表面,再将贴图保存到镜头。使用间接光照时,其他实体可以使用玻璃;带有贴图的实体不能使用玻璃。请关闭选定的反射、各向异性和程序化表面效果。临时贴图文件路径使用 GPU。"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.cpu_denoise_help": "يقلل التشويش في كل تحديث للصورة. قد ينعّم التفاصيل الدقيقة وحواف عمق المجال. يبقى EXR الخام دون تغيير. تستخدم تعديلات الصورة المكتملة صورتها الخام ولا تطبّق تقليل التشويش مرة أخرى."
},
"de": {
"render.cpu_denoise_help": "Verringert das Rauschen bei jeder Bildaktualisierung. Feine Details und Übergänge der Tiefenschärfe können weicher werden. Die EXR-Rohdaten bleiben unverändert. Nachträgliche Anpassungen eines fertigen Bildes verwenden dessen Rohbild und wenden die Rauschreduzierung nicht erneut an."
},
"en": {
"render.cpu_denoise_help": "Reduces noise in every image update. It may soften fine detail and depth-of-field edges. Raw EXR is unchanged. Adjusting a completed image uses its raw image and does not apply noise reduction again."
},
"he": {
"render.cpu_denoise_help": "מפחיתה רעש בכל עדכון תמונה. היא עלולה לרכך פרטים עדינים וקצוות של עומק שדה. קובץ EXR הגולמי אינו משתנה. התאמות של תמונה שהושלמה משתמשות בתמונה הגולמית שלה ואינן מחילות שוב הפחתת רעש."
},
"ja": {
"render.cpu_denoise_help": "画像が更新されるたびにノイズを減らします。細部や被写界深度によるぼけの境界が柔らかくなる場合があります。RAW EXRは変更されません。完成画像の調整にはそのRAW画像を使用し、ノイズ低減は再適用しません。"
},
"ko": {
"render.cpu_denoise_help": "이미지가 갱신될 때마다 노이즈를 줄입니다. 미세한 디테일과 피사계 심도 경계가 부드러워질 수 있습니다. 원본 EXR은 바뀌지 않습니다. 완성된 이미지를 조정할 때는 해당 원본 이미지를 사용하며 노이즈 감소를 다시 적용하지 않습니다."
},
"vi": {
"render.cpu_denoise_help": "Giảm nhiễu mỗi khi ảnh được cập nhật. Có thể làm mềm chi tiết nhỏ và biên vùng mờ do độ sâu trường ảnh. EXR thô không thay đổi. Khi điều chỉnh ảnh đã hoàn tất, hệ thống dùng ảnh thô của ảnh đó và không áp dụng giảm nhiễu lần nữa."
},
"zh": {
"render.cpu_denoise_help": "每次图像更新时减少噪点,可能使细节和景深模糊边缘变柔。原始EXR保持不变。调整已完成的图像时使用其原始图像,不会再次降噪。"
}
}
@@ -1,50 +0,0 @@
{
"ar": {
"render.cpu_studio_enable": "تفعيل الإضاءة غير المباشرة لهذا التوزيع",
"render.cpu_studio_enable_apply": "تفعيل الإضاءة غير المباشرة وتطبيقها",
"render.cpu_studio_indirect_help": "يحتاج توزيع الشمس هذا إلى إضاءة غير مباشرة بعمق 8 وظلال متتبعة وعينة كاميرا واحدة لكل مرور. إذا كان التصيير التدريجي معطلاً، يبدأ بـ 16 عينة لكل بكسل وبذرة 0. تُحفظ الإعدادات التدريجية الحالية وملف الموارد. تمنع الإعدادات غير المتوافقة التطبيق دون تغييرها.",
"render.cpu_studio_radiance_limit": "سطوع المصدر المساحي في هذا التوزيع هو {radiance}، ويتجاوز حد CPU البالغ 64. تُحفظ الإضاءة المؤلَّفة؛ اختر توزيعاً آخر أو GPU."
},
"de": {
"render.cpu_studio_enable": "Indirekte Beleuchtung für dieses Lichtset aktivieren",
"render.cpu_studio_enable_apply": "Indirekte Beleuchtung aktivieren und anwenden",
"render.cpu_studio_indirect_help": "Dieses Sonnen-Lichtset benötigt indirekte Beleuchtung mit Tiefe 8, verfolgte Schatten und eine Kamerastichprobe pro Durchlauf. Ist progressives Rendern ausgeschaltet, beginnt es mit 16 Stichproben pro Pixel und Startwert 0. Vorhandene progressive Einstellungen und das Ressourcenprofil bleiben erhalten. Unvereinbare Einstellungen verhindern die Anwendung, ohne sie zu ändern.",
"render.cpu_studio_radiance_limit": "Dieses Lichtset hat eine Flächenstrahldichte von {radiance}, über der CPU-Grenze von 64. Die vorgegebene Beleuchtung bleibt erhalten; wählen Sie ein anderes Lichtset oder GPU."
},
"en": {
"render.cpu_studio_enable": "Enable indirect lighting for this rig",
"render.cpu_studio_enable_apply": "Enable indirect lighting and apply",
"render.cpu_studio_indirect_help": "This Sun rig needs indirect lighting at depth 8, traced shadows and one camera sample per pass. If progressive rendering is off, it starts at 16 samples per pixel with seed 0. Existing progressive settings and the resource profile are kept. Incompatible settings stop the apply without changing them.",
"render.cpu_studio_radiance_limit": "This rig has area radiance {radiance}, above the CPU limit of 64. Its authored lighting is kept; choose another rig or GPU."
},
"he": {
"render.cpu_studio_enable": "הפעלת תאורה עקיפה עבור מערך זה",
"render.cpu_studio_enable_apply": "הפעלת תאורה עקיפה והחלה",
"render.cpu_studio_indirect_help": "מערך השמש הזה דורש תאורה עקיפה בעומק 8, צללים מחושבים ודגימת מצלמה אחת בכל מעבר. אם רינדור הדרגתי כבוי, הוא מתחיל ב־16 דגימות לפיקסל עם זרע 0. הגדרות הדרגתיות קיימות ופרופיל המשאבים נשמרים. הגדרות שאינן תואמות עוצרות את ההחלה בלי לשנותן.",
"render.cpu_studio_radiance_limit": "עוצמת מקור השטח במערך זה היא {radiance}, מעל מגבלת CPU של 64. התאורה המקורית נשמרת; בחרו מערך אחר או GPU."
},
"ja": {
"render.cpu_studio_enable": "このリグで間接照明を有効にする",
"render.cpu_studio_enable_apply": "間接照明を有効にして適用",
"render.cpu_studio_indirect_help": "この太陽リグには深度8の間接照明、追跡した影、パスごとに1つのカメラサンプルが必要です。プログレッシブ描画がオフなら、ピクセルごと16サンプル、シード0で開始します。既存のプログレッシブ設定とリソースプロファイルは維持します。非対応の設定がある場合は変更せず適用を中止します。",
"render.cpu_studio_radiance_limit": "このリグの面光源の放射輝度は{radiance}で、CPU上限64を超えます。作成された照明は維持します。別のリグかGPUを選んでください。"
},
"ko": {
"render.cpu_studio_enable": "이 리그의 간접 조명 켜기",
"render.cpu_studio_enable_apply": "간접 조명을 켜고 적용",
"render.cpu_studio_indirect_help": "이 태양 리그에는 깊이 8의 간접 조명, 추적된 그림자, 패스당 카메라 샘플 1개가 필요합니다. 점진적 렌더링이 꺼져 있으면 픽셀당 샘플 16개와 시드 0으로 시작합니다. 기존 점진적 설정과 리소스 프로필은 유지됩니다. 호환되지 않는 설정은 변경하지 않고 적용을 중단합니다.",
"render.cpu_studio_radiance_limit": "이 리그의 면 광원 방사 휘도 {radiance}은(는) CPU 한도 64를 넘습니다. 작성된 조명은 유지됩니다. 다른 리그나 GPU를 선택하세요."
},
"vi": {
"render.cpu_studio_enable": "Bật chiếu sáng gián tiếp cho bộ đèn này",
"render.cpu_studio_enable_apply": "Bật chiếu sáng gián tiếp và áp dụng",
"render.cpu_studio_indirect_help": "Bộ đèn Mặt Trời này cần chiếu sáng gián tiếp với độ sâu 8, bóng được truy vết và một mẫu máy ảnh mỗi lượt. Nếu kết xuất tăng dần đang tắt, bắt đầu với 16 mẫu mỗi điểm ảnh và hạt giống 0. Giữ nguyên thiết lập tăng dần và hồ sơ tài nguyên hiện có. Thiết lập không tương thích sẽ ngăn áp dụng mà không thay đổi chúng.",
"render.cpu_studio_radiance_limit": "Độ chói bức xạ đèn diện tích của bộ này là {radiance}, vượt giới hạn CPU 64. Giữ nguyên ánh sáng đã tạo; hãy chọn bộ đèn khác hoặc GPU."
},
"zh": {
"render.cpu_studio_enable": "为此灯组启用间接光照",
"render.cpu_studio_enable_apply": "启用间接光照并应用",
"render.cpu_studio_indirect_help": "此太阳灯组需要深度为8的间接光照、追踪阴影,以及每轮一个相机采样。如果渐进渲染关闭,则以每像素16个采样和种子0开始。保留现有渐进设置和资源配置。不兼容的设置会阻止应用,且不会被更改。",
"render.cpu_studio_radiance_limit": "此灯组的面光源辐射亮度为{radiance},超过CPU上限64。保留原有灯光,请选择其他灯组或GPU。"
}
}
-66
View File
@@ -1,66 +0,0 @@
{
"ar": {
"render.cpu_celestial_adopt": "تتبع الأشعة على المعالج مع إضاءة غير مباشرة · عمق المسار {depth} · {spp} عينة لكل بكسل · ظلال متتبعة · بذرة {seed} · عينة أولية واحدة",
"render.cpu_celestial_adopt_label": "تتبع الأشعة على المعالج مع إضاءة غير مباشرة",
"render.cpu_celestial_path_required": "تستخدم الشمس المحدودة والسماء المتدرجة الإضاءة غير المباشرة على المعالج.",
"render.cpu_celestial_switch": "اختر تتبع الأشعة على المعالج مع الإضاءة غير المباشرة للاحتفاظ بهذه الشمس أو السماء.",
"render.cpu_celestial_unportable": "أبقِ تتبع المسارات على المعالج الرسومي لإعدادات عينات النفاذ الحالية.",
"render.cpu_sky_bounds": "يجب أن يكون دوران السماء محدودًا ضمن ±1,000,000 راديان، وأن تكون الشدة بين 0 و100."
},
"de": {
"render.cpu_celestial_adopt": "CPU-Raytracing mit indirekter Beleuchtung · Pfadtiefe {depth} · {spp} SPP · verfolgte Schatten · Seed {seed} · 1 Primärsample",
"render.cpu_celestial_adopt_label": "CPU-Raytracing mit indirekter Beleuchtung",
"render.cpu_celestial_path_required": "Endliche Sonne und Verlaufshimmel verwenden indirekte CPU-Beleuchtung.",
"render.cpu_celestial_switch": "Wähle CPU-Raytracing mit indirekter Beleuchtung, um diese Sonne oder diesen Himmel beizubehalten.",
"render.cpu_celestial_unportable": "Behalte GPU-Pathtracing für die aktuellen Transmissions-Sample-Einstellungen bei.",
"render.cpu_sky_bounds": "Die Himmelsrotation muss endlich innerhalb ±1.000.000 Radiant liegen; die Intensität muss 0–100 sein."
},
"en": {
"render.cpu_celestial_adopt": "CPU ray tracing with indirect lighting · path depth {depth} · {spp} SPP · traced shadows · seed {seed} · 1 primary sample",
"render.cpu_celestial_adopt_label": "CPU ray tracing with indirect lighting",
"render.cpu_celestial_path_required": "Finite Sun and gradient Sky use CPU indirect lighting.",
"render.cpu_celestial_switch": "Choose CPU ray tracing with indirect lighting to keep this Sun or Sky.",
"render.cpu_celestial_unportable": "Keep GPU path tracing for the current transmission sample settings.",
"render.cpu_sky_bounds": "Sky rotation must be finite within ±1,000,000 radians; intensity must be 0–100."
},
"he": {
"render.cpu_celestial_adopt": "מעקב קרניים במעבד עם תאורה עקיפה · עומק מסלול {depth} · {spp} דגימות לפיקסל · צללים במעקב · זרע {seed} · דגימה ראשית אחת",
"render.cpu_celestial_adopt_label": "מעקב קרניים במעבד עם תאורה עקיפה",
"render.cpu_celestial_path_required": "שמש בעלת גודל סופי ושמיים מדורגים משתמשים בתאורה עקיפה במעבד.",
"render.cpu_celestial_switch": "כדי לשמור על השמש או השמיים האלה, יש לבחור מעקב קרניים במעבד עם תאורה עקיפה.",
"render.cpu_celestial_unportable": "יש לשמור על מעקב מסלולים במעבד הגרפי עבור הגדרות דגימות ההעברה הנוכחיות.",
"render.cpu_sky_bounds": "סיבוב השמיים חייב להיות סופי בטווח ±1,000,000 רדיאנים, והעוצמה חייבת להיות בטווח 0–100."
},
"ja": {
"render.cpu_celestial_adopt": "間接照明付き CPU レイトレーシング · パス深度 {depth} · {spp} SPP · 追跡シャドウ · シード {seed} · プライマリサンプル1個",
"render.cpu_celestial_adopt_label": "間接照明付き CPU レイトレーシング",
"render.cpu_celestial_path_required": "有限の太陽とグラデーション空は CPU の間接照明を使用します。",
"render.cpu_celestial_switch": "この太陽や空を維持するには、間接照明を使用する CPU レイトレーシングを選択してください。",
"render.cpu_celestial_unportable": "現在の透過サンプル設定には GPU パストレーシングを使用してください。",
"render.cpu_sky_bounds": "空の回転は ±1,000,000 ラジアン以内の有限値、強度は 0~100 にしてください。"
},
"ko": {
"render.cpu_celestial_adopt": "간접 조명을 사용하는 CPU 레이 트레이싱 · 경로 깊이 {depth} · {spp} SPP · 추적 그림자 · 시드 {seed} · 기본 샘플1개",
"render.cpu_celestial_adopt_label": "간접 조명을 사용하는 CPU 레이 트레이싱",
"render.cpu_celestial_path_required": "유한 태양과 그라데이션 하늘은 CPU 간접 조명을 사용합니다.",
"render.cpu_celestial_switch": "이 태양 또는 하늘을 유지하려면 간접 조명을 사용하는 CPU 레이 트레이싱을 선택하세요.",
"render.cpu_celestial_unportable": "현재 투과 샘플 설정에는 GPU 경로 추적을 유지하세요.",
"render.cpu_sky_bounds": "하늘 회전은 ±1,000,000 라디안 이내의 유한 값이어야 하며 강도는 0~100이어야 합니다."
},
"vi": {
"render.cpu_celestial_adopt": "Dò tia CPU với chiếu sáng gián tiếp · độ sâu đường đi {depth} · {spp} SPP · bóng đổ dò tia · seed {seed} · 1 mẫu chính",
"render.cpu_celestial_adopt_label": "Dò tia CPU với chiếu sáng gián tiếp",
"render.cpu_celestial_path_required": "Mặt Trời hữu hạn và bầu trời chuyển sắc dùng chiếu sáng gián tiếp CPU.",
"render.cpu_celestial_switch": "Chọn dò tia CPU với chiếu sáng gián tiếp để giữ Mặt Trời hoặc bầu trời này.",
"render.cpu_celestial_unportable": "Giữ dò đường đi GPU cho cài đặt mẫu truyền sáng hiện tại.",
"render.cpu_sky_bounds": "Góc xoay bầu trời phải hữu hạn trong ±1.000.000 radian; cường độ phải từ 0–100."
},
"zh": {
"render.cpu_celestial_adopt": "CPU 光线追踪与间接照明 · 路径深度 {depth} · {spp} SPP · 追踪阴影 · 种子 {seed} · 1 个主样本",
"render.cpu_celestial_adopt_label": "CPU 光线追踪与间接照明",
"render.cpu_celestial_path_required": "有限太阳和渐变天空使用 CPU 间接照明。",
"render.cpu_celestial_switch": "选择带间接照明的 CPU 光线追踪,以保留此太阳或天空。",
"render.cpu_celestial_unportable": "当前透射采样设置请继续使用 GPU 路径追踪。",
"render.cpu_sky_bounds": "天空旋转必须为 ±1,000,000 弧度内的有限值;强度必须为 0–100。"
}
}
-34
View File
@@ -1,34 +0,0 @@
{
"ar": {
"render.shot_lens_cpu_progressive_reason": "فعّل أخذ العينات التدريجي في قسم «أخذ العينات» قبل تمكين عمق المجال على CPU.",
"render.shot_lens_raytrace_reason": "يتوفر عمق المجال مع تتبع الأشعة على CPU وتتبع المسارات على GPU."
},
"de": {
"render.shot_lens_cpu_progressive_reason": "Vor der CPU-Schärfentiefe unter Sampling die progressive Abtastung übernehmen.",
"render.shot_lens_raytrace_reason": "Schärfentiefe ist für CPU-Raytracing und GPU-Pathtracing verfügbar."
},
"en": {
"render.shot_lens_cpu_progressive_reason": "Adopt progressive sampling in Sampling before enabling CPU depth of field.",
"render.shot_lens_raytrace_reason": "Depth of field is available for CPU ray tracing and GPU path tracing."
},
"he": {
"render.shot_lens_cpu_progressive_reason": "יש להפעיל דגימה הדרגתית בחלונית הדגימה לפני הפעלת עומק שדה ב־CPU.",
"render.shot_lens_raytrace_reason": "עומק שדה זמין בעקיבת קרניים ב־CPU ובעקיבת נתיבים ב־GPU."
},
"ja": {
"render.shot_lens_cpu_progressive_reason": "CPUの被写界深度を有効にするには、サンプリングでプログレッシブ方式を適用してください。",
"render.shot_lens_raytrace_reason": "被写界深度はCPUレイトレーシングとGPUパストレーシングで利用できます。"
},
"ko": {
"render.shot_lens_cpu_progressive_reason": "CPU 피사계 심도를 켜기 전에 샘플링에서 점진적 샘플링을 적용하세요.",
"render.shot_lens_raytrace_reason": "피사계 심도는 CPU 레이 트레이싱과 GPU 패스 트레이싱에서 사용할 수 있습니다."
},
"vi": {
"render.shot_lens_cpu_progressive_reason": "Bật lấy mẫu lũy tiến trong mục Lấy mẫu trước khi bật độ sâu trường ảnh trên CPU.",
"render.shot_lens_raytrace_reason": "Độ sâu trường ảnh khả dụng với dò tia trên CPU và dò đường đi trên GPU."
},
"zh": {
"render.shot_lens_cpu_progressive_reason": "启用CPU景深前,请在采样中应用渐进式采样。",
"render.shot_lens_raytrace_reason": "CPU光线追踪和GPU路径追踪均支持景深。"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.cpu_transparent_help": "يزيل PNG الشفاف الخلفية ويحافظ على تغطية الحواف. يجب أن تبقى عتامة الأجسام والأوجه عند 100%."
},
"de": {
"render.cpu_transparent_help": "Transparentes PNG entfernt den Hintergrund und erhält die Kantenabdeckung. Körper- und Flächendeckkraft müssen 100 % bleiben."
},
"en": {
"render.cpu_transparent_help": "Transparent PNG removes the background and keeps edge coverage. Body and face opacity must stay at 100%."
},
"he": {
"render.cpu_transparent_help": "PNG שקוף מסיר את הרקע ושומר על כיסוי הקצוות. אטימות הגופים והפאות חייבת להישאר 100%."
},
"ja": {
"render.cpu_transparent_help": "透明PNGは背景を除き、輪郭の被覆率を保持します。ボディと面の不透明度は100%にしてください。"
},
"ko": {
"render.cpu_transparent_help": "투명 PNG는 배경을 제거하고 가장자리 커버리지를 유지합니다. 바디와 면의 불투명도는 100%여야 합니다."
},
"vi": {
"render.cpu_transparent_help": "PNG trong suốt loại bỏ nền và giữ độ phủ ở biên. Độ đục của thân và mặt phải giữ ở 100%."
},
"zh": {
"render.cpu_transparent_help": "透明PNG移除背景并保留边缘覆盖率。实体和面的不透明度必须保持100%。"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.directional_sun_limit": "تدعم إضاءة GPU ثمانية مصادر ضوء اتجاهية إجمالاً، من بينها شمس واحدة بظلال ناعمة كحد أقصى. انسخ ضوءاً اتجاهياً بظلال حادة لإضافة مصدر بعيد آخر."
},
"de": {
"render.directional_sun_limit": "Die GPU unterstützt insgesamt acht gerichtete Lichtquellen, darunter höchstens eine weiche Sonne. Dupliziere ein hartes gerichtetes Licht für eine weitere entfernte Quelle."
},
"en": {
"render.directional_sun_limit": "GPU lighting supports eight directional sources in total, including at most one soft Sun. Duplicate a hard directional light to add another distant source."
},
"he": {
"render.directional_sun_limit": "תאורת GPU תומכת בשמונה מקורות אור כיווניים בסך הכול, ובהם לכל היותר שמש אחת בעלת צללים רכים. שכפלו אור כיווני בעל צללים חדים כדי להוסיף מקור מרוחק נוסף."
},
"ja": {
"render.directional_sun_limit": "GPUでは指向性光源を合計8個まで使用でき、柔らかい影の太陽は1個までです。遠方の光源を追加するには、硬い影の指向性ライトを複製してください。"
},
"ko": {
"render.directional_sun_limit": "GPU는 부드러운 태양 하나를 포함해 방향성 광원을 총 8개까지 지원합니다. 원거리 광원을 추가하려면 선명한 그림자의 방향성 조명을 복제하세요."
},
"vi": {
"render.directional_sun_limit": "GPU hỗ trợ tổng cộng tám nguồn sáng định hướng, trong đó có tối đa một Mặt trời với bóng mềm. Nhân đôi đèn định hướng có bóng sắc để thêm nguồn sáng ở xa."
},
"zh": {
"render.directional_sun_limit": "GPU 总共支持八个平行光源,其中最多一个为柔和太阳光。复制硬阴影平行光可添加另一个远处光源。"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.gpu_path_not_started": "لم يبدأ إعداد متتبع المسارات على المعالج الرسومي بعد."
},
"de": {
"render.gpu_path_not_started": "Die Einrichtung des GPU-Pfadtracers wurde noch nicht gestartet."
},
"en": {
"render.gpu_path_not_started": "GPU path tracer setup has not started."
},
"he": {
"render.gpu_path_not_started": "הגדרת מעקב המסלולים ב-GPU טרם התחילה."
},
"ja": {
"render.gpu_path_not_started": "GPUパストレーサーのセットアップはまだ開始されていません。"
},
"ko": {
"render.gpu_path_not_started": "GPU 경로 추적기 설정이 아직 시작되지 않았습니다."
},
"vi": {
"render.gpu_path_not_started": "Quá trình thiết lập bộ dò đường đi GPU chưa bắt đầu."
},
"zh": {
"render.gpu_path_not_started": "GPU路径追踪器的设置尚未开始。"
}
}
@@ -1,58 +0,0 @@
{
"ar": {
"render.spot_axis": "اتجاه انبعاث الضوء",
"render.spot_gpu_help": "تُقاس الزوايا من اتجاه انبعاث الضوء. يتلاشى الضوء بين الزاويتين الداخلية والخارجية. تتطلب نطاقات التلاشي الضيقة جداً التصيير باستخدام CPU.",
"render.spot_help": "تُقاس الزوايا من اتجاه انبعاث الضوء. يتلاشى الضوء بين الزاويتين الداخلية والخارجية.",
"render.spot_inner": "نصف الزاوية الداخلية",
"render.spot_outer": "نصف الزاوية الخارجية"
},
"de": {
"render.spot_axis": "Abstrahlrichtung",
"render.spot_gpu_help": "Die Winkel werden von der Abstrahlrichtung aus gemessen. Zwischen innerem und äußerem Winkel wird das Licht schwächer. Sehr schmale Übergänge erfordern CPU-Rendering.",
"render.spot_help": "Die Winkel werden von der Abstrahlrichtung aus gemessen. Zwischen innerem und äußerem Winkel wird das Licht schwächer.",
"render.spot_inner": "Innerer Halbwinkel",
"render.spot_outer": "Äußerer Halbwinkel"
},
"en": {
"render.spot_axis": "Emission direction",
"render.spot_gpu_help": "Angles are measured from the emission direction. Light fades between the inner and outer angles. Very narrow fade ranges require CPU rendering.",
"render.spot_help": "Angles are measured from the emission direction. Light fades between the inner and outer angles.",
"render.spot_inner": "Inner half-angle",
"render.spot_outer": "Outer half-angle"
},
"he": {
"render.spot_axis": "כיוון פליטת האור",
"render.spot_gpu_help": "הזוויות נמדדות מכיוון פליטת האור. האור דועך בין הזווית הפנימית לחיצונית. טווחי דעיכה צרים מאוד דורשים רינדור באמצעות CPU.",
"render.spot_help": "הזוויות נמדדות מכיוון פליטת האור. האור דועך בין הזווית הפנימית לחיצונית.",
"render.spot_inner": "חצי זווית פנימית",
"render.spot_outer": "חצי זווית חיצונית"
},
"ja": {
"render.spot_axis": "光の照射方向",
"render.spot_gpu_help": "角度は光の照射方向から測ります。内側の角度から外側の角度にかけて光が弱まります。減衰範囲が非常に狭い場合はCPUレンダリングが必要です。",
"render.spot_help": "角度は光の照射方向から測ります。内側の角度から外側の角度にかけて光が弱まります。",
"render.spot_inner": "内側の半角",
"render.spot_outer": "外側の半角"
},
"ko": {
"render.spot_axis": "빛의 방출 방향",
"render.spot_gpu_help": "각도는 빛의 방출 방향을 기준으로 측정합니다. 안쪽 각도와 바깥쪽 각도 사이에서 빛이 약해집니다. 감쇠 범위가 매우 좁으면 CPU 렌더링이 필요합니다.",
"render.spot_help": "각도는 빛의 방출 방향을 기준으로 측정합니다. 안쪽 각도와 바깥쪽 각도 사이에서 빛이 약해집니다.",
"render.spot_inner": "안쪽 반각",
"render.spot_outer": "바깥쪽 반각"
},
"vi": {
"render.spot_axis": "Hướng phát sáng",
"render.spot_gpu_help": "Các góc được đo từ hướng phát sáng. Ánh sáng yếu dần giữa góc trong và góc ngoài. Dải chuyển tiếp rất hẹp cần kết xuất bằng CPU.",
"render.spot_help": "Các góc được đo từ hướng phát sáng. Ánh sáng yếu dần giữa góc trong và góc ngoài.",
"render.spot_inner": "Nửa góc trong",
"render.spot_outer": "Nửa góc ngoài"
},
"zh": {
"render.spot_axis": "光线发射方向",
"render.spot_gpu_help": "角度以光线发射方向为基准测量。光线在内角和外角之间逐渐减弱。极窄的衰减范围需要使用CPU渲染。",
"render.spot_help": "角度以光线发射方向为基准测量。光线在内角和外角之间逐渐减弱。",
"render.spot_inner": "内半角",
"render.spot_outer": "外半角"
}
}
@@ -1,50 +0,0 @@
{
"ar": {
"render.adaptive.pilot_progress": "تمريرات تمهيدية تكيفية · {current}/{target}",
"render.adaptive.preview_help": "توجّه الصور التمهيدية توزيع العينات ولا تدخل في الصورة النهائية. تستخدم تكرارات التصيير ميزانية منفصلة لكل بكسل؛ ولا يمثّل عدد التكرارات عددًا موحدًا من العينات لكل بكسل.",
"render.adaptive.production_progress": "التصيير التكيفي · {current}/{target} تكرارات",
"render.live.adaptive": "مباشر · {width} × {height} · {progress}"
},
"de": {
"render.adaptive.pilot_progress": "Adaptive Pilotphase · {current}/{target} Durchgänge",
"render.adaptive.preview_help": "Pilotbilder bestimmen die Verteilung und sind vom Endbild ausgeschlossen. Produktionsiterationen nutzen ein eigenes Budget pro Pixel; die Iterationszahl ist keine einheitliche Samplezahl pro Pixel.",
"render.adaptive.production_progress": "Adaptive Produktion · {current}/{target} Iterationen",
"render.live.adaptive": "Live · {width} × {height} · {progress}"
},
"en": {
"render.adaptive.pilot_progress": "Adaptive pilots · {current}/{target} passes",
"render.adaptive.preview_help": "Pilot images guide allocation and are excluded from the final image. Production iterations use a separate budget for each pixel; the iteration count is not uniform samples per pixel.",
"render.adaptive.production_progress": "Adaptive production · {current}/{target} iterations",
"render.live.adaptive": "Live · {width} × {height} · {progress}"
},
"he": {
"render.adaptive.pilot_progress": "מעברים מקדימים אדפטיביים · {current}/{target}",
"render.adaptive.preview_help": "התמונות המקדימות מנחות את הקצאת הדגימות ואינן נכללות בתמונה הסופית. איטרציות ההדמיה משתמשות בתקציב נפרד לכל פיקסל; מספר האיטרציות אינו מספר דגימות אחיד לכל פיקסל.",
"render.adaptive.production_progress": "הדמיה אדפטיבית · {current}/{target} איטרציות",
"render.live.adaptive": "חי · {width} × {height} · {progress}"
},
"ja": {
"render.adaptive.pilot_progress": "適応パイロット · {current}/{target} パス",
"render.adaptive.preview_help": "パイロット画像は配分の決定に使われ、最終画像には含まれません。本処理はピクセルごとに別の予算を使うため、反復回数は全ピクセル共通のサンプル数ではありません。",
"render.adaptive.production_progress": "適応本処理 · {current}/{target} 回",
"render.live.adaptive": "ライブ · {width} × {height} · {progress}"
},
"ko": {
"render.adaptive.pilot_progress": "적응형 파일럿 · {current}/{target} 패스",
"render.adaptive.preview_help": "파일럿 이미지는 예산 배분에 사용되며 최종 이미지에서 제외됩니다. 본 처리는 픽셀마다 별도의 예산을 사용하므로 반복 횟수는 모든 픽셀의 동일한 샘플 수를 뜻하지 않습니다.",
"render.adaptive.production_progress": "적응형 본 처리 · {current}/{target} 회",
"render.live.adaptive": "라이브 · {width} × {height} · {progress}"
},
"vi": {
"render.adaptive.pilot_progress": "Các lượt thăm dò thích ứng · {current}/{target}",
"render.adaptive.preview_help": "Ảnh thăm dò định hướng việc phân bổ mẫu và không được đưa vào ảnh cuối cùng. Các vòng kết xuất sử dụng ngân sách riêng cho từng pixel; số vòng không phải số mẫu đồng đều trên mỗi pixel.",
"render.adaptive.production_progress": "Kết xuất thích ứng · {current}/{target} vòng lặp",
"render.live.adaptive": "Trực tiếp · {width} × {height} · {progress}"
},
"zh": {
"render.adaptive.pilot_progress": "自适应预采样 · {current}/{target} 轮",
"render.adaptive.preview_help": "预采样图像用于分配预算,不计入最终图像。正式采样为每个像素使用独立预算;迭代次数不表示所有像素具有相同的采样数。",
"render.adaptive.production_progress": "自适应正式采样 · {current}/{target} 轮迭代",
"render.live.adaptive": "实时 · {width} × {height} · {progress}"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.batch_current_settings_help": "يستخدم إعدادات الصورة الحالية مع كاميرا كل لقطة محفوظة، لقطة واحدة في كل مرة."
},
"de": {
"render.batch_current_settings_help": "Verwendet die aktuellen Bildeinstellungen mit jeder gespeicherten Aufnahmekamera, eine Aufnahme nach der anderen."
},
"en": {
"render.batch_current_settings_help": "Uses the current image settings with each saved shot camera, one shot at a time."
},
"he": {
"render.batch_current_settings_help": "משתמש בהגדרות התמונה הנוכחיות עם המצלמה של כל שוט שמור, שוט אחד בכל פעם."
},
"ja": {
"render.batch_current_settings_help": "現在の画像設定と各保存済みショットのカメラで、1ショットずつレンダリングします。"
},
"ko": {
"render.batch_current_settings_help": "현재 이미지 설정과 저장된 각 샷의 카메라를 사용해 한 번에 한 샷씩 렌더링합니다."
},
"vi": {
"render.batch_current_settings_help": "Dùng thiết lập ảnh hiện tại với máy ảnh của từng góc chụp đã lưu, lần lượt từng góc chụp."
},
"zh": {
"render.batch_current_settings_help": "使用当前图像设置和各个已保存镜头的相机,逐个渲染镜头。"
}
}
@@ -1,98 +0,0 @@
{
"ar": {
"cmd.render.coat.bind": "حفظ الطلاء الشفاف",
"cmd.render.coat.unbind": "إزالة الطلاء الشفاف",
"render.coat_discard": "تجاهل تعديل الطلاء",
"render.coat_pending_edit": "لم يُحفظ تعديل الطلاء هذا. احفظه مع اللقطة أو تجاهل التعديل.",
"render.coat_remove": "إزالة الطلاء المحفوظ",
"render.coat_remove_note": "يزيل طلاء هذا الهدف من اللقطة. تبقى الهندسة والمظاهر والمواد الفيزيائية دون تغيير.",
"render.coat_remove_title": "إزالة الطلاء الشفاف المحفوظ؟",
"render.coat_revalidate_saved": "تغيّر الطلاء المحفوظ. تجاهل هذا التعديل وأعد فتح الهدف قبل تعديله مجددًا.",
"render.coat_save": "حفظ الطلاء مع اللقطة",
"render.coat_saved_help": "يضيف الطلاء الشفاف طبقة لامعة إلى الأسطح المعتمة. احفظه مع اللقطة. لا يمكن استخدام الزجاج على الهدف نفسه، ولا تجاوزات الانعكاس المخصص والتباين الاتجاهي على CPU."
},
"de": {
"cmd.render.coat.bind": "Klarlack speichern",
"cmd.render.coat.unbind": "Klarlack entfernen",
"render.coat_discard": "Klarlackänderung verwerfen",
"render.coat_pending_edit": "Diese Klarlackänderung ist ungespeichert. Mit der Aufnahme speichern oder verwerfen.",
"render.coat_remove": "Gespeicherten Klarlack entfernen",
"render.coat_remove_note": "Entfernt den Klarlack dieses Ziels aus der Aufnahme. Geometrie, Aussehen und physikalische Materialien bleiben unverändert.",
"render.coat_remove_title": "Gespeicherten Klarlack entfernen?",
"render.coat_revalidate_saved": "Der gespeicherte Klarlack wurde geändert. Diese Änderung verwerfen und das Ziel vor der nächsten Bearbeitung erneut öffnen.",
"render.coat_save": "Klarlack in Aufnahme speichern",
"render.coat_saved_help": "Klarlack fügt undurchsichtigen Flächen eine glänzende Schicht hinzu. Mit der Aufnahme speichern. Glas kann nicht dasselbe Ziel verwenden. Auf der CPU dürfen auch benutzerdefinierte Reflexions- und Anisotropieüberschreibungen dieses Ziel nicht verwenden."
},
"en": {
"cmd.render.coat.bind": "Save Clear Coat",
"cmd.render.coat.unbind": "Remove Clear Coat",
"render.coat_discard": "Discard coat edit",
"render.coat_pending_edit": "This coat edit is unsaved. Save it with the shot or discard it.",
"render.coat_remove": "Remove saved coat",
"render.coat_remove_note": "Removes this target’s coat from the shot. Geometry, appearances and physical materials stay unchanged.",
"render.coat_remove_title": "Remove saved clear coat?",
"render.coat_revalidate_saved": "The saved coat changed. Discard this edit and reopen the target before editing it again.",
"render.coat_save": "Save coat to shot",
"render.coat_saved_help": "Clear coat adds a glossy layer to opaque surfaces. Save it with the shot. Glass cannot share this target. CPU custom reflection and anisotropy overrides cannot share it either."
},
"he": {
"cmd.render.coat.bind": "שמירת ציפוי שקוף",
"cmd.render.coat.unbind": "הסרת ציפוי שקוף",
"render.coat_discard": "ביטול עריכת הציפוי",
"render.coat_pending_edit": "שינוי הציפוי הזה לא נשמר. יש לשמור אותו עם התצלום או לבטל את השינוי.",
"render.coat_remove": "הסרת ציפוי שמור",
"render.coat_remove_note": "מסיר את הציפוי של היעד הזה מהתצלום. הגאומטריה, המראה והחומרים הפיזיקליים אינם משתנים.",
"render.coat_remove_title": "להסיר את הציפוי השקוף השמור?",
"render.coat_revalidate_saved": "הציפוי השמור השתנה. יש לבטל את העריכה הזו ולפתוח מחדש את היעד לפני עריכה נוספת.",
"render.coat_save": "שמירת הציפוי בתצלום",
"render.coat_saved_help": "ציפוי שקוף מוסיף שכבה מבריקה למשטחים אטומים. יש לשמור אותו עם התצלום. זכוכית אינה יכולה להשתמש באותו יעד, וגם לא דריסות של השתקפות מותאמת אישית ואנאיזוטרופיה ב־CPU."
},
"ja": {
"cmd.render.coat.bind": "クリアコートを保存",
"cmd.render.coat.unbind": "クリアコートを削除",
"render.coat_discard": "コートの編集を破棄",
"render.coat_pending_edit": "クリアコートの変更は未保存です。ショットに保存するか破棄してください。",
"render.coat_remove": "保存済みコートを削除",
"render.coat_remove_note": "この対象のコートをショットから削除します。形状、外観、物理材料は変更されません。",
"render.coat_remove_title": "保存済みクリアコートを削除しますか?",
"render.coat_revalidate_saved": "保存済みコートが変更されています。この編集を破棄し、対象を開き直してから編集してください。",
"render.coat_save": "コートをショットに保存",
"render.coat_saved_help": "クリアコートは不透明な表面に光沢のある層を追加します。ショットに保存してください。同じ対象にガラスは使用できません。CPUのカスタム反射や異方性の上書きも、この対象と併用できません。"
},
"ko": {
"cmd.render.coat.bind": "클리어 코트 저장",
"cmd.render.coat.unbind": "클리어 코트 제거",
"render.coat_discard": "코트 편집 버리기",
"render.coat_pending_edit": "이 코트 편집은 저장되지 않았습니다. 샷에 저장하거나 편집을 버리세요.",
"render.coat_remove": "저장된 코트 제거",
"render.coat_remove_note": "이 대상의 코트를 샷에서 제거합니다. 형상, 외관 및 물리 재료는 변경되지 않습니다.",
"render.coat_remove_title": "저장된 클리어 코트를 제거할까요?",
"render.coat_revalidate_saved": "저장된 코트가 변경되었습니다. 이 편집을 버리고 대상을 다시 연 뒤 편집하세요.",
"render.coat_save": "샷에 코트 저장",
"render.coat_saved_help": "클리어 코트는 불투명 표면에 광택 층을 추가합니다. 샷에 저장하세요. 같은 대상에 유리를 사용할 수 없습니다. CPU 사용자 지정 반사 또는 이방성 재정의도 이 대상을 함께 사용할 수 없습니다."
},
"vi": {
"cmd.render.coat.bind": "Lưu lớp phủ bóng",
"cmd.render.coat.unbind": "Xóa lớp phủ bóng",
"render.coat_discard": "Hủy chỉnh sửa lớp phủ",
"render.coat_pending_edit": "Chỉnh sửa lớp phủ này chưa được lưu. Hãy lưu cùng cảnh chụp hoặc hủy chỉnh sửa.",
"render.coat_remove": "Xóa lớp phủ đã lưu",
"render.coat_remove_note": "Xóa lớp phủ của đích này khỏi cảnh chụp. Hình học, diện mạo và vật liệu vật lý không thay đổi.",
"render.coat_remove_title": "Xóa lớp phủ bóng đã lưu?",
"render.coat_revalidate_saved": "Lớp phủ đã lưu đã thay đổi. Hãy hủy chỉnh sửa này và mở lại đích trước khi sửa tiếp.",
"render.coat_save": "Lưu lớp phủ vào cảnh chụp",
"render.coat_saved_help": "Lớp phủ bóng thêm một lớp sáng bóng lên bề mặt đục. Hãy lưu cùng cảnh chụp. Kính không thể dùng chung đích này. Ghi đè phản xạ tùy chỉnh và tính dị hướng CPU cũng không thể dùng chung đích."
},
"zh": {
"cmd.render.coat.bind": "保存清漆",
"cmd.render.coat.unbind": "移除清漆",
"render.coat_discard": "放弃清漆编辑",
"render.coat_pending_edit": "清漆编辑尚未保存。请保存到镜头或放弃编辑。",
"render.coat_remove": "移除已保存清漆",
"render.coat_remove_note": "从镜头中移除此目标的清漆。几何、外观和物理材料保持不变。",
"render.coat_remove_title": "移除已保存的清漆?",
"render.coat_revalidate_saved": "已保存的清漆发生了变化。请放弃此编辑,重新打开目标后再编辑。",
"render.coat_save": "将清漆保存到镜头",
"render.coat_saved_help": "清漆为不透明表面添加光泽层。请随镜头保存。同一目标不能使用玻璃,也不能使用CPU自定义反射或各向异性覆盖。"
}
}
@@ -1,64 +0,0 @@
{
"ar": {
"render.check_glass_cpu": "يدعم CPU صفائح زجاج مستوية وصناديق محاذية للمحاور بعد التحقق منها. تتطلب الشبكات المغلقة العامة والتعشيق والتشتت الداخلي إضاءة غير مباشرة. لا تزال الظلال النافذة عبر الزجاج المغلق غير مدعومة.",
"render.check_glass_gpu": "يدعم GPU أوساط زجاج منفصلة متحققًا منها، أو تعشيقًا متحققًا منه عند تفعيله صراحةً. يتطلب التعشيق أغلفة خارجية محدبة وأجسامًا داخلية محتواة بالكامل وحدودًا غير متلامسة.",
"render.check_media_remaining": "لا تزال تأثيرات الزجاج الخشن وشبكات الكثافة والإزاحة والنقل الطيفي غير متاحة.",
"render.check_media_scope": "يتطلب التشتت الداخلي النشط وسطًا زجاجيًا مغلقًا مع إيقاف نفاذ أشعة الظل المستقيمة وإزالة الضجيج. ويتطلب GPU أيضًا طبقة عينات فرينل واحدة. لا يمكن جمع الغلاف الجوي الخارجي النشط مع الزجاج أو إزالة ضجيج الأسطح.",
"render.cpu_material_certification": "يتحقق فحص CPU من هندسة الزجاج المدعومة قبل التصيير. يستخدم الزجاج المغلق المسافة الهندسية."
},
"de": {
"render.check_glass_cpu": "Die CPU unterstützt geprüfte ebene Glasscheiben und achsenparallele Boxen. Allgemeine geschlossene Netze, Verschachtelung und innere Streuung erfordern indirekte Beleuchtung. Durch geschlossenes Glas übertragene Schatten bleiben nicht unterstützt.",
"render.check_glass_gpu": "Die GPU unterstützt geprüfte getrennte Glasmedien oder ausdrücklich aktivierte geprüfte Verschachtelung. Dafür müssen die äußeren Körper konvex und die inneren streng enthalten sein; Grenzen dürfen sich nicht berühren.",
"render.check_media_remaining": "Raues Glas, Dichtegitter, Displacement und spektraler Lichttransport bleiben nicht verfügbar.",
"render.check_media_scope": "Aktive innere Streuung benötigt ein geschlossenes Glasmedium ohne gerade Schattenübertragung und ohne Rauschreduzierung. Die GPU benötigt außerdem eine Fresnel-Schicht. Aktive äußere Atmosphäre kann nicht mit Glas oder Oberflächen-Rauschreduzierung kombiniert werden.",
"render.cpu_material_certification": "Die CPU-Prüfung validiert unterstützte Glasgeometrie vor dem Rendern. Geschlossenes Glas verwendet geometrische Abstände."
},
"en": {
"render.check_glass_cpu": "CPU supports certified planar Glass sheets and axis-aligned boxes. General closed meshes, nesting and interior scattering require Indirect lighting. Closed transmitted shadows remain unsupported.",
"render.check_glass_gpu": "GPU supports certified disjoint Glass or explicit certified nesting. Nesting requires convex parents, strictly contained children and no touching boundaries.",
"render.check_media_remaining": "Rough Glass, density grids, displacement and spectral transport remain unavailable.",
"render.check_media_scope": "Active interior scattering needs a closed Glass medium, straight shadow transmission off and Denoise off. GPU also needs one Fresnel stratum. Active exterior Atmosphere cannot combine with Glass or surface Denoise.",
"render.cpu_material_certification": "CPU Check validates supported Glass geometry before rendering. Closed Glass uses geometric distance."
},
"es": {
"render.cpu_material_certification": "La comprobación de CPU valida la geometría de vidrio admitida antes de renderizar. El vidrio cerrado usa la distancia geométrica."
},
"fr": {
"render.cpu_material_certification": "La vérification CPU valide la géométrie de verre prise en charge avant le rendu. Le verre fermé utilise la distance géométrique."
},
"he": {
"render.check_glass_cpu": "ה־CPU תומך בלוחות זכוכית מישוריים ובתיבות מקבילות לצירים שעברו אימות. רשתות סגורות כלליות, קינון ופיזור פנימי דורשים תאורה עקיפה. העברת צל דרך זכוכית סגורה עדיין אינה נתמכת.",
"render.check_glass_gpu": "ה־GPU תומך בנפחי זכוכית נפרדים שעברו אימות או בקינון מאומת שמופעל במפורש. קינון דורש גופים חיצוניים קמורים, גופים פנימיים המוכלים בתוכם ממש וגבולות שאינם נוגעים זה בזה.",
"render.check_media_remaining": "זכוכית מחוספסת, רשתות צפיפות, הסטת משטח והעברת אור ספקטרלית עדיין אינן זמינות.",
"render.check_media_scope": "פיזור פנימי פעיל דורש נפח זכוכית סגור, העברת קרני צל ישרות כבויה והסרת רעש כבויה. ה־GPU דורש גם שכבת פרנל אחת. אי אפשר לשלב אטמוספירה חיצונית פעילה עם זכוכית או עם הסרת רעש משטחית.",
"render.cpu_material_certification": "בדיקת CPU מאמתת את גאומטריית הזכוכית הנתמכת לפני הרינדור. זכוכית סגורה משתמשת במרחק גאומטרי."
},
"ja": {
"render.check_glass_cpu": "CPUは検証済みの平面ガラス薄板と軸に平行な箱に対応します。一般の閉じたメッシュ、入れ子、内部散乱には間接照明が必要です。閉じたガラスを通る透過影には未対応です。",
"render.check_glass_gpu": "GPUは検証済みの分離したガラス、または明示的に有効にした検証済みの入れ子に対応します。入れ子には凸形状の親、厳密に内包された子、接触しない境界が必要です。",
"render.check_media_remaining": "粗いガラス、密度グリッド、ディスプレイスメント、分光輸送には未対応です。",
"render.check_media_scope": "有効な内部散乱には閉じたガラス媒質を使い、直線の影透過とノイズ除去をオフにします。GPUではフレネル層を1つにします。有効な外部の大気はガラスや表面ノイズ除去と併用できません。",
"render.cpu_material_certification": "CPUの確認では、レンダリング前に対応するガラス形状を検証します。閉じたガラスには形状から得られる距離を使います。"
},
"ko": {
"render.check_glass_cpu": "CPU는 검증된 평면 유리판과 축 정렬 상자를 지원합니다. 일반적인 닫힌 메시, 중첩 및 내부 산란에는 간접광이 필요합니다. 닫힌 유리를 통과하는 투과 그림자는 아직 지원하지 않습니다.",
"render.check_glass_gpu": "GPU는 검증된 분리 유리 또는 명시적으로 활성화한 검증된 중첩을 지원합니다. 중첩에는 볼록한 바깥 형상, 완전히 내부에 포함된 안쪽 형상 및 서로 닿지 않는 경계가 필요합니다.",
"render.check_media_remaining": "거친 유리, 밀도 격자, 디스플레이스먼트 및 분광 광전달은 아직 지원하지 않습니다.",
"render.check_media_scope": "활성 내부 산란에는 닫힌 유리 매질이 필요하며 직선 그림자 투과와 노이즈 제거를 꺼야 합니다. GPU에는 프레넬 계층도 하나만 필요합니다. 활성 외부 대기는 유리 또는 표면 노이즈 제거와 함께 사용할 수 없습니다.",
"render.cpu_material_certification": "CPU 검사는 렌더링 전에 지원되는 유리 형상을 검증합니다. 닫힌 유리는 기하학적 거리를 사용합니다."
},
"vi": {
"render.check_glass_cpu": "CPU hỗ trợ các tấm kính phẳng và hộp thẳng theo trục đã được kiểm chứng. Lưới kín tổng quát, cấu trúc lồng nhau và tán xạ bên trong cần Chiếu sáng gián tiếp. Chưa hỗ trợ bóng truyền qua kính kín.",
"render.check_glass_gpu": "GPU hỗ trợ các khối kính tách rời đã được kiểm chứng hoặc cấu trúc lồng nhau được kiểm chứng và bật rõ ràng. Cấu trúc lồng nhau cần lớp bao lồi, vật thể con nằm hoàn toàn bên trong và các ranh giới không chạm nhau.",
"render.check_media_remaining": "Chưa hỗ trợ kính nhám, lưới mật độ, dịch chuyển bề mặt và truyền sáng quang phổ.",
"render.check_media_scope": "Tán xạ bên trong đang hoạt động cần môi trường kính kín, tắt truyền tia bóng thẳng và tắt Khử nhiễu. GPU cũng cần một tầng Fresnel. Không thể kết hợp Khí quyển bên ngoài đang hoạt động với kính hoặc Khử nhiễu bề mặt.",
"render.cpu_material_certification": "Kiểm tra trên CPU xác thực hình học thủy tinh được hỗ trợ trước khi kết xuất. Thủy tinh kín sử dụng khoảng cách hình học."
},
"zh": {
"render.check_glass_cpu": "CPU 支持经验证的平面玻璃薄片和轴对齐盒体。一般闭合网格、嵌套和内部散射需要间接光照。仍不支持穿过闭合玻璃的透射阴影。",
"render.check_glass_gpu": "GPU 支持经验证的互不相交玻璃介质,或明确启用的经验证嵌套。嵌套要求外层物体为凸体、内层物体严格包含于其中,且边界互不接触。",
"render.check_media_remaining": "仍不支持粗糙玻璃、密度网格、位移和光谱传输。",
"render.check_media_scope": "启用内部散射需要闭合玻璃介质,并关闭直线阴影透射和降噪。GPU 还需要只使用一个菲涅耳分层。启用的外部大气不能与玻璃或表面降噪同时使用。",
"render.cpu_material_certification": "CPU 检查会在渲染前验证所支持的玻璃几何体。封闭玻璃使用几何距离。"
}
}
@@ -1,58 +0,0 @@
{
"ar": {
"render.cpu_opaque_hint": "يستخدم تتبع الأشعة على CPU خلفية معتمة.",
"render.output_master_unavailable": "لتصدير EXR، اختر صورة مكتملة تحتوي على بيانات EXR خام. فعّل EXR الخام قبل تصيير صور جديدة.",
"render.output_presentation_limits": "تدعم مؤثرات الصور على CPU وإخراج EXR صوراً بعرض وارتفاع لا يتجاوزان 8192 بكسل، وبإجمالي لا يتجاوز 16,777,216 بكسل.",
"render.output_raytrace_only": "تتطلب مؤثرات الصور تتبع الأشعة على CPU أو تتبع المسارات على GPU.",
"render.presentation_banner": "تعمل مؤثرات إخراج الصورة مع تتبع الأشعة على CPU وGPU. فتح هذه الصفحة لا يغيّر الطريقة مطلقًا."
},
"de": {
"render.cpu_opaque_hint": "CPU-Raytracing verwendet einen undurchsichtigen Hintergrund.",
"render.output_master_unavailable": "Zum EXR-Export ein fertiges Bild mit EXR-Rohdaten auswählen. EXR-Rohdaten vor dem Rendern neuer Bilder aktivieren.",
"render.output_presentation_limits": "CPU-Bildeffekte und EXR-Ausgabe unterstützen Bilder mit bis zu 8192 Pixeln Breite oder Höhe und insgesamt höchstens 16.777.216 Pixeln.",
"render.output_raytrace_only": "Bildeffekte erfordern CPU-Raytracing oder GPU-Pathtracing.",
"render.presentation_banner": "Bildeffekte funktionieren mit CPU- und GPU-Raytracing. Das Öffnen dieser Seite ändert die Methode nicht."
},
"en": {
"render.cpu_opaque_hint": "CPU ray tracing uses an opaque background.",
"render.output_master_unavailable": "Select a completed image with raw EXR data to export EXR. Enable raw EXR before rendering new images.",
"render.output_presentation_limits": "CPU image effects and EXR output support images up to 8192 pixels wide or high, with at most 16,777,216 pixels in total.",
"render.output_raytrace_only": "Image effects require CPU ray tracing or GPU path tracing.",
"render.presentation_banner": "Presentation effects work with CPU and GPU ray tracing. Opening this page never changes the method."
},
"he": {
"render.cpu_opaque_hint": "עקיבת קרניים ב־CPU משתמשת ברקע אטום.",
"render.output_master_unavailable": "כדי לייצא EXR, יש לבחור תמונה שהושלמה ומכילה נתוני EXR גולמיים. יש להפעיל EXR גולמי לפני רינדור תמונות חדשות.",
"render.output_presentation_limits": "אפקטים של תמונה ב־CPU ופלט EXR תומכים בתמונות ברוחב ובגובה של עד 8192 פיקסלים, ועד 16,777,216 פיקסלים בסך הכול.",
"render.output_raytrace_only": "אפקטים של תמונה דורשים עקיבת קרניים ב־CPU או עקיבת נתיבים ב־GPU.",
"render.presentation_banner": "אפקטים של תצוגת התמונה פועלים בעקיבת קרניים ב־CPU וב־GPU. פתיחת דף זה לעולם אינה משנה את השיטה."
},
"ja": {
"render.cpu_opaque_hint": "CPUレイトレーシングでは不透明な背景を使用します。",
"render.output_master_unavailable": "EXRを書き出すには、RAW EXRデータを持つ完成画像を選択してください。新しい画像は、レンダリング前にRAW EXRを有効にしてください。",
"render.output_presentation_limits": "CPUの画像効果とEXR出力は、幅・高さとも8192ピクセル以下、合計16,777,216ピクセル以下の画像に対応します。",
"render.output_raytrace_only": "画像効果にはCPUレイトレーシングまたはGPUパストレーシングが必要です。",
"render.presentation_banner": "画像効果はCPUとGPUのレイトレーシングで使用できます。このページを開いても方式は変わりません。"
},
"ko": {
"render.cpu_opaque_hint": "CPU 레이 트레이싱은 불투명한 배경을 사용합니다.",
"render.output_master_unavailable": "EXR을 내보내려면 원본 EXR 데이터가 있는 완성 이미지를 선택하세요. 새 이미지를 렌더링하기 전에 원본 EXR을 활성화하세요.",
"render.output_presentation_limits": "CPU 이미지 효과와 EXR 출력은 너비와 높이가 각각 최대 8192픽셀이고 총 16,777,216픽셀 이하인 이미지를 지원합니다.",
"render.output_raytrace_only": "이미지 효과에는 CPU 레이 트레이싱 또는 GPU 패스 트레이싱이 필요합니다.",
"render.presentation_banner": "이미지 효과는 CPU 및 GPU 레이 트레이싱에서 사용할 수 있습니다. 이 페이지를 열어도 방식이 바뀌지 않습니다."
},
"vi": {
"render.cpu_opaque_hint": "Dò tia trên CPU sử dụng nền không trong suốt.",
"render.output_master_unavailable": "Để xuất EXR, hãy chọn ảnh đã hoàn tất có dữ liệu EXR thô. Bật EXR thô trước khi kết xuất ảnh mới.",
"render.output_presentation_limits": "Hiệu ứng ảnh trên CPU và đầu ra EXR hỗ trợ ảnh có chiều rộng và chiều cao tối đa 8192 pixel, với tổng cộng không quá 16.777.216 pixel.",
"render.output_raytrace_only": "Hiệu ứng ảnh yêu cầu dò tia trên CPU hoặc dò đường đi trên GPU.",
"render.presentation_banner": "Các hiệu ứng hình ảnh hoạt động với dò tia trên CPU và GPU. Mở trang này không bao giờ thay đổi phương pháp."
},
"zh": {
"render.cpu_opaque_hint": "CPU光线追踪使用不透明背景。",
"render.output_master_unavailable": "要导出EXR,请选择包含原始EXR数据的已完成图像。渲染新图像前请先启用原始EXR。",
"render.output_presentation_limits": "CPU图像效果和EXR输出支持宽度、高度均不超过8192像素且总像素数不超过16,777,216的图像。",
"render.output_raytrace_only": "图像效果需要CPU光线追踪或GPU路径追踪。",
"render.presentation_banner": "图像效果支持CPU和GPU光线追踪。打开此页面不会更改渲染方式。"
}
}
@@ -1,36 +0,0 @@
{
"ar": {
"prefs.render_legacy_image_defaults": "استخدام الإعدادات الافتراضية السابقة لصور التصيير",
"prefs.render_legacy_image_defaults_help": "الاحتفاظ بسير العمل اليدوي السابق: إعدادات جديدة بالتصيير النقطي على CPU، وأخذ العينات الثابت لتتبع الأشعة على CPU، وفتح النتائج يدويًا. إعادة ملاءمة العرض عند دخول التصيير، وتبديل اللقطات دون استعادة كاميراتها، واستخدام التأطير والتنقل السابقين. تعطيل التحديث التلقائي للصورة المباشرة. لا تتغير الإعدادات المحفوظة."
},
"de": {
"prefs.render_legacy_image_defaults": "Bisherige Render-Bildvorgaben verwenden",
"prefs.render_legacy_image_defaults_help": "Den bisherigen manuellen Ablauf beibehalten: neue Setups mit CPU-Raster, feste Abtastung beim CPU-Raytracing und manuell geöffnete Ergebnisse. Beim Wechsel zu Render die Ansicht neu einpassen, Aufnahmen ohne Wiederherstellung ihrer Kamera wechseln und die bisherige Bildausrichtung und Navigation verwenden. Automatische Live-Bildrückmeldungen deaktivieren. Gespeicherte Setups bleiben unverändert."
},
"en": {
"prefs.render_legacy_image_defaults": "Use previous Render image defaults",
"prefs.render_legacy_image_defaults_help": "Keep the previous manual workflow: new setups use CPU raster, CPU ray tracing keeps fixed sampling, and you open rendered results manually. Refit on Render entry, switch shots without restoring their cameras, and use the previous framing and navigation. Disable automatic live image feedback. Saved setups are unchanged."
},
"he": {
"prefs.render_legacy_image_defaults": "שימוש בברירות המחדל הקודמות לתמונות הדמיה",
"prefs.render_legacy_image_defaults_help": "שמירה על תהליך העבודה הידני הקודם: הגדרות חדשות ברסטר CPU, דגימה קבועה בעקיבת קרניים ב־CPU ופתיחת התוצאות ידנית. התאמת התצוגה מחדש בכניסה להדמיה, מעבר בין צילומים בלי לשחזר את המצלמות שלהם ושימוש במסגור ובניווט הקודמים. עדכון אוטומטי של התמונה החיה מושבת. הגדרות שמורות אינן משתנות."
},
"ja": {
"prefs.render_legacy_image_defaults": "以前のレンダー画像の既定値を使用",
"prefs.render_legacy_image_defaults_help": "以前の手動の画像ワークフローを使用します。新しいセットアップはCPUラスタ、CPUレイトレーシングは固定サンプリングとし、結果は手動で開きます。レンダーに入るたびにビューをフィットし、ショットを切り替えても保存カメラを復元せず、以前のフレーミングとナビゲーションを使用します。自動のライブ画像更新は無効にします。保存済みのセットアップは変更しません。"
},
"ko": {
"prefs.render_legacy_image_defaults": "이전 렌더 이미지 기본값 사용",
"prefs.render_legacy_image_defaults_help": "이전의 수동 이미지 작업 방식을 유지합니다. 새 설정은 CPU 래스터를 사용하고 CPU 광선 추적은 고정 샘플링을 사용하며 결과는 직접 엽니다. 렌더에 들어갈 때 뷰를 다시 맞추고, 샷을 전환해도 저장된 카메라를 복원하지 않으며, 이전의 프레이밍과 탐색 방식을 사용합니다. 자동 실시간 이미지 피드백을 끕니다. 저장된 설정은 변경하지 않습니다.",
"render.method_raster": "CPU 래스터 (도식)",
"render.result_provisional": "임시 이미지"
},
"vi": {
"prefs.render_legacy_image_defaults": "Dùng mặc định ảnh Kết xuất trước đây",
"prefs.render_legacy_image_defaults_help": "Giữ quy trình hình ảnh thủ công trước đây: thiết lập mới dùng raster CPU, dò tia CPU dùng lấy mẫu cố định và mở kết quả thủ công. Căn vừa lại khung nhìn khi vào Kết xuất, chuyển góc chụp mà không khôi phục camera đã lưu, đồng thời dùng cách lấy khung hình và điều hướng trước đây. Tắt phản hồi ảnh trực tiếp tự động. Các thiết lập đã lưu không thay đổi."
},
"zh": {
"prefs.render_legacy_image_defaults": "使用以前的渲染图像默认值",
"prefs.render_legacy_image_defaults_help": "保留以前的手动图像流程:新设置使用 CPU 光栅渲染,CPU 光线追踪使用固定采样,并手动打开结果。进入渲染时重新适配视图,切换镜头时不恢复其保存的相机,并使用以前的取景和导航方式。禁用自动实时图像反馈。已保存的设置保持不变。"
}
}
@@ -1,34 +0,0 @@
{
"ar": {
"render.light_space_world": "أضواء بإحداثيات العالم",
"render.light_space_world_help": "تستخدم مواضع الأضواء واتجاهاتها إحداثيات العالم. لا يؤدي تدوير الكاميرا حول النموذج إلى تحريك الأضواء."
},
"de": {
"render.light_space_world": "Lichter in Weltkoordinaten",
"render.light_space_world_help": "Lichtpositionen und -richtungen verwenden Weltkoordinaten. Beim Umkreisen mit der Kamera bleiben die Lichter an ihrer Position."
},
"en": {
"render.light_space_world": "World-space lights",
"render.light_space_world_help": "Light positions and directions use world coordinates. Orbiting the camera does not move them."
},
"he": {
"render.light_space_world": "אורות בקואורדינטות העולם",
"render.light_space_world_help": "מיקומי האורות וכיווניהם משתמשים בקואורדינטות העולם. סיבוב המצלמה סביב המודל אינו מזיז את האורות."
},
"ja": {
"render.light_space_world": "ワールド座標のライト",
"render.light_space_world_help": "ライトの位置と方向はワールド座標を使用します。カメラを周回させてもライトは移動しません。"
},
"ko": {
"render.light_space_world": "월드 좌표의 조명",
"render.light_space_world_help": "조명의 위치와 방향은 월드 좌표를 사용합니다. 카메라를 회전해도 조명은 움직이지 않습니다."
},
"vi": {
"render.light_space_world": "Đèn trong hệ tọa độ thế giới",
"render.light_space_world_help": "Vị trí và hướng của đèn dùng hệ tọa độ thế giới. Xoay camera quanh mô hình không làm đèn di chuyển."
},
"zh": {
"render.light_space_world": "世界坐标光源",
"render.light_space_world_help": "光源的位置和方向使用世界坐标。环绕旋转相机不会移动光源。"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"cmd.view.render_live": "إيقاف التصيير المباشر مؤقتًا أو استئنافه"
},
"de": {
"cmd.view.render_live": "Live-Rendering pausieren oder fortsetzen"
},
"en": {
"cmd.view.render_live": "Pause or Resume Live Render"
},
"he": {
"cmd.view.render_live": "השהיה או חידוש של הדמיה חיה"
},
"ja": {
"cmd.view.render_live": "ライブレンダーを一時停止・再開"
},
"ko": {
"cmd.view.render_live": "실시간 렌더링 일시 중지 또는 재개"
},
"vi": {
"cmd.view.render_live": "Tạm dừng hoặc tiếp tục kết xuất trực tiếp"
},
"zh": {
"cmd.view.render_live": "暂停或继续实时渲染"
}
}
@@ -1,130 +0,0 @@
{
"ar": {
"render.live.final_changed": "تغيّر طلب التصيير أثناء إيقاف التصيير المباشر. ابدأ الصورة النهائية من جديد.",
"render.live.final_waiting": "جارٍ تحضير الصورة النهائية · تحرير موارد التصيير المباشر",
"render.live.invalid_size": "يتطلب التصيير المباشر عرضًا وارتفاعًا موجبين للإخراج.",
"render.live.pause": "إيقاف المباشر مؤقتًا",
"render.live.paused": "مباشر · متوقف مؤقتًا",
"render.live.paused_outdated": "مباشر · متوقف مؤقتًا · غير محدّث",
"render.live.quality_help": "جودة تفاعلية: بحد أقصى 512 بكسل للضلع الأطول. تستخدم المصيّر المحدد ومؤثراته المدعومة. تبقى دقة الصورة النهائية وإعداداتها وتصديرها مستقلة.",
"render.live.refused": "التصيير المباشر غير متاح: {reason}",
"render.live.resume": "استئناف المباشر",
"render.live.samples": "مباشر · {width} × {height} · {current}/{target} عينة",
"render.live.stopped": "توقف التصيير المباشر",
"render.live.updating": "مباشر · جودة تفاعلية (حتى 512 بكسل) · جارٍ التحديث",
"render.live.waiting_canvas": "في انتظار لوحة التصيير",
"render.live.worker_stopped": "توقفت مهمة التقاط التصيير المباشر قبل إرجاع نتيجة"
},
"de": {
"render.live.final_changed": "Die Render-Anfrage hat sich beim Anhalten des Live-Renderings geändert. Starten Sie das finale Bild erneut.",
"render.live.final_waiting": "Finales Bild vorbereiten · Live-Render-Ressourcen freigeben",
"render.live.invalid_size": "Live-Rendering benötigt eine positive Ausgabebreite und -höhe.",
"render.live.pause": "Live pausieren",
"render.live.paused": "Live · Pausiert",
"render.live.paused_outdated": "Live · Pausiert · Veraltet",
"render.live.quality_help": "Interaktive Qualität: höchstens 512 Pixel an der längsten Kante. Verwendet den gewählten Renderer und seine unterstützten Effekte. Endauflösung, Einstellungen und Export bleiben getrennt.",
"render.live.refused": "Live nicht verfügbar: {reason}",
"render.live.resume": "Live fortsetzen",
"render.live.samples": "Live · {width} × {height} · {current}/{target} Samples",
"render.live.stopped": "Live-Rendering angehalten",
"render.live.updating": "Live · Interaktive Qualität (bis 512 px) · Aktualisierung",
"render.live.waiting_canvas": "Warten auf die Render-Ansicht",
"render.live.worker_stopped": "Der Aufnahmeprozess für das Live-Rendering wurde vor der Rückgabe eines Ergebnisses beendet"
},
"en": {
"render.live.final_changed": "The render request changed while live rendering was stopping. Start the final image again.",
"render.live.final_waiting": "Preparing final image · releasing live-render resources",
"render.live.invalid_size": "Live rendering needs a positive output width and height.",
"render.live.pause": "Pause live",
"render.live.paused": "Live · Paused",
"render.live.paused_outdated": "Live · Paused · Out of date",
"render.live.quality_help": "Interactive quality: at most 512 pixels on the longest edge. Uses the selected renderer and its supported effects. Final resolution, settings and export remain separate.",
"render.live.refused": "Live unavailable: {reason}",
"render.live.resume": "Resume live",
"render.live.samples": "Live · {width} × {height} · {current}/{target} samples",
"render.live.stopped": "Live rendering stopped",
"render.live.updating": "Live · Interactive quality (up to 512 px) · Updating",
"render.live.waiting_canvas": "Waiting for the Render canvas",
"render.live.worker_stopped": "The live-render capture worker stopped before returning a result"
},
"he": {
"render.live.final_changed": "בקשת ההדמיה השתנתה בזמן עצירת ההדמיה החיה. יש להתחיל את התמונה הסופית מחדש.",
"render.live.final_waiting": "מכין תמונה סופית · משחרר משאבי הדמיה חיה",
"render.live.invalid_size": "הדמיה חיה דורשת רוחב וגובה פלט גדולים מאפס.",
"render.live.pause": "השהיית הדמיה חיה",
"render.live.paused": "חי · מושהה",
"render.live.paused_outdated": "חי · מושהה · לא מעודכן",
"render.live.quality_help": "איכות אינטראקטיבית: לכל היותר 512 פיקסלים בצד הארוך. משתמשת במנוע ההדמיה שנבחר ובאפקטים הנתמכים בו. רזולוציית התמונה הסופית, ההגדרות והייצוא נשארים נפרדים.",
"render.live.refused": "הדמיה חיה אינה זמינה: {reason}",
"render.live.resume": "חידוש הדמיה חיה",
"render.live.samples": "חי · {width} × {height} · {current}/{target} דגימות",
"render.live.stopped": "ההדמיה החיה נעצרה",
"render.live.updating": "חי · איכות אינטראקטיבית (עד 512 פיקסלים) · מתעדכן",
"render.live.waiting_canvas": "ממתין למשטח ההדמיה",
"render.live.worker_stopped": "תהליך הלכידה של ההדמיה החיה נעצר לפני שהחזיר תוצאה"
},
"ja": {
"render.live.final_changed": "ライブレンダリングの停止中にリクエストが変更されました。最終画像をもう一度開始してください。",
"render.live.final_waiting": "最終画像を準備中 · ライブレンダーのリソースを解放中",
"render.live.invalid_size": "ライブレンダリングには正の出力幅と高さが必要です。",
"render.live.pause": "ライブを一時停止",
"render.live.paused": "ライブ · 一時停止中",
"render.live.paused_outdated": "ライブ · 一時停止中 · 更新が必要",
"render.live.quality_help": "インタラクティブ品質: 長辺は最大512ピクセルです。選択したレンダラーと対応する効果を使用します。最終解像度、設定、書き出しは別に保持します。",
"render.live.refused": "ライブを利用できません: {reason}",
"render.live.resume": "ライブを再開",
"render.live.samples": "ライブ · {width} × {height} · {current}/{target} サンプル",
"render.live.stopped": "ライブレンダリングを停止しました",
"render.live.updating": "ライブ · インタラクティブ品質(最大512 px)· 更新中",
"render.live.waiting_canvas": "レンダーキャンバスを待機中",
"render.live.worker_stopped": "ライブレンダリングのキャプチャーワーカーが結果を返す前に停止しました"
},
"ko": {
"render.live.final_changed": "라이브 렌더링을 중지하는 동안 렌더 요청이 변경되었습니다. 최종 이미지를 다시 시작하세요.",
"render.live.final_waiting": "최종 이미지 준비 중 · 라이브 렌더 리소스 해제 중",
"render.live.invalid_size": "라이브 렌더링에는 양수의 출력 너비와 높이가 필요합니다.",
"render.live.pause": "라이브 일시 중지",
"render.live.paused": "라이브 · 일시 중지됨",
"render.live.paused_outdated": "라이브 · 일시 중지됨 · 업데이트 필요",
"render.live.quality_help": "대화형 품질: 가장 긴 변은 최대 512픽셀입니다. 선택한 렌더러와 지원하는 효과를 사용합니다. 최종 해상도, 설정 및 내보내기는 별도로 유지됩니다.",
"render.live.refused": "라이브 사용 불가: {reason}",
"render.live.resume": "라이브 재개",
"render.live.samples": "라이브 · {width} × {height} · {current}/{target} 샘플",
"render.live.stopped": "라이브 렌더링 중지됨",
"render.live.updating": "라이브 · 대화형 품질(최대 512 px) · 업데이트 중",
"render.live.waiting_canvas": "렌더 캔버스 대기 중",
"render.live.worker_stopped": "라이브 렌더 캡처 작업이 결과를 반환하기 전에 중지되었습니다"
},
"vi": {
"render.live.final_changed": "Yêu cầu kết xuất đã thay đổi trong lúc dừng kết xuất trực tiếp. Hãy bắt đầu lại ảnh cuối cùng.",
"render.live.final_waiting": "Đang chuẩn bị ảnh cuối · Giải phóng tài nguyên kết xuất trực tiếp",
"render.live.invalid_size": "Kết xuất trực tiếp yêu cầu chiều rộng và chiều cao đầu ra lớn hơn không.",
"render.live.pause": "Tạm dừng trực tiếp",
"render.live.paused": "Trực tiếp · Tạm dừng",
"render.live.paused_outdated": "Trực tiếp · Tạm dừng · Chưa cập nhật",
"render.live.quality_help": "Chất lượng tương tác: tối đa 512 pixel ở cạnh dài nhất. Sử dụng bộ kết xuất đã chọn và các hiệu ứng được bộ đó hỗ trợ. Độ phân giải cuối, thiết lập và thao tác xuất vẫn độc lập.",
"render.live.refused": "Kết xuất trực tiếp không khả dụng: {reason}",
"render.live.resume": "Tiếp tục trực tiếp",
"render.live.samples": "Trực tiếp · {width} × {height} · {current}/{target} mẫu",
"render.live.stopped": "Kết xuất trực tiếp đã dừng",
"render.live.updating": "Trực tiếp · Chất lượng tương tác (tối đa 512 px) · Đang cập nhật",
"render.live.waiting_canvas": "Đang chờ khung vẽ Kết xuất",
"render.live.worker_stopped": "Luồng thu nhận dữ liệu cho kết xuất trực tiếp đã dừng trước khi trả về kết quả"
},
"zh": {
"render.live.final_changed": "停止实时渲染时渲染请求已更改。请重新开始最终图像渲染。",
"render.live.final_waiting": "正在准备最终图像 · 释放实时渲染资源",
"render.live.invalid_size": "实时渲染需要正的输出宽度和高度。",
"render.live.pause": "暂停实时渲染",
"render.live.paused": "实时 · 已暂停",
"render.live.paused_outdated": "实时 · 已暂停 · 已过时",
"render.live.quality_help": "交互质量:最长边最多为 512 像素。使用所选渲染器及其支持的效果。最终分辨率、设置和导出保持独立。",
"render.live.refused": "实时渲染不可用:{reason}",
"render.live.resume": "恢复实时渲染",
"render.live.samples": "实时 · {width} × {height} · {current}/{target} 次采样",
"render.live.stopped": "实时渲染已停止",
"render.live.updating": "实时 · 交互质量(最多 512 px)· 正在更新",
"render.live.waiting_canvas": "正在等待渲染画布",
"render.live.worker_stopped": "实时渲染捕获工作线程在返回结果之前已停止"
}
}
@@ -1,82 +0,0 @@
{
"en": {
"render.batch_owner_limit": "At most 32 document shot queues can be retained. Finish or cancel an existing queue first.",
"render.batch_preparing": "Preparing next shot",
"render.batch_waiting_worker": "Waiting for render preparation",
"render.preparation_cancelled": "Render preparation cancelled",
"render.preparation_checking": "Checking render",
"render.preparation_retirement_failed": "Render preparation cleanup failed. This window cannot prepare another image.",
"render.preparation_retiring": "Finishing render preparation",
"render.preparation_unavailable": "Render preparation unavailable"
},
"de": {
"render.batch_owner_limit": "Es können höchstens 32 Dokument-Bildfolgen vorgehalten werden. Schließen Sie zuerst eine vorhandene Folge ab oder brechen Sie sie ab.",
"render.batch_preparing": "Nächste Aufnahme wird vorbereitet",
"render.batch_waiting_worker": "Warten auf die Rendering-Vorbereitung",
"render.preparation_cancelled": "Rendering-Vorbereitung abgebrochen",
"render.preparation_checking": "Rendering wird geprüft",
"render.preparation_retirement_failed": "Die Bereinigung der Rendering-Vorbereitung ist fehlgeschlagen. Dieses Fenster kann kein weiteres Bild vorbereiten.",
"render.preparation_retiring": "Rendering-Vorbereitung wird abgeschlossen",
"render.preparation_unavailable": "Rendering-Vorbereitung nicht verfügbar"
},
"ja": {
"render.batch_owner_limit": "保持できるドキュメントのショットキューは最大32個です。既存のキューを完了するかキャンセルしてください。",
"render.batch_preparing": "次のショットを準備中",
"render.batch_waiting_worker": "レンダリングの準備待ち",
"render.preparation_cancelled": "レンダリングの準備をキャンセルしました",
"render.preparation_checking": "レンダリングを確認中",
"render.preparation_retirement_failed": "レンダリング準備の後処理に失敗しました。このウィンドウでは別の画像を準備できません。",
"render.preparation_retiring": "レンダリングの準備を終了中",
"render.preparation_unavailable": "レンダリングの準備を利用できません"
},
"ko": {
"render.batch_owner_limit": "문서 샷 대기열은 최대 32개까지 유지할 수 있습니다. 기존 대기열을 완료하거나 취소하세요.",
"render.batch_preparing": "다음 샷 준비 중",
"render.batch_waiting_worker": "렌더링 준비 대기 중",
"render.preparation_cancelled": "렌더링 준비가 취소되었습니다",
"render.preparation_checking": "렌더링 확인 중",
"render.preparation_retirement_failed": "렌더링 준비 정리에 실패했습니다. 이 창에서는 다른 이미지를 준비할 수 없습니다.",
"render.preparation_retiring": "렌더링 준비 마무리 중",
"render.preparation_unavailable": "렌더링 준비를 사용할 수 없음"
},
"zh": {
"render.batch_owner_limit": "最多可保留32个文档的镜头队列。请先完成或取消现有队列。",
"render.batch_preparing": "正在准备下一个镜头",
"render.batch_waiting_worker": "等待渲染准备",
"render.preparation_cancelled": "渲染准备已取消",
"render.preparation_checking": "正在检查渲染",
"render.preparation_retirement_failed": "渲染准备清理失败。此窗口无法再准备其他图像。",
"render.preparation_retiring": "正在完成渲染准备",
"render.preparation_unavailable": "渲染准备不可用"
},
"ar": {
"render.batch_owner_limit": "يمكن الاحتفاظ بقوائم لقطات 32 مستندًا كحد أقصى. أكمل قائمة موجودة أو ألغها أولًا.",
"render.batch_preparing": "جارٍ إعداد اللقطة التالية",
"render.batch_waiting_worker": "في انتظار إعداد التصيير",
"render.preparation_cancelled": "أُلغي إعداد التصيير",
"render.preparation_checking": "جارٍ التحقق من التصيير",
"render.preparation_retirement_failed": "تعذّر تنظيف موارد إعداد التصيير. لا يمكن لهذه النافذة إعداد صورة أخرى.",
"render.preparation_retiring": "جارٍ إنهاء إعداد التصيير",
"render.preparation_unavailable": "إعداد التصيير غير متاح"
},
"he": {
"render.batch_owner_limit": "ניתן לשמור תורי צילומים של 32 מסמכים לכל היותר. יש להשלים או לבטל תור קיים תחילה.",
"render.batch_preparing": "מכין את הצילום הבא",
"render.batch_waiting_worker": "ממתין להכנת הרינדור",
"render.preparation_cancelled": "הכנת הרינדור בוטלה",
"render.preparation_checking": "בודק רינדור",
"render.preparation_retirement_failed": "ניקוי משאבי הכנת הרינדור נכשל. לא ניתן להכין תמונה נוספת בחלון זה.",
"render.preparation_retiring": "מסיים את הכנת הרינדור",
"render.preparation_unavailable": "הכנת הרינדור אינה זמינה"
},
"vi": {
"render.batch_owner_limit": "Chỉ có thể giữ hàng đợi cảnh của tối đa 32 tài liệu. Hãy hoàn tất hoặc hủy một hàng đợi hiện có trước.",
"render.batch_preparing": "Đang chuẩn bị cảnh tiếp theo",
"render.batch_waiting_worker": "Đang chờ chuẩn bị kết xuất",
"render.preparation_cancelled": "Đã hủy chuẩn bị kết xuất",
"render.preparation_checking": "Đang kiểm tra kết xuất",
"render.preparation_retirement_failed": "Không thể giải phóng tài nguyên chuẩn bị kết xuất. Cửa sổ này không thể chuẩn bị ảnh khác.",
"render.preparation_retiring": "Đang hoàn tất chuẩn bị kết xuất",
"render.preparation_unavailable": "Không thể chuẩn bị kết xuất"
}
}
@@ -1,58 +0,0 @@
{
"ar": {
"render.cpu_fixed_retained": "تم الاحتفاظ بأخذ العينات الثابت",
"render.cpu_progressive_adopt": "استخدام أخذ العينات التدريجي",
"render.cpu_progressive_adopt_help": "يستخدم أخذ العينات التدريجي عينة كاميرا واحدة لكل تمريرة. يبقى حجم الصورة والأضواء وإعدادات الانعكاس دون تغيير.",
"render.cpu_progressive_always": "أخذ العينات التدريجي مفعّل دائمًا",
"render.cpu_progressive_reflection_adopt": "اضبط محاولات الانعكاس المحددة على 1 قبل تفعيل أخذ العينات التدريجي."
},
"de": {
"render.cpu_fixed_retained": "Feste Abtastung beibehalten",
"render.cpu_progressive_adopt": "Progressive Abtastung verwenden",
"render.cpu_progressive_adopt_help": "Die progressive Abtastung verwendet ein Kamerasample pro Durchlauf. Bildgröße, Lichtquellen und Reflexionseinstellungen bleiben unverändert.",
"render.cpu_progressive_always": "Progressive Abtastung ist immer aktiv",
"render.cpu_progressive_reflection_adopt": "Setzen Sie die Reflexionsversuche ausgewählter Körper auf 1, bevor Sie die progressive Abtastung übernehmen."
},
"en": {
"render.cpu_fixed_retained": "Fixed sampling retained",
"render.cpu_progressive_adopt": "Use progressive sampling",
"render.cpu_progressive_adopt_help": "Adopting progressive uses one camera sample per pass. Image size, lights and reflection settings stay unchanged.",
"render.cpu_progressive_always": "Progressive sampling is always on",
"render.cpu_progressive_reflection_adopt": "Set selected reflection attempts to 1 before adopting progressive sampling."
},
"he": {
"render.cpu_fixed_retained": "הדגימה הקבועה נשמרה",
"render.cpu_progressive_adopt": "שימוש בדגימה הדרגתית",
"render.cpu_progressive_adopt_help": "מעבר לדגימה הדרגתית משתמש בדגימת מצלמה אחת לכל מעבר. גודל התמונה, האורות והגדרות ההחזר נשארים ללא שינוי.",
"render.cpu_progressive_always": "דגימה הדרגתית פעילה תמיד",
"render.cpu_progressive_reflection_adopt": "יש לקבוע את מספר ניסיונות ההחזר שנבחרו ל־1 לפני המעבר לדגימה הדרגתית."
},
"ja": {
"render.cpu_fixed_retained": "固定サンプリングを維持",
"render.cpu_progressive_adopt": "プログレッシブサンプリングを使用",
"render.cpu_progressive_adopt_help": "切り替えると各パスで1つのカメラサンプルを使用します。画像サイズ、照明、反射設定は変わりません。",
"render.cpu_progressive_always": "プログレッシブサンプリングは常に有効です",
"render.cpu_progressive_reflection_adopt": "切り替える前に、選択した反射の試行回数を1に設定してください。"
},
"ko": {
"render.cpu_fixed_retained": "고정 샘플링 유지",
"render.cpu_progressive_adopt": "점진적 샘플링 사용",
"render.cpu_progressive_adopt_help": "전환하면 패스마다 카메라 샘플 하나를 사용합니다. 이미지 크기, 조명 및 반사 설정은 유지됩니다.",
"render.cpu_progressive_always": "점진적 샘플링은 항상 켜져 있습니다",
"render.cpu_progressive_reflection_adopt": "전환하기 전에 선택한 반사의 시도 횟수를 1로 설정하세요."
},
"vi": {
"render.cpu_fixed_retained": "Đã giữ lấy mẫu cố định",
"render.cpu_progressive_adopt": "Dùng lấy mẫu lũy tiến",
"render.cpu_progressive_adopt_help": "Lấy mẫu lũy tiến sử dụng một mẫu máy ảnh cho mỗi lượt. Kích thước ảnh, nguồn sáng và thiết lập phản xạ không thay đổi.",
"render.cpu_progressive_always": "Lấy mẫu lũy tiến luôn bật",
"render.cpu_progressive_reflection_adopt": "Đặt số lần thử phản xạ đã chọn thành 1 trước khi chuyển sang lấy mẫu lũy tiến."
},
"zh": {
"render.cpu_fixed_retained": "保留固定采样",
"render.cpu_progressive_adopt": "使用渐进采样",
"render.cpu_progressive_adopt_help": "启用后每轮使用一个相机样本。图像大小、灯光和反射设置保持不变。",
"render.cpu_progressive_always": "渐进采样始终开启",
"render.cpu_progressive_reflection_adopt": "启用渐进采样前,请将所选反射的尝试次数设为1。"
}
}
@@ -1,42 +0,0 @@
{
"ar": {
"render.quality_budget_help": "يضبط الحجم والعينات والعمق والبذرة وتقليل التشويش. تُحفظ إعدادات الصورة الأخرى.",
"render.quality_denoise_off": "تقليل التشويش: متوقف",
"render.quality_denoise_on": "تقليل التشويش: مفعّل"
},
"de": {
"render.quality_budget_help": "Legt Größe, Samples, Tiefe, Startwert und Rauschreduzierung fest. Andere Bildeinstellungen bleiben erhalten.",
"render.quality_denoise_off": "Rauschreduzierung: Aus",
"render.quality_denoise_on": "Rauschreduzierung: Ein"
},
"en": {
"render.quality_budget_help": "Sets size, samples, depth, seed and noise reduction. Other image settings are kept.",
"render.quality_denoise_off": "Noise reduction: Off",
"render.quality_denoise_on": "Noise reduction: On"
},
"he": {
"render.quality_budget_help": "קובע גודל, דגימות, עומק, זרע והפחתת רעש. הגדרות התמונה האחרות נשמרות.",
"render.quality_denoise_off": "הפחתת רעש: כבויה",
"render.quality_denoise_on": "הפחתת רעש: פעילה"
},
"ja": {
"render.quality_budget_help": "サイズ、サンプル数、深度、シード、ノイズ低減を設定します。他の画像設定は維持されます。",
"render.quality_denoise_off": "ノイズ低減:オフ",
"render.quality_denoise_on": "ノイズ低減:オン"
},
"ko": {
"render.quality_budget_help": "크기, 샘플 수, 깊이, 시드 및 노이즈 제거를 설정합니다. 다른 이미지 설정은 유지됩니다.",
"render.quality_denoise_off": "노이즈 제거: 꺼짐",
"render.quality_denoise_on": "노이즈 제거: 켜짐"
},
"vi": {
"render.quality_budget_help": "Đặt kích thước, số mẫu, độ sâu, hạt giống và giảm nhiễu. Giữ nguyên các thiết lập ảnh khác.",
"render.quality_denoise_off": "Giảm nhiễu: Tắt",
"render.quality_denoise_on": "Giảm nhiễu: Bật"
},
"zh": {
"render.quality_budget_help": "设置尺寸、采样数、深度、种子和降噪。其他图像设置保持不变。",
"render.quality_denoise_off": "降噪:关闭",
"render.quality_denoise_on": "降噪:开启"
}
}
@@ -1,26 +0,0 @@
{
"ar": {
"render.quality_summary": "{width} × {height} · {samples} عينة · العمق {depth} · البذرة {seed} · {denoise}"
},
"de": {
"render.quality_summary": "{width} × {height} · {samples} Samples · Tiefe {depth} · Startwert {seed} · {denoise}"
},
"en": {
"render.quality_summary": "{width} × {height} · {samples} samples · depth {depth} · seed {seed} · {denoise}"
},
"he": {
"render.quality_summary": "{width} × {height} · {samples} דגימות · עומק {depth} · זרע {seed} · {denoise}"
},
"ja": {
"render.quality_summary": "{width} × {height} · {samples} サンプル · 深度 {depth} · シード {seed} · {denoise}"
},
"ko": {
"render.quality_summary": "{width} × {height} · 샘플 {samples}개 · 깊이 {depth} · 시드 {seed} · {denoise}"
},
"vi": {
"render.quality_summary": "{width} × {height} · {samples} mẫu · độ sâu {depth} · hạt giống {seed} · {denoise}"
},
"zh": {
"render.quality_summary": "{width} × {height} · {samples} 次采样 · 深度 {depth} · 种子 {seed} · {denoise}"
}
}
@@ -1,50 +0,0 @@
{
"ar": {
"render.live.source_current": "{method} · مباشر",
"render.live.source_outdated": "{method} · الصورة السابقة",
"render.live.source_outdated_help": "يعرض آخر صورة ملتقطة أثناء تحديث التصيير المباشر أو عند عدم توفره. قد تختلف عن المشهد أو إعدادات الصورة الحالية.",
"render.live.source_settings_help": "افتح «الإخراج» لتعديل المصيّر وإعدادات الصورة."
},
"de": {
"render.live.source_current": "{method} · Live",
"render.live.source_outdated": "{method} · Vorheriges Bild",
"render.live.source_outdated_help": "Zeigt das zuletzt aufgenommene Bild, während das Live-Rendering aktualisiert wird oder nicht verfügbar ist. Es kann von der aktuellen Szene oder den Bildeinstellungen abweichen.",
"render.live.source_settings_help": "Ausgabe öffnen, um Renderer und Bildeinstellungen zu bearbeiten."
},
"en": {
"render.live.source_current": "{method} · Live",
"render.live.source_outdated": "{method} · Previous image",
"render.live.source_outdated_help": "Shows the last captured image while live rendering updates or is unavailable. It may differ from the current scene or image settings.",
"render.live.source_settings_help": "Open Output to edit the renderer and image settings."
},
"he": {
"render.live.source_current": "{method} · חי",
"render.live.source_outdated": "{method} · תמונה קודמת",
"render.live.source_outdated_help": "מציג את התמונה האחרונה שנלכדה בזמן שההדמיה החיה מתעדכנת או אינה זמינה. היא עשויה להיות שונה מהסצנה או מהגדרות התמונה הנוכחיות.",
"render.live.source_settings_help": "יש לפתוח את חלונית הפלט כדי לערוך את מנוע ההדמיה ואת הגדרות התמונה."
},
"ja": {
"render.live.source_current": "{method} · ライブ",
"render.live.source_outdated": "{method} · 前の画像",
"render.live.source_outdated_help": "ライブレンダリングの更新中や利用できない間は、最後に取得した画像を表示します。現在のシーンや画像設定とは異なる場合があります。",
"render.live.source_settings_help": "出力を開いてレンダラーと画像設定を編集します。"
},
"ko": {
"render.live.source_current": "{method} · 라이브",
"render.live.source_outdated": "{method} · 이전 이미지",
"render.live.source_outdated_help": "라이브 렌더링이 업데이트 중이거나 사용할 수 없는 동안 마지막으로 캡처한 이미지를 표시합니다. 현재 장면 또는 이미지 설정과 다를 수 있습니다.",
"render.live.source_settings_help": "출력을 열어 렌더러와 이미지 설정을 편집합니다."
},
"vi": {
"render.live.source_current": "{method} · Trực tiếp",
"render.live.source_outdated": "{method} · Ảnh trước",
"render.live.source_outdated_help": "Hiển thị ảnh đã chụp gần nhất trong khi kết xuất trực tiếp đang cập nhật hoặc không khả dụng. Ảnh có thể khác cảnh hoặc thiết lập ảnh hiện tại.",
"render.live.source_settings_help": "Mở mục Đầu ra để sửa bộ kết xuất và thiết lập ảnh."
},
"zh": {
"render.live.source_current": "{method} · 实时",
"render.live.source_outdated": "{method} · 上一幅图像",
"render.live.source_outdated_help": "实时渲染更新或不可用时显示上次捕获的图像。它可能与当前场景或图像设置不同。",
"render.live.source_settings_help": "打开输出以编辑渲染器和图像设置。"
}
}
@@ -1,34 +0,0 @@
{
"ar": {
"prefs.layout_page.hover_panel_menus": "تبديل قوائم اللوحات عند مرور المؤشر",
"prefs.layout_page.hover_panel_menus_help": "انقر على اسم لوحة في الشريط لفتح قائمتها. مرّر المؤشر فوق اسم لوحة أخرى للتبديل. حرّك المؤشر خارج الشريط والقائمة المفتوحة لإغلاقها."
},
"de": {
"prefs.layout_page.hover_panel_menus": "Bereichsmenüs beim Darüberfahren wechseln",
"prefs.layout_page.hover_panel_menus_help": "Klicken Sie auf einen Bereichsnamen, um das Menü zu öffnen. Bewegen Sie den Zeiger auf einen anderen Bereichsnamen, um das Menü zu wechseln. Außerhalb des Menübands und des geöffneten Menüs schließt es sich."
},
"en": {
"prefs.layout_page.hover_panel_menus": "Switch panel menus on hover",
"prefs.layout_page.hover_panel_menus_help": "Click a ribbon panel name to open its menu. Hover another panel name to switch. Move outside the ribbon and open menu to close it."
},
"he": {
"prefs.layout_page.hover_panel_menus": "מעבר בין תפריטי לוחות בריחוף",
"prefs.layout_page.hover_panel_menus_help": "לחצו על שם לוח ברצועת הכלים כדי לפתוח את התפריט שלו. העבירו את הסמן מעל שם של לוח אחר כדי לעבור לתפריט שלו. הזיזו את הסמן אל מחוץ לרצועת הכלים ולתפריט הפתוח כדי לסגור אותו."
},
"ja": {
"prefs.layout_page.hover_panel_menus": "ポイントしてパネルメニューを切り替える",
"prefs.layout_page.hover_panel_menus_help": "リボンのパネル名をクリックしてメニューを開きます。別のパネル名にポインターを合わせると切り替わります。リボンと開いているメニューの外に移動すると閉じます。"
},
"ko": {
"prefs.layout_page.hover_panel_menus": "포인터를 올려 패널 메뉴 전환",
"prefs.layout_page.hover_panel_menus_help": "리본의 패널 이름을 클릭하여 메뉴를 엽니다. 다른 패널 이름에 포인터를 올리면 메뉴가 전환됩니다. 리본과 열린 메뉴 밖으로 포인터를 이동하면 메뉴가 닫힙니다."
},
"vi": {
"prefs.layout_page.hover_panel_menus": "Chuyển menu nhóm khi di chuột",
"prefs.layout_page.hover_panel_menus_help": "Nhấp vào tên nhóm trên dải công cụ để mở menu. Di chuột lên tên nhóm khác để chuyển menu. Di chuyển con trỏ ra ngoài dải công cụ và menu đang mở để đóng menu."
},
"zh": {
"prefs.layout_page.hover_panel_menus": "悬停切换面板菜单",
"prefs.layout_page.hover_panel_menus_help": "点击功能区的面板名称打开菜单。将指针悬停在另一面板名称上即可切换菜单。将指针移到功能区和已打开菜单之外即可关闭菜单。"
}
}
@@ -1,26 +0,0 @@
{
"en": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "The origin axis is perpendicular to the sketch plane, so it has no line in the plane"
},
"ar": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "محور الأصل عمودي على مستوى الرسم، لذا ليس له خط في المستوى"
},
"de": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "Die Ursprungsachse steht senkrecht auf der Skizzenebene und hat daher keine Linie in ihr"
},
"he": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "ציר הראשית ניצב למישור הסקיצה, ולכן אין לו קו במישור"
},
"ja": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "原点軸はスケッチ平面に垂直なため、平面内に線がありません"
},
"ru": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "Ось начала координат перпендикулярна плоскости эскиза, поэтому линии в этой плоскости нет"
},
"vi": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "Trục gốc vuông góc với mặt phẳng phác thảo nên không có đường thẳng trong mặt phẳng này"
},
"zh": {
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "原点轴垂直于草图平面,因此在该平面内没有直线"
}
}
+8
View File
@@ -433,6 +433,7 @@
"Select bodies (a face picks its body)": "Selecione corpos (uma face seleciona seu corpo)", "Select bodies (a face picks its body)": "Selecione corpos (uma face seleciona seu corpo)",
"Select bodies or faces instead": "Selecionar corpos ou faces em vez disso", "Select bodies or faces instead": "Selecionar corpos ou faces em vez disso",
"Select edges": "Selecione arestas", "Select edges": "Selecione arestas",
"Select the curves to divide first": "Selecione primeiro as curvas a dividir",
"Selection filter": "Filtro de seleção", "Selection filter": "Filtro de seleção",
"Semantic faces share their appearance across instances.": "Faces semânticas compartilham a aparência entre instâncias.", "Semantic faces share their appearance across instances.": "Faces semânticas compartilham a aparência entre instâncias.",
"Send your report on GitHub": "Envie seu relatório no GitHub", "Send your report on GitHub": "Envie seu relatório no GitHub",
@@ -878,6 +879,7 @@
"cmd.sketch_options": "Opções da paleta de esboço", "cmd.sketch_options": "Opções da paleta de esboço",
"cmd.sketch_paste": "Colar entidades do esboço", "cmd.sketch_paste": "Colar entidades do esboço",
"cmd.sketch_point3d": "Ponto 3D", "cmd.sketch_point3d": "Ponto 3D",
"cmd.sketch_point_divide": "Dividir curva",
"cmd.sketch_polygon_circumscribed": "Polígono circunscrito", "cmd.sketch_polygon_circumscribed": "Polígono circunscrito",
"cmd.sketch_polygon_edge": "Polígono por aresta", "cmd.sketch_polygon_edge": "Polígono por aresta",
"cmd.sketch_polygon_inscribed": "Polígono inscrito", "cmd.sketch_polygon_inscribed": "Polígono inscrito",
@@ -1055,6 +1057,7 @@
"help.licences": "Licenças", "help.licences": "Licenças",
"help.mit": "Licença MIT", "help.mit": "Licença MIT",
"help.notice": "NOTICE", "help.notice": "NOTICE",
"help.sketch.point.divide": "Coloca pontos que dividem as curvas escolhidas em comprimentos iguais. Os pontos ficam em cada curva e mantêm o espaçamento quando ela muda.",
"help.solid.chamfer": "Corta as arestas selecionadas com um bisel plano na distância que você definir. Use para quebrar arestas vivas ou facilitar a entrada de um pino ou parafuso.", "help.solid.chamfer": "Corta as arestas selecionadas com um bisel plano na distância que você definir. Use para quebrar arestas vivas ou facilitar a entrada de um pino ou parafuso.",
"help.solid.extrude": "Empurra um perfil de esboço para o 3D ao longo de uma distância, adicionando ou removendo material. Use para transformar um contorno plano em um bloco, um ressalto ou um rebaixo.", "help.solid.extrude": "Empurra um perfil de esboço para o 3D ao longo de uma distância, adicionando ou removendo material. Use para transformar um contorno plano em um bloco, um ressalto ou um rebaixo.",
"help.solid.fillet": "Arredonda as arestas selecionadas com uma concordância circular suave do raio que você definir. Use para suavizar arestas vivas, por resistência, conforto ou aparência.", "help.solid.fillet": "Arredonda as arestas selecionadas com uma concordância circular suave do raio que você definir. Use para suavizar arestas vivas, por resistência, conforto ou aparência.",
@@ -1408,6 +1411,8 @@
"sample.plate.name": "Placa de exemplo", "sample.plate.name": "Placa de exemplo",
"sample.vents.about": "Rasgos em padrão retangular: linhas, colunas e passo são parâmetros", "sample.vents.about": "Rasgos em padrão retangular: linhas, colunas e passo são parâmetros",
"sample.vents.name": "Placa de ventilação", "sample.vents.name": "Placa de ventilação",
"scale.per_axis": "Por eixo",
"scale.uniform": "Uniforme",
"search.command_keys": "Enter executar Shift+Enter executar e manter aberto Esc fechar", "search.command_keys": "Enter executar Shift+Enter executar e manter aberto Esc fechar",
"search.commands": "Comandos", "search.commands": "Comandos",
"search.design": "Neste projeto", "search.design": "Neste projeto",
@@ -1439,6 +1444,7 @@
"shortcut.pin": "Fixar no topo da caixa S", "shortcut.pin": "Fixar no topo da caixa S",
"shortcut.unpin": "Desafixar", "shortcut.unpin": "Desafixar",
"sketch.degrees_of_freedom": "{count} graus de liberdade", "sketch.degrees_of_freedom": "{count} graus de liberdade",
"sketch.divide_hint": "Os pontos dividem cada curva em comprimentos iguais e os mantêm quando ela muda.",
"sketch.dof_left": "{count} graus de liberdade restantes", "sketch.dof_left": "{count} graus de liberdade restantes",
"sketch.dof_left_one": "{count} grau de liberdade restante", "sketch.dof_left_one": "{count} grau de liberdade restante",
"sketch.draw_curves": "Desenhar como {linetype}", "sketch.draw_curves": "Desenhar como {linetype}",
@@ -2015,6 +2021,7 @@
"ui.heading_create_sketch": "CRIAR ESBOÇO", "ui.heading_create_sketch": "CRIAR ESBOÇO",
"ui.heading_cylinder": "CILINDRO", "ui.heading_cylinder": "CILINDRO",
"ui.heading_design": "PROJETO", "ui.heading_design": "PROJETO",
"ui.heading_divide_curve": "DIVIDIR CURVA",
"ui.heading_draft": "ÂNGULO DE SAÍDA", "ui.heading_draft": "ÂNGULO DE SAÍDA",
"ui.heading_edit": "EDITAR", "ui.heading_edit": "EDITAR",
"ui.heading_extrude": "EXTRUDAR", "ui.heading_extrude": "EXTRUDAR",
@@ -2272,6 +2279,7 @@
"ui.scale": "Escala", "ui.scale": "Escala",
"ui.second_rail": "Segundo trilho", "ui.second_rail": "Segundo trilho",
"ui.section_analysis": "Análise de seção", "ui.section_analysis": "Análise de seção",
"ui.segments": "Segmentos",
"ui.select": "Selecionar", "ui.select": "Selecionar",
"ui.selectOther": "Selecionar outro…", "ui.selectOther": "Selecionar outro…",
"ui.selectTangentChain": "Selecionar cadeia tangente", "ui.selectTangentChain": "Selecionar cadeia tangente",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Citește traseele unui desen SVG într-o schiță, scalate, rotite și plasate așa cum stabiliți. Folosiți-o pentru a transforma un logo sau un contur vectorial în curbe pe care le puteți extruda.", "help.sketch.insert_svg": "Citește traseele unui desen SVG într-o schiță, scalate, rotite și plasate așa cum stabiliți. Folosiți-o pentru a transforma un logo sau un contur vectorial în curbe pe care le puteți extruda.",
"help.sketch.inspect": "Deschide un raport despre schița deschisă: câte grade de libertate au rămas și dacă este complet constrânsă. Folosiți-l pentru a afla ce se mai mișcă înainte de a finaliza schița.", "help.sketch.inspect": "Deschide un raport despre schița deschisă: câte grade de libertate au rămas și dacă este complet constrânsă. Folosiți-l pentru a afla ce se mai mișcă înainte de a finaliza schița.",
"help.sketch.intersect": "Adaugă curbele sau punctele în care corpuri, fețe, muchii sau alte schițe taie planul schiței. Rămân legate și urmează modelul când acesta se schimbă.", "help.sketch.intersect": "Adaugă curbele sau punctele în care corpuri, fețe, muchii sau alte schițe taie planul schiței. Rămân legate și urmează modelul când acesta se schimbă.",
"help.sketch.intersection_curve": "Creează curbe 3D acolo unde se întâlnesc două corpuri sau fețe, legate de ele. Folosiți-le ca trasee sau ghidaje care urmează modelul.", "help.sketch.intersection_curve": "Creează curbe 3D acolo unde se întâlnesc două corpuri, fețe sau curbe ale altor schițe, legate de ele. Folosiți-le ca trasee sau ghidaje care urmează modelul.",
"help.sketch.isoparametric_curve": "Creează o curbă 3D pe direcția U sau V a unei fețe, printr-un punct ales de dumneavoastră, legată de față. Folosiți-o ca traseu sau linie de separare care urmează suprafața.", "help.sketch.isoparametric_curve": "Creează o curbă 3D pe direcția U sau V a unei fețe, printr-un punct ales de dumneavoastră, legată de față. Folosiți-o ca traseu sau linie de separare care urmează suprafața.",
"help.sketch.line": "Desenează linii conectate punct cu punct, ca lanț deschis sau contur închis. Este instrumentul de bază pentru majoritatea profilurilor.", "help.sketch.line": "Desenează linii conectate punct cu punct, ca lanț deschis sau contur închis. Este instrumentul de bază pentru majoritatea profilurilor.",
"help.sketch.line.midpoint": "Desenează o linie de la mijlocul ei spre un capăt, celălalt capăt fiind în oglindă. Folosiți-o pentru linii centrate pe un punct, de exemplu o muchie simetrică.", "help.sketch.line.midpoint": "Desenează o linie de la mijlocul ei spre un capăt, celălalt capăt fiind în oglindă. Folosiți-o pentru linii centrate pe un punct, de exemplu o muchie simetrică.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Placă exemplu", "sample.plate.name": "Placă exemplu",
"sample.vents.about": "Canale într-o matrice dreptunghiulară: rândurile, coloanele și pasul sunt parametri", "sample.vents.about": "Canale într-o matrice dreptunghiulară: rândurile, coloanele și pasul sunt parametri",
"sample.vents.name": "Placă de ventilație", "sample.vents.name": "Placă de ventilație",
"scale.per_axis": "Pe axe",
"scale.uniform": "Uniform",
"search.command_keys": "Enter execută Shift+Enter execută și păstrează deschis Esc închide", "search.command_keys": "Enter execută Shift+Enter execută și păstrează deschis Esc închide",
"search.commands": "Comenzi", "search.commands": "Comenzi",
"search.design": "În acest proiect", "search.design": "În acest proiect",
+10 -1
View File
@@ -567,6 +567,7 @@
"Select edges": "Выберите рёбра", "Select edges": "Выберите рёбра",
"Select points of the sketch being edited": "Выберите точки редактируемого эскиза", "Select points of the sketch being edited": "Выберите точки редактируемого эскиза",
"Select the centre the pattern turns around first": "Сначала выберите центр, вокруг которого поворачивается массив", "Select the centre the pattern turns around first": "Сначала выберите центр, вокруг которого поворачивается массив",
"Select the curves to divide first": "Сначала выберите кривые для деления",
"Select the curves to offset first": "Сначала выберите кривые для смещения", "Select the curves to offset first": "Сначала выберите кривые для смещения",
"Select the mirror line": "Выберите линию зеркала", "Select the mirror line": "Выберите линию зеркала",
"Select the sketch curves or points to mirror first": "Сначала выберите кривые или точки эскиза для зеркального отражения", "Select the sketch curves or points to mirror first": "Сначала выберите кривые или точки эскиза для зеркального отражения",
@@ -647,6 +648,7 @@
"The direction must be an axis or a straight sketch curve that lies in the sketch plane": "Направление должно быть осью или прямолинейной кривой эскиза, лежащей в плоскости эскиза", "The direction must be an axis or a straight sketch curve that lies in the sketch plane": "Направление должно быть осью или прямолинейной кривой эскиза, лежащей в плоскости эскиза",
"The mirror line cannot also be mirrored": "Линию зеркала нельзя одновременно отражать", "The mirror line cannot also be mirrored": "Линию зеркала нельзя одновременно отражать",
"The mirror line must be a straight curve of this sketch, not an origin axis": "Линия зеркала должна быть прямолинейной кривой этого эскиза, а не осью начала координат", "The mirror line must be a straight curve of this sketch, not an origin axis": "Линия зеркала должна быть прямолинейной кривой этого эскиза, а не осью начала координат",
"The origin axis is perpendicular to the sketch plane, so it has no line in the plane": "Ось начала координат перпендикулярна плоскости эскиза, поэтому линии в этой плоскости нет",
"The saved author occurrence is missing. Select a valid author placement before rebinding.": "Сохранённое исходное вхождение отсутствует. Выберите корректное исходное положение перед перепривязкой.", "The saved author occurrence is missing. Select a valid author placement before rebinding.": "Сохранённое исходное вхождение отсутствует. Выберите корректное исходное положение перед перепривязкой.",
"Then": "Затем", "Then": "Затем",
"These features will be deleted:": "Эти операции будут удалены:", "These features will be deleted:": "Эти операции будут удалены:",
@@ -1184,6 +1186,7 @@
"cmd.sketch_options": "Параметры палитры эскиза", "cmd.sketch_options": "Параметры палитры эскиза",
"cmd.sketch_paste": "Вставить элементы эскиза", "cmd.sketch_paste": "Вставить элементы эскиза",
"cmd.sketch_point3d": "3D-точка", "cmd.sketch_point3d": "3D-точка",
"cmd.sketch_point_divide": "Разделить кривую",
"cmd.sketch_polygon_circumscribed": "Описанный многоугольник", "cmd.sketch_polygon_circumscribed": "Описанный многоугольник",
"cmd.sketch_polygon_edge": "Многоугольник по ребру", "cmd.sketch_polygon_edge": "Многоугольник по ребру",
"cmd.sketch_polygon_inscribed": "Вписанный многоугольник", "cmd.sketch_polygon_inscribed": "Вписанный многоугольник",
@@ -1610,7 +1613,7 @@
"help.sketch.insert_svg": "Читает контуры рисунка SVG в эскиз, масштабируя, поворачивая и размещая их так, как вы зададите. Используйте, чтобы превратить логотип или векторный контур в кривые, которые можно выдавить.", "help.sketch.insert_svg": "Читает контуры рисунка SVG в эскиз, масштабируя, поворачивая и размещая их так, как вы зададите. Используйте, чтобы превратить логотип или векторный контур в кривые, которые можно выдавить.",
"help.sketch.inspect": "Открывает отчёт об открытом эскизе: сколько осталось степеней свободы и определён ли он полностью. Используйте, чтобы выяснить, что ещё двигается, прежде чем завершить эскиз.", "help.sketch.inspect": "Открывает отчёт об открытом эскизе: сколько осталось степеней свободы и определён ли он полностью. Используйте, чтобы выяснить, что ещё двигается, прежде чем завершить эскиз.",
"help.sketch.intersect": "Добавляет кривые или точки, где тела, грани, рёбра или другие эскизы пересекают плоскость эскиза. Они остаются связанными и следуют за моделью при её изменении.", "help.sketch.intersect": "Добавляет кривые или точки, где тела, грани, рёбра или другие эскизы пересекают плоскость эскиза. Они остаются связанными и следуют за моделью при её изменении.",
"help.sketch.intersection_curve": "Создаёт 3D-кривые там, где встречаются два тела или две грани, связанные с ними. Используйте как траектории или направляющие, следующие за моделью.", "help.sketch.intersection_curve": "Создаёт 3D-кривые там, где встречаются два тела, две грани или кривые других эскизов, связанные с ними. Используйте как траектории или направляющие, следующие за моделью.",
"help.sketch.isoparametric_curve": "Создаёт 3D-кривую вдоль направления U или V грани через выбранную точку, связанную с гранью. Используйте как траекторию или линию разделения, следующую за поверхностью.", "help.sketch.isoparametric_curve": "Создаёт 3D-кривую вдоль направления U или V грани через выбранную точку, связанную с гранью. Используйте как траекторию или линию разделения, следующую за поверхностью.",
"help.sketch.line": "Рисует соединённые линии точка за точкой, как открытую цепочку или замкнутый контур. Это основной инструмент для большинства профилей.", "help.sketch.line": "Рисует соединённые линии точка за точкой, как открытую цепочку или замкнутый контур. Это основной инструмент для большинства профилей.",
"help.sketch.line.midpoint": "Рисует линию от её середины до одного конца, второй конец отражается зеркально. Используйте для линий с центром в точке, например симметричного ребра.", "help.sketch.line.midpoint": "Рисует линию от её середины до одного конца, второй конец отражается зеркально. Используйте для линий с центром в точке, например симметричного ребра.",
@@ -1622,6 +1625,7 @@
"help.sketch.pattern.circular": "Копирует геометрию эскиза вокруг центральной точки на полный круг или заданный угол. Используйте для окружностей болтов, спиц и зубьев.", "help.sketch.pattern.circular": "Копирует геометрию эскиза вокруг центральной точки на полный круг или заданный угол. Используйте для окружностей болтов, спиц и зубьев.",
"help.sketch.pattern.rectangular": "Копирует геометрию эскиза рядами и столбцами с заданным шагом. Используйте для сеток отверстий, пазов или вентиляционных прорезей.", "help.sketch.pattern.rectangular": "Копирует геометрию эскиза рядами и столбцами с заданным шагом. Используйте для сеток отверстий, пазов или вентиляционных прорезей.",
"help.sketch.point": "Ставит точку эскиза. Используйте как ориентир для размеров, ограничений, центров отверстий или последующих операций.", "help.sketch.point": "Ставит точку эскиза. Используйте как ориентир для размеров, ограничений, центров отверстий или последующих операций.",
"help.sketch.point.divide": "Ставит точки, делящие выбранные кривые на равные по длине части. Точки остаются на каждой кривой и сохраняют шаг при её изменении.",
"help.sketch.point3d": "Ставит точку в пространстве при включённом 3D-эскизе. Используйте как ориентир для 3D-кривых и траекторий.", "help.sketch.point3d": "Ставит точку в пространстве при включённом 3D-эскизе. Используйте как ориентир для 3D-кривых и траекторий.",
"help.sketch.polygon.circumscribed": "Рисует правильный многоугольник вокруг окружности; размер задаётся от центра до середины стороны. Используйте, когда известен размер под ключ, например у шестигранной гайки.", "help.sketch.polygon.circumscribed": "Рисует правильный многоугольник вокруг окружности; размер задаётся от центра до середины стороны. Используйте, когда известен размер под ключ, например у шестигранной гайки.",
"help.sketch.polygon.edge": "Рисует правильный многоугольник по двум концам одной стороны. Используйте, когда известны длина и положение стороны.", "help.sketch.polygon.edge": "Рисует правильный многоугольник по двум концам одной стороны. Используйте, когда известны длина и положение стороны.",
@@ -3750,6 +3754,8 @@
"sample.plate.name": "Образец пластины", "sample.plate.name": "Образец пластины",
"sample.vents.about": "Пазы в прямоугольном массиве: число рядов, столбцов и шаг заданы параметрами", "sample.vents.about": "Пазы в прямоугольном массиве: число рядов, столбцов и шаг заданы параметрами",
"sample.vents.name": "Вентиляционная пластина", "sample.vents.name": "Вентиляционная пластина",
"scale.per_axis": "По осям",
"scale.uniform": "Равномерно",
"search.command_keys": "Enter выполнить Shift+Enter выполнить и оставить открытым Esc закрыть", "search.command_keys": "Enter выполнить Shift+Enter выполнить и оставить открытым Esc закрыть",
"search.commands": "Команды", "search.commands": "Команды",
"search.design": "В этом дизайне", "search.design": "В этом дизайне",
@@ -3837,6 +3843,7 @@
"sketch.dimension_applied": "Размер применён", "sketch.dimension_applied": "Размер применён",
"sketch.dimension_applied_defined": "Размер применён; параметр `{name}` определён", "sketch.dimension_applied_defined": "Размер применён; параметр `{name}` определён",
"sketch.dimension_applied_renamed": "Размер применён; параметру присвоено имя `{name}`", "sketch.dimension_applied_renamed": "Размер применён; параметру присвоено имя `{name}`",
"sketch.divide_hint": "Точки делят каждую кривую на равные по длине части и сохраняют их при её изменении.",
"sketch.dof_left": "Осталось степеней свободы: {count}", "sketch.dof_left": "Осталось степеней свободы: {count}",
"sketch.dof_left_one": "Осталась {count} степень свободы", "sketch.dof_left_one": "Осталась {count} степень свободы",
"sketch.draw_curves": "Рисовать как {linetype}", "sketch.draw_curves": "Рисовать как {linetype}",
@@ -4626,6 +4633,7 @@
"ui.heading_create_sketch": "СОЗДАТЬ ЭСКИЗ", "ui.heading_create_sketch": "СОЗДАТЬ ЭСКИЗ",
"ui.heading_cylinder": "ЦИЛИНДР", "ui.heading_cylinder": "ЦИЛИНДР",
"ui.heading_design": "ДИЗАЙН", "ui.heading_design": "ДИЗАЙН",
"ui.heading_divide_curve": "РАЗДЕЛИТЬ КРИВУЮ",
"ui.heading_draft": "УКЛОН", "ui.heading_draft": "УКЛОН",
"ui.heading_edit": "ИЗМЕНИТЬ", "ui.heading_edit": "ИЗМЕНИТЬ",
"ui.heading_equation_curve": "КРИВАЯ ПО УРАВНЕНИЮ", "ui.heading_equation_curve": "КРИВАЯ ПО УРАВНЕНИЮ",
@@ -4953,6 +4961,7 @@
"ui.second_rail": "Вторая направляющая", "ui.second_rail": "Вторая направляющая",
"ui.section_analysis": "Анализ сечения", "ui.section_analysis": "Анализ сечения",
"ui.section_size": "Размер сечения", "ui.section_size": "Размер сечения",
"ui.segments": "Сегменты",
"ui.select": "Выбрать", "ui.select": "Выбрать",
"ui.selectOther": "Выбрать другое…", "ui.selectOther": "Выбрать другое…",
"ui.selectTangentChain": "Выбрать касательную цепочку", "ui.selectTangentChain": "Выбрать касательную цепочку",
+1 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Учитава путање SVG цртежа у скицу, скалиране, окренуте и постављене како зададете. Користите га да логотип или векторски обрис претворите у криве које можете екструдирати.", "help.sketch.insert_svg": "Учитава путање SVG цртежа у скицу, скалиране, окренуте и постављене како зададете. Користите га да логотип или векторски обрис претворите у криве које можете екструдирати.",
"help.sketch.inspect": "Отвара извештај о отвореној скици: колико је степени слободе остало и да ли је потпуно ограничена. Користите га да сазнате шта се још помера пре него што завршите скицу.", "help.sketch.inspect": "Отвара извештај о отвореној скици: колико је степени слободе остало и да ли је потпуно ограничена. Користите га да сазнате шта се још помера пре него што завршите скицу.",
"help.sketch.intersect": "Додаје криве или тачке у којима тела, лица, ивице или друге скице секу раван скице. Оне остају повезане и прате модел када се он промени.", "help.sketch.intersect": "Додаје криве или тачке у којима тела, лица, ивице или друге скице секу раван скице. Оне остају повезане и прате модел када се он промени.",
"help.sketch.intersection_curve": "Прави 3D криве тамо где се два тела или лица састају, повезане са њима. Користите их као путање или водилице које прате модел.", "help.sketch.intersection_curve": "Прави 3D криве тамо где се два тела, лица или криве других скица састају, повезане са њима. Користите их као путање или водилице које прате модел.",
"help.sketch.isoparametric_curve": "Прави 3D криву дуж U или V смера лица кроз тачку коју изаберете, повезану са лицем. Користите је као путању или линију поделе која прати површ.", "help.sketch.isoparametric_curve": "Прави 3D криву дуж U или V смера лица кроз тачку коју изаберете, повезану са лицем. Користите је као путању или линију поделе која прати површ.",
"help.sketch.line": "Црта повезане линије тачку по тачку, као отворени ланац или затворени обрис. То је основни алат за већину профила.", "help.sketch.line": "Црта повезане линије тачку по тачку, као отворени ланац или затворени обрис. То је основни алат за већину профила.",
"help.sketch.line.midpoint": "Црта линију од њене средишње тачке до једног краја, а други крај се пресликава. Користите је за линије центриране на тачки, на пример за симетричну ивицу.", "help.sketch.line.midpoint": "Црта линију од њене средишње тачке до једног краја, а други крај се пресликава. Користите је за линије центриране на тачки, на пример за симетричну ивицу.",
+3 -1
View File
@@ -1622,7 +1622,7 @@
"help.sketch.insert_svg": "Läser in banorna från en SVG-ritning i en skiss, skalade, vridna och placerade där du anger. Använd det för att göra en logotyp eller en vektorkontur till kurvor som du kan extrudera.", "help.sketch.insert_svg": "Läser in banorna från en SVG-ritning i en skiss, skalade, vridna och placerade där du anger. Använd det för att göra en logotyp eller en vektorkontur till kurvor som du kan extrudera.",
"help.sketch.inspect": "Öppnar en rapport om den öppna skissen: hur många frihetsgrader som återstår och om den är fullt definierad. Använd det för att ta reda på vad som fortfarande rör sig innan du avslutar skissen.", "help.sketch.inspect": "Öppnar en rapport om den öppna skissen: hur många frihetsgrader som återstår och om den är fullt definierad. Använd det för att ta reda på vad som fortfarande rör sig innan du avslutar skissen.",
"help.sketch.intersect": "Lägger till de kurvor eller punkter där kroppar, ytor, kanter eller andra skisser korsar skissplanet. De förblir länkade och följer modellen när den ändras.", "help.sketch.intersect": "Lägger till de kurvor eller punkter där kroppar, ytor, kanter eller andra skisser korsar skissplanet. De förblir länkade och följer modellen när den ändras.",
"help.sketch.intersection_curve": "Skapar 3D-kurvor där två kroppar eller ytor möts, länkade till dem. Använd dem som banor eller styrkurvor som följer modellen.", "help.sketch.intersection_curve": "Skapar 3D-kurvor där två kroppar, ytor eller kurvor från andra skisser möts, länkade till dem. Använd dem som banor eller styrkurvor som följer modellen.",
"help.sketch.isoparametric_curve": "Skapar en 3D-kurva längs en ytas U- eller V-riktning genom en punkt som du väljer, länkad till ytan. Använd den som en bana eller delningslinje som följer ytan.", "help.sketch.isoparametric_curve": "Skapar en 3D-kurva längs en ytas U- eller V-riktning genom en punkt som du väljer, länkad till ytan. Använd den som en bana eller delningslinje som följer ytan.",
"help.sketch.line": "Ritar sammanhängande linjer punkt för punkt, som en öppen kedja eller en sluten kontur. Det är det grundläggande verktyget för de flesta profiler.", "help.sketch.line": "Ritar sammanhängande linjer punkt för punkt, som en öppen kedja eller en sluten kontur. Det är det grundläggande verktyget för de flesta profiler.",
"help.sketch.line.midpoint": "Ritar en linje från dess mittpunkt ut till ena änden, med den andra änden speglad. Använd det för linjer centrerade på en punkt, till exempel en symmetrisk kant.", "help.sketch.line.midpoint": "Ritar en linje från dess mittpunkt ut till ena änden, med den andra änden speglad. Använd det för linjer centrerade på en punkt, till exempel en symmetrisk kant.",
@@ -3808,6 +3808,8 @@
"sample.plate.name": "Exempelplatta", "sample.plate.name": "Exempelplatta",
"sample.vents.about": "Spår i ett rektangulärt mönster: rader, kolumner och delning är parametrar", "sample.vents.about": "Spår i ett rektangulärt mönster: rader, kolumner och delning är parametrar",
"sample.vents.name": "Ventilationsplatta", "sample.vents.name": "Ventilationsplatta",
"scale.per_axis": "Per axel",
"scale.uniform": "Likformig",
"search.command_keys": "Enter kör Shift+Enter kör och behåll öppen Esc stäng", "search.command_keys": "Enter kör Shift+Enter kör och behåll öppen Esc stäng",
"search.commands": "Kommandon", "search.commands": "Kommandon",
"search.design": "I denna konstruktion", "search.design": "I denna konstruktion",
+3 -1
View File
@@ -1621,7 +1621,7 @@
"help.sketch.insert_svg": "Bir SVG çiziminin yollarını, belirlediğiniz ölçekte, açıda ve konumda bir eskize okur. Bir logoyu veya vektör dış hattını ekstrüzyon yapabileceğiniz eğrilere dönüştürmek için kullanın.", "help.sketch.insert_svg": "Bir SVG çiziminin yollarını, belirlediğiniz ölçekte, açıda ve konumda bir eskize okur. Bir logoyu veya vektör dış hattını ekstrüzyon yapabileceğiniz eğrilere dönüştürmek için kullanın.",
"help.sketch.inspect": "Açık eskiz için bir rapor açar: kaç serbestlik derecesi kaldığını ve tam kısıtlı olup olmadığını. Eskizi bitirmeden önce nelerin hâlâ hareket ettiğini öğrenmek için kullanın.", "help.sketch.inspect": "Açık eskiz için bir rapor açar: kaç serbestlik derecesi kaldığını ve tam kısıtlı olup olmadığını. Eskizi bitirmeden önce nelerin hâlâ hareket ettiğini öğrenmek için kullanın.",
"help.sketch.intersect": "Gövdelerin, yüzlerin, kenarların veya diğer eskizlerin eskiz düzlemini kestiği eğrileri ya da noktaları ekler. Bağlı kalır ve model değiştiğinde onu izler.", "help.sketch.intersect": "Gövdelerin, yüzlerin, kenarların veya diğer eskizlerin eskiz düzlemini kestiği eğrileri ya da noktaları ekler. Bağlı kalır ve model değiştiğinde onu izler.",
"help.sketch.intersection_curve": "İki gövdenin veya yüzün buluştuğu yerde, onlara bağlı 3B eğriler oluşturur. Bunları modeli izleyen yollar veya kılavuz raylar olarak kullanın.", "help.sketch.intersection_curve": "İki gövdenin, yüzün veya diğer eskizlerin eğrilerinin buluştuğu yerde, onlara bağlı 3B eğriler oluşturur. Bunları modeli izleyen yollar veya kılavuz raylar olarak kullanın.",
"help.sketch.isoparametric_curve": "Bir yüzün U veya V yönü boyunca, seçtiğiniz bir noktadan geçen ve yüze bağlı bir 3B eğri oluşturur. Yüzeyi izleyen bir yol veya bölme çizgisi olarak kullanın.", "help.sketch.isoparametric_curve": "Bir yüzün U veya V yönü boyunca, seçtiğiniz bir noktadan geçen ve yüze bağlı bir 3B eğri oluşturur. Yüzeyi izleyen bir yol veya bölme çizgisi olarak kullanın.",
"help.sketch.line": "Bağlantılı çizgileri nokta nokta, açık bir zincir veya kapalı bir dış hat olarak çizer. Çoğu profil için temel araçtır.", "help.sketch.line": "Bağlantılı çizgileri nokta nokta, açık bir zincir veya kapalı bir dış hat olarak çizer. Çoğu profil için temel araçtır.",
"help.sketch.line.midpoint": "Bir çizgiyi orta noktasından bir uca doğru çizer; diğer uç yansıtılır. Bir nokta etrafında ortalanmış çizgiler, örneğin simetrik bir kenar için kullanın.", "help.sketch.line.midpoint": "Bir çizgiyi orta noktasından bir uca doğru çizer; diğer uç yansıtılır. Bir nokta etrafında ortalanmış çizgiler, örneğin simetrik bir kenar için kullanın.",
@@ -3807,6 +3807,8 @@
"sample.plate.name": "Örnek plaka", "sample.plate.name": "Örnek plaka",
"sample.vents.about": "Dikdörtgen desende yuvalar: satırlar, sütunlar ve aralık parametredir", "sample.vents.about": "Dikdörtgen desende yuvalar: satırlar, sütunlar ve aralık parametredir",
"sample.vents.name": "Havalandırma plakası", "sample.vents.name": "Havalandırma plakası",
"scale.per_axis": "Eksen başına",
"scale.uniform": "Tekdüze",
"search.command_keys": "Enter çalıştır Shift+Enter çalıştır ve açık tut Esc kapat", "search.command_keys": "Enter çalıştır Shift+Enter çalıştır ve açık tut Esc kapat",
"search.commands": "Komutlar", "search.commands": "Komutlar",
"search.design": "Bu tasarımda", "search.design": "Bu tasarımda",
+3 -1
View File
@@ -1681,7 +1681,7 @@
"help.sketch.insert_svg": "Зчитує контури малюнка SVG в ескіз, масштабовані, повернуті й розміщені так, як ви задасте. Використовуйте, щоб перетворити логотип або векторний контур на криві, які можна видавити.", "help.sketch.insert_svg": "Зчитує контури малюнка SVG в ескіз, масштабовані, повернуті й розміщені так, як ви задасте. Використовуйте, щоб перетворити логотип або векторний контур на криві, які можна видавити.",
"help.sketch.inspect": "Відкриває звіт про відкритий ескіз: скільки ступенів вільності залишилося і чи він повністю обмежений. Використовуйте його, щоб дізнатися, що ще рухається, перш ніж завершити ескіз.", "help.sketch.inspect": "Відкриває звіт про відкритий ескіз: скільки ступенів вільності залишилося і чи він повністю обмежений. Використовуйте його, щоб дізнатися, що ще рухається, перш ніж завершити ескіз.",
"help.sketch.intersect": "Додає криві чи точки, де тіла, грані, ребра або інші ескізи перетинають площину ескізу. Вони залишаються пов'язаними й слідують за моделлю, коли вона змінюється.", "help.sketch.intersect": "Додає криві чи точки, де тіла, грані, ребра або інші ескізи перетинають площину ескізу. Вони залишаються пов'язаними й слідують за моделлю, коли вона змінюється.",
"help.sketch.intersection_curve": "Створює 3D-криві там, де сходяться два тіла чи грані, пов'язані з ними. Використовуйте їх як траєкторії або напрямні, що слідують за моделлю.", "help.sketch.intersection_curve": "Створює 3D-криві там, де сходяться два тіла, грані чи криві інших ескізів, пов'язані з ними. Використовуйте їх як траєкторії або напрямні, що слідують за моделлю.",
"help.sketch.isoparametric_curve": "Створює 3D-криву, пов'язану з гранню, вздовж напрямку U або V грані через вибрану вами точку. Використовуйте як траєкторію або лінію розділення, що слідує за поверхнею.", "help.sketch.isoparametric_curve": "Створює 3D-криву, пов'язану з гранню, вздовж напрямку U або V грані через вибрану вами точку. Використовуйте як траєкторію або лінію розділення, що слідує за поверхнею.",
"help.sketch.line": "Малює з'єднані прямі точка за точкою — як розімкнений ланцюг або замкнений контур. Це основний інструмент для більшості профілів.", "help.sketch.line": "Малює з'єднані прямі точка за точкою — як розімкнений ланцюг або замкнений контур. Це основний інструмент для більшості профілів.",
"help.sketch.line.midpoint": "Малює пряму від її середини до одного кінця, а другий кінець відображається дзеркально. Використовуйте для прямих, центрованих на точці, наприклад симетричного краю.", "help.sketch.line.midpoint": "Малює пряму від її середини до одного кінця, а другий кінець відображається дзеркально. Використовуйте для прямих, центрованих на точці, наприклад симетричного краю.",
@@ -4074,6 +4074,8 @@
"sample.plate.name": "Зразкова пластина", "sample.plate.name": "Зразкова пластина",
"sample.vents.about": "Пази в прямокутному масиві: рядки, стовпці та крок є параметрами", "sample.vents.about": "Пази в прямокутному масиві: рядки, стовпці та крок є параметрами",
"sample.vents.name": "Вентиляційна пластина", "sample.vents.name": "Вентиляційна пластина",
"scale.per_axis": "По осях",
"scale.uniform": "Рівномірно",
"search.command_keys": "Enter виконати Shift+Enter виконати й залишити відкритим Esc закрити", "search.command_keys": "Enter виконати Shift+Enter виконати й залишити відкритим Esc закрити",
"search.commands": "Команди", "search.commands": "Команди",
"search.design": "У цьому проєкті", "search.design": "У цьому проєкті",
+479 -1
View File
File diff suppressed because it is too large Load Diff
+2924 -2915
View File
File diff suppressed because it is too large Load Diff
+479 -1
View File
File diff suppressed because it is too large Load Diff
+192 -31
View File
@@ -16,6 +16,9 @@ struct U {
ana_c: array<vec4<f32>, 8>, ana_c: array<vec4<f32>, 8>,
ana_f: vec4<f32>, // x = 1: stripe the negative draft and blocked faces ana_f: vec4<f32>, // x = 1: stripe the negative draft and blocked faces
depth: vec4<f32>, // x = 1: reversed depth (1 near, 0 far); y, z: the faces' push (`FACE_BIAS`) depth: vec4<f32>, // x = 1: reversed depth (1 near, 0 far); y, z: the faces' push (`FACE_BIAS`)
// Where the drawn geometry is moved in the world: identity, or a dragged component's move
// from where its scene was built (`MovingLayer`)
model: mat4x4<f32>,
tint: vec4<f32>, // xyz added to a whole hovered body's colour before lighting tint: vec4<f32>, // xyz added to a whole hovered body's colour before lighting
sel: vec4<f32>, // xyz a whole selected body's colour before lighting sel: vec4<f32>, // xyz a whole selected body's colour before lighting
// the section hatch colours by part (`solidcraft_render::hatch`), the first the cap's own // the section hatch colours by part (`solidcraft_render::hatch`), the first the cap's own
@@ -25,6 +28,16 @@ struct U {
sky: vec4<f32>, // xyz = world up; w = 1: shade in linear light with a sky fill (#7974) sky: vec4<f32>, // xyz = world up; w = 1: shade in linear light with a sky fill (#7974)
}; };
/// A scene's point in the world (see `U.model`).
fn placed(p: vec3<f32>) -> vec3<f32> {
return (u.model * vec4<f32>(p, 1.0)).xyz;
}
/// A scene's direction in the world (see `placed`).
fn turned(n: vec3<f32>) -> vec3<f32> {
return (u.model * vec4<f32>(n, 0.0)).xyz;
}
fn reversed() -> bool { fn reversed() -> bool {
return u.depth.x > 0.5; return u.depth.x > 0.5;
} }
@@ -83,10 +96,11 @@ struct TOut {
}; };
@vertex @vertex
fn vs_tri(@location(0) p: vec3<f32>, @location(1) n: vec3<f32>, @location(2) c: u32) -> TOut { fn vs_tri(@location(0) local: vec3<f32>, @location(1) n: vec3<f32>, @location(2) c: u32) -> TOut {
var o: TOut; var o: TOut;
let p = placed(local);
o.pos = u.vp * vec4<f32>(p, 1.0); o.pos = u.vp * vec4<f32>(p, 1.0);
o.n = n; o.n = turned(n);
let e = palette_entry(c); let e = palette_entry(c);
o.c = unpack_color(e.x); o.c = unpack_color(e.x);
o.h = e.y; o.h = e.y;
@@ -95,7 +109,8 @@ fn vs_tri(@location(0) p: vec3<f32>, @location(1) n: vec3<f32>, @location(2) c:
} }
/// Shared triangles (in their part's own frame) drawn at one placement: the rows of its rigid /// Shared triangles (in their part's own frame) drawn at one placement: the rows of its rigid
/// move (`r0`..`r2`, a point's coordinates are their dot products with (p, 1)) and its colour. /// move (`r0`..`r2`, a point's coordinates are their dot products with (p, 1)) and its colour,
/// then moved like the rest of its scene (`placed`: a dragged component's layer).
/// The vertex colour (location 2) is not read. /// The vertex colour (location 2) is not read.
@vertex @vertex
fn vs_tri_inst( fn vs_tri_inst(
@@ -107,10 +122,11 @@ fn vs_tri_inst(
@location(6) c: u32, @location(6) c: u32,
) -> TOut { ) -> TOut {
let q = vec4<f32>(p, 1.0); let q = vec4<f32>(p, 1.0);
let wp = vec3<f32>(dot(r0, q), dot(r1, q), dot(r2, q)); let wp = placed(vec3<f32>(dot(r0, q), dot(r1, q), dot(r2, q)));
let pn = vec3<f32>(dot(r0.xyz, n), dot(r1.xyz, n), dot(r2.xyz, n));
var o: TOut; var o: TOut;
o.pos = u.vp * vec4<f32>(wp, 1.0); o.pos = u.vp * vec4<f32>(wp, 1.0);
o.n = vec3<f32>(dot(r0.xyz, n), dot(r1.xyz, n), dot(r2.xyz, n)); o.n = turned(pn);
let e = palette_entry(c); let e = palette_entry(c);
o.c = unpack_color(e.x); o.c = unpack_color(e.x);
o.h = e.y; o.h = e.y;
@@ -140,7 +156,7 @@ fn vs_tri_inst_flat(
@location(6) c: u32, @location(6) c: u32,
) -> FOut { ) -> FOut {
let q = vec4<f32>(p, 1.0); let q = vec4<f32>(p, 1.0);
let wp = vec3<f32>(dot(r0, q), dot(r1, q), dot(r2, q)); let wp = placed(vec3<f32>(dot(r0, q), dot(r1, q), dot(r2, q)));
var o: FOut; var o: FOut;
o.pos = u.vp * vec4<f32>(wp, 1.0); o.pos = u.vp * vec4<f32>(wp, 1.0);
o.rp = wp - u.eye.xyz; o.rp = wp - u.eye.xyz;
@@ -785,7 +801,9 @@ fn lifted_z(p: vec3<f32>, c: vec4<f32>, px: f32, half: vec2<f32>) -> f32 {
} }
@vertex @vertex
fn vs_line(@builtin(vertex_index) vi: u32, @location(0) a: vec3<f32>, @location(1) b: vec3<f32>, @location(2) c: u32, @location(3) wbits: u32) -> LOut { fn vs_line(@builtin(vertex_index) vi: u32, @location(0) local_a: vec3<f32>, @location(1) local_b: vec3<f32>, @location(2) c: u32, @location(3) wbits: u32) -> LOut {
let a = placed(local_a);
let b = placed(local_b);
var pa = a; var pa = a;
var pb = b; var pb = b;
var ca = u.vp * vec4<f32>(a, 1.0); var ca = u.vp * vec4<f32>(a, 1.0);
@@ -832,7 +850,7 @@ fn vs_line(@builtin(vertex_index) vi: u32, @location(0) a: vec3<f32>, @location(
var z = base.z; var z = base.z;
if (lifted && base.w > 1e-6) { if (lifted && base.w > 1e-6) {
let p = select(pa, pb, t > 0.5); let p = select(pa, pb, t > 0.5);
let g = grazing(p, octahedral(wbits & 4095u), octahedral((wbits >> 12u) & 4095u)); let g = grazing(p, turned(octahedral(wbits & 4095u)), turned(octahedral((wbits >> 12u) & 4095u)));
z = lifted_z(p, base, wd * 0.5 * g + 1.0, half); z = lifted_z(p, base, wd * 0.5 * g + 1.0, half);
} }
var o: LOut; var o: LOut;
@@ -883,10 +901,10 @@ fn fs_line_all(i: LOut) -> @location(0) vec4<f32> {
return out_color(i.c); return out_color(i.c);
} }
// Point clouds (`view/clouds.rs`): each point is a round dot a few pixels across, facing the // Point clouds and their cells (`view/clouds.rs`): dots, segments as beads (or lines when they
// screen, depth-tested and written like the model's faces, so the model hides the points behind // have no size) and triangles, from one record per element. The cloud's style colours them by
// it and they hide it. The cloud's style colours them by their own colour, a ramp or a palette, // their own colour, a ramp or a palette, and shows only those whose filtered values lie in its
// and shows only those whose filtered values lie in its ranges or sets. // ranges or sets; values vary across an element, so a range cuts it where its value crosses an end.
struct Cloud { struct Cloud {
style: vec4<f32>, // x: colour (0 own, 1 ramp, 2 palette), y: dot size (px), z, w: ramp range style: vec4<f32>, // x: colour (0 own, 1 ramp, 2 palette), y: dot size (px), z, w: ramp range
@@ -895,43 +913,88 @@ struct Cloud {
@group(1) @binding(3) var<uniform> cloud: Cloud; @group(1) @binding(3) var<uniform> cloud: Cloud;
struct CIn { struct CIn {
@location(0) p: vec3<f32>, @location(0) a: vec3<f32>,
@location(1) v: f32, @location(1) b: vec3<f32>,
@location(2) f: vec4<f32>, @location(2) c: vec3<f32>,
@location(3) rgb: vec4<f32>, @location(8) before: vec3<f32>,
@location(9) after: vec3<f32>,
@location(3) v: vec3<f32>,
@location(4) f0: vec3<f32>,
@location(5) f1: vec3<f32>,
@location(10) f2: vec3<f32>,
@location(11) f3: vec3<f32>,
@location(6) size: vec2<f32>,
@location(7) rgb: vec4<f32>,
}; };
struct COut { struct COut {
@builtin(position) pos: vec4<f32>, @builtin(position) pos: vec4<f32>,
@location(0) wp: vec3<f32>, @location(0) wp: vec3<f32>,
@location(1) v: f32, @location(1) n: vec3<f32>, // zero: not lit
@location(2) f: vec4<f32>, @location(2) v: f32,
@location(3) rgb: vec3<f32>, @location(3) f: vec4<f32>,
@location(4) at: vec2<f32>, // the place on its disc @location(4) rgb: vec3<f32>,
@location(5) @interpolate(flat) has: u32, @location(5) at: vec2<f32>, // a dot's place on its disc
@location(6) @interpolate(flat) has: u32,
}; };
fn cloud_out(i: CIn, w: vec3<f32>, wp: vec3<f32>, pos: vec4<f32>, n: vec3<f32>) -> COut {
var o: COut;
o.pos = pos;
o.wp = wp;
o.n = n;
o.v = dot(w, i.v);
o.f = vec4<f32>(dot(w, i.f0), dot(w, i.f1), dot(w, i.f2), dot(w, i.f3));
o.rgb = i.rgb.rgb;
o.at = vec2<f32>(0.0);
o.has = u32(round(i.rgb.a * 255.0));
return o;
}
fn behind(c: vec4<f32>) -> bool {
return near_z(c) < 0.0;
}
@vertex @vertex
fn vs_cloud_dot(@builtin(vertex_index) vi: u32, i: CIn) -> COut { fn vs_cloud_dot(@builtin(vertex_index) vi: u32, i: CIn) -> COut {
var xs = array<f32, 6>(-1.0, 1.0, 1.0, -1.0, 1.0, -1.0); var xs = array<f32, 6>(-1.0, 1.0, 1.0, -1.0, 1.0, -1.0);
var ys = array<f32, 6>(-1.0, -1.0, 1.0, -1.0, 1.0, 1.0); var ys = array<f32, 6>(-1.0, -1.0, 1.0, -1.0, 1.0, 1.0);
let at = vec2<f32>(xs[vi], ys[vi]); let at = vec2<f32>(xs[vi], ys[vi]);
let size = max(cloud.style.y, 1.0); let size = max(cloud.style.y, 1.0);
let centre = u.vp * vec4<f32>(i.p, 1.0); let centre = u.vp * vec4<f32>(i.a, 1.0);
var o: COut; var pos = vec4<f32>(centre.xy + at * size / u.screen.xy * centre.w, centre.z, centre.w);
o.pos = vec4<f32>(centre.xy + at * size / u.screen.xy * centre.w, centre.z, centre.w); if (behind(centre)) { pos = vec4<f32>(0.0, 0.0, 0.0, -1.0); }
// Behind the eye: nothing. var o = cloud_out(i, vec3<f32>(1.0, 0.0, 0.0), i.a, pos, vec3<f32>(0.0));
if (near_z(centre) < 0.0) { o.pos = vec4<f32>(0.0, 0.0, 0.0, -1.0); }
o.wp = i.p;
o.v = i.v;
o.f = i.f;
o.rgb = i.rgb.rgb;
o.has = u32(round(i.rgb.a * 255.0));
// Dots under two pixels are squares: a disc that small loses its centre pixel. // Dots under two pixels are squares: a disc that small loses its centre pixel.
o.at = at * select(1.0, 0.0, size < 2.0); o.at = at * select(1.0, 0.0, size < 2.0);
return o; return o;
} }
/// The least half-width of a segment on screen, in pixels.
const MIN_HALF_PX: f32 = 0.75;
/// The frame of a bead along `d`: along it, across it level, and up, its height axis.
fn bead_frame(d: vec3<f32>) -> mat3x3<f32> {
var t = vec3<f32>(1.0, 0.0, 0.0);
if (length(d) > 1e-9) { t = d / length(d); }
var side = cross(vec3<f32>(0.0, 0.0, 1.0), t);
if (length(side) < 1e-6) { side = vec3<f32>(1.0, 0.0, 0.0); }
side = normalize(side);
return mat3x3<f32>(t, side, cross(t, side));
}
/// Corner `j` (0…9) of a bead's cross-section, a stadium: its place across and up, and its
/// normal. Corners 0…4 go up the right half-disc, 5…9 down the left one, so 4–5 is the flat top
/// and 9–0 the flat bottom.
fn stadium(j: u32, size: vec2<f32>) -> vec4<f32> {
let k = j % 10u;
let right = k < 5u;
let a = -1.5707963 + 0.7853982 * f32(k % 5u) + select(3.1415927, 0.0, right);
let r = 0.5 * size.y;
let flat_half = 0.5 * max(size.x - size.y, 0.0);
return vec4<f32>(select(-flat_half, flat_half, right) + r * cos(a), r * sin(a), cos(a), sin(a));
}
/// Whether filter `f` keeps the value `v`. /// Whether filter `f` keeps the value `v`.
fn cloud_keeps(f: vec4<f32>, v: f32) -> bool { fn cloud_keeps(f: vec4<f32>, v: f32) -> bool {
if (f.x < 0.5) { return true; } if (f.x < 0.5) { return true; }
@@ -940,6 +1003,101 @@ fn cloud_keeps(f: vec4<f32>, v: f32) -> bool {
return k >= 0 && k < 32 && ((bitcast<u32>(f.w) >> u32(k)) & 1u) != 0u; return k >= 0 && k < 32 && ((bitcast<u32>(f.w) >> u32(k)) & 1u) != 0u;
} }
/// Whether filter `f` leaves out a whole element with values `v` at its corners: all on one
/// side of a range, or one value at every corner, not kept. A set of values with corners that
/// differ may keep part of the element: its fragments decide.
fn cloud_drops(f: vec4<f32>, v: vec3<f32>) -> bool {
if (f.x > 1.5) { return all(v == vec3<f32>(v.x)) && !cloud_keeps(f, v.x); }
return f.x > 0.5 && (all(v < vec3<f32>(f.y)) || all(v > vec3<f32>(f.z)));
}
/// Whether a filter leaves out the whole element.
fn filtered_out(i: CIn) -> bool {
let has = u32(round(i.rgb.a * 255.0));
let values = array<vec3<f32>, 4>(i.f0, i.f1, i.f2, i.f3);
for (var k = 0u; k < 4u; k++) {
if (((has >> k) & 1u) != 0u && cloud_drops(cloud.filters[k], values[k])) { return true; }
}
return false;
}
/// The part in front of the near plane of the segment between clip-space `a` and `b`, as
/// fractions of it from `a`; empty (first above second) when all of it is behind. Clip-space
/// coordinates are affine along a line, so the crossing is exact.
fn in_front(a: vec4<f32>, b: vec4<f32>) -> vec2<f32> {
let za = near_z(a);
let zb = near_z(b);
if (za < 0.0 && zb < 0.0) { return vec2<f32>(1.0, 0.0); }
let t = za / (za - zb);
return vec2<f32>(select(0.0, t, za < 0.0), select(1.0, t, zb < 0.0));
}
@vertex
fn vs_cloud_segment(@builtin(vertex_index) vi: u32, i: CIn) -> COut {
// Corner `vi % 10` of the cross-section at the start (`vi < 10`) or the end; the index
// buffer joins them into the bead's sides.
let pa = u.vp * vec4<f32>(i.a, 1.0);
let pb = u.vp * vec4<f32>(i.b, 1.0);
let part = in_front(pa, pb);
if (filtered_out(i) || part.x > part.y) {
return cloud_out(i, vec3<f32>(1.0, 0.0, 0.0), i.a, vec4<f32>(0.0, 0.0, 0.0, -1.0), vec3<f32>(0.0));
}
// Where the near plane cuts it, the bead ends there, square; its numbers are exact at `e`.
let at_end = vi >= 10u;
let e = select(part.x, part.y, at_end);
let cut = e != select(0.0, 1.0, at_end);
let f = bead_frame(i.b - i.a);
let c = stadium(vi % 10u, i.size);
let axis = mix(i.a, i.b, e);
// Where it meets the next or the previous bead, the cross-section lies in the plane halfway
// between their directions, stretched across to keep its width: both beads end on the same
// section. A turn sharper than 120° ends square instead.
let other = select(i.a - i.before, i.after - i.b, at_end);
var across_dir = f[1];
var stretch = 1.0;
if (!cut && length(other) > 1e-9) {
let g = bead_frame(other);
let mid = f[1] + g[1];
if (length(mid) > 1e-6 && dot(normalize(mid), f[1]) > 0.5) {
across_dir = normalize(mid);
stretch = 1.0 / dot(across_dir, f[1]);
}
}
let wp = axis + across_dir * (c.x * stretch) + f[2] * c.y;
let ca = u.vp * vec4<f32>(axis, 1.0);
let cw = u.vp * vec4<f32>(wp, 1.0);
let half = u.screen.xy * 0.5;
var pos = cw;
// At least a pixel and a half across: a bead seen from afar, or a line without size. A corner
// behind the eye has no place on the screen and needs no widening: the rasteriser clips it.
if (cw.w > 0.0) {
let c0 = mix(pa, pb, part.x);
let c1 = mix(pa, pb, part.y);
let along = (c1.xy / c1.w - c0.xy / c0.w) * half;
var across = vec2<f32>(-along.y, along.x);
if (length(across) < 1e-6) { across = vec2<f32>(1.0, 0.0); }
across = normalize(across);
var px = (cw.xy / cw.w - ca.xy / ca.w) * half;
if (length(px) < MIN_HALF_PX * abs(c.z)) {
px = across * c.z * MIN_HALF_PX;
pos = vec4<f32>((ca.xy / ca.w + px / half) * cw.w, cw.z, cw.w);
}
}
let n = select(f[1] * c.z + f[2] * c.w, vec3<f32>(0.0), i.size.y <= 0.0);
return cloud_out(i, vec3<f32>(1.0 - e, e, 0.0), wp, pos, n);
}
@vertex
fn vs_cloud_triangle(@builtin(vertex_index) vi: u32, i: CIn) -> COut {
// Not `w[vi] = 1.0`: the Windows D3D12 shader compiler cannot write through a dynamic vector index.
let w = vec3<f32>(f32(vi == 0u), f32(vi == 1u), f32(vi == 2u));
let wp = i.a * w.x + i.b * w.y + i.c * w.z;
var n = cross(i.b - i.a, i.c - i.a);
if (length(n) > 0.0) { n = normalize(n); }
// The true clip-space corner, even behind the eye: the rasteriser clips a triangle exactly.
return cloud_out(i, w, wp, u.vp * vec4<f32>(wp, 1.0), n);
}
fn cloud_ramp(t: f32) -> vec3<f32> { fn cloud_ramp(t: f32) -> vec3<f32> {
var stops = array<vec3<f32>, 5>( var stops = array<vec3<f32>, 5>(
vec3<f32>(40.0, 70.0, 200.0), vec3<f32>(30.0, 170.0, 230.0), vec3<f32>(60.0, 200.0, 90.0), vec3<f32>(40.0, 70.0, 200.0), vec3<f32>(30.0, 170.0, 230.0), vec3<f32>(60.0, 200.0, 90.0),
@@ -974,5 +1132,8 @@ fn fs_cloud(o: COut) -> @location(0) vec4<f32> {
} else if ((o.has & 16u) != 0u && mode > 0.5) { } else if ((o.has & 16u) != 0u && mode > 0.5) {
c = cloud_ramp((o.v - cloud.style.z) / max(cloud.style.w - cloud.style.z, 1e-12)); c = cloud_ramp((o.v - cloud.style.z) / max(cloud.style.w - cloud.style.z, 1e-12));
} }
if (length(o.n) > 0.5) {
c = c * (0.45 + 0.55 * abs(dot(normalize(o.n), normalize(u.back.xyz))));
}
return out_color(vec4<f32>(c, 1.0)); return out_color(vec4<f32>(c, 1.0));
} }
+218
View File
@@ -0,0 +1,218 @@
{
"order": 155,
"provenance": "Original SolidCraft mapping of Solarized (MIT palette)",
"base": "dark",
"borders": {},
"colors": {
"accent": "#268bd2",
"accent_soft": "#073642",
"agent_busy": "#268bd2",
"agent_ok": "#859900",
"app_bar": "#002b36",
"app_bar_hover": "#073642",
"app_bar_hover_button": "#073642",
"app_bar_hover_strong": "#586e75",
"app_bar_hover_subtle": "#073642",
"app_bar_separator": "#586e75",
"app_bar_tab_active": "#073642",
"app_bar_text": "#93a1a1",
"axis_x": "#dc322f",
"axis_y": "#859900",
"axis_z": "#346e88",
"bend_down": "#b58900",
"bend_up": "#859900",
"body": "#586e75",
"body_edge": "#346e88",
"body_selected": "#073642",
"border": "#586e75",
"box_crossing": "#859900",
"box_window": "#268bd2",
"chip": "#268bd2",
"construction_geom": "#cb4b16",
"construction_plane": "#b4870022",
"continuity": [
"#859900",
"#346e88",
"#b58900",
"#6c71c4"
],
"control_border": "#586e75",
"control_fill": "#073642",
"cube_border": "#586e75",
"cube_face": "#073642",
"cube_hover": "#586e75",
"cube_text": "#93a1a1",
"dialog_bg": "#073642",
"dialog_body": "#073642",
"dialog_border": "#586e75",
"dialog_footer": "#073642",
"dialog_label": "#93a1a1",
"dialog_rule": "#586e75",
"dimension": "#2aa198",
"dimension_driven": "#1f7f78",
"error": "#dc322f",
"field": "#002b36",
"file_background": "#073642",
"file_border": "#586e75",
"file_dim": "#93a1a1",
"file_image_tint": "#002b36",
"file_primary": "#586e75",
"file_primary_border": "#268bd2",
"file_primary_ink": "#ffffff",
"file_rail": "#1b6397",
"file_rail_hover": "#2670a6",
"file_rail_ink": "#ffffff",
"file_recovery": "#073642",
"file_recovery_border": "#b58900",
"file_recovery_ink": "#93a1a1",
"file_recovery_well": "#002b36",
"file_surface": "#073642",
"form_accent": "#6b70c3",
"form_dim": "#839496",
"form_error": "#dc322f",
"form_error_fill": "#586e75",
"form_fill": "#a2a9f8",
"form_ink": "#93a1a1",
"form_primary": "#268bd2",
"form_soft": "#073642",
"form_success": "#859900",
"form_success_fill": "#586e75",
"form_tab_ink": "#565a9d",
"glyph_bg": "#073642",
"glyph_edge": "#da2f2d",
"glyph_text": "#da2f2d",
"grid": "#073642",
"grid_major": "#586e75",
"hover": "#586e75",
"hover_edge": "#346e88",
"hover_edge_halo": "#002b36",
"hover_profile": "#268cd228",
"hover_profile_edge": "#346e88",
"icon": "#93a1a1",
"icons.agent": "#6c71c4",
"icons.highlight": "#93a1a1",
"icons.marker_halo": "#002b36cc",
"interference": "#dc322f",
"logo": [
"#268bd2",
"#346e88",
"#586e75"
],
"manipulator": "#268bd2",
"mesh_accent": "#97751d",
"mesh_fill": "#d7aa3c",
"mesh_ink": "#7b5d00",
"mesh_soft": "#073642",
"on_accent": "#ffffff",
"origin_plane": "#b3860028",
"origin_plane_edge": "#b6890088",
"origin_plane_hover": "#288bd340",
"origin_point": "#839496",
"overlay": "#073642",
"panel": "#073642",
"panel_header": "#002b36",
"preview_add": "#346e88",
"preview_cut": "#dc323066",
"preview_new": "#b58900",
"preview_sketch": "#859900",
"profile_fill": "#35718722",
"render_accent": "#cf317e",
"render_fill": "#f986b4",
"render_ink": "#ad2c6b",
"render_soft": "#073642",
"rubber_band": "#268bd2",
"section_cap": "#b58900",
"sel_edge": "#346e88",
"sel_edge_rim": "#346e88",
"sel_face": "#073642",
"sel_profile": "#073642",
"sel_profile_edge": "#346e88",
"sel_vertex": "#346e88",
"selected_bg": "#0a3e50",
"selected_ink": "#93a1a1",
"sheet_fill": "#58c6bc",
"sheet_ink": "#1d6d67",
"sheet_soft": "#073642",
"sketch": "#346e88",
"sketch_accent": "#738400",
"sketch_centerline": "#b58900",
"sketch_construction": "#b58900",
"sketch_fixed": "#93a1a1",
"sketch_halo": "#002b36",
"sketch_ink": "#5a6800",
"sketch_locked": "#859900",
"sketch_lost": "#dc322f",
"sketch_point": "#93a1a1",
"sketch_point_free": "#346e88",
"sketch_projected": "#6c71c4",
"sketch_soft": "#073642",
"surface_accent": "#cb4b16",
"surface_fill": "#fb906b",
"surface_ink": "#a83e12",
"surface_soft": "#073642",
"tab_on_fill_dark": "#002b36",
"text": "#93a1a1",
"text_dim": "#839496",
"timeline": "#073642",
"timeline_item": "#073642",
"timeline_item_error": "#eabcad",
"timeline_marker": "#839496",
"toolbar": "#073642",
"viewport_bottom": "#002b36",
"viewport_top": "#002b36",
"warning": "#b58900"
},
"format": "solidcraft-theme/1",
"icon_palette": {
"constraint": [
"#fee0dc",
"#fb8d81",
"#da2f2d"
],
"construction": [
"#fee1d7",
"#fb906b",
"#cb4b16"
],
"form": [
"#e3e6fe",
"#a2a9f8",
"#6b70c3"
],
"guide": "#839496",
"ink": "#fdf6e3",
"line": "#93a1a1",
"mesh": [
"#fde5b2",
"#d7aa3c",
"#97751d"
],
"passive-1": "#586e75",
"passive-2": "#073642",
"passive-3": "#002b36",
"sketch": [
"#def67b",
"#a8be40",
"#738400"
],
"solid": [
"#d5ebff",
"#67b9fb",
"#1480c6"
],
"surface": [
"#fee1d7",
"#fb906b",
"#cb4b16"
]
},
"name": "Solarized Dark",
"radii": {
"control_radius": 6,
"radius_lg": 8,
"radius_md": 6,
"radius_sm": 4,
"radius_xl": 10,
"sketch_mode_radius": 7
}
}
@@ -1 +0,0 @@
| assets/locales/pending/ribbon-panel-hover.json | SolidCraft contributors | Original ribbon panel menu preference labels and translations | MIT OR Apache-2.0 |
+7 -21
View File
@@ -210,13 +210,16 @@ fn map_plane_ref(m: &Mat, p: &mut PlaneRef) {
map_plane_ref(m, base); map_plane_ref(m, base);
map_geo_ref(m, point); map_geo_ref(m, point);
} }
PlaneRef::AtAngle { base, axis_origin, axis_dir, line, .. } => { PlaneRef::AtAngle { base, axis_origin, axis_dir, line, pivot, .. } => {
map_plane_ref(m, base); map_plane_ref(m, base);
*axis_origin = apply_point(m, *axis_origin); *axis_origin = apply_point(m, *axis_origin);
*axis_dir = apply_vector(m, *axis_dir); *axis_dir = apply_vector(m, *axis_dir);
if let Some(g) = line { if let Some(g) = line {
map_geo_ref(m, g); map_geo_ref(m, g);
} }
if let Some(g) = pivot {
map_geo_ref(m, g);
}
} }
// Named origin planes and construction planes are the component's own. // Named origin planes and construction planes are the component's own.
PlaneRef::Origin { .. } | PlaneRef::Construction { .. } => {} PlaneRef::Origin { .. } | PlaneRef::Construction { .. } => {}
@@ -353,25 +356,7 @@ impl Document {
/// Every placement of each component: (component, occurrence path ids, world transform). /// Every placement of each component: (component, occurrence path ids, world transform).
/// A branch stops past [`MAX_PLACEMENT_DEPTH`] levels, the walk past [`MAX_PLACEMENTS`] placements. /// A branch stops past [`MAX_PLACEMENT_DEPTH`] levels, the walk past [`MAX_PLACEMENTS`] placements.
pub fn placements(&self) -> Vec<(u64, Vec<u64>, Mat)> { pub fn placements(&self) -> Vec<(u64, Vec<u64>, Mat)> {
let mut out = vec![(0, Vec::new(), IDENTITY)]; crate::occurrence_tree::OccurrenceTree::new(self).placements_with(|o| o.transform)
let mut stack: Vec<(u64, Vec<u64>, Mat)> = vec![(0, Vec::new(), IDENTITY)];
while let Some((comp, path, m)) = stack.pop() {
if out.len() > MAX_PLACEMENTS {
break;
}
// Only this branch stops past the depth limit; the others are still walked.
if path.len() > MAX_PLACEMENT_DEPTH {
continue;
}
for o in self.occurrences.iter().filter(|o| o.parent == comp) {
let mut p = path.clone();
p.push(o.id);
let w = mat_mul(&m, &o.transform);
out.push((o.component, p.clone(), w));
stack.push((o.component, p, w));
}
}
out
} }
/// Every body as the world shows it: its world name ("Body1", or "Body1 (Occ:2)" for a /// Every body as the world shows it: its world name ("Body1", or "Body1 (Occ:2)" for a
@@ -461,13 +446,14 @@ impl Document {
if self.component_within(parent, component) { if self.component_within(parent, component) {
return true; return true;
} }
let tree = crate::occurrence_tree::OccurrenceTree::new(self);
let mut stack = vec![component]; let mut stack = vec![component];
let mut seen = std::collections::BTreeSet::new(); let mut seen = std::collections::BTreeSet::new();
while let Some(c) = stack.pop() { while let Some(c) = stack.pop() {
if !seen.insert(c) || seen.len() > MAX_PLACEMENTS { if !seen.insert(c) || seen.len() > MAX_PLACEMENTS {
continue; continue;
} }
for o in self.occurrences.iter().filter(|o| o.parent == c) { for o in tree.children(c) {
if o.component == parent { if o.component == parent {
return true; return true;
} }
+8 -2
View File
@@ -119,11 +119,14 @@ fn remap_plane(p: &mut PlaneRef, ids: &BTreeMap<u64, u64>, bodies: &BTreeMap<Str
remap_plane(base, ids, bodies, depth + 1)?; remap_plane(base, ids, bodies, depth + 1)?;
remap_geo(point, ids, bodies, depth + 1)?; remap_geo(point, ids, bodies, depth + 1)?;
} }
PlaneRef::AtAngle { base, line, .. } => { PlaneRef::AtAngle { base, line, pivot, .. } => {
remap_plane(base, ids, bodies, depth + 1)?; remap_plane(base, ids, bodies, depth + 1)?;
if let Some(g) = line { if let Some(g) = line {
remap_geo(g, ids, bodies, depth + 1)?; remap_geo(g, ids, bodies, depth + 1)?;
} }
if let Some(g) = pivot {
remap_geo(g, ids, bodies, depth + 1)?;
}
} }
PlaneRef::Face { name, anchor, .. } => { PlaneRef::Face { name, anchor, .. } => {
if let Some(name) = name { if let Some(name) = name {
@@ -323,11 +326,14 @@ fn checked_plane(p: &PlaneRef, depth: usize) -> crate::Result<()> {
} }
match p { match p {
PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => checked_plane(base, depth + 1)?, PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => checked_plane(base, depth + 1)?,
PlaneRef::AtAngle { base, line, .. } => { PlaneRef::AtAngle { base, line, pivot, .. } => {
checked_plane(base, depth + 1)?; checked_plane(base, depth + 1)?;
if let Some(g) = line { if let Some(g) = line {
checked_geo(g, depth + 1)?; checked_geo(g, depth + 1)?;
} }
if let Some(g) = pivot {
checked_geo(g, depth + 1)?;
}
} }
PlaneRef::Midplane { a, b } | PlaneRef::TwoEdges { a, b } | PlaneRef::AxisPoint { axis: a, point: b } => { PlaneRef::Midplane { a, b } | PlaneRef::TwoEdges { a, b } | PlaneRef::AxisPoint { axis: a, point: b } => {
checked_geo(a, depth + 1)?; checked_geo(a, depth + 1)?;
+1 -1
View File
@@ -185,7 +185,7 @@ fn shell_planar_format13_keeps_v12_documents_and_refuses_future() {
} }
assert_eq!(legacy, current, "the migration preserves every prior field"); assert_eq!(legacy, current, "the migration preserves every prior field");
legacy["format"] = json!(crate::format::format_string(crate::format::FORMAT + 1)); legacy["format"] = json!(crate::format::format_string(crate::format::FORMAT + 1));
assert!(crate::format::read(&legacy.to_string()).is_err()); assert!(crate::format::read(&legacy.to_string()).unwrap().newer_file.is_some());
} }
#[test] #[test]
+2 -1
View File
@@ -923,9 +923,10 @@ impl PlaneRef {
refs.push(point.as_mut()); refs.push(point.as_mut());
refs refs
} }
PlaneRef::AtAngle { base, line, .. } => { PlaneRef::AtAngle { base, line, pivot, .. } => {
let mut v = base.refs_mut(); let mut v = base.refs_mut();
v.extend(line.as_deref_mut()); v.extend(line.as_deref_mut());
v.extend(pivot.as_deref_mut());
v v
} }
PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => base.refs_mut(), PlaneRef::Offset { base, .. } | PlaneRef::Flipped { base, .. } => base.refs_mut(),

Some files were not shown because too many files have changed in this diff Show More