Compare commits
297 Commits
v0.26.0
...
chat-pdf-text
| Author | SHA1 | Date | |
|---|---|---|---|
| 08a117416d | |||
| bd1525dcfb | |||
| 1e5eb1e3b8 | |||
| a1483d63c1 | |||
| 491687d4c1 | |||
| 66bd64cc5e | |||
| f9146cdd58 | |||
| 23e7ac767e | |||
| 3ac7a196c9 | |||
| 202e713cf1 | |||
| 63923da2ca | |||
| 7e22aed739 | |||
| 966b10e731 | |||
| 99eda4cd1b | |||
| 47292bb2bd | |||
| 37dc878f31 | |||
| 7da02460d8 | |||
| f73f4da665 | |||
| ef5985f841 | |||
| 71bb4f7c98 | |||
| 92af4a21c8 | |||
| 5d6c5bab39 | |||
| 8251be9c06 | |||
| 3d744cc8a2 | |||
| 1447bc772a | |||
| 7b24a1dc1e | |||
| d95f40ac88 | |||
| 82ac9a6b03 | |||
| 6ab46b6488 | |||
| 991082fbaf | |||
| 4d338ba2eb | |||
| 94b399e98f | |||
| 5aa41703f7 | |||
| d9aa73b597 | |||
| 6e4e94a8a8 | |||
| ae2a5b2c0d | |||
| 81cbcef31c | |||
| e3d9090e6c | |||
| b8e93270b4 | |||
| ef628d1c86 | |||
| d93b1cb282 | |||
| a66a517c40 | |||
| f3ee34d372 | |||
| c94d1e9894 | |||
| 46a2d6b53c | |||
| c9935007e8 | |||
| 7b9d37c787 | |||
| 8a6a064d37 | |||
| f35f3197c3 | |||
| 78499f44af | |||
| 5b5201f1a6 | |||
| f28ff15ffb | |||
| 4f8bbec9fb | |||
| 77ebf1326c | |||
| fdc95337cf | |||
| 0e053e5e61 | |||
| 6bbb4276c0 | |||
| 6d641c87c4 | |||
| 553f5fb9b8 | |||
| 88dd699715 | |||
| c092e0551b | |||
| c320dc421c | |||
| 0f489a5777 | |||
| 3df709be63 | |||
| 875ac2ce49 | |||
| 698275874f | |||
| 0d4470cd8c | |||
| 5dfc3481c1 | |||
| 8f1b456275 | |||
| b596bfc730 | |||
| d11d268597 | |||
| 4b0ba62c69 | |||
| 313d2bdb41 | |||
| 079f6e61e6 | |||
| 4a781b8cd8 | |||
| 87206f20c8 | |||
| 5a24d4095a | |||
| 3e62553d9c | |||
| d4fb5538e6 | |||
| f6393ef211 | |||
| 355b486595 | |||
| 2356a63aea | |||
| 57c0121cb3 | |||
| 9b97e06f71 | |||
| 9c5a636987 | |||
| 18b00a4192 | |||
| 988caa83fc | |||
| 18dc05c83d | |||
| 5cf18ba8c3 | |||
| 9454afe13a | |||
| 70d39bb4f3 | |||
| a4fd998539 | |||
| 1c673e38c7 | |||
| b43712cdb0 | |||
| 184d4720be | |||
| f08623be3c | |||
| 31218b1451 | |||
| cb34eef6aa | |||
| b9e9521128 | |||
| e59a2bcf80 | |||
| 6fcdca1bb7 | |||
| a985b8ee17 | |||
| c857f2fe70 | |||
| 9416e975e0 | |||
| 5f11d92458 | |||
| 97550dc37e | |||
| 4456e0470a | |||
| 561336aab6 | |||
| 82b38f5bae | |||
| 43a22bed46 | |||
| cd12d9d8e7 | |||
| 15e3245180 | |||
| 730dc5f6c3 | |||
| 3cdc68aaf1 | |||
| e3c08471b6 | |||
| a7048f41ab | |||
| 1c0001af8e | |||
| 8b1ee94296 | |||
| 791abbd9b1 | |||
| 6255a10e80 | |||
| d05a114241 | |||
| 6ebfe91661 | |||
| d0b357d532 | |||
| cc047a29c1 | |||
| 32c8b23199 | |||
| 21366ec47e | |||
| 699d730151 | |||
| a4274f9b59 | |||
| d6d6c7d9ee | |||
| 5bd85dded6 | |||
| e5ef3bad02 | |||
| 4aa2d6248e | |||
| bd4a234461 | |||
| 162b3cd4ed | |||
| 420dff36c8 | |||
| 3cdfec798f | |||
| c32f6b60eb | |||
| 5fe8d5a757 | |||
| 4e78acc7a2 | |||
| 4cd90e6806 | |||
| 8a888ff0f3 | |||
| 5530c3c68e | |||
| 35601da3f0 | |||
| 1d566398d8 | |||
| 3e01081ff9 | |||
| 420785b514 | |||
| dcae86e456 | |||
| 443e5cd59d | |||
| b4799575fd | |||
| 5a0abb8710 | |||
| cb05e1e0f7 | |||
| 6fdd58dec6 | |||
| 5b0a86a5b2 | |||
| 28e26209f3 | |||
| 986de7ec9a | |||
| 7c7c0a57bd | |||
| 54b07d3e0b | |||
| 7dc341ae55 | |||
| 5e0e168ae9 | |||
| be8bd43a18 | |||
| 884c47496b | |||
| b2d727f4b2 | |||
| 4f5ed7bfa6 | |||
| f03d0a20bd | |||
| c6c91e6f43 | |||
| 2f56d77e90 | |||
| 68b53a4c77 | |||
| 2235389344 | |||
| 9509348320 | |||
| fd8ddc23b7 | |||
| 07d692ee0d | |||
| 00f9243c0d | |||
| 1e1be6934f | |||
| 6a183cce02 | |||
| dd6a91533d | |||
| 93d0298d25 | |||
| cf86f18c11 | |||
| 63f053e4fe | |||
| 81039a0e10 | |||
| 375dc01602 | |||
| fe3f913d76 | |||
| 90f0353724 | |||
| 4f3ac07aec | |||
| 710a3f8f11 | |||
| 4cee4db19b | |||
| 036d4234a1 | |||
| 7341b8f6be | |||
| 0f2ad19bdb | |||
| 1643b74111 | |||
| 815e7de7e7 | |||
| 3cc10acafa | |||
| 06dfbc4000 | |||
| 2d56f5d599 | |||
| 2f7a9a1fc0 | |||
| 7ad2bbd391 | |||
| c10d36a0b5 | |||
| aee57875f5 | |||
| d2fcab8432 | |||
| c7a1cee357 | |||
| 883f8e8e90 | |||
| a6b272dec8 | |||
| 2a749f4294 | |||
| 5241c64aa6 | |||
| c688054db0 | |||
| d77b0434dd | |||
| 0818ad0ed4 | |||
| 54f74a613e | |||
| 74791e0220 | |||
| afe7dcd4e1 | |||
| fed7ea0c88 | |||
| dfa8ae9a60 | |||
| 53b2f73d2e | |||
| 1dce42e744 | |||
| aad3d56ec2 | |||
| 8719cc7b57 | |||
| 651addda84 | |||
| dd16cc9faf | |||
| 6747ea0dcf | |||
| 4215fb11c2 | |||
| 504fe1afcb | |||
| 7367b81ffe | |||
| 183226d2b6 | |||
| 514563187b | |||
| 5286f50fd9 | |||
| 46487216d0 | |||
| 39250092a3 | |||
| a1fd2be2c8 | |||
| bd8cb4e6d6 | |||
| c1925bb219 | |||
| 75035ac4a5 | |||
| ae47ed342b | |||
| 03cf8f3e90 | |||
| 0baf49b25f | |||
| 9bcda52408 | |||
| f4e52c4d3e | |||
| 2da969cf5c | |||
| dd8308e835 | |||
| 6f9788ccba | |||
| 46a6686380 | |||
| ec76068a0b | |||
| 99664a4d35 | |||
| e55eff7c5d | |||
| d8d22cd52a | |||
| 40ff251e5f | |||
| 081c4bca73 | |||
| de5cee9bf1 | |||
| 09bf603588 | |||
| f071f00155 | |||
| 8fb452b05e | |||
| e4cfbbd0c3 | |||
| 746e1c633d | |||
| 674ef84b53 | |||
| be757154d6 | |||
| 3b983dc550 | |||
| b5217b1e86 | |||
| 5dccc3d978 | |||
| 800b6b4486 | |||
| 11f208f665 | |||
| ba52632985 | |||
| 4571701179 | |||
| 4c6382c0a3 | |||
| 0e01dc9bad | |||
| c0d84ad460 | |||
| af9772fb3c | |||
| 3449f0def2 | |||
| 0889ef9dfc | |||
| 1937dea04b | |||
| a545f32113 | |||
| 937d5f0176 | |||
| 05a7a4fef9 | |||
| 33c27106ff | |||
| 17807ab6dc | |||
| 1445b5a4f0 | |||
| 066de1b005 | |||
| d6876d6e67 | |||
| a1e7337d3c | |||
| 951b5eb1d3 | |||
| 5221103369 | |||
| 9b7a6ea04d | |||
| fe265d74b1 | |||
| eb29c4b2d8 | |||
| f1ab19422b | |||
| 0a187f5cb1 | |||
| 7adbe00377 | |||
| 0243afdc0b | |||
| 8e6a107f6e | |||
| 4ad18407dc | |||
| 5695785e3e | |||
| c2e1dbe6e4 | |||
| bda5f69c5c | |||
| 78d05e35bb | |||
| 70fdc27703 | |||
| b650d7b49b | |||
| 883aff8816 | |||
| 43cf7774aa | |||
| 29749c73f3 | |||
| 05081e8428 |
@@ -15,7 +15,9 @@
|
||||
# nightly. The reference tests and the doc tests run in the merge queue, on main and nightly, not
|
||||
# on pull requests (the fast lane, in Select checks); a break there is fixed forward on main. The
|
||||
# Windows jobs (D3D12 shaders and app startup) run nightly, and in the merge queue only for a group
|
||||
# that changes what they exercise. Only main saves the build caches; pull requests restore them.
|
||||
# that changes what they exercise. The wasm compile check runs in the merge queue for a group that
|
||||
# touches the crates below the apps, the web app or the manifests. Dependency advisories run nightly
|
||||
# and on any pull request or merge group that changes Cargo.lock or a Cargo.toml. Only main saves the build caches; pull requests restore them.
|
||||
# sccache is on a Blacksmith sticky disk that only main commits.
|
||||
# A push to main runs only the repository checks when a passing merge-queue run tested that very
|
||||
# commit, or when nothing a build reads changed since the last push to main whose run passed.
|
||||
@@ -78,8 +80,13 @@ env:
|
||||
|
||||
jobs:
|
||||
dependency-advisories:
|
||||
# Nightly and by hand: advisories, bans and sources for everything. A pull request or merge
|
||||
# group that changes Cargo.lock or a Cargo.toml (Select checks' `deps`) checks the advisories
|
||||
# only, so a dependency with a known vulnerability is caught before it lands, not the next
|
||||
# morning; other pull requests skip it. `ci` requires it whenever `deps` is true.
|
||||
name: Dependency advisories
|
||||
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
||||
needs: changes
|
||||
if: ${{ !cancelled() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || needs.changes.outputs.deps == 'true') }}
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -88,7 +95,12 @@ jobs:
|
||||
- name: Install advisory scanner
|
||||
run: cargo install cargo-deny --version 0.20.2 --locked
|
||||
- name: Check locked dependencies
|
||||
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
||||
run: cargo deny --locked check --warn unmaintained advisories bans sources
|
||||
# deny.toml denies unmaintained crates; like the nightly, they are reported, not fatal.
|
||||
- name: Check advisories for the changed dependencies
|
||||
if: github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'
|
||||
run: cargo deny --locked check --warn unmaintained advisories
|
||||
|
||||
changes:
|
||||
name: Select checks
|
||||
@@ -115,6 +127,10 @@ jobs:
|
||||
packages: ${{ steps.paths.outputs.packages }}
|
||||
oracle: ${{ steps.paths.outputs.oracle }}
|
||||
doctests: ${{ steps.paths.outputs.doctests }}
|
||||
# Cargo.lock or a Cargo.toml changed (pull requests and merge groups): Dependency advisories.
|
||||
deps: ${{ steps.paths.outputs.deps }}
|
||||
# A merge group reaches the wasm build: Compile WebAssembly.
|
||||
wasm: ${{ steps.paths.outputs.wasm }}
|
||||
# The passing run a merge of main carries forward (its URL), when this push is only that.
|
||||
carried: ${{ steps.paths.outputs.carried }}
|
||||
steps:
|
||||
@@ -143,6 +159,8 @@ jobs:
|
||||
goldens=false
|
||||
windows=false
|
||||
gpu_paths=false
|
||||
deps=false
|
||||
wasm=false
|
||||
full=true
|
||||
packages=
|
||||
# Whether the NUL-separated paths in $1 reach any code: scripts/ci/affected.py selects
|
||||
@@ -183,6 +201,21 @@ jobs:
|
||||
esac
|
||||
done < "$1"
|
||||
}
|
||||
# Whether the NUL-separated paths in $1 change the dependencies (Cargo.lock or any
|
||||
# Cargo.toml: deps), and whether they reach what `cargo xtask wasm` compiles (wasm): the
|
||||
# crates below the apps, the web app, the vendored crates, the manifests and lockfile, the
|
||||
# toolchain and cargo config, and this workflow. #8227 put a native-only call in
|
||||
# crates/ui-egui and the merge queue passed it, because nothing built for wasm there.
|
||||
deps_wasm_paths() {
|
||||
while IFS= read -r -d '' path; do
|
||||
case "$path" in
|
||||
Cargo.lock|Cargo.toml|*/Cargo.toml) deps=true ;;
|
||||
esac
|
||||
case "$path" in
|
||||
crates/*|apps/solidcraft-web/*|vendor/*|Cargo.lock|Cargo.toml|rust-toolchain*|.cargo/*|.github/workflows/ci.yml) wasm=true ;;
|
||||
esac
|
||||
done < "$1"
|
||||
}
|
||||
# Opt-in for a big render change: a pull request labelled render-tests, or a merge group
|
||||
# holding one (its pull requests are the (#N) of its squash commits), runs them whatever
|
||||
# the paths say.
|
||||
@@ -228,14 +261,17 @@ jobs:
|
||||
if git diff --no-renames --name-only -z "$GROUP_BASE_SHA...$GROUP_HEAD_SHA" > "$RUNNER_TEMP/ci-paths"; then
|
||||
windows_paths "$RUNNER_TEMP/ci-paths" "$GROUP_BASE_SHA...$GROUP_HEAD_SHA"
|
||||
gpu_paths "$RUNNER_TEMP/ci-paths"
|
||||
deps_wasm_paths "$RUNNER_TEMP/ci-paths"
|
||||
if [ "$gpu_paths" = false ] && group_has_render_label "$GROUP_BASE_SHA..$GROUP_HEAD_SHA"; then
|
||||
gpu_paths=true
|
||||
fi
|
||||
else
|
||||
windows=true
|
||||
gpu_paths=true
|
||||
deps=true
|
||||
wasm=true
|
||||
fi
|
||||
echo "windows=$windows gpu_paths=$gpu_paths for $GROUP_BASE_SHA...$GROUP_HEAD_SHA"
|
||||
echo "windows=$windows gpu_paths=$gpu_paths deps=$deps wasm=$wasm for $GROUP_BASE_SHA...$GROUP_HEAD_SHA"
|
||||
elif [ "$EVENT_NAME" != pull_request ]; then
|
||||
# The nightly run and Run workflow: everything, Windows included.
|
||||
native=true
|
||||
@@ -256,6 +292,10 @@ jobs:
|
||||
done < "$RUNNER_TEMP/ci-paths"
|
||||
# Computed as for a merge group, then turned off below (the fast lane).
|
||||
windows_paths "$RUNNER_TEMP/ci-paths" "$BASE_SHA...$HEAD_SHA"
|
||||
# The advisories run on the pull request itself (it builds nothing of ours: about two minutes, most of it installing cargo-deny);
|
||||
# the wasm compile waits for the merge queue.
|
||||
deps_wasm_paths "$RUNNER_TEMP/ci-paths"
|
||||
wasm=false
|
||||
# Pull requests build and test the touched packages and their dependents; nothing
|
||||
# selected means no code changed.
|
||||
select_packages "$RUNNER_TEMP/ci-paths"
|
||||
@@ -327,6 +367,8 @@ jobs:
|
||||
echo "windows=$windows"
|
||||
echo "oracle=$oracle"
|
||||
echo "doctests=$doctests"
|
||||
echo "deps=$deps"
|
||||
echo "wasm=$wasm"
|
||||
echo "carried=$carried"
|
||||
echo "full=$full"
|
||||
echo "quick=$quick"
|
||||
@@ -364,6 +406,9 @@ jobs:
|
||||
cargo test -p xtask ui_containers --locked
|
||||
- name: Sorted lists
|
||||
run: cargo xtask lists
|
||||
# New UI text must reach every complete catalog; report it here, before review (#8542).
|
||||
- name: Translations in the complete catalogs
|
||||
run: cargo xtask i18n --check
|
||||
- name: Agent router and skills cite real files
|
||||
run: |
|
||||
cargo xtask skills
|
||||
@@ -943,7 +988,7 @@ jobs:
|
||||
# commit's real run instead: the merge queue reads `ci` from the newest run of a commit, so a
|
||||
# run without a passing `ci` would block a pull request that passed (#1850, #3182, #3252).
|
||||
name: ci
|
||||
needs: [changes, checks, quick-compile, clippy, build-tests, tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup]
|
||||
needs: [changes, checks, quick-compile, clippy, build-tests, tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup, dependency-advisories, wasm]
|
||||
if: always() && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
@@ -997,6 +1042,10 @@ jobs:
|
||||
ORACLE: ${{ needs.oracle.result }}
|
||||
WINDOWS_FXC: ${{ needs.windows-fxc.result }}
|
||||
WINDOWS_STARTUP: ${{ needs.windows-startup.result }}
|
||||
DEPS_RUN: ${{ needs.changes.outputs.deps }}
|
||||
ADVISORIES: ${{ needs.dependency-advisories.result }}
|
||||
WASM_RUN: ${{ needs.changes.outputs.wasm }}
|
||||
WASM: ${{ needs.wasm.result }}
|
||||
run: |
|
||||
test "$CHANGES" = success
|
||||
test "$CHECKS" = success
|
||||
@@ -1026,6 +1075,14 @@ jobs:
|
||||
test "$WINDOWS_FXC" = success
|
||||
test "$WINDOWS_STARTUP" = success
|
||||
fi
|
||||
# Cargo.lock or a Cargo.toml changed on a pull request or in a merge group.
|
||||
if [ "$DEPS_RUN" = true ]; then
|
||||
test "$ADVISORIES" = success
|
||||
fi
|
||||
# A merge group that reaches the wasm build.
|
||||
if [ "$WASM_RUN" = true ]; then
|
||||
test "$WASM" = success
|
||||
fi
|
||||
- name: Note a carried result
|
||||
if: needs.changes.outputs.carried != ''
|
||||
env:
|
||||
@@ -1033,9 +1090,13 @@ jobs:
|
||||
run: |
|
||||
echo "This push only merges main into a change that already passed; the heavy checks were not repeated. Passing run: $CARRIED" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# Every crate below the apps and the web app must build for the browser (`cargo xtask wasm`, a
|
||||
# cargo check, no tests). In the merge queue for a group that reaches the wasm build (Select
|
||||
# checks' `wasm`), where `ci` requires it; by hand with cross_compile.
|
||||
wasm:
|
||||
name: Compile WebAssembly (manual)
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.cross_compile
|
||||
name: Compile WebAssembly
|
||||
needs: changes
|
||||
if: ${{ !cancelled() && ((github.event_name == 'workflow_dispatch' && inputs.cross_compile) || needs.changes.outputs.wasm == 'true') }}
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
@@ -1096,3 +1157,49 @@ jobs:
|
||||
. "$HOME/.cargo/env"
|
||||
export CRAFT_FONTS_DIR="$PWD/craft-fonts"
|
||||
cargo check --all-targets --locked --target riscv64gc-unknown-linux-gnu
|
||||
|
||||
# Nobody watches the nightly run, and it failed every day from 2026-10-16 to 2026-10-28 before
|
||||
# anyone noticed. When a nightly fails, open one issue, "Nightly CI is failing" (label `ci`), or
|
||||
# comment on it if it is already open; when a nightly passes, close it. A nightly that neither
|
||||
# failed nor fully passed (cancelled) leaves the issue as it is. The only job that may write issues.
|
||||
nightly-alert:
|
||||
name: Nightly alert
|
||||
needs: [dependency-advisories, changes, checks, ci, build-tests, action-matrix, action-matrix-determinism, property-tests]
|
||||
if: always() && github.event_name == 'schedule'
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Open, update or close the nightly issue
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
RESULTS: ${{ toJSON(needs) }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
SHA: ${{ github.sha }}
|
||||
run: |
|
||||
title="Nightly CI is failing"
|
||||
failed=$(jq -r 'to_entries[] | select(.value.result == "failure") | .key' <<<"$RESULTS")
|
||||
unfinished=$(jq -r 'to_entries[] | select(.value.result != "success" and .value.result != "failure") | "\(.key) (\(.value.result))"' <<<"$RESULTS")
|
||||
issue=$(gh issue list --state open --label ci --limit 100 --json number,title \
|
||||
--jq "[.[] | select(.title == \"$title\")] | first | .number // empty")
|
||||
if [ -n "$failed" ]; then
|
||||
body="The nightly run on ${SHA:0:9} failed: $RUN_URL
|
||||
|
||||
Failed jobs: $(paste -sd , - <<<"$failed" | sed 's/,/, /g')."
|
||||
if [ -n "$issue" ]; then
|
||||
gh issue comment "$issue" --body "$body"
|
||||
else
|
||||
gh issue create --title "$title" --label ci --body "$body
|
||||
|
||||
This issue is opened and updated by the nightly run (the nightly-alert job in .github/workflows/ci.yml) and closed by the first nightly that passes."
|
||||
fi
|
||||
elif [ -z "$unfinished" ]; then
|
||||
if [ -n "$issue" ]; then
|
||||
gh issue close "$issue" --comment "The nightly run on ${SHA:0:9} passed: $RUN_URL"
|
||||
fi
|
||||
echo "The nightly passed."
|
||||
else
|
||||
echo "Nothing failed, but not every job finished: $unfinished. The issue is left as it is."
|
||||
fi
|
||||
|
||||
@@ -52,6 +52,7 @@ jobs:
|
||||
# effort: a fork PR just doesn't get the `changes-default` label from here.
|
||||
label:
|
||||
name: Label changes-default
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
continue-on-error: true
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
# (see the windows job). Nothing else is signed yet.
|
||||
#
|
||||
# Linux x86_64, aarch64 AppImage (+ .zsync), .deb, .rpm, .flatpak, .snap, .tar.gz packaging/linux
|
||||
# Arch Linux x86_64, aarch64 .pkg.tar.zst, repackaged from the .tar.gz the arch job
|
||||
# FreeBSD x86_64 .tar.gz (built in a FreeBSD VM) packaging/freebsd
|
||||
# macOS universal .dmg, and the CLI as a .zip (both archs built in parallel) packaging/macos
|
||||
# Windows x64, x86, arm64 .msi and a portable .zip; x64 also the plain .exe packaging/windows
|
||||
@@ -206,6 +207,45 @@ jobs:
|
||||
path: dist/release/*.flatpak
|
||||
if-no-files-found: error
|
||||
|
||||
arch:
|
||||
name: Arch Linux ${{ matrix.arch }}
|
||||
needs: [version, linux]
|
||||
if: needs.version.outputs.build == 'true'
|
||||
# makepkg only repackages the tarball's prebuilt binaries, so both architectures build here.
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x86_64, aarch64]
|
||||
env:
|
||||
VERSION: ${{ needs.version.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
name: release-linux-${{ matrix.arch }}
|
||||
path: dist/linux
|
||||
# The Craft apps' shared Arch packaging (storytold/craft-common-actions, MIT OR Apache-2.0):
|
||||
# makepkg in an archlinux:base-devel container. The package is named after the tarball's
|
||||
# .desktop file (io.tangencylabs.solidcraft) and written as
|
||||
# dist/release/solidcraft-<version>-linux-<arch>.pkg.tar.zst.
|
||||
- uses: storytold/craft-common-actions/actions/arch-package@fa5ef18780cf5e7d5d3b8de068de56cffc83cac5 # main
|
||||
with:
|
||||
tarball: dist/linux/solidcraft-${{ env.VERSION }}-linux-${{ matrix.arch }}.tar.gz
|
||||
arch: ${{ matrix.arch }}
|
||||
- name: Check the package
|
||||
env:
|
||||
PKG: dist/release/solidcraft-${{ env.VERSION }}-linux-${{ matrix.arch }}.pkg.tar.zst
|
||||
run: |
|
||||
tar --zstd -tf "$PKG" | grep -E '^usr/bin/solidcraft$|^usr/bin/solidcraft-cli$|^usr/share/applications/io\.tangencylabs\.solidcraft\.desktop$'
|
||||
tar --zstd -xOf "$PKG" .PKGINFO | grep -E '^(pkgname|pkgver|arch) = '
|
||||
tar --zstd -xOf "$PKG" .PKGINFO | grep -qx 'pkgname = io.tangencylabs.solidcraft'
|
||||
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: release-arch-${{ matrix.arch }}
|
||||
path: dist/release/*.pkg.tar.zst
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
|
||||
snap:
|
||||
@@ -571,7 +611,7 @@ jobs:
|
||||
|
||||
release:
|
||||
name: GitHub Release or dry-run artifacts
|
||||
needs: [version, linux, flatpak, snap, freebsd, macos, windows, web]
|
||||
needs: [version, linux, flatpak, arch, snap, freebsd, macos, windows, web]
|
||||
if: needs.version.outputs.build == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -597,7 +637,7 @@ jobs:
|
||||
shopt -s nullglob
|
||||
for f in "solidcraft-$VERSION-"*; do
|
||||
case "$f" in
|
||||
*.msi | *-portable.zip | *.dmg | *.AppImage | *.deb | *.rpm | *.flatpak | *.snap)
|
||||
*.msi | *-portable.zip | *.dmg | *.AppImage | *.deb | *.rpm | *.flatpak | *.snap | *.pkg.tar.zst)
|
||||
cp -- "$f" "solidcraft-${f#"solidcraft-$VERSION-"}" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -603,6 +603,31 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
|
||||
| assets/icons/ui/design/svg/model/finish_edit.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| `assets/locales/pending/sketch-tracking-guides.json` | SolidCraft contributors | Original alignment-guide preference labels and help text | MIT OR Apache-2.0 |
|
||||
| assets/locales/pending/point-clouds.json | SolidCraft contributors | Original point-cloud UI strings and translations | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/feature_group.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/mesh_body.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/timeline_play.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/timeline_stop.svg | SolidCraft contributors | Original history playback icon; canonical grey_cube base and original action cue | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/flat/status_pin.svg | SolidCraft contributors | Original analytic pin icon for persistent viewport results | MIT OR Apache-2.0 |
|
||||
| assets/locales/pending/render-wear.json | SolidCraft contributors | Original UI labels and translations | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/equation_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
|
||||
| assets/locales/pending/sketch-recent-snap.json | SolidCraft contributors | Original preference messages for the recent centre and midpoint snap | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_horizontal.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_vertical.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_angle.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_parallel.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_perpendicular.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_external.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_at.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_two.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_bisector.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-circle.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-circle.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-flower.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-flower.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-involute.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-involute.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-line.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-line.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-parabola.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-parabola.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-spiral.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-spiral.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-wave.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-wave.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
|
||||
## Code adapted from sibling projects
|
||||
|
||||
|
||||
@@ -117,7 +117,8 @@ The [architecture page](docs/architecture.md) has the layer table. The short ver
|
||||
not.) Permissive
|
||||
dependencies are fine. Note which one you're adding and why in the PR. THIRD-PARTY-LICENSES.txt
|
||||
lists it once the change lands: the Generated files workflow rewrites it on `main`.
|
||||
Nightly/manual CI also scans advisories, bans and sources with cargo-deny; see
|
||||
Nightly/manual CI also scans advisories, bans and sources with cargo-deny, and a PR that
|
||||
changes Cargo.lock or a Cargo.toml checks the advisories; see
|
||||
[the local command and coverage limits](docs/book/src/dev/testing.md#dependency-advisories).
|
||||
3. **Every asset is original or openly licensed and has a row in
|
||||
[ATTRIBUTION.md](ATTRIBUTION.md).** Icons are drawn in code (`crates/ui-egui/src/icons.rs`).
|
||||
@@ -278,6 +279,11 @@ Some files gain an item in many pull requests at once. They are kept so that two
|
||||
each add an item only meet when their items are neighbours, which spares everyone a conflict
|
||||
and a fresh CI run:
|
||||
|
||||
- **Growing Rust lists**: use slices (`const ITEMS: &[Item] = &[...];`) without a written
|
||||
length. `cargo xtask lists` rejects non-test const/static arrays with more than ten lines
|
||||
of entries, except fixed standard or algorithm tables listed with reasons in `xtask/src/lists.rs`.
|
||||
Built-in themes need only a JSON file in `assets/styles/ui/themes/`, with a unique nonnegative
|
||||
integer `order` (the picker order) and its own `provenance` line; keep existing order values.
|
||||
- **Message catalogs** (`assets/locales/*.json`): one message per line, sorted by id. Add your
|
||||
message anywhere and run `cargo xtask lists --fix`; `cargo xtask lists` (in `cargo xtask ci`
|
||||
and the Lists workflow) fails on an unsorted catalog or an id that appears twice.
|
||||
@@ -300,7 +306,9 @@ and a fresh CI run:
|
||||
- **Design format**: one file per change, never an edit to a shared number (above).
|
||||
- **New UI strings and attribution rows**: one new file per change, `assets/locales/pending/<slug>.json`
|
||||
and `attribution/pending/<slug>.md`, instead of editing the catalogs or the ATTRIBUTION.md table;
|
||||
`cargo xtask fold-pending` folds them on `main` (see the README in each folder).
|
||||
`cargo xtask fold-pending` folds them on `main` (see the README in each folder). A new English
|
||||
message also needs every catalog delivered complete (`COMPLETE` in `crates/ui-egui/src/i18n.rs`:
|
||||
today ar, he, ja, vi, and zh) in the same pending file; `cargo xtask i18n --check` reports any gap.
|
||||
|
||||
## Sending a change
|
||||
|
||||
|
||||
@@ -130,10 +130,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cipher 0.4.4",
|
||||
"cpufeatures 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35f0f96ce78e38c3dc6d8948aa8163d06385be74000f3c7a95bf1eef35d3ea32"
|
||||
dependencies = [
|
||||
"cipher 0.5.2",
|
||||
"cpubits",
|
||||
"cpufeatures 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
@@ -148,6 +159,21 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc-no-stdlib"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||
|
||||
[[package]]
|
||||
name = "alloc-stdlib"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
@@ -504,6 +530,15 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.5.1"
|
||||
@@ -544,6 +579,16 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "5.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
@@ -755,7 +800,16 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
"cipher 0.4.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cbc"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896"
|
||||
dependencies = [
|
||||
"cipher 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -844,7 +898,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common 0.1.7",
|
||||
"inout",
|
||||
"inout 0.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
|
||||
dependencies = [
|
||||
"crypto-common 0.2.2",
|
||||
"inout 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -969,6 +1033,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48"
|
||||
|
||||
[[package]]
|
||||
name = "cpubits"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
@@ -1078,9 +1148,9 @@ version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"block-padding",
|
||||
"cbc",
|
||||
"aes 0.8.4",
|
||||
"block-padding 0.3.3",
|
||||
"cbc 0.1.2",
|
||||
"dbus",
|
||||
"fastrand",
|
||||
"hkdf",
|
||||
@@ -1190,6 +1260,15 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "ecb"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26f2a8b3e564eba0877223dc343703ad0385794e882e6d13f3a4dd5c6b1f41ac"
|
||||
dependencies = [
|
||||
"cipher 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ecolor"
|
||||
version = "0.36.2"
|
||||
@@ -1706,7 +1785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
"weezl 0.1.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2164,10 +2243,20 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"block-padding 0.3.3",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b5cf4372d022092674a83b8febf5865f7a573cc0c5baec5e49c879b6a20978f"
|
||||
dependencies = [
|
||||
"block-padding 0.4.2",
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@@ -2432,6 +2521,33 @@ version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||
|
||||
[[package]]
|
||||
name = "lopdf"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfffda0fe1ab0157e1a13c14bebd3f28671f2fccb7922f0722ec53926e6922d3"
|
||||
dependencies = [
|
||||
"aes 0.9.3",
|
||||
"bitflags 2.13.2",
|
||||
"brotli-decompressor",
|
||||
"cbc 0.2.1",
|
||||
"ecb",
|
||||
"encoding_rs",
|
||||
"flate2",
|
||||
"getrandom 0.4.3",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"log",
|
||||
"md-5",
|
||||
"nom",
|
||||
"rand 0.10.3",
|
||||
"rangemap",
|
||||
"sha2 0.11.1",
|
||||
"stringprep",
|
||||
"thiserror 2.0.21",
|
||||
"weezl 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matext4cgmath"
|
||||
version = "0.1.0"
|
||||
@@ -2441,6 +2557,16 @@ dependencies = [
|
||||
"num-complex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
@@ -2624,6 +2750,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
@@ -3430,6 +3565,7 @@ version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
|
||||
dependencies = [
|
||||
"chacha20",
|
||||
"getrandom 0.4.3",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
@@ -3474,6 +3610,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08"
|
||||
|
||||
[[package]]
|
||||
name = "rangemap"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.2"
|
||||
@@ -3773,9 +3915,9 @@ checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.15"
|
||||
version = "0.103.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
|
||||
checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -3858,8 +4000,8 @@ version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"cbc",
|
||||
"aes 0.8.4",
|
||||
"cbc 0.1.2",
|
||||
"futures-util",
|
||||
"generic-array",
|
||||
"hkdf",
|
||||
@@ -4210,7 +4352,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"eframe",
|
||||
@@ -4235,6 +4377,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"solidcraft-3dx-client",
|
||||
"solidcraft-engine",
|
||||
"solidcraft-gpu",
|
||||
"solidcraft-space-mouse",
|
||||
"solidcraft-ui-egui",
|
||||
"ureq",
|
||||
@@ -4245,11 +4388,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-3dx-client"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-cli"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4261,7 +4404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-derive"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4270,7 +4413,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-doc"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -4287,7 +4430,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-engine"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4308,7 +4451,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-geom"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4317,7 +4460,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-gpu"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4337,7 +4480,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-io"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"cadmpeg-core",
|
||||
"cadmpeg-ir",
|
||||
@@ -4361,7 +4504,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-kernel"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proptest",
|
||||
@@ -4381,7 +4524,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-mcp"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"solidcraft-engine",
|
||||
@@ -4390,7 +4533,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-render"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"moxcms",
|
||||
@@ -4399,12 +4542,12 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"solidcraft-geom",
|
||||
"weezl",
|
||||
"weezl 0.1.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-sketch"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"harfrust",
|
||||
"serde",
|
||||
@@ -4417,20 +4560,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-space-mouse"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-egui"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
"egui-wgpu",
|
||||
"image",
|
||||
"log",
|
||||
"lopdf",
|
||||
"minisign-verify",
|
||||
"nix 0.31.3",
|
||||
"pollster 0.4.0",
|
||||
@@ -4454,7 +4598,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-web"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
@@ -4509,6 +4653,17 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
"unicode-properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
@@ -4630,7 +4785,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"weezl 0.1.12",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
@@ -4669,6 +4824,12 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.53.2"
|
||||
@@ -4974,6 +5135,21 @@ version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.13.3"
|
||||
@@ -5362,9 +5538,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
|
||||
checksum = "58ec80e73fd8baf57bf0d9615554c75348bda990d6d5bbeab964dd068319fecb"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
@@ -5375,6 +5551,12 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2"
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "30.0.1"
|
||||
@@ -5845,8 +6027,6 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.30.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"android-activity",
|
||||
@@ -5999,7 +6179,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"serde",
|
||||
|
||||
@@ -5,7 +5,7 @@ members = ["crates/*", "apps/*", "xtask"]
|
||||
exclude = ["vendor"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.26.0"
|
||||
version = "0.27.1"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
@@ -161,6 +161,10 @@ matext4cgmath = { path = "vendor/matext4cgmath" }
|
||||
# Keep OpenGL pipelines, resolve textures and CAD callbacks at the same safe sample count.
|
||||
egui-wgpu = { path = "vendor/egui-wgpu" }
|
||||
|
||||
# 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 = { path = "vendor/winit" }
|
||||
|
||||
# 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.
|
||||
[profile.mutants]
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/296178?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-296178" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/296178/daily" alt="tangency-labs%2Fsolidcraft | Trendshift" width="250" height="55"/></a>
|
||||
<a href="https://trendshift.io/repositories/296178?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-296178" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/296178/daily?language=Rust" alt="tangency-labs%2Fsolidcraft | Trendshift (Rust)" width="250" height="55"/></a>
|
||||
<a href="https://trendshift.io/repositories/296178?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-296178" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/296178/daily" alt="tangency-labs%2Fsolidcraft | Trendshift" width="250" height="55"/></a>
|
||||
<a href="https://trendshift.io/repositories/296178?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-296178" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/296178/daily?language=Rust" alt="tangency-labs%2Fsolidcraft | Trendshift (Rust)" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||

|
||||
@@ -98,7 +98,7 @@ More commands, the Windows cross-build and the browser build are in [docs/buildi
|
||||
runs its own design session, or with `--connect` it drives the running app so you can watch.
|
||||
Claude Code: `claude mcp add solidcraft -- solidcraft-cli mcp`. If a terminal doesn't find
|
||||
`solidcraft-cli` (older Windows installers don't put it on `PATH`), give its full path (by default
|
||||
`"C:\Program Files\SolidCraft\solidcraft-cli.exe"`). Tools, access rules and an example session:
|
||||
`"C:\\Program Files\\SolidCraft\\solidcraft-cli.exe"`). Tools, access rules and an example session:
|
||||
[docs/mcp.md](docs/mcp.md).
|
||||
|
||||
## Scripts
|
||||
@@ -150,3 +150,4 @@ Tinkercad are trademarks of their respective owners, named only to describe comp
|
||||
[linux-appimage]: https://github.com/tangency-labs/solidcraft/releases/latest/download/solidcraft-linux-x86_64.AppImage
|
||||
[snap-store]: https://snapcraft.io/solidcraft
|
||||
[web-app]: https://solidcraft.io/app
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ rustls-native-certs 0.8.5 (Apache-2.0 OR ISC OR MIT)
|
||||
rustls-pki-types 1.15.1 (MIT OR Apache-2.0)
|
||||
rustls-platform-verifier 0.7.1 (MIT OR Apache-2.0)
|
||||
rustls-platform-verifier-android 0.2.0 (MIT OR Apache-2.0)
|
||||
rustls-webpki 0.103.15 (ISC)
|
||||
rustls-webpki 0.103.16 (ISC)
|
||||
rustversion 1.0.23 (MIT OR Apache-2.0)
|
||||
ruzstd 0.9.1 (MIT)
|
||||
schannel 0.1.29 (MIT)
|
||||
@@ -435,7 +435,7 @@ truck-topology 0.6.0 (Apache-2.0)
|
||||
ttf-parser 0.25.1 (MIT OR Apache-2.0)
|
||||
twox-hash 2.1.5 (MIT)
|
||||
type-map 0.5.1 (MIT/Apache-2.0)
|
||||
typed-path 0.12.3 (MIT OR Apache-2.0)
|
||||
typed-path 0.13.0 (MIT OR Apache-2.0)
|
||||
typeid 1.0.3 (MIT OR Apache-2.0)
|
||||
typenum 1.20.1 (MIT OR Apache-2.0)
|
||||
uds_windows 1.2.1 (MIT)
|
||||
@@ -474,7 +474,7 @@ wayland-sys 0.31.11 (MIT)
|
||||
web-sys 0.3.106 (MIT OR Apache-2.0)
|
||||
web-time 1.1.0 (MIT OR Apache-2.0)
|
||||
webbrowser 1.2.4 (MIT OR Apache-2.0)
|
||||
webpki-root-certs 1.0.9 (CDLA-Permissive-2.0)
|
||||
webpki-root-certs 1.0.10 (CDLA-Permissive-2.0)
|
||||
weezl 0.1.12 (MIT OR Apache-2.0)
|
||||
wgpu 30.0.1 (MIT OR Apache-2.0)
|
||||
wgpu-core 30.0.1 (MIT OR Apache-2.0)
|
||||
@@ -552,7 +552,7 @@ zeroize_derive 1.5.0 (Apache-2.0 OR MIT)
|
||||
zerotrie 0.2.5 (Unicode-3.0)
|
||||
zerovec 0.11.8 (Unicode-3.0)
|
||||
zerovec-derive 0.11.6 (Unicode-3.0)
|
||||
zip 9.0.4 (MIT)
|
||||
zip 9.1.3 (MIT)
|
||||
zlib-rs 0.6.8 (Zlib)
|
||||
zmij 1.0.23 (MIT)
|
||||
zopfli 0.8.3 (Apache-2.0)
|
||||
@@ -596,7 +596,7 @@ pin-project 1.1.13, pin-project-internal 1.1.13, pin-project-lite 0.2.17, piper
|
||||
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,
|
||||
serde_derive 1.0.229, serde_derive_internals 0.30.0, serde_json 1.0.151, serde_path_to_error 0.1.20,
|
||||
serde_repr 0.1.21, simd_cesu8 1.2.0, smol_str 0.2.2, syn 1.0.109, syn 2.0.119, syn 3.0.6, thiserror
|
||||
1.0.69, thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.12.3, typeid
|
||||
1.0.69, thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.13.0, typeid
|
||||
1.0.3, 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, 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, zbus_names 3.0.0, zmij 1.0.23, zvariant_utils 2.1.0, zvariant_utils
|
||||
@@ -1339,7 +1339,7 @@ libc 0.2.190, litrs 1.0.0, num_enum 0.7.6, num_enum_derive 0.7.6, proc-macro2 1.
|
||||
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.151, serde_path_to_error 0.1.20, serde_repr 0.1.21, syn 2.0.119, syn 3.0.6, thiserror 1.0.69,
|
||||
thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.12.3, typeid 1.0.3,
|
||||
thiserror 2.0.21, thiserror-impl 1.0.69, thiserror-impl 2.0.21, typed-path 0.13.0, typeid 1.0.3,
|
||||
unicode-ident 1.0.26, utf8-zero 0.8.1
|
||||
================================================================================
|
||||
|
||||
@@ -12431,7 +12431,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
rustls-webpki 0.103.15
|
||||
rustls-webpki 0.103.16
|
||||
================================================================================
|
||||
|
||||
Except as otherwise noted, this project is licensed under the following
|
||||
@@ -15274,7 +15274,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
webpki-root-certs 1.0.9
|
||||
webpki-root-certs 1.0.10
|
||||
================================================================================
|
||||
|
||||
# Community Data License Agreement - Permissive - Version 2.0
|
||||
@@ -16401,7 +16401,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
zip 9.0.4
|
||||
zip 9.1.3
|
||||
================================================================================
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
@@ -66,7 +66,7 @@ fn run() -> Result<(), String> {
|
||||
let mut session = Session::default();
|
||||
eprintln!("Generating original CAD scene from {recipe_path}");
|
||||
let generation_start = Instant::now();
|
||||
let (commands, command_timings) = session.run_script_timed(&recipe, false).map_err(|e| e.to_string())?;
|
||||
let (commands, command_timings) = session.run_script_timed(&recipe, false, &mut |_, _| {}).map_err(|e| e.to_string())?;
|
||||
let generation_seconds = generation_start.elapsed().as_secs_f64();
|
||||
let design_path = output.with_extension(solidcraft_engine::io::DESIGN_EXT);
|
||||
session.execute("file.save_as", &json!({"path":design_path})).map_err(|e| e.to_string())?;
|
||||
@@ -87,7 +87,7 @@ fn run() -> Result<(), String> {
|
||||
let gpu_host_start = Instant::now();
|
||||
let policy = solidcraft_gpu::select::Policy::from_env().map_err(|e| e.to_string())?;
|
||||
let (adapter, report) =
|
||||
solidcraft_gpu::select::pick_vulkan(policy, |_| true).ok_or("no Vulkan adapter satisfies the requested GPU policy")?;
|
||||
solidcraft_gpu::select::pick_path(policy, |_| true).ok_or("no Vulkan or Metal adapter satisfies the requested GPU policy")?;
|
||||
session.register_render_job_host(solidcraft_gpu::path::host_on_adapter(&adapter).map_err(|e| e.to_string())?).map_err(|e| e.to_string())?;
|
||||
(Some(report), Some(gpu_host_start.elapsed().as_secs_f64()))
|
||||
} else {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
//!
|
||||
//! ```text
|
||||
//! solidcraft-cli run <script.json|design.sc|part.step|mesh.3mf> [--in design|part.step|mesh.3mf] [--out FILE]... [--save FILE] [--quiet] [--results] [--timings] [--profile] [--json-out FILE] [--allow-errors]
|
||||
//! [--param-check off|warn|strict]
|
||||
//! solidcraft-cli eval <script.json|design.sc|part.step> [--in design.sc|part.step] [--json-out FILE] (alias: inspect) measurements as JSON
|
||||
//! solidcraft-cli script <design.sc> [--out script.json] the design's history as a command script
|
||||
//! solidcraft-cli bench-open <design.sc | part.step> [--parse-only] [--save OUT.sc] [--display LEVEL [--edit NAME EXPR]] [--ops script.json] loading timings as JSON lines
|
||||
@@ -57,7 +58,7 @@ struct Command {
|
||||
}
|
||||
|
||||
/// `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] [--json-out FILE] [--allow-errors]\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 (--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";
|
||||
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] [--json-out FILE] [--allow-errors]\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 (--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";
|
||||
/// `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] (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";
|
||||
/// `script`'s lines in the usage.
|
||||
@@ -299,18 +300,36 @@ fn load_checked(path: &str, check: solidcraft_engine::schema::ParamCheck) -> Res
|
||||
s.execute("doc.open", &json!({"path": path})).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
let script = if v.get("features").is_some() && v.get("commands").is_none() { recipe::to_script(&v)? } else { v };
|
||||
// Warn level: each step's `param_warnings` as it completes, even when a later step fails
|
||||
// (stderr, so stdout stays the caller's).
|
||||
let mut warn = |step: usize, r: &Value| {
|
||||
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());
|
||||
}
|
||||
};
|
||||
s.run_script_each(&script, &mut warn).map_err(|e| e.to_string())?;
|
||||
run_script_warning(&mut s, path, &script)?;
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
/// Run `script`, read from `path`, on `s`. At the warn level each step's `param_warnings` go to
|
||||
/// stderr as the step completes, even when a later step fails (stdout stays the caller's).
|
||||
fn run_script_warning(s: &mut Session, path: &str, script: &Value) -> Result<Vec<Value>, String> {
|
||||
s.run_script_each(script, &mut |step, r| print_param_warnings(path, step, r)).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// `--param-check off|warn|strict`: how calls that break a command's parameter contract are
|
||||
/// treated (docs/mcp.md); off when the option isn't given.
|
||||
fn parse_param_check(cmd: &str, args: &[String]) -> Result<solidcraft_engine::schema::ParamCheck, String> {
|
||||
match flag(args, "--param-check") {
|
||||
None if args.iter().any(|a| a == "--param-check") => Err(format!("{cmd}: --param-check wants off, warn or strict")),
|
||||
None => Ok(solidcraft_engine::schema::ParamCheck::Off),
|
||||
Some(v) => {
|
||||
solidcraft_engine::schema::ParamCheck::parse(v).ok_or_else(|| format!("{cmd}: --param-check wants off, warn or strict, not `{v}`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flag<'a>(args: &'a [String], name: &str) -> Option<&'a str> {
|
||||
args.iter().position(|a| a == name).and_then(|i| args.get(i + 1)).map(String::as_str)
|
||||
}
|
||||
@@ -367,7 +386,15 @@ fn print_json(v: &Value, file: Option<&str>) -> Result<(), String> {
|
||||
fn cmd_run(args: &[String]) -> Result<(), String> {
|
||||
install_renderer();
|
||||
let json_out = json_out(args)?;
|
||||
known_args("run", args, &["--in", "--out", "--save", "--json-out"], &["--quiet", "--results", "--timings", "--profile", "--allow-errors"], true)?;
|
||||
// Before the option check, so a bare `--param-check` gets the words `mcp` uses.
|
||||
let check = parse_param_check("run", args)?;
|
||||
known_args(
|
||||
"run",
|
||||
args,
|
||||
&["--in", "--out", "--save", "--json-out", "--param-check"],
|
||||
&["--quiet", "--results", "--timings", "--profile", "--allow-errors"],
|
||||
true,
|
||||
)?;
|
||||
let base = flag(args, "--in");
|
||||
let path = positional(args);
|
||||
if path.is_none() && base.is_none() {
|
||||
@@ -380,23 +407,25 @@ fn cmd_run(args: &[String]) -> Result<(), String> {
|
||||
let (mut s, results) = if want_results || timings {
|
||||
// Collect every command's result or time (scripts only), then process requested files too.
|
||||
let mut s = match base {
|
||||
Some(b) => load(b)?,
|
||||
Some(b) => load_checked(b, check)?,
|
||||
None => Session::default(),
|
||||
};
|
||||
s.param_check = check;
|
||||
let needs = if want_results { "--results needs a script" } else { "--timings needs a script" };
|
||||
let v = read_json(path.ok_or(needs)?)?;
|
||||
let script = path.ok_or(needs)?;
|
||||
let v = read_json(script)?;
|
||||
let out = if timings {
|
||||
let (r, mut t) = s.run_script_timed(&v, profile).map_err(|e| e.to_string())?;
|
||||
let (r, mut t) = s.run_script_timed(&v, profile, &mut |step, r| print_param_warnings(script, step, r)).map_err(|e| e.to_string())?;
|
||||
if want_results && let Some(o) = t.as_object_mut() {
|
||||
o.insert("results".into(), Value::Array(r));
|
||||
}
|
||||
t
|
||||
} else {
|
||||
Value::Array(s.run_script(&v).map_err(|e| e.to_string())?)
|
||||
Value::Array(run_script_warning(&mut s, script, &v)?)
|
||||
};
|
||||
(s, Some(out))
|
||||
} else {
|
||||
(open(base, path)?, None)
|
||||
(open(base, path, check)?, None)
|
||||
};
|
||||
// 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
|
||||
@@ -421,16 +450,16 @@ fn cmd_run(args: &[String]) -> Result<(), String> {
|
||||
}
|
||||
|
||||
/// The session `run`, `eval` and `snapshot` start from: `--in` (a design or STEP file) with the
|
||||
/// positional script run on top of it, or either one alone.
|
||||
fn open(base: Option<&str>, path: Option<&String>) -> Result<Session, String> {
|
||||
/// positional script run on top of it, or either one alone, with scripts run at `check`.
|
||||
fn open(base: Option<&str>, path: Option<&String>, check: solidcraft_engine::schema::ParamCheck) -> Result<Session, String> {
|
||||
match (base, path) {
|
||||
(Some(b), Some(p)) => {
|
||||
let mut s = load(b)?;
|
||||
s.run_script(&read_json(p)?).map_err(|e| e.to_string())?;
|
||||
let mut s = load_checked(b, check)?;
|
||||
run_script_warning(&mut s, p, &read_json(p)?)?;
|
||||
Ok(s)
|
||||
}
|
||||
(Some(b), None) => load(b),
|
||||
(None, Some(p)) => load(p),
|
||||
(Some(b), None) => load_checked(b, check),
|
||||
(None, Some(p)) => load_checked(p, check),
|
||||
(None, None) => Err(usage()),
|
||||
}
|
||||
}
|
||||
@@ -473,7 +502,7 @@ fn timeline_ok(s: &Session) -> Result<(), String> {
|
||||
fn cmd_eval(args: &[String]) -> Result<(), String> {
|
||||
let json_out = json_out(args)?;
|
||||
known_args("eval", args, &["--in", "--json-out"], &[], true)?;
|
||||
let mut s = open(flag(args, "--in"), positional(args))?;
|
||||
let mut s = open(flag(args, "--in"), positional(args), solidcraft_engine::schema::ParamCheck::Off)?;
|
||||
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 out = json!({
|
||||
@@ -567,7 +596,7 @@ fn cmd_snapshot(args: &[String]) -> Result<(), String> {
|
||||
Some(x) => x.parse().ok().filter(|n| (16..=8192).contains(n)).ok_or_else(|| format!("{name} must be 16 to 8192 pixels, not `{x}`")),
|
||||
};
|
||||
let (w, h) = (size("--width", 1280)?, size("--height", 800)?);
|
||||
let mut s = open(flag(args, "--in"), positional(args))?;
|
||||
let mut s = open(flag(args, "--in"), positional(args), solidcraft_engine::schema::ParamCheck::Off)?;
|
||||
// How the bodies are drawn and where the model is cut, through the commands the app's
|
||||
// Appearance dialog and Section Analysis run (`preview`).
|
||||
preview::apply(&mut s, &flags(args, "--body"), &flags(args, "--tool"), flag(args, "--section"))?;
|
||||
@@ -691,17 +720,8 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
eprintln!("solidcraft mcp: the design's folder is left out because {why}; add it with --allow-path if you mean it");
|
||||
}
|
||||
}
|
||||
// How a headless session treats calls that break a command's parameter contract (docs/mcp.md).
|
||||
let param_check = match flag(args, "--param-check") {
|
||||
None if args.iter().any(|a| a == "--param-check") => return Err("mcp: --param-check wants off, warn or strict".into()),
|
||||
None => solidcraft_engine::schema::ParamCheck::Off,
|
||||
Some(v) => {
|
||||
solidcraft_engine::schema::ParamCheck::parse(v).ok_or_else(|| format!("mcp: --param-check wants off, warn or strict, not `{v}`"))?
|
||||
}
|
||||
};
|
||||
if param_check != solidcraft_engine::schema::ParamCheck::Off && flag(args, "--connect").is_some() {
|
||||
eprintln!("solidcraft mcp: --param-check applies to headless sessions; calls to the app are not checked yet");
|
||||
}
|
||||
// How calls that break a command's parameter contract are treated, headless or bridged.
|
||||
let param_check = parse_param_check("mcp", args)?;
|
||||
let backend: Box<dyn solidcraft_mcp::Backend> = match (flag(args, "--connect"), flag(args, "--in")) {
|
||||
(Some(_), Some(_)) => return Err("mcp: use either --connect or --in, not both".into()),
|
||||
(Some(addr), None) => {
|
||||
@@ -709,7 +729,7 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
return Err(format!("mcp: --connect wants HOST:PORT, such as 127.0.0.1:7878, not `{addr}`"));
|
||||
};
|
||||
// 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"));
|
||||
let mut remote = solidcraft_mcp::Remote::new(addr, flag(args, "--token")).with_param_check(param_check);
|
||||
if let Err(e) = remote.try_connect() {
|
||||
eprintln!(
|
||||
"solidcraft mcp: no SolidCraft app at {addr} yet ({e}); start it with `solidcraft --control {port}` \
|
||||
@@ -729,7 +749,8 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
let auto = !args.iter().any(|a| a == "--headless");
|
||||
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)");
|
||||
return serve_mcp(Box::new(solidcraft_mcp::Remote::new(&format!("127.0.0.1:{port}"), flag(args, "--token"))), scope);
|
||||
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);
|
||||
}
|
||||
let mut headless = solidcraft_mcp::Headless::default();
|
||||
headless.session.param_check = param_check;
|
||||
|
||||
@@ -288,3 +288,47 @@ fn undoing_an_edit_after_opening_reuses_the_saved_results() {
|
||||
let _ = std::fs::remove_file(&path);
|
||||
let _ = std::fs::remove_file(format!("{}.bak", path.display()));
|
||||
}
|
||||
|
||||
/// A design saved before body names were pinned (#6403) pins them as it opens, as its first
|
||||
/// command would, and opening it is no change. That command pinned them as part of itself, so
|
||||
/// undoing it went back to the unpinned design, which no evaluated result matched: the first
|
||||
/// undo after opening from the command line evaluated every feature again (82-93 s in a
|
||||
/// 5,484-feature design); `doc.open` pinned them after opening, which marked the design changed.
|
||||
#[test]
|
||||
fn a_design_saved_before_names_were_pinned_opens_pinned_and_unchanged() {
|
||||
let plate = solidcraft_engine::sample::samples().into_iter().find(|s| s.name == "Sample Plate").unwrap();
|
||||
let mut built = Session::default();
|
||||
for c in (plate.script)()["commands"].as_array().unwrap() {
|
||||
built.execute(c["command"].as_str().unwrap(), &c["params"]).unwrap();
|
||||
}
|
||||
let mut doc = built.design().into_owned();
|
||||
for f in &mut doc.features {
|
||||
f.body_names.clear();
|
||||
}
|
||||
doc.reserved_body_names.clear();
|
||||
let unpinned = Session::new(doc);
|
||||
let design = unpinned.design();
|
||||
let saved = unpinned.model.saved(&design).unwrap();
|
||||
let bytes = solidcraft_engine::io::write_design_container_with_cache(&design, solidcraft_engine::io::DesignCompression::Fast, None, Some(&saved))
|
||||
.unwrap();
|
||||
let path = temp("unpinned");
|
||||
std::fs::write(&path, &bytes).unwrap();
|
||||
let file = path.to_string_lossy().to_string();
|
||||
// As the command line opens a design (`load`), and as the app does (`doc.open`).
|
||||
let (doc, saved) = solidcraft_engine::io::read_design_file(&file, None::<fn(solidcraft_engine::io::DesignPreview)>).unwrap();
|
||||
for (how, mut s) in [("opened_at", Session::opened_at(doc, saved.as_ref(), Some(&file))), ("doc.open", open(&path))] {
|
||||
assert_eq!(s.model.last_recomputed, 0, "{how}: taken from the file");
|
||||
assert!(s.doc.features.iter().any(|f| !f.body_names.is_empty()), "{how}: the names are pinned");
|
||||
assert!(!s.is_dirty(), "{how}: opening is no change");
|
||||
let read: Vec<Arc<ModelState>> = s.model.results.iter().map(|r| r.state.clone()).collect();
|
||||
s.execute("solid.box", &json!({"length": 3, "width": 3, "height": 3, "operation": "new"})).unwrap();
|
||||
// As in a large design, whose evaluation cache keeps only a few results: undo finds the
|
||||
// results in the model itself or evaluates them again.
|
||||
*s.model.cache.lock().unwrap() = Default::default();
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(s.model.last_recomputed, 0, "{how}: the first undo evaluates nothing");
|
||||
assert!(s.model.results.iter().zip(&read).all(|(r, st)| Arc::ptr_eq(&r.state, st)), "{how}: the states read from the file");
|
||||
assert!(!s.is_dirty(), "{how}: undone to the design as opened");
|
||||
}
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
@@ -496,6 +496,78 @@ fn timings_and_profile_report_each_command() {
|
||||
assert!(String::from_utf8_lossy(&output.stderr).contains("--timings needs a script"));
|
||||
}
|
||||
|
||||
/// #6921: `--param-check` checks a script's steps against their contracts on every path `run`
|
||||
/// takes (a script alone, on an `--in` design or script, with `--results`, `--timings` or
|
||||
/// `--profile`), and a warning reaches stderr even when a later step fails.
|
||||
#[test]
|
||||
fn param_check_reaches_every_script_run_takes() {
|
||||
let dir = Scratch::new();
|
||||
let typo = dir.0.join("typo.json");
|
||||
let step = json!({"command": "solid.box", "params": {"length": 2, "width": 3, "height": 4, "operaton": "new"}});
|
||||
std::fs::write(&typo, json!({"commands": [step.clone()]}).to_string()).unwrap();
|
||||
let base = dir.0.join("base.solidcraft");
|
||||
json_output(cli().arg("run").arg(dir.script()).arg("--save").arg(&base).output().unwrap());
|
||||
let saved = dir.0.join("saved.solidcraft");
|
||||
let start = dir.script();
|
||||
let (typo, base, saved_arg, start) = (typo.to_str().unwrap(), base.to_str().unwrap(), saved.to_str().unwrap(), start.to_str().unwrap());
|
||||
let paths = [&[][..], &["--in", base], &["--in", start], &["--results"], &["--timings"], &["--timings", "--profile"]];
|
||||
let run = |level: Option<&str>, extra: &[&str]| {
|
||||
std::fs::remove_file(&saved).ok();
|
||||
let check = level.map(|l| ["--param-check", l]).into_iter().flatten();
|
||||
cli().args(["run", typo, "--save", saved_arg]).args(check).args(extra).output().unwrap()
|
||||
};
|
||||
|
||||
// Off, the default: the step runs as it always has, without a word.
|
||||
let off = run(None, &[]);
|
||||
assert!(off.status.success() && !String::from_utf8_lossy(&off.stderr).contains("operaton"), "{off:?}");
|
||||
assert_eq!(body_count(&saved), 1);
|
||||
|
||||
// Warn: each path runs the step, saves, and reports it on stderr; `--results` keeps it too.
|
||||
for extra in paths {
|
||||
let output = run(Some("warn"), extra);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert!(output.status.success(), "{extra:?}: {stderr}");
|
||||
assert!(stderr.contains("step 1: unknown key `operaton`; did you mean `operation`?"), "{extra:?}: {stderr}");
|
||||
assert!(saved.exists(), "{extra:?}");
|
||||
if extra == ["--results"] {
|
||||
let results: Value = serde_json::from_slice(&output.stdout).unwrap();
|
||||
assert!(results[0]["param_warnings"][0].as_str().is_some_and(|w| w.contains("operaton")), "{results}");
|
||||
}
|
||||
}
|
||||
|
||||
// Strict: on each path the run stops at the step, and nothing is written.
|
||||
for extra in paths {
|
||||
let output = run(Some("strict"), extra);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert_eq!(output.status.code(), Some(1), "{extra:?}: {stderr}");
|
||||
assert!(stderr.contains("unknown key `operaton`"), "{extra:?}: {stderr}");
|
||||
assert!(!saved.exists(), "{extra:?}");
|
||||
}
|
||||
|
||||
// Warn, with a later step that fails: the run fails, and the first step's warning is still
|
||||
// reported, timed or not.
|
||||
let failing = dir.0.join("failing.json");
|
||||
let fail = json!({"command": "solid.extrude", "params": {"sketch": "Nope"}});
|
||||
std::fs::write(&failing, json!({"commands": [step, fail]}).to_string()).unwrap();
|
||||
for extra in [&[][..], &["--timings"]] {
|
||||
let output = cli().arg("run").arg(&failing).args(["--param-check", "warn"]).args(extra).output().unwrap();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert_eq!(output.status.code(), Some(1), "{extra:?}: {stderr}");
|
||||
assert!(stderr.contains("step 1: unknown key `operaton`") && stderr.contains("no sketch `Nope`"), "{extra:?}: {stderr}");
|
||||
}
|
||||
|
||||
// A level it doesn't know and a missing value fail.
|
||||
for (bad, says) in [
|
||||
(&["--param-check", "loud"][..], "--param-check wants off, warn or strict, not `loud`"),
|
||||
(&["--param-check"], "run: --param-check wants off, warn or strict"),
|
||||
] {
|
||||
let output = cli().args(["run", typo]).args(bad).output().unwrap();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert_eq!(output.status.code(), Some(1), "{bad:?}: {stderr}");
|
||||
assert!(stderr.contains(says), "{bad:?}: {stderr}");
|
||||
}
|
||||
}
|
||||
|
||||
fn render_setup_script(dir: &Scratch, job: Value) -> PathBuf {
|
||||
let path = dir.0.join("render.json");
|
||||
std::fs::write(
|
||||
|
||||
@@ -34,7 +34,7 @@ serde_json = { workspace = true }
|
||||
web-sys = { version = "0.3", features = [
|
||||
"Window", "Document", "Element", "HtmlElement", "HtmlCanvasElement", "Location", "Navigator", "StorageManager",
|
||||
"FileSystemHandle", "FileSystemDirectoryHandle", "FileSystemFileHandle", "FileSystemGetFileOptions", "FileSystemWritableFileStream",
|
||||
"WritableStream", "File", "FileList", "Blob", "BlobPropertyBag", "Url", "HtmlAnchorElement", "HtmlInputElement", "Storage",
|
||||
"WritableStream", "File", "FileList", "Blob", "BlobPropertyBag", "Url", "HtmlAnchorElement", "HtmlInputElement", "Storage", "StorageEvent",
|
||||
"IdbFactory", "IdbDatabase", "IdbObjectStore", "IdbOpenDbRequest", "IdbRequest", "IdbTransaction", "IdbTransactionMode",
|
||||
"Headers", "ReadableStream", "ReadableStreamDefaultReader",
|
||||
"BeforeUnloadEvent", "Event", "EventTarget", "KeyboardEvent", "Response", "FormData", "RequestInit", "MediaQueryList", "Gamepad", "Performance",
|
||||
|
||||
@@ -119,6 +119,43 @@ fn closes_design(key: &str, command: bool, shift: bool, alt: bool, design_shown:
|
||||
design_shown && command && !shift && !alt && key.eq_ignore_ascii_case("w")
|
||||
}
|
||||
|
||||
/// The settings a tab last wrote to the browser's storage, or loaded from another tab (#8644).
|
||||
/// Every open tab of the app shares that storage, and eframe saves each tab's whole copy every
|
||||
/// 30 s and when the page loses focus, so a tab still holding old settings put them back over a
|
||||
/// change made in another. A change is now written in the frame it is made, and the other tabs
|
||||
/// load it ([`settings_written`]).
|
||||
#[cfg(any(target_arch = "wasm32", test))]
|
||||
#[derive(Default, Debug)]
|
||||
struct PrefsWriter {
|
||||
written: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "wasm32", test))]
|
||||
impl PrefsWriter {
|
||||
/// `prefs` if they are not the settings written or loaded last (they count as written from
|
||||
/// now on).
|
||||
fn take(&mut self, prefs: String) -> Option<String> {
|
||||
if self.written.as_deref() == Some(prefs.as_str()) {
|
||||
return None;
|
||||
}
|
||||
self.written = Some(prefs.clone());
|
||||
Some(prefs)
|
||||
}
|
||||
|
||||
/// The settings the tab holds after loading another tab's: the tab doesn't write them back.
|
||||
fn loaded(&mut self, prefs: String) {
|
||||
self.written = Some(prefs);
|
||||
}
|
||||
}
|
||||
|
||||
/// The settings another tab wrote, from a `storage` event (the browser sends one to every other
|
||||
/// tab of the page when one tab writes). Other keys, and settings taken away (clearing the site's
|
||||
/// data), leave this tab's settings as they are.
|
||||
#[cfg(any(target_arch = "wasm32", test))]
|
||||
fn settings_written(key: Option<&str>, value: Option<String>) -> Option<String> {
|
||||
value.filter(|_| key == Some(solidcraft_ui_egui::prefs::STORAGE_KEY))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod web {
|
||||
use std::rc::Rc;
|
||||
@@ -217,6 +254,24 @@ mod web {
|
||||
on_key.forget();
|
||||
}
|
||||
|
||||
/// Settings another tab wrote, waiting for this tab's next frame (#8644).
|
||||
type PrefsInbox = Rc<std::cell::Cell<Option<String>>>;
|
||||
|
||||
/// Settings another tab of the app writes go to `inbox`, and this tab draws a frame, which
|
||||
/// loads them.
|
||||
fn hear_settings_from_other_tabs(window: &web_sys::Window, ctx: &egui::Context, inbox: PrefsInbox) {
|
||||
let ctx = ctx.clone();
|
||||
let on_storage = wasm_bindgen::closure::Closure::<dyn FnMut(web_sys::StorageEvent)>::new(move |e: web_sys::StorageEvent| {
|
||||
if let Some(prefs) = crate::settings_written(e.key().as_deref(), e.new_value()) {
|
||||
inbox.set(Some(prefs));
|
||||
ctx.request_repaint();
|
||||
}
|
||||
});
|
||||
let _ = window.add_event_listener_with_callback("storage", on_storage.as_ref().unchecked_ref());
|
||||
// The listener lives as long as the page.
|
||||
on_storage.forget();
|
||||
}
|
||||
|
||||
const JAPANESE_FONT_PATH: &str = "./fonts/BIZUDPGothic-Regular.ttf";
|
||||
|
||||
type FontLoadResult = Rc<std::cell::RefCell<Option<Result<Vec<u8>, String>>>>;
|
||||
@@ -246,9 +301,48 @@ mod web {
|
||||
font_language: String,
|
||||
space_mouse: SpaceMouse,
|
||||
wheel_gestures: solidcraft_ui_egui::WebWheelGestures,
|
||||
/// The settings this tab wrote or loaded last, and those another tab wrote since (#8644).
|
||||
prefs_writer: crate::PrefsWriter,
|
||||
other_tab_prefs: PrefsInbox,
|
||||
}
|
||||
|
||||
impl Shell {
|
||||
/// The settings as they are kept between visits: with the user's own language, not a
|
||||
/// session-only English fallback.
|
||||
fn persisted_prefs(&mut self) -> String {
|
||||
let saved = self.font.persisted_language(&self.app.preferences.language).to_owned();
|
||||
let live = std::mem::replace(&mut self.app.preferences.language, saved);
|
||||
let prefs = self.app.prefs();
|
||||
self.app.preferences.language = live;
|
||||
prefs
|
||||
}
|
||||
|
||||
/// A settings change goes to the browser's storage in the frame it is made, and from
|
||||
/// there to the other open tabs (#8644). Input is what changes settings, so a frame
|
||||
/// without any is skipped; eframe's own save still catches anything else.
|
||||
fn store_prefs(&mut self, ctx: &egui::Context) {
|
||||
if !self.launch.persists() || ctx.input(|i| i.events.is_empty()) {
|
||||
return;
|
||||
}
|
||||
let prefs = self.persisted_prefs();
|
||||
let Some(prefs) = self.prefs_writer.take(prefs) else { return };
|
||||
let stored =
|
||||
web_sys::window().and_then(|w| w.local_storage().ok().flatten()).map(|s| s.set_item(solidcraft_ui_egui::prefs::STORAGE_KEY, &prefs));
|
||||
if !matches!(stored, Some(Ok(()))) {
|
||||
log::warn!("settings: the browser's storage did not take them; they are saved again later");
|
||||
self.prefs_writer = crate::PrefsWriter::default();
|
||||
}
|
||||
}
|
||||
|
||||
/// Settings another tab wrote replace this tab's, so this tab's own saves keep them
|
||||
/// instead of putting its older copy back (#8644).
|
||||
fn load_other_tabs_prefs(&mut self) {
|
||||
let Some(prefs) = self.other_tab_prefs.take() else { return };
|
||||
self.app.load_prefs(&prefs);
|
||||
let held = self.persisted_prefs();
|
||||
self.prefs_writer.loaded(held);
|
||||
}
|
||||
|
||||
/// Files from the computer, writes to store, messages and the autosave.
|
||||
fn files_tick(&mut self, ctx: &egui::Context) {
|
||||
if !self.launch.persists() {
|
||||
@@ -647,6 +741,8 @@ mod web {
|
||||
|
||||
impl eframe::App for Shell {
|
||||
fn logic(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
// First: a language another tab chose fetches its font this frame.
|
||||
self.load_other_tabs_prefs();
|
||||
self.tick_font(ctx);
|
||||
self.app.logic(ctx);
|
||||
self.api.poll();
|
||||
@@ -689,6 +785,7 @@ mod web {
|
||||
self.recovery_prompt(&ctx);
|
||||
}
|
||||
self.watch_text_for_font(&ctx);
|
||||
self.store_prefs(&ctx);
|
||||
}
|
||||
fn persist_egui_memory(&self) -> bool {
|
||||
self.launch.persists()
|
||||
@@ -697,11 +794,8 @@ mod web {
|
||||
if !self.launch.persists() {
|
||||
return;
|
||||
}
|
||||
// Persist the user's own language, not a session-only English fallback.
|
||||
let saved = self.font.persisted_language(&self.app.preferences.language).to_owned();
|
||||
let live = std::mem::replace(&mut self.app.preferences.language, saved);
|
||||
storage.set_string(solidcraft_ui_egui::prefs::STORAGE_KEY, self.app.prefs());
|
||||
self.app.preferences.language = live;
|
||||
let prefs = self.persisted_prefs();
|
||||
storage.set_string(solidcraft_ui_egui::prefs::STORAGE_KEY, prefs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,6 +916,12 @@ mod web {
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let mut app = SolveApp::new(Session::default(), services).with_control(receiver);
|
||||
app.embedded = launch.embed;
|
||||
// Listening before reading: settings another tab writes from now on are
|
||||
// newer than those read here.
|
||||
let other_tab_prefs = PrefsInbox::default();
|
||||
if launch.persists() {
|
||||
hear_settings_from_other_tabs(&window, &cc.egui_ctx, other_tab_prefs.clone());
|
||||
}
|
||||
if launch.persists() && let Some(p) = cc.storage.and_then(|s| solidcraft_ui_egui::prefs::stored(|k| s.get_string(k))) {
|
||||
app.load_prefs(&p);
|
||||
}
|
||||
@@ -865,6 +965,8 @@ mod web {
|
||||
font_language,
|
||||
space_mouse: SpaceMouse::default(),
|
||||
wheel_gestures: solidcraft_ui_egui::WebWheelGestures::default(),
|
||||
prefs_writer: crate::PrefsWriter::default(),
|
||||
other_tab_prefs,
|
||||
}))
|
||||
}),
|
||||
)
|
||||
@@ -1001,4 +1103,28 @@ mod tests {
|
||||
assert!(!closes_design("w", false, false, false, true));
|
||||
assert!(!closes_design("s", true, false, false, true));
|
||||
}
|
||||
|
||||
/// A tab writes its settings when they change, and not again while they stay the same; the
|
||||
/// settings it loaded from another tab aren't written back (#8644).
|
||||
#[test]
|
||||
fn changed_settings_are_written_once_and_loaded_ones_not_at_all() {
|
||||
let mut writer = PrefsWriter::default();
|
||||
assert_eq!(writer.take(r#"{"a":1}"#.into()).as_deref(), Some(r#"{"a":1}"#), "the first settings are written");
|
||||
assert_eq!(writer.take(r#"{"a":1}"#.into()), None, "the same settings are not written again");
|
||||
assert_eq!(writer.take(r#"{"a":2}"#.into()).as_deref(), Some(r#"{"a":2}"#), "a change is written at once");
|
||||
writer.loaded(r#"{"a":3}"#.into());
|
||||
assert_eq!(writer.take(r#"{"a":3}"#.into()), None, "settings from another tab are not written back");
|
||||
assert_eq!(writer.take(r#"{"a":4}"#.into()).as_deref(), Some(r#"{"a":4}"#), "this tab's next change is written");
|
||||
}
|
||||
|
||||
/// Only the settings another tab wrote are loaded: not other keys, and not settings taken
|
||||
/// away by clearing the site's data (#8644).
|
||||
#[test]
|
||||
fn only_settings_another_tab_wrote_are_loaded() {
|
||||
let key = solidcraft_ui_egui::prefs::STORAGE_KEY;
|
||||
assert_eq!(settings_written(Some(key), Some("{}".into())).as_deref(), Some("{}"));
|
||||
assert_eq!(settings_written(Some("solidcraft.webgl"), Some("1".into())), None);
|
||||
assert_eq!(settings_written(Some(key), None), None, "removed settings leave this tab's");
|
||||
assert_eq!(settings_written(None, None), None, "clearing all storage leaves this tab's settings");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ neg_cmp_op_on_partial_ord = "allow"
|
||||
|
||||
[dependencies]
|
||||
solidcraft-engine = { workspace = true }
|
||||
# The D3D12 shader compiler the window starts with (#6756).
|
||||
solidcraft-gpu = { workspace = true }
|
||||
solidcraft-ui-egui = { workspace = true }
|
||||
solidcraft-space-mouse = { workspace = true }
|
||||
eframe = { workspace = true, features = ["default_fonts", "wgpu", "accesskit", "wayland", "x11", "links"] }
|
||||
|
||||
@@ -4,6 +4,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let icon = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../assets/icons/app/windows/exports/solidcraft-executable.ico");
|
||||
println!("cargo:rerun-if-changed={}", icon.display());
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_PKG_VERSION");
|
||||
if std::env::var("CARGO_CFG_TARGET_OS")? != "windows" {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -11,7 +12,21 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let copy = out.join("solidcraft.ico");
|
||||
std::fs::copy(icon, ©)?;
|
||||
let rc = out.join("solidcraft.rc");
|
||||
std::fs::write(&rc, format!("1 ICON \"{}\"\n", copy.display().to_string().replace('\\', "/")))?;
|
||||
let icon_line = format!("1 ICON \"{}\"\n", copy.display().to_string().replace('\\', "/"));
|
||||
std::fs::write(&rc, format!("{icon_line}{}", version_resource(&std::env::var("CARGO_PKG_VERSION")?)))?;
|
||||
embed_resource::compile_for(&rc, ["solidcraft"], embed_resource::NONE).manifest_required()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The Windows version resource (what Explorer's Details tab shows and what a launcher reads).
|
||||
/// `FileVersion` and `ProductVersion` are the package version verbatim (`0.25.1`, `0.26.0-rc.1`):
|
||||
/// ArtCraft's launcher parses the `ProductVersion` string as semver, so a fourth `.0` would not
|
||||
/// read. The binary `FILEVERSION` fields need four numbers and take the leading `major.minor.patch`.
|
||||
fn version_resource(version: &str) -> String {
|
||||
let mut numbers = version.split(['-', '+']).next().unwrap_or("").split('.').map(|p| p.parse::<u16>().unwrap_or(0));
|
||||
let mut next = || numbers.next().unwrap_or(0);
|
||||
let (major, minor, patch) = (next(), next(), next());
|
||||
format!(
|
||||
"1 VERSIONINFO\nFILEVERSION {major},{minor},{patch},0\nPRODUCTVERSION {major},{minor},{patch},0\nFILEOS 0x40004\nFILETYPE 0x1\n{{\nBLOCK \"StringFileInfo\"\n{{\nBLOCK \"040904B0\"\n{{\nVALUE \"CompanyName\", \"SolidCraft contributors\"\nVALUE \"FileDescription\", \"SolidCraft, parametric 3D CAD\"\nVALUE \"FileVersion\", \"{version}\"\nVALUE \"InternalName\", \"solidcraft\"\nVALUE \"OriginalFilename\", \"solidcraft.exe\"\nVALUE \"ProductName\", \"SolidCraft\"\nVALUE \"ProductVersion\", \"{version}\"\n}}\n}}\nBLOCK \"VarFileInfo\"\n{{\nVALUE \"Translation\", 0x0409, 1200\n}}\n}}\n"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ const MAX_BAD_LINES: usize = 8;
|
||||
const EVENT_GAP: Duration = Duration::from_millis(100);
|
||||
|
||||
static OPEN: AtomicUsize = AtomicUsize::new(0);
|
||||
/// The token files this launch wrote (its control port, the agent chat's endpoint), removed
|
||||
/// when the app ends.
|
||||
static TOKEN_FILES: std::sync::Mutex<Vec<std::path::PathBuf>> = std::sync::Mutex::new(Vec::new());
|
||||
/// The token files this launch wrote (its control port, the agent chat's endpoint) and the
|
||||
/// token in each, removed when the app ends unless another launch has written the file since.
|
||||
static TOKEN_FILES: std::sync::Mutex<Vec<(std::path::PathBuf, String)>> = std::sync::Mutex::new(Vec::new());
|
||||
|
||||
/// A new random token: 32 bytes from the operating system, as hex.
|
||||
fn new_token() -> Option<String> {
|
||||
@@ -35,20 +35,21 @@ fn new_token() -> Option<String> {
|
||||
Some(bytes.iter().map(|b| format!("{b:02x}")).collect())
|
||||
}
|
||||
|
||||
/// Remove this launch's token file (at exit).
|
||||
/// Remove this launch's token files and discovery file (at exit), leaving any that another
|
||||
/// launch has written since (#8794).
|
||||
pub fn remove_token_file() {
|
||||
if let Ok(files) = TOKEN_FILES.lock() {
|
||||
for p in files.iter() {
|
||||
control_auth::remove_token_file(p);
|
||||
for (path, token) in files.iter() {
|
||||
control_auth::remove_token_file(path, token);
|
||||
}
|
||||
}
|
||||
if let Some(port) = APP_PORT.lock().ok().and_then(|p| *p) {
|
||||
control_auth::remove_current_port(port);
|
||||
if let Some((port, token)) = APP_PORT.lock().ok().and_then(|p| p.clone()) {
|
||||
control_auth::remove_current_port(port, &token);
|
||||
}
|
||||
}
|
||||
|
||||
/// The port the app's own channel listens on, for removing the discovery file at exit.
|
||||
static APP_PORT: std::sync::Mutex<Option<u16>> = std::sync::Mutex::new(None);
|
||||
/// The port the app's own channel listens on and its token, for removing the discovery file at exit.
|
||||
static APP_PORT: std::sync::Mutex<Option<(u16, String)>> = std::sync::Mutex::new(None);
|
||||
|
||||
pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<ControlRequest> {
|
||||
let (tx, rx) = channel::<ControlRequest>();
|
||||
@@ -61,7 +62,7 @@ pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<Co
|
||||
};
|
||||
match listener {
|
||||
Ok(l) => {
|
||||
if let Some(port) = listen_on_listener(l, token, tx, ctx, false) {
|
||||
if let Some(port) = listen_on_listener(l, token.clone(), tx, ctx, false) {
|
||||
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)");
|
||||
}
|
||||
@@ -69,7 +70,7 @@ pub fn start(listen_on: control_auth::Listen, ctx: egui::Context) -> Receiver<Co
|
||||
match control_auth::write_current_port(port) {
|
||||
Ok(_) => {
|
||||
if let Ok(mut p) = APP_PORT.lock() {
|
||||
*p = Some(port);
|
||||
*p = Some((port, token));
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("solidcraft: could not write the control discovery file ({e})"),
|
||||
@@ -112,7 +113,7 @@ fn listen_on_listener(listener: TcpListener, token: String, tx: Sender<ControlRe
|
||||
Ok(()) => {
|
||||
eprintln!("solidcraft: control server listening on 127.0.0.1:{port} (token in {})", path.display());
|
||||
if let Ok(mut files) = TOKEN_FILES.lock() {
|
||||
files.push(path);
|
||||
files.push((path, token.clone()));
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!(
|
||||
@@ -474,6 +475,14 @@ fn send_events(design: &DesignWatch, lines: &Lines, stop: &AtomicBool, mut seen:
|
||||
}
|
||||
}
|
||||
|
||||
/// What this app's control channel does beyond the methods every version has, for a client to
|
||||
/// find out before it relies on it (an older app answers `control.capabilities` with "unknown
|
||||
/// method"). `param_check`: the levels `engine.execute`, `engine.batch` and `engine.script` take
|
||||
/// as a request's own parameter check (#9184).
|
||||
fn capabilities() -> Value {
|
||||
json!({"param_check": solidcraft_engine::schema::ParamCheck::ALL.map(|l| l.name())})
|
||||
}
|
||||
|
||||
/// Write `reply` on the connection: through its subscription once it has one.
|
||||
fn answer(out: &mut TcpStream, events: Option<&Subscription>, reply: &Value) -> std::io::Result<()> {
|
||||
match events {
|
||||
@@ -534,15 +543,20 @@ fn serve_with(
|
||||
let id = msg.get("id").cloned().unwrap_or(Value::Null);
|
||||
let method = msg.get("method").and_then(Value::as_str).unwrap_or("").to_string();
|
||||
let params = msg.get("params").cloned().unwrap_or(json!({}));
|
||||
// A request that timed out may have finished since (#1618). `control.running` only
|
||||
// looks, so it leaves that reply where it is.
|
||||
let late = pending.as_ref().filter(|_| method != "control.running").and_then(|p| match p.reply.try_recv() {
|
||||
// A request that timed out may have finished since (#1618). `control.running` and
|
||||
// `control.capabilities` only look, so they leave that reply where it is.
|
||||
let late = pending.as_ref().filter(|_| !matches!(method.as_str(), "control.running" | "control.capabilities")).and_then(|p| match p
|
||||
.reply
|
||||
.try_recv()
|
||||
{
|
||||
Ok(reply) => Some(reply),
|
||||
Err(TryRecvError::Disconnected) => Some(json!({"ok": false, "error": "the app ended the request without a reply"})),
|
||||
Err(TryRecvError::Empty) => None,
|
||||
});
|
||||
let mut r = if method == "control.running" {
|
||||
json!({"ok": true, "result": running.result(connection)})
|
||||
} else if method == "control.capabilities" {
|
||||
json!({"ok": true, "result": capabilities()})
|
||||
} else if method == "control.pending" {
|
||||
match (pending.take(), late) {
|
||||
(None, _) => json!({"ok": true, "result": {"pending": null}}),
|
||||
@@ -749,6 +763,9 @@ mod tests {
|
||||
let mut watcher = open();
|
||||
let (r, rows) = running(&mut watcher, &|_| true);
|
||||
assert!(r["ok"] == true && rows.is_empty(), "idle: {r}");
|
||||
// What the app's control channel does beyond the methods every version has (#9184).
|
||||
let r = watcher(json!({"id": 0, "method": "control.capabilities", "token": token}));
|
||||
assert_eq!((&r["ok"], &r["result"]["param_check"]), (&json!(true), &json!(["off", "warn", "strict"])), "{r}");
|
||||
|
||||
let mut export = open();
|
||||
let path = "/private/part.step";
|
||||
@@ -780,6 +797,9 @@ mod tests {
|
||||
let own: Vec<&Value> = r["result"]["running"].as_array().unwrap().iter().filter(|row| row["self"] == true).collect();
|
||||
assert_eq!(own.len(), 1, "{r}");
|
||||
assert_eq!(own[0]["command"], "file.export", "{r}");
|
||||
// So may it ask what the app can do: answered at once, not refused as busy.
|
||||
let r = export(json!({"id": 8, "method": "control.capabilities"}));
|
||||
assert_eq!(r["result"]["param_check"], json!(["off", "warn", "strict"]), "{r}");
|
||||
|
||||
gate_tx.send(()).unwrap();
|
||||
assert_eq!(queued.join().unwrap()["result"], "engine.batch");
|
||||
|
||||
@@ -1016,6 +1016,10 @@ fn main() -> eframe::Result {
|
||||
app.session.doc_mut().name = "Sample Plate".into();
|
||||
app.session.mark_saved();
|
||||
app.session.undo.clear();
|
||||
// Built straight into the session, so nothing asked for a fit: frame it at the
|
||||
// home view as any opened design is (#9195). The fit waits for the first layout.
|
||||
app.cam.set_view(solidcraft_engine::render::StandardView::Iso);
|
||||
app.fit_view();
|
||||
}
|
||||
// Lock files next to open designs: a design open on another computer says so (#5467),
|
||||
// the files given at launch included.
|
||||
@@ -1124,6 +1128,8 @@ fn wgpu_options(cpu: bool, preference: Option<&str>) -> eframe::egui_wgpu::WgpuC
|
||||
let intel_mac = cfg!(all(target_os = "macos", target_arch = "x86_64"));
|
||||
let indirect = std::env::var(startup::INDIRECT_VALIDATION_ENV).ok();
|
||||
setup.instance_descriptor.flags = startup::window_instance_flags(setup.instance_descriptor.flags, intel_mac, indirect.as_deref());
|
||||
// Never a `dxcompiler.dll` another program put on PATH (#6756).
|
||||
setup.instance_descriptor.backend_options.dx12.shader_compiler = solidcraft_gpu::dx12_compiler();
|
||||
let environment = std::env::var("WGPU_ADAPTER_NAME").ok();
|
||||
let adapter = graphics().and_then(|v| v.get("adapter").and_then(serde_json::Value::as_str).map(str::to_string));
|
||||
startup::configure_adapter(setup, cpu, environment, adapter);
|
||||
|
||||
@@ -255,7 +255,7 @@ pub const FLOAT_DEPTH_STENCIL: eframe::wgpu::Features = eframe::wgpu::Features::
|
||||
/// asks for a float one only when whichever it picks has it.
|
||||
pub fn float_depth_everywhere(options: &eframe::egui_wgpu::WgpuConfiguration) -> bool {
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &options.wgpu_setup else { return false };
|
||||
let mut desc = eframe::wgpu::InstanceDescriptor::new_without_display_handle_from_env();
|
||||
let mut desc = solidcraft_gpu::instance_descriptor_from_env();
|
||||
desc.backends = setup.instance_descriptor.backends;
|
||||
let instance = eframe::wgpu::Instance::new(desc);
|
||||
let adapters = pollster::block_on(instance.enumerate_adapters(setup.instance_descriptor.backends));
|
||||
@@ -272,6 +272,7 @@ pub fn has_hardware_adapter(backends: eframe::wgpu::Backends) -> bool {
|
||||
let mut desc = eframe::wgpu::InstanceDescriptor::new_without_display_handle();
|
||||
desc.backends = backends;
|
||||
desc.flags = eframe::wgpu::InstanceFlags::from_build_config().with_env();
|
||||
desc.backend_options.dx12.shader_compiler = solidcraft_gpu::dx12_compiler();
|
||||
let instance = eframe::wgpu::Instance::new(desc);
|
||||
let adapters = pollster::block_on(instance.enumerate_adapters(backends));
|
||||
let found: Vec<String> = adapters.iter().map(|a| format!("{} ({:?})", a.get_info().name, a.get_info().device_type)).collect();
|
||||
@@ -591,7 +592,7 @@ mod tests {
|
||||
if cfg!(target_os = "windows") && std::env::var_os(WGPU_BACKEND_ENV).is_none() {
|
||||
assert_eq!(backends, eframe::wgpu::Backends::DX12);
|
||||
}
|
||||
let mut desc = eframe::wgpu::InstanceDescriptor::new_without_display_handle_from_env();
|
||||
let mut desc = solidcraft_gpu::instance_descriptor_from_env();
|
||||
desc.backends = backends;
|
||||
let instance = eframe::wgpu::Instance::new(desc);
|
||||
let adapters = pollster::block_on(instance.enumerate_adapters(backends));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Built-in model appearances: names, sRGB colours and metalness.
|
||||
pub const LIBRARY: [(&str, [u8; 3], f64); 20] = [
|
||||
pub const LIBRARY: &[(&str, [u8; 3], f64)] = &[
|
||||
("Aluminum - Satin", [204, 208, 214], 1.0),
|
||||
("Aluminum - Anodized Black", [44, 46, 50], 1.0),
|
||||
("Aluminum - Anodized Blue", [52, 92, 160], 1.0),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Original illustrative opaque finishes; not measured optical or engineering data.
|
||||
//! (name, sRGB color, metal fraction, perceptual roughness). IOR is an illustrative 1.5.
|
||||
//! Separate names preserve the scalar library's appearance and saved assignments.
|
||||
pub const OPAQUE_FINISHES: [(&str, [u8; 3], f64, f64); 6] = [
|
||||
pub const OPAQUE_FINISHES: &[(&str, [u8; 3], f64, f64)] = &[
|
||||
("Steel - Satin PBR", [158, 164, 172], 1.0, 0.4),
|
||||
("Aluminum - Satin PBR", [204, 208, 214], 1.0, 0.3),
|
||||
("Copper - Clean PBR", [204, 122, 80], 1.0, 0.25),
|
||||
|
||||
@@ -16,7 +16,7 @@ const fn glass(transmission_linear_rgb: [f64; 3], ior: f64, reference_path_mm: f
|
||||
GlassRecipe { transmission_linear_rgb, dielectric_ior: ior, reference_path_mm, boundary }
|
||||
}
|
||||
|
||||
pub const STARTER_PACK: [VisualPreset; 40] = [
|
||||
pub const STARTER_PACK: &[VisualPreset] = &[
|
||||
VisualPreset::opaque(
|
||||
"starter.wood.oak-honey",
|
||||
"Wood - Honey Oak Uniform Preview",
|
||||
|
||||
@@ -188,7 +188,7 @@ surface = [
|
||||
sketch = [
|
||||
"arc3", "arc_center", "arc_slot", "arc_slot_center", "arc_tangent",
|
||||
"blend", "circle", "circle2", "circle3", "circle_tt",
|
||||
"circle_ttt", "conic", "constrainer", "dimension", "ellipse",
|
||||
"circle_ttt", "conic", "constrainer", "dimension", "ellipse", "equation_curve",
|
||||
"extend", "finish", "fit_section", "include",
|
||||
"intersect", "intersection_curve", "iso_curve", "line", "line_mid",
|
||||
"offset", "offset_two_sides", "offset_symmetric", "point", "polygon", "polygon_circumscribed", "polygon_edge",
|
||||
@@ -204,5 +204,11 @@ constraint = [
|
||||
"c_polygon", "c_smooth", "c_symmetry", "c_tangent",
|
||||
]
|
||||
construction = [
|
||||
"centerline", "construction", "infinite",
|
||||
"centerline", "construction", "construction_line", "construction_line_angle",
|
||||
"construction_line_bisector", "construction_line_horizontal", "construction_line_parallel",
|
||||
"construction_line_perpendicular", "construction_line_tangent_at", "construction_line_tangent_external",
|
||||
"construction_line_tangent_two", "construction_line_vertical", "infinite",
|
||||
]
|
||||
mesh = [
|
||||
"mesh_body",
|
||||
]
|
||||
|
||||
@@ -70,6 +70,16 @@ configuration_table false
|
||||
conic false
|
||||
constrainer false
|
||||
construction false
|
||||
construction_line false
|
||||
construction_line_angle false
|
||||
construction_line_bisector false
|
||||
construction_line_horizontal false
|
||||
construction_line_parallel false
|
||||
construction_line_perpendicular false
|
||||
construction_line_tangent_at false
|
||||
construction_line_tangent_external false
|
||||
construction_line_tangent_two false
|
||||
construction_line_vertical false
|
||||
contact_all false
|
||||
contact_new false
|
||||
contact_off false
|
||||
@@ -95,6 +105,7 @@ edit false
|
||||
ellipse false
|
||||
emboss false
|
||||
environment_map false
|
||||
equation_curve false
|
||||
error false
|
||||
explode false
|
||||
export false
|
||||
@@ -103,6 +114,7 @@ extend false
|
||||
extrude false
|
||||
eye false
|
||||
fastener false
|
||||
feature_group false
|
||||
fillet false
|
||||
finish false
|
||||
finish_edit false
|
||||
@@ -143,6 +155,7 @@ loft false
|
||||
lookat false
|
||||
material false
|
||||
measure false
|
||||
mesh_body false
|
||||
mesh_export false
|
||||
min_radius false
|
||||
mirror false
|
||||
@@ -222,6 +235,7 @@ settings_monitor false
|
||||
settings_mouse false
|
||||
settings_palette false
|
||||
settings_plug false
|
||||
sheet false
|
||||
sheet_rules false
|
||||
shell false
|
||||
shield false
|
||||
@@ -257,6 +271,7 @@ split_face false
|
||||
spun false
|
||||
star false
|
||||
status_error false
|
||||
status_pin false
|
||||
status_recovery false
|
||||
style false
|
||||
style_hidden_edges false
|
||||
@@ -288,6 +303,8 @@ svg false
|
||||
sweep false
|
||||
text false
|
||||
thread false
|
||||
timeline_play false
|
||||
timeline_stop false
|
||||
torus false
|
||||
trace false
|
||||
trim false
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Pinned result</title>
|
||||
<path d="M32 57C25 48 14 35 14 24A18 18 0 0 1 50 24C50 35 39 48 32 57Z" fill="none" stroke="currentColor" stroke-width="5.6" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M25 24A7 7 0 1 0 39 24A7 7 0 1 0 25 24Z" fill="none" stroke="currentColor" stroke-width="5.6" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 429 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Construction line through two points</title>
|
||||
<path d="M8 52L56 12" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="20" cy="42" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="20" cy="42" r="3.4" fill="#236ead"/>
|
||||
<circle cx="44" cy="22" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="44" cy="22" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 472 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Construction line at an angle</title>
|
||||
<path d="M10.26 48.66L58.26 48.66" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M28.65 33.23A24 24 0 0 1 34.26 48.66" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M10.26 48.66L54.26 11.66" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="10.26" cy="48.66" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="10.26" cy="48.66" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 646 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Angle bisector</title>
|
||||
<path d="M13.92 12.18L9.92 52.17L54.92 44.17" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M12.11 30.29A22 22 0 0 1 31.58 48.33" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M9.92 52.17L47.3 11.83" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 526 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Horizontal construction line</title>
|
||||
<path d="M8 32L56 32" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="32" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="32" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 362 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Parallel construction line</title>
|
||||
<path d="M9 37L41 9" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M23 55L55 27" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 380 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Perpendicular construction line</title>
|
||||
<path d="M8 44L56 44" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 8L32 56" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 34L42 34L42 44" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 490 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Tangent at a curve point</title>
|
||||
<circle cx="32" cy="34.26" r="17" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M8 17.26L56 17.26" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="32" cy="17.26" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="17.26" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 480 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Tangent through an external point</title>
|
||||
<circle cx="21.74" cy="38.77" r="14" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M53.6 8.23L28.55 55.9" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="51.74" cy="11.77" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="51.74" cy="11.77" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Common tangent to two curves</title>
|
||||
<circle cx="20" cy="33.59" r="12" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="46" cy="33.59" r="8" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M6 19.27L58 27.36" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 509 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Vertical construction line</title>
|
||||
<path d="M32 8L32 56" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="32" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="32" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 360 B |
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Equation curve</title>
|
||||
<path d="M12 8L12 56M6 32L58 32" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M12 32C15.42 24.83 18.72 18 22.5 18C26.28 18 29.58 24.83 33 32C36.42 39.17 39.72 46 43.5 46C47.28 46 50.58 39.17 54 32" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="12" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="12" cy="32" r="3.4" fill="#236ead"/>
|
||||
<circle cx="54" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="54" cy="32" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 666 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Feature group</title>
|
||||
<path d="M28.5 11L50.5 11A4.5 4.5 0 0 1 55 15.5L55 28.5A4.5 4.5 0 0 1 50.5 33L28.5 33A4.5 4.5 0 0 1 24 28.5L24 15.5A4.5 4.5 0 0 1 28.5 11Z" fill="#8e9faf" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M21 20L43 20A4.5 4.5 0 0 1 47.5 24.5L47.5 37.5A4.5 4.5 0 0 1 43 42L21 42A4.5 4.5 0 0 1 16.5 37.5L16.5 24.5A4.5 4.5 0 0 1 21 20Z" fill="#b8c3cf" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M13.5 29L35.5 29A4.5 4.5 0 0 1 40 33.5L40 46.5A4.5 4.5 0 0 1 35.5 51L13.5 51A4.5 4.5 0 0 1 9 46.5L9 33.5A4.5 4.5 0 0 1 13.5 29Z" fill="#b9ddf8" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M16 40L33 40" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 947 B |
@@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Mesh body</title>
|
||||
<path d="M8.62 18.5L32 32L32 59L8.62 45.5Z" fill="#328bd3"/>
|
||||
<path d="M55.38 18.5L32 32L32 59L55.38 45.5Z" fill="#236ead"/>
|
||||
<path d="M32 5L55.38 18.5L32 32L8.62 18.5Z" fill="#b9ddf8"/>
|
||||
<path d="M8.62 18.5L55.38 18.5" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M8.62 18.5L32 59" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M55.38 18.5L32 59" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 5L55.38 18.5L55.38 45.5L32 59L8.62 45.5L8.62 18.5Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M8.62 18.5L32 32L55.38 18.5" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 32L32 59" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><title>Play History</title><path d="M11.22 20L32 32L32 56L11.22 44Z" fill="#b8c3cf"/><path d="M52.78 20L32 32L32 56L52.78 44Z" fill="#8e9faf"/><path d="M32 8L52.78 20L32 32L11.22 20Z" fill="#e2e8ef"/><path d="M32 8L52.78 20L52.78 44L32 56L11.22 44L11.22 20Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M11.22 20L32 32L52.78 20" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M32 32L32 56" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M35 34L56 46L35 58Z" fill="#ffffff" stroke="#ffffff" stroke-width="4.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M35 34L56 46L35 58Z" fill="#236ead" stroke="#236ead" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
||||
|
After Width: | Height: | Size: 935 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><title>Stop History</title><path d="M11.22 20L32 32L32 56L11.22 44Z" fill="#b8c3cf"/><path d="M52.78 20L32 32L32 56L52.78 44Z" fill="#8e9faf"/><path d="M32 8L52.78 20L32 32L11.22 20Z" fill="#e2e8ef"/><path d="M32 8L52.78 20L52.78 44L32 56L11.22 44L11.22 20Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M11.22 20L32 32L52.78 20" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M32 32L32 56" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M36 35L53 35A2 2 0 0 1 55 37L55 54A2 2 0 0 1 53 56L36 56A2 2 0 0 1 34 54L34 37A2 2 0 0 1 36 35Z" fill="#ffffff" stroke="#ffffff" stroke-width="4.55" stroke-linejoin="round" stroke-linecap="round"/><path d="M36 35L53 35A2 2 0 0 1 55 37L55 54A2 2 0 0 1 53 56L36 56A2 2 0 0 1 34 54L34 37A2 2 0 0 1 36 35Z" fill="#236ead" stroke="#236ead" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -15,6 +15,17 @@ pub(crate) fn transport_glyph(p: &egui::Painter, c: egui::Pos2, what: &str, col:
|
||||
}
|
||||
"back" => tri(-1.0, 0.0),
|
||||
"forward" => tri(1.0, 0.0),
|
||||
// Play History: larger than the step arrows so it doesn't read as Forward, and two bars
|
||||
// while it plays.
|
||||
"play" => {
|
||||
let pts = vec![pos2(c.x - 4.5, c.y - 7.0), pos2(c.x + 6.5, c.y), pos2(c.x - 4.5, c.y + 7.0)];
|
||||
p.add(egui::Shape::convex_polygon(pts, col, Stroke::NONE));
|
||||
}
|
||||
"pause" => {
|
||||
for dx in [-3.0, 3.0] {
|
||||
p.rect_filled(Rect::from_center_size(pos2(c.x + dx, c.y), vec2(3.0, 12.0)), 0.5, col);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tri(1.0, -1.0);
|
||||
bar(5.0);
|
||||
|
||||
@@ -852,6 +852,16 @@
|
||||
"cmd.sheet_refold": "Buk tilbage",
|
||||
"cmd.sheet_rules": "Vis pladeregler",
|
||||
"cmd.sheet_unfold": "Fold ud",
|
||||
"cmd.sketch.construction_line": "Hjælpelinje",
|
||||
"cmd.sketch.construction_line.angle": "Hjælpelinje med vinkel",
|
||||
"cmd.sketch.construction_line.bisector": "Vinkelhalveringslinje",
|
||||
"cmd.sketch.construction_line.horizontal": "Vandret hjælpelinje",
|
||||
"cmd.sketch.construction_line.parallel": "Parallel hjælpelinje",
|
||||
"cmd.sketch.construction_line.perpendicular": "Vinkelret hjælpelinje",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tangent i kurvepunkt",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangent gennem eksternt punkt",
|
||||
"cmd.sketch.construction_line.tangent_two": "Fælles tangent",
|
||||
"cmd.sketch.construction_line.vertical": "Lodret hjælpelinje",
|
||||
"cmd.sketch_arc_center_point": "Bue med centrum",
|
||||
"cmd.sketch_arc_tangent": "Tangentbue",
|
||||
"cmd.sketch_arc_three_point": "Trepunktsbue",
|
||||
@@ -1903,6 +1913,7 @@
|
||||
"ui.constant": "Konstant",
|
||||
"ui.constraints_conflict": "Bindinger er i konflikt",
|
||||
"ui.construction": "Konstruktionsgeometri",
|
||||
"ui.construction.ribbon_label": "Hjælpelinjer",
|
||||
"ui.context_menu": "Genvejsmenu",
|
||||
"ui.continuity_g0": "G0-knæk",
|
||||
"ui.continuity_g1": "G1-tangentkontinuitet",
|
||||
@@ -2202,6 +2213,7 @@
|
||||
"ui.pan_zoom_orbit": "Panorér, zoom, rotér visning",
|
||||
"ui.parallel": "Parallel",
|
||||
"ui.parameters": "Parametre",
|
||||
"ui.part_size_needs_a_part": "Vælg en indsat standarddel (en skrue, møtrik, skive eller stift) for at ændre dens størrelse. Brug Skalering til at gøre et emne større eller mindre.",
|
||||
"ui.part_size_shared": "Genopbygger delen og erstatter alle tilføjede features. Alle forekomster af komponenten opdateres.",
|
||||
"ui.paste": "Indsæt",
|
||||
"ui.path": "Bane",
|
||||
@@ -2354,6 +2366,10 @@
|
||||
"ui.symmetric": "Symmetrisk",
|
||||
"ui.symmetry": "Symmetri",
|
||||
"ui.system": "System",
|
||||
"ui.tab_assemble": "Samling",
|
||||
"ui.tab_manage": "Administrér",
|
||||
"ui.tab_sheet_metal": "Plade",
|
||||
"ui.tab_view": "Visning",
|
||||
"ui.tangent": "Tangent",
|
||||
"ui.taper_angle": "Konusvinkel",
|
||||
"ui.tapped": "Med gevind",
|
||||
|
||||
@@ -1,22 +1,74 @@
|
||||
{
|
||||
"A Single hole snaps to the middle of its face and to the centres of its round edges": "A Single hole snaps to the middle of its face and to the centres of its round edges",
|
||||
"Base Center": "Base Centre",
|
||||
"Center X": "Centre X",
|
||||
"Center Y": "Centre Y",
|
||||
"Center of mass": "Centre of mass",
|
||||
"Centre to centre": "Centre to centre",
|
||||
"Circle center": "Circle centre",
|
||||
"Colour": "Colour",
|
||||
"Copy all licences": "Copy all licences",
|
||||
"Customize Toolbar": "Customise Toolbar",
|
||||
"Customize…": "Customise…",
|
||||
"Face center": "Face centre",
|
||||
"Favorites": "Favourites",
|
||||
"Favourite": "Favourite",
|
||||
"Mass Center": "Mass Centre",
|
||||
"Modeled": "Modelled",
|
||||
"Select the centre the pattern turns around first": "Select the centre the pattern turns around first",
|
||||
"Snap to face and edge centres": "Snap to face and edge centres",
|
||||
"Specialise": "Specialise",
|
||||
"cmd.appearance_favorite": "Favourite Look",
|
||||
"cmd.component_cycle_color": "Cycle Component Colour",
|
||||
"cmd.construct_point_center": "Point At Centre Of Circle/Sphere/Torus",
|
||||
"cmd.inspect_center_of_mass": "Centre of Mass",
|
||||
"cmd.inspect_colored_components": "Enable Component Colours",
|
||||
"cmd.inspect_colored_components_disable": "Disable Component Colours",
|
||||
"cmd.parameters_favorite": "Favourite Parameter",
|
||||
"cmd.render_aging_describe": "Layered Surface Aging",
|
||||
"cmd.render_effects_describe": "Lens and Creative Effects",
|
||||
"cmd.sketch.construction_line": "Construction Line",
|
||||
"cmd.sketch.construction_line.angle": "Construction Line at Angle",
|
||||
"cmd.sketch.construction_line.bisector": "Angle Bisector",
|
||||
"cmd.sketch.construction_line.horizontal": "Horizontal Construction Line",
|
||||
"cmd.sketch.construction_line.parallel": "Parallel Construction Line",
|
||||
"cmd.sketch.construction_line.perpendicular": "Perpendicular Construction Line",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tangent at Curve Point",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangent through External Point",
|
||||
"cmd.sketch.construction_line.tangent_two": "Common Tangent",
|
||||
"cmd.sketch.construction_line.vertical": "Vertical Construction Line",
|
||||
"cmd.sketch_arc_center_point": "Centre Point Arc",
|
||||
"cmd.sketch_circle_center": "Centre Diameter Circle",
|
||||
"cmd.sketch_rectangle_center": "Centre Rectangle",
|
||||
"cmd.sketch_slot_arc_center": "Centre Point Arc Slot",
|
||||
"cmd.sketch_slot_center_point": "Centre Point Slot",
|
||||
"cmd.sketch_slot_center_to_center": "Centre to Centre Slot",
|
||||
"color.copy": "Click to copy colour values",
|
||||
"color.edit": "Click to edit colour",
|
||||
"color.gamma": "Showing colour values in 0-255 gamma space",
|
||||
"color.linear": "Showing colour values in 0-1 linear space",
|
||||
"color.selected": "Selected colour",
|
||||
"dxf.cancelled": "DXF export cancelled",
|
||||
"dxf.cancelling": "Cancelling DXF export",
|
||||
"help.apache": "Apache licence 2.0",
|
||||
"help.appearance.assign": "Gives the selected bodies, faces or components a colour or a material look, without changing their weight. Use it to tell parts apart or to preview a finish.",
|
||||
"help.face.delete": "Removes the selected faces and lets the neighbouring faces close the gap, or leaves the gap open as a surface. Use it to take off a rounded edge, a hole or a boss that is in the way.",
|
||||
"help.font_details": "The interface uses egui's built-in fonts (Ubuntu Light and Hack, under the Ubuntu Font Licence and the MIT/Bitstream Vera licence; Noto Emoji and the emoji icon font, under the OFL and MIT). Sketch text uses Liberation Sans (SIL OFL 1.1). The Crafting Apps' optional font pack, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), is not bundled in SolidCraft builds.",
|
||||
"help.licences": "Licences",
|
||||
"help.material.assign": "Sets what the selected bodies are made of, such as steel, aluminium or ABS. Use it so that the mass and weight match the real part.",
|
||||
"help.mit": "MIT licence",
|
||||
"help.solid.draft": "Tilts the selected faces by the angle you set, measured from a neutral plane. Use it on moulded or cast parts so that they slide out of the mould.",
|
||||
"help.solid.revolve": "Spins a sketch profile around an axis to make a round solid. Use it for shafts, knobs, bowls and any part that is round about a centre line.",
|
||||
"help.solid.split_body": "Cuts a body into separate bodies with a plane, the face of another body or a sketch line. Use it to make parts that are printed, machined or coloured on their own.",
|
||||
"help.solid.split_face": "Divides the selected faces along a plane, the face of another body or sketch curves, without cutting the body. Use it to give part of a face its own draft, colour or offset.",
|
||||
"help.third_party": "Third-party licences",
|
||||
"home.new_mm_hint": "Millimetres · opens in Design",
|
||||
"navbar.custom.customise": "Customise navigation bar…",
|
||||
"navbar.custom.position_centre": "Centre",
|
||||
"navbar.description.separator": "A thin line that groups neighbouring slots.",
|
||||
"pattern.alignment_hint": "Counts include the original. Centre balances copies; Flip chooses the extra side for even totals.",
|
||||
"prefs.bottom_centre": "Bottom centre",
|
||||
"prefs.logo_theme": "Theme's colours",
|
||||
"prefs.max_file_size": "Largest file to open",
|
||||
"prefs.max_file_size_design": "Design files",
|
||||
"prefs.max_file_size_flag": "This run started with --max-file-size {size}, which applies until SolidCraft closes. These settings apply when it starts without it.",
|
||||
@@ -24,6 +76,11 @@
|
||||
"prefs.max_file_size_step": "STEP and import files",
|
||||
"prefs.max_file_size_web": "The web app opens STEP and import files up to 512 MB and designs up to 256 MB: a browser tab can't hold larger files. The desktop app can raise these limits.",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.sketch_conflict_colour": "Conflicting geometry in the conflict colour",
|
||||
"prefs.sketch_conflict_colour_note": "While a sketch's constraints conflict, the curves and points a failing constraint holds are drawn in the conflict colour too, not only its glyph or dimension. Off: they keep their usual colours.",
|
||||
"prefs.sketch_construction_lines": "Extended construction line tools",
|
||||
"prefs.sketch_recent_snap": "Auto snap to recent centres and midpoints",
|
||||
"prefs.sketch_recent_snap_note": "While drawing, snap the cursor where the guides of the two most recent circle centres or straight-edge midpoints cross. Off: those guides stay visual and the cursor does not move.",
|
||||
"prefs.sketch_state_icons": "Sketch icons in the colour of their state",
|
||||
"prefs.sketch_state_icons_note": "In History and the browser, a sketch's icon takes the colour of its state (under constrained, fully constrained or conflicting) and its tooltip names the state. Off: every sketch has the same icon.",
|
||||
"prefs.sketch_tracking_guides": "Centre and midpoint alignment guides",
|
||||
@@ -35,6 +92,9 @@
|
||||
"prefs.theme_follow_note": "Reloaded whenever another tool rewrites it. Choosing a theme stops following it.",
|
||||
"prefs.theme_follow_off": "Off",
|
||||
"prefs.theme_follow_stop": "Stop following",
|
||||
"prefs.trackpad_zoom_modifier.help": "Hold only this key to zoom at the pointer with vertical scroll. Off keeps the existing scroll behaviour.",
|
||||
"prefs.view": "View behaviour",
|
||||
"prefs.viewport_background_colour": "Colour",
|
||||
"render.aging_add": "Add aging layer",
|
||||
"render.aging_airborne": "Airborne dust / participating medium",
|
||||
"render.aging_airborne_help": "Airborne dust is a separate finite homogeneous scattering volume. It changes transport and raw EXR, not the surface-aging stack. Existing volume/glass/denoising restrictions remain explicit; no atmosphere is added automatically.",
|
||||
@@ -62,6 +122,9 @@
|
||||
"render.aging_target_help": "A named target must still match its captured index and name. Global masks are world-anchored; they do not follow moving parts. This is neither cavity detection nor true edge wear. Filter the list to reach additional bodies.",
|
||||
"render.aging_target_search": "Filter body names",
|
||||
"render.aging_upward": "Upward-facing deposition",
|
||||
"render.appearance_editor.base_colour": "Base colour",
|
||||
"render.backdrop_first": "Start / centre colour",
|
||||
"render.backdrop_second": "End / edge colour",
|
||||
"render.backdrop_x": "Centre X",
|
||||
"render.backdrop_y": "Centre Y",
|
||||
"render.background_camera_section": "Camera background · PNG presentation",
|
||||
@@ -69,20 +132,38 @@
|
||||
"render.background_hdr_separate": "The current HDR resources illuminate and reflect on surfaces; they are not automatically displayed as a panorama behind the subject. Changing a gradient does not rotate or recolour the lighting.",
|
||||
"render.background_lighting_section": "HDR illumination · separate from camera background",
|
||||
"render.background_no_alpha_override": "A camera background is not added to transparent output silently. Raw-master regrading uses captured coverage and does not reapply denoising; the source EXR remains unchanged.",
|
||||
"render.background_not_light": "Background colour is presentation, not an additional lighting source.",
|
||||
"render.background_regrade": "Apply to retained raw master",
|
||||
"render.background_stage_occlusion": "This shot includes physical stage geometry. A large floor or wall can fill the frame and hide a camera-only background. Clear or resize the stage deliberately, or change its physical reflectance. Regrading cannot remove captured geometry.",
|
||||
"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.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.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_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_linear_color": "Linear colour (R, G, B)",
|
||||
"render.effects_gpu_only": "These effects require GPU path tracing. Changing the page never switches the renderer automatically.",
|
||||
"render.effects_help": "Combine ordered colour looks and image-space lens effects. Rendering and raw-master regrading use the same saved settings. Raw EXR stays unchanged. These are original artistic controls, not calibrated lens or branded-film emulations.",
|
||||
"render.effects_reset_lens": "Reset lens effects",
|
||||
"render.effects_seed": "Pattern seed",
|
||||
"render.env_colour": "Colour",
|
||||
"render.environment.radial_only": "Centre and radius apply to Radial mode.",
|
||||
"render.error_finish_gesture": "finish the modelling gesture before previewing",
|
||||
"render.error_finish_operation": "finish the current modelling operation before entering Render",
|
||||
"render.film_grain": "Photographic grain",
|
||||
"render.flare_ghosts": "Ghost rings per source",
|
||||
"render.flare_halo": "Flare halo",
|
||||
"render.flare_streak": "Anamorphic-style streak",
|
||||
"render.flare_strength": "Highlight flare strength",
|
||||
"render.flare_threshold": "Scene-linear flare threshold",
|
||||
"render.frame_centre_mark": "Centre mark",
|
||||
"render.hdr_primaries_declared": "The source declares its colour primaries.",
|
||||
"render.hdr_primaries_srgb": "Colour primaries: sRGB/D65",
|
||||
"render.hdr_primaries_undeclared": "The source does not declare primaries; review the renderer colour requirements.",
|
||||
"render.image_cancelled": "Render cancelled",
|
||||
"render.image_cancelling": "Cancelling",
|
||||
"render.image_scene_stale": "Finish the modelling gesture or refresh the scene before checking or starting an image.",
|
||||
"render.inspector_colour": "Colour",
|
||||
"render.layer_down": "Move down",
|
||||
"render.layer_enabled": "Layer enabled",
|
||||
"render.layer_remove": "Remove layer",
|
||||
@@ -90,6 +171,18 @@
|
||||
"render.layer_up": "Move up",
|
||||
"render.lens_effects_help": "Flare uses up to four separated bright sources in the actual linear image. Ghosts, halo, streaks, chromatic offsets and radial distortion are artistic image-space approximations. Spatial effects need opaque output; outside samples extend the image edge. Grain is deterministic. No physics, EXR or geometry is altered.",
|
||||
"render.lens_effects_title": "Lens-inspired & photographic",
|
||||
"render.library_center": "Rig centre",
|
||||
"render.library_favorite": "Add favourite",
|
||||
"render.library_favorites": "Favourites",
|
||||
"render.library_inspect_only": "Select to inspect; nothing is applied automatically. Favourites and recent history belong to this open document session.",
|
||||
"render.library_rig_help": "Fit once at an explicit centre and physical extent. Complete rigs include passive cards; calibration blockers still refuse. Conservative emitter/card clearance is checked before saving.",
|
||||
"render.library_source_preview_help": "Authored base-colour source map. This is not a rendered or measured material preview.",
|
||||
"render.library_unfavorite": "Remove favourite",
|
||||
"render.light_behaviour": "BEHAVIOUR",
|
||||
"render.light_preview_help": "Live view is unshadowed; Area lights use a centre-sample approximation. Render uses the complete light model.",
|
||||
"render.light_product_centre": "Product centre",
|
||||
"render.light_temperature": "Colour temperature",
|
||||
"render.lighting_colour": "Colour",
|
||||
"render.look_add": "Add colour look",
|
||||
"render.look_bleach": "Bleach-bypass-inspired",
|
||||
"render.look_cool": "Cool",
|
||||
@@ -101,6 +194,11 @@
|
||||
"render.look_teal_orange": "Teal / orange",
|
||||
"render.look_title": "Creative look stack",
|
||||
"render.look_warm": "Warm",
|
||||
"render.material_color_map": "Base colour image (sRGB)",
|
||||
"render.material_color_replace": "Base map replaces body colour",
|
||||
"render.material_map_required": "Choose a colour image or a normal image before using maps.",
|
||||
"render.material_maps": "Planar colour and normal maps",
|
||||
"render.material_maps_help": "PNG/JPEG up to 1024×1024; 16 MiB encoded total. U and V are orthogonal world-mm repeat vectors (maximum 128 repeats). Colour is sRGB; normal data uses OpenGL +Y. Files are captured at Check/Start.",
|
||||
"render.opaque_preview_help": "Opaque PBR and simple colours; blended transparency. Refraction, HDRI and final rendering are not available yet.",
|
||||
"render.page_aging": "Aging & contamination",
|
||||
"render.page_background": "Backgrounds",
|
||||
@@ -108,22 +206,45 @@
|
||||
"render.radial_distortion": "Radial distortion",
|
||||
"render.ribbon_aging": "Aging",
|
||||
"render.ribbon_effects": "Effects",
|
||||
"render.ribbon_studios_help": "Browse implemented studio compositions and review their replacements before applying. Concept-only scenes remain labelled.",
|
||||
"render.sharpening": "Detail sharpening",
|
||||
"render.soft_focus": "Soft focus",
|
||||
"render.stage_panels.centre": "Centre",
|
||||
"render.stage_panels.source_note": "Authored base-colour source map. Not a measured material.",
|
||||
"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_hdr_help": "Radiance .hdr, 2:1 panorama, up to 2048 × 1024. EXR is unavailable. The colour assumption applies only when primaries are unspecified.",
|
||||
"sketch_text.align_center": "Centre",
|
||||
"ui.3d_mouse_kind_cap": "Return to Centre",
|
||||
"ui.3d_mouse_looks_like_cap": "The reading stays put while you hold it, the way a Return to Centre device does.",
|
||||
"ui.3d_mouse_orbit_tip": "Traced: the 3D mouse turns the view around the part of the model in the middle of the view when the turn begins, marked by a faint ball. Classic: around the view's centre",
|
||||
"ui.3d_mouse_step_pull": "Pull the cap towards you, hold it, then let go.",
|
||||
"ui.3d_mouse_switch_cap": "Calibrate as Return to Centre",
|
||||
"ui.agent_chat_minimize": "Minimise to a strip",
|
||||
"ui.ai_mode_edits_note": "Modelling commands run without asking; saving, opening, exporting and other file or destructive actions still ask.",
|
||||
"ui.center": "Centre",
|
||||
"ui.center_arc_follows_cursor": "Centre point arc follows the cursor's direction",
|
||||
"ui.center_arc_follows_cursor_tip": "A centre point arc runs clockwise or counter-clockwise the way the cursor goes round its centre. Off: always counter-clockwise from the start.",
|
||||
"ui.centerline": "Centreline",
|
||||
"ui.colour_vision": "Colour vision",
|
||||
"ui.colour_vision_note": "Changes the colours that carry a meaning: sketch states, axes, bends, analyses and icons. If you use Windows colour filters, keep this Off.",
|
||||
"ui.colour_vision_off_tip": "The theme's own colours",
|
||||
"ui.construction.ribbon_label": "X-Lines",
|
||||
"ui.customizeToolbar": "Customise Toolbar…",
|
||||
"ui.default_modelling_orientation": "Default modelling orientation",
|
||||
"ui.design_properties.license": "Licence",
|
||||
"ui.design_properties.organization": "Organisation",
|
||||
"ui.export_keymap_tip": "Keys, S box favourites and the toolbar, as a file",
|
||||
"ui.layout_compact": "Compact",
|
||||
"ui.layout_floating": "Floating",
|
||||
"ui.material_review.claims": "Sources and licences are unverified claims. Missing values remain unknown.",
|
||||
"ui.point_cloud_color_by": "Colour By",
|
||||
"ui.point_cloud_file_colors": "File Colours",
|
||||
"ui.point_cloud_no_file_colors": "The file has no colours",
|
||||
"ui.point_cloud_single_color": "Single Colour",
|
||||
"ui.properties.inertia_note": "About the centre of mass, in world axes (g·{unit}²)",
|
||||
"ui.ribbon_labels": "Show text under ribbon icons",
|
||||
"ui.view_centre": "View centre",
|
||||
"ui.workspace_layout": "Workspace layout",
|
||||
"ui.zoom_to_cursor_tip": "The wheel zooms towards the point under the cursor (off: towards the view's centre)",
|
||||
"update.prefs_flatpak": "Flatpak updates this copy ({version}): run {command} or use your software centre. SolidCraft doesn't check."
|
||||
|
||||
@@ -692,6 +692,9 @@
|
||||
"cam.roller": "롤러",
|
||||
"cam.roller_pick": "롤러 (선택 사항)",
|
||||
"cam.tip_pick": "끝점 (선택 사항)",
|
||||
"camera.shot_pitch": "피치",
|
||||
"camera.shot_roll": "롤",
|
||||
"camera.shot_yaw": "요",
|
||||
"choose a profile": "프로파일을 선택하세요",
|
||||
"choose the cam's and the follower's joints": "캠과 종동절의 관절을 선택하세요",
|
||||
"choose the joints to couple": "연결할 관절을 선택하세요",
|
||||
@@ -699,9 +702,12 @@
|
||||
"click sketch curves": "스케치 곡선 클릭",
|
||||
"cmd.appearance_assign": "외관",
|
||||
"cmd.appearance_chain": "외관 출처",
|
||||
"cmd.appearance_copy": "외관 복사",
|
||||
"cmd.appearance_favorite": "외관 즐겨찾기",
|
||||
"cmd.appearance_library": "외관 라이브러리",
|
||||
"cmd.appearance_list": "외관 목록",
|
||||
"cmd.appearance_paint": "모양 칠하기",
|
||||
"cmd.appearance_paste": "외관 붙여넣기",
|
||||
"cmd.appearance_pick_up": "모양 가져오기",
|
||||
"cmd.appearance_replace": "모양 바꾸기",
|
||||
"cmd.assembly_bom": "자재 명세서",
|
||||
@@ -710,6 +716,7 @@
|
||||
"cmd.browser_move": "브라우저 항목 이동",
|
||||
"cmd.browser_order": "브라우저 항목 정렬",
|
||||
"cmd.browser_rename_group": "그룹 이름 변경",
|
||||
"cmd.browser_reparent": "구성 요소로 이동",
|
||||
"cmd.browser_ungroup": "그룹 해제",
|
||||
"cmd.browser_visibility": "표시/숨기기",
|
||||
"cmd.canvas_calibrate": "캔버스 보정",
|
||||
@@ -732,6 +739,7 @@
|
||||
"cmd.component_metadata": "부품 속성",
|
||||
"cmd.component_metadata_set": "부품 속성 변경",
|
||||
"cmd.component_move_bodies": "바디를 구성 요소로 이동",
|
||||
"cmd.component_move_features": "특성을 구성 요소로 이동",
|
||||
"cmd.component_move_sketches": "스케치를 구성 요소로 이동",
|
||||
"cmd.component_paste_new": "새로 붙여넣기",
|
||||
"cmd.component_properties": "구성 요소 물리 속성",
|
||||
@@ -914,9 +922,15 @@
|
||||
"cmd.render_library_surface_unbind": "Remove Surface Binding",
|
||||
"cmd.render_library_targets": "렌더 리소스 대상 찾기",
|
||||
"cmd.render_lights_add": "조명 추가",
|
||||
"cmd.render_lights_duplicate": "렌더 조명 복제",
|
||||
"cmd.render_lights_list": "렌더 조명 목록",
|
||||
"cmd.render_lights_mute": "조명 음소거",
|
||||
"cmd.render_lights_remove": "렌더 조명 제거",
|
||||
"cmd.render_lights_set": "렌더 조명 설정",
|
||||
"cmd.render_lights_solo": "광원 단독 표시",
|
||||
"cmd.render_output_size": "렌더 출력 크기 설정",
|
||||
"cmd.render_preflight": "렌더 요청 확인",
|
||||
"cmd.render_preflight_copy": "렌더 검사 보고서 복사",
|
||||
"cmd.render_result_close": "렌더 이미지 닫기",
|
||||
"cmd.render_result_copy": "렌더 이미지 복사",
|
||||
"cmd.render_result_pin": "표시된 렌더 결과 유지",
|
||||
@@ -944,6 +958,16 @@
|
||||
"cmd.sheet_refold": "다시 접기",
|
||||
"cmd.sheet_rules": "판금 규칙 목록",
|
||||
"cmd.sheet_unfold": "펼치기",
|
||||
"cmd.sketch.construction_line": "보조 직선",
|
||||
"cmd.sketch.construction_line.angle": "각도 지정 보조 직선",
|
||||
"cmd.sketch.construction_line.bisector": "각의 이등분선",
|
||||
"cmd.sketch.construction_line.horizontal": "수평 보조 직선",
|
||||
"cmd.sketch.construction_line.parallel": "평행 보조 직선",
|
||||
"cmd.sketch.construction_line.perpendicular": "직교 보조 직선",
|
||||
"cmd.sketch.construction_line.tangent_at": "곡선 위 점에서의 접선",
|
||||
"cmd.sketch.construction_line.tangent_external": "외부 점을 지나는 접선",
|
||||
"cmd.sketch.construction_line.tangent_two": "공통 접선",
|
||||
"cmd.sketch.construction_line.vertical": "수직 보조 직선",
|
||||
"cmd.sketch_arc_center_point": "중심점 호",
|
||||
"cmd.sketch_arc_tangent": "접선 호",
|
||||
"cmd.sketch_arc_three_point": "3점 호",
|
||||
@@ -973,6 +997,8 @@
|
||||
"cmd.sketch_draw_dimensioned": "치수가 있는 스케치 개체 그리기",
|
||||
"cmd.sketch_edit": "스케치 편집",
|
||||
"cmd.sketch_edit_text": "텍스트 편집",
|
||||
"cmd.sketch_equation_curve": "방정식 곡선",
|
||||
"cmd.sketch_equation_curve_edit": "방정식 곡선 편집",
|
||||
"cmd.sketch_export_dxf": "DXF로 저장",
|
||||
"cmd.sketch_finish_auto_constrain": "자동 구속으로 완료",
|
||||
"cmd.sketch_fit_curves_to_section": "메시 단면에 곡선 맞추기",
|
||||
@@ -1056,15 +1082,18 @@
|
||||
"cmd.timeline_export_script": "명령 스크립트 내보내기",
|
||||
"cmd.timeline_inspect": "특성 검사",
|
||||
"cmd.timeline_paste": "특성 붙여넣기",
|
||||
"cmd.timeline_play": "기록 재생",
|
||||
"cmd.timeline_redefine": "특성 편집",
|
||||
"cmd.timeline_rename": "이름 변경",
|
||||
"cmd.timeline_reorder": "특성 순서 변경",
|
||||
"cmd.timeline_roll_to": "이력 마커 이동",
|
||||
"cmd.timeline_rollback": "타임라인 마커 이동",
|
||||
"cmd.timeline_stop": "기록 재생 중지",
|
||||
"cmd.timeline_suppress": "특성 비활성화",
|
||||
"cmd.view.render_browser": "렌더 브라우저",
|
||||
"cmd.view.render_dock": "렌더 도크 이동",
|
||||
"cmd.view.render_focus": "렌더 집중 보기",
|
||||
"cmd.view.status_items": "뷰포트 상태 항목",
|
||||
"cmd.view_ambient_occlusion": "앰비언트 오클루전",
|
||||
"cmd.view_angle_readout": "뷰 각도",
|
||||
"cmd.view_apply": "이름 있는 보기 복원",
|
||||
@@ -1074,15 +1103,20 @@
|
||||
"cmd.view_navigate": "보기 탐색",
|
||||
"cmd.view_normal_to": "선택 항목에 수직",
|
||||
"cmd.view_rename": "이름 있는 보기 이름 변경",
|
||||
"cmd.view_render_frame": "렌더 프레임 가이드",
|
||||
"cmd.view_save": "새 이름 있는 보기",
|
||||
"cmd.view_shots_strip": "샷 스트립",
|
||||
"color.copy": "클릭하여 색상 값 복사",
|
||||
"color.edit": "클릭하여 색상 편집",
|
||||
"color.gamma": "색상 값을 0-255 감마 공간으로 표시 중",
|
||||
"color.hex": "Hex",
|
||||
"color.hex_help": "#rrggbb 또는 #rrggbbaa 입력. 6자리 값은 불투명도 유지",
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "색조",
|
||||
"color.linear": "색상 값을 0-1 선형 공간으로 표시 중",
|
||||
"color.saturation_value": "채도 및 명도",
|
||||
"color.selected": "선택한 색상",
|
||||
"config.column_filter_empty": "일치하는 열이 없습니다",
|
||||
"contact.components_count": "구성요소 {count}개",
|
||||
"contact.enabled_label": "활성화됨",
|
||||
"coupling.gear_1": "기어 1",
|
||||
@@ -1175,6 +1209,17 @@
|
||||
"help.mit": "MIT 라이선스",
|
||||
"help.notice": "NOTICE",
|
||||
"help.pointcloud.insert": "PLY, XYZ 또는 PTS 스캔을 모델 옆에 포인트 클라우드로 삽입합니다. 측정 데이터를 참고하여 모델링할 때 사용합니다.",
|
||||
"help.sketch.construction_line": "두 점을 지나는 무한 보조 직선을 만듭니다. 스케치 프로파일을 나누지 않고 작도할 수 있습니다.",
|
||||
"help.sketch.construction_line.angle": "스케치 X축을 기준으로 지정한 각도의 무한 보조 직선을 만듭니다. 점을 선택한 뒤 각도를 입력하거나 방향을 선택합니다.",
|
||||
"help.sketch.construction_line.bisector": "교차하는 두 스케치 직선을 선택한 뒤 두 각의 이등분선 중 하나를 선택합니다. 결과는 원본 직선의 편집을 따릅니다.",
|
||||
"help.sketch.construction_line.horizontal": "한 점을 지나는 무한 수평 보조 직선을 만듭니다. 나중에 편집해도 수평 구속이 유지됩니다.",
|
||||
"help.sketch.construction_line.parallel": "스케치 직선을 선택한 뒤 평행한 무한 보조 직선을 배치합니다. 다른 참조를 선택하려면 마우스 오른쪽 버튼을 클릭합니다.",
|
||||
"help.sketch.construction_line.perpendicular": "스케치 직선을 선택한 뒤 직교하는 무한 보조 직선을 배치합니다. 다른 참조를 선택하려면 마우스 오른쪽 버튼을 클릭합니다.",
|
||||
"help.sketch.construction_line.tangent_at": "원이나 원호 위의 점, 또는 열린 스플라인이나 원뿔 곡선의 끝점에 접선을 만듭니다. 곡선을 선택한 뒤 접점을 선택합니다.",
|
||||
"help.sketch.construction_line.tangent_external": "원 또는 원호, 외부 점, 접선 해를 차례로 선택합니다. 미리보기에는 그려진 원호 위의 접점만 표시됩니다.",
|
||||
"help.sketch.construction_line.tangent_two": "두 원 또는 원호를 선택한 뒤 미리보기에서 공통 접선을 선택합니다. 접점은 그려진 곡선 위에 있어야 합니다.",
|
||||
"help.sketch.construction_line.vertical": "한 점을 지나는 무한 수직 보조 직선을 만듭니다. 나중에 편집해도 수직 구속이 유지됩니다.",
|
||||
"help.sketch.equation_curve": "범위에 걸쳐 수식으로 곡선을 그립니다: x(t)와 y(t), 또는 y = f(x). 수식에 매개변수를 쓸 수 있으며 곡선이 그 값을 따라갑니다. 사인파, 나선, 기어 이의 인벌류트에 사용합니다.",
|
||||
"help.solid.chamfer": "선택한 모서리를 지정한 거리만큼 평평하게 깎습니다. 날카로운 모서리를 다듬거나 핀 또는 나사가 쉽게 들어가도록 할 때 사용합니다.",
|
||||
"help.solid.extrude": "스케치 프로파일을 지정한 거리만큼 3D로 밀어내 재료를 더하거나 제거합니다. 평면 윤곽을 블록, 보스 또는 포켓으로 만들 때 사용합니다.",
|
||||
"help.solid.fillet": "선택한 모서리를 지정한 반지름의 매끄러운 원호로 둥글게 만듭니다. 강도, 편의성 또는 외관을 위해 날카로운 모서리를 부드럽게 할 때 사용합니다.",
|
||||
@@ -1182,6 +1227,7 @@
|
||||
"help.solid.revolve": "스케치 프로파일을 축을 중심으로 회전시켜 둥근 솔리드를 만듭니다. 샤프트, 손잡이, 그릇 및 중심선을 기준으로 둥근 모든 부품에 사용합니다.",
|
||||
"help.solid.shell": "솔리드의 속을 비우고 지정한 두께의 벽을 남기며, 선택한 면을 열 수도 있습니다. 상자, 커버 및 기타 얇은 벽 부품에 사용합니다.",
|
||||
"help.third_party": "타사 라이선스",
|
||||
"help.timeline.play": "남은 피처를 하나씩 재생하고 각 재생성 후 0.5초 동안 멈춥니다. 이 명령을 다시 실행하거나 Escape 키를 누르면 중지됩니다. 끝으로 이동은 즉시 마지막 단계로 이동합니다.",
|
||||
"history.sketch_under_constrained": "구속 부족 (자유도 {count}개)",
|
||||
"history.sketch_under_constrained_one": "구속 부족 (자유도 {count}개)",
|
||||
"home.back": "{name}(으)로 돌아가기",
|
||||
@@ -1310,6 +1356,8 @@
|
||||
"nav.maya.help": "Alt+왼쪽 드래그는 회전, Alt+가운데 드래그는 이동, Alt+오른쪽 드래그는 확대/축소입니다. 가운데 드래그로도 이동합니다",
|
||||
"nav.openscad.help": "빈 공간에서 왼쪽 드래그는 회전, Shift+왼쪽 드래그는 상자 선택, 스케치 형상 드래그는 편집입니다. 오른쪽 또는 가운데 드래그는 이동, Shift+오른쪽 또는 Shift+가운데 드래그는 확대/축소입니다",
|
||||
"nav.perspective.sketch": "스케치 편집 중에는 직교 뷰를 사용합니다. 원근 뷰를 전환하려면 스케치를 마치세요.",
|
||||
"nav.right_drag_orbits.help": "끄면 오른쪽 드래그는 카메라에 영향을 주지 않고 오른쪽 버튼은 컨텍스트 메뉴만 엽니다. SolidWorks 마우스 매핑을 선택하면 꺼집니다.",
|
||||
"nav.right_drag_orbits.label": "오른쪽 드래그로 회전",
|
||||
"nav.solidworks.help": "가운데 드래그는 회전, Ctrl+가운데 드래그는 이동, Shift+가운데 드래그는 확대/축소, 오른쪽 드래그는 회전입니다",
|
||||
"nav.tinkercad.help": "오른쪽 드래그는 회전, 가운데 또는 Shift+오른쪽 드래그는 이동입니다",
|
||||
"nav.touchpad.help": "Shift를 누른 채 포인터를 움직이면 화면이 이동하고, Alt/Option을 누른 채 움직이면 회전합니다. 마우스 버튼은 필요 없습니다. 세로 스크롤로 확대/축소합니다.",
|
||||
@@ -1474,6 +1522,8 @@
|
||||
"prefs.bodies_folders_never": "표시 안 함",
|
||||
"prefs.bodies_folders_several": "바디가 여러 개일 때만",
|
||||
"prefs.bottom": "아래쪽",
|
||||
"prefs.bottom_centre": "하단 가운데",
|
||||
"prefs.bottom_right": "오른쪽 아래",
|
||||
"prefs.browser": "브라우저",
|
||||
"prefs.built_in": "기본 제공",
|
||||
"prefs.button_left": "왼쪽 드래그",
|
||||
@@ -1521,6 +1571,8 @@
|
||||
"prefs.history": "이력",
|
||||
"prefs.history_origin_bodies": "원점과 바디를 맨 위에 표시",
|
||||
"prefs.history_origin_bodies_note": "왼쪽 또는 브라우저 아래의 히스토리가 활성 구성 요소의 바디 폴더와 원점으로 시작하며, 브라우저처럼 표시 아이콘과 메뉴가 있습니다. 아래쪽 히스토리는 바뀌지 않습니다.",
|
||||
"prefs.history_play_button": "기록 컨트롤에 기록 재생 버튼 표시",
|
||||
"prefs.history_play_button_note": "기록 컨트롤의 한 단계 뒤로와 한 단계 앞으로 사이에 기록 재생을 추가합니다. 컨트롤을 마우스 오른쪽 버튼으로 클릭해 표시하거나 숨길 수도 있습니다.",
|
||||
"prefs.hold_stop_snapping": "누르고 있으면 스냅 중지",
|
||||
"prefs.icons_only": "아이콘만",
|
||||
"prefs.imported_file": "가져온 파일",
|
||||
@@ -1534,6 +1586,8 @@
|
||||
"prefs.layout_note": "컴팩트는 패널을 창 가장자리에 고정합니다. 브라우저 반투명은 플로팅에서 사용할 수 있습니다. 어시스턴트 위치는 어시스턴트 페이지에서 바꿀 수 있습니다.",
|
||||
"prefs.left": "왼쪽",
|
||||
"prefs.left_click": "왼쪽 클릭",
|
||||
"prefs.line_drag_draws_one": "누른 채 드래그하면 선 하나 그리기",
|
||||
"prefs.line_drag_draws_one_note": "선 도구에서 누르고 드래그한 뒤 놓으면 누른 곳에서 놓은 곳까지 선 하나를 그리고 거기서 끝납니다. 클릭하면 이전처럼 이어지는 선을 그립니다. 끄면: 드래그는 클릭처럼 놓은 곳에 점을 둡니다.",
|
||||
"prefs.live_input": "실시간 입력",
|
||||
"prefs.live_preview": "실시간 미리보기",
|
||||
"prefs.max_file_size": "열 수 있는 최대 파일 크기",
|
||||
@@ -1558,7 +1612,12 @@
|
||||
"prefs.origin_plane_names": "원점 평면 이름",
|
||||
"prefs.origin_plane_names_note": "브라우저, 대화 상자, 목록에 표시되는 이름입니다. {top}은 XY, {front}는 XZ, {right}는 YZ이며 Z가 위쪽입니다. 명령, 스크립트, 저장된 디자인은 XY, XZ, YZ를 유지합니다.",
|
||||
"prefs.overall_speed": "전체 속도",
|
||||
"prefs.persistent_ribbon_pressed": "활성 리본 명령 강조 표시",
|
||||
"prefs.persistent_ribbon_pressed_help": "효과가 켜져 있는 동안 리본 명령을 강조 표시합니다. 끄면 이전의 중립적인 모양과 명령 도움말을 유지합니다.",
|
||||
"prefs.perspective_fov": "시야각",
|
||||
"prefs.preview_choices": "선택 항목 미리보기",
|
||||
"prefs.project_options_dialog": "Project 옵션 대화상자",
|
||||
"prefs.project_options_dialog_note": "켜기: 투영 전에 지오메트리 또는 바디와 투영 링크를 선택합니다. 끄기: 기존 직접 선택 작업 흐름을 유지합니다.",
|
||||
"prefs.quality_default": "기본값",
|
||||
"prefs.quality_fastest": "가장 빠름",
|
||||
"prefs.quality_slowest": "가장 느림",
|
||||
@@ -1577,6 +1636,17 @@
|
||||
"prefs.shift_add_ctrl_toggle": "Shift는 추가만, Ctrl / Cmd는 토글",
|
||||
"prefs.shift_add_note": "켬: Shift는 추가, Ctrl / Cmd는 토글. 끔(기본값): 둘 다 토글.",
|
||||
"prefs.shortcuts": "단축키",
|
||||
"prefs.single_surface_analysis": "표면 분석 하나만 사용",
|
||||
"prefs.single_surface_analysis_help": "끄면 표면 음영 분석과 연속성 분석을 함께 유지할 수 있습니다. 켜면 마지막으로 시작하거나 변경한 분석만 유지됩니다.",
|
||||
"prefs.sketch_align_points": "그리는 동안 다른 스케치 점에 맞추기",
|
||||
"prefs.sketch_align_points_note": "그리는 동안 점이 한 스케치 점과 수평으로, 다른 점과 수직으로 동시에 맞춰지고 점선 안내선이 표시됩니다. 클릭하면 두 정렬이 모두 유지됩니다. 끄기: 이전 점에만, 한 번에 한 축씩 맞춥니다.",
|
||||
"prefs.sketch_conflict_colour": "충돌하는 기하를 충돌 색상으로 표시",
|
||||
"prefs.sketch_conflict_colour_note": "스케치의 구속 조건이 충돌하는 동안 실패한 구속 조건의 글리프나 치수뿐 아니라 그 구속 조건이 잡고 있는 곡선과 점도 충돌 색상으로 그립니다. 끄기: 평소 색상을 유지합니다.",
|
||||
"prefs.sketch_construction_lines": "확장 보조 직선 도구",
|
||||
"prefs.sketch_open_look_at": "스케치를 열 때 정면으로 돌리기",
|
||||
"prefs.sketch_open_look_at_note": "끄기: 스케치를 만들거나 편집해도 뷰가 그대로입니다. 필요할 때 '바라보기'로 스케치를 정면으로 봅니다.",
|
||||
"prefs.sketch_recent_snap": "최근 중심과 중점에 자동 스냅",
|
||||
"prefs.sketch_recent_snap_note": "그리는 동안 최근에 사용한 두 원의 중심 또는 직선 모서리 중점의 안내선이 만나는 위치로 커서를 스냅합니다. 끄기: 안내선은 보기만 하고 커서는 움직이지 않습니다.",
|
||||
"prefs.sketch_selection": "스케치 및 선택",
|
||||
"prefs.sketch_selection_heading": "스케치 및 선택",
|
||||
"prefs.sketch_selection_note": "스케치가 스냅되는 방식과 클릭으로 선택하는 방식입니다.",
|
||||
@@ -1609,9 +1679,17 @@
|
||||
"prefs.timeline_half_hour": "−30분",
|
||||
"prefs.timeline_now": "지금",
|
||||
"prefs.timeline_quarter_hour": "−15",
|
||||
"prefs.toast_place": "알림",
|
||||
"prefs.toggle_item": "항목을 추가하거나 다시 제거",
|
||||
"prefs.toolbar": "도구 모음",
|
||||
"prefs.toolbar_tabs": "도구 모음 탭",
|
||||
"prefs.top": "위쪽",
|
||||
"prefs.trackpad_zoom_modifier": "다음 키를 누른 채 두 손가락으로 스크롤하여 확대/축소",
|
||||
"prefs.trackpad_zoom_modifier.alt": "⌥ / Alt",
|
||||
"prefs.trackpad_zoom_modifier.cmd": "⌘",
|
||||
"prefs.trackpad_zoom_modifier.ctrl": "Ctrl",
|
||||
"prefs.trackpad_zoom_modifier.help": "이 키만 누른 채 세로로 스크롤하면 포인터 위치를 기준으로 확대/축소합니다. 끄면 기존 스크롤 동작을 유지합니다.",
|
||||
"prefs.trackpad_zoom_modifier.off": "끄기",
|
||||
"prefs.translucent": "반투명",
|
||||
"prefs.under_browser": "브라우저 아래",
|
||||
"prefs.under_cursor": "커서 아래",
|
||||
@@ -1624,10 +1702,16 @@
|
||||
"prefs.wheel": "휠",
|
||||
"prefs.wheel_trackpad": "휠 및 트랙패드",
|
||||
"prefs.workspace": "작업 공간",
|
||||
"prefs.zoom_stop_at_model": "모델에서 확대/축소 멈추기",
|
||||
"prefs.zoom_stop_at_model_tip": "3D 마우스와 장치 앱은 뷰 중앙의 표면을 향해 확대/축소하고, 드래그 확대/축소는 드래그 시작점을 고정합니다. 끄면 모델을 통과할 수 있습니다. 휠과 핀치는 별도의 커서로 확대/축소 설정을 사용합니다",
|
||||
"prefs.zoom_toward_cursor": "확대/축소, 커서 방향으로",
|
||||
"properties.title": "속성: {name}",
|
||||
"recovery.days_ago": "{count}일 전",
|
||||
"recovery.detail": "{file} · 피처 {features}개 · {when} 자동 저장",
|
||||
"recovery.discard_all": "모두 버리기",
|
||||
"recovery.discard_all_detail": "이 작업은 되돌릴 수 없습니다.",
|
||||
"recovery.discard_all_title": "자동 저장 {count}개를 버리시겠습니까?",
|
||||
"recovery.discard_all_title_one": "자동 저장 1개를 버리시겠습니까?",
|
||||
"recovery.hours_ago": "{count}시간 전",
|
||||
"recovery.just_now": "방금",
|
||||
"recovery.min_ago": "{count}분 전",
|
||||
@@ -1674,6 +1758,7 @@
|
||||
"render.appearance_editor.v_up": "텍스처 V가 위쪽을 향함",
|
||||
"render.appearance_editor.weight": "가중치",
|
||||
"render.appearances": "외관",
|
||||
"render.assign_help": "클릭하여 선택 항목에 적용하거나 드래그하여 미리 보고 놓으세요. 선택이 없으면 칠하기를 시작합니다.",
|
||||
"render.background": "장면 배경",
|
||||
"render.bloom_enable": "표시 블룸",
|
||||
"render.bloom_help": "양의 선형 하이라이트를 세 번의 정규화 필터로 확산하는 출력 전용 효과입니다. 반경은 출력 픽셀 단위이며 sRGB 전에 더합니다. 렌즈·볼륨·수렴 개선이 아니며 원본 EXR은 변하지 않습니다.",
|
||||
@@ -1681,6 +1766,7 @@
|
||||
"render.bloom_radius": "블룸 반경",
|
||||
"render.bloom_strength": "블룸 강도",
|
||||
"render.bloom_threshold": "선형 하이라이트 임계값",
|
||||
"render.browse_looks": "찾아보기…",
|
||||
"render.category_metal": "금속",
|
||||
"render.category_paint": "페인트",
|
||||
"render.category_plastic": "플라스틱",
|
||||
@@ -1688,6 +1774,82 @@
|
||||
"render.check_opaque": "투명도: 불투명 표면만 지원하며 배경 알파를 지원합니다.",
|
||||
"render.check_sorted_alpha": "투명도: 정렬된 알파 근사.",
|
||||
"render.check_transmission": "투명도: 물리적 투과.",
|
||||
"render.children.absolute_floor": "절대 하한",
|
||||
"render.children.adaptive": "적응형",
|
||||
"render.children.add_look_reason": "활성 상태와 강도를 편집하려면 룩을 추가하세요.",
|
||||
"render.children.all_shots": "모든 샷",
|
||||
"render.children.bloom": "블룸",
|
||||
"render.children.check": "검사",
|
||||
"render.children.check_now": "지금 검사",
|
||||
"render.children.chromatic": "색수차",
|
||||
"render.children.compact": "소형",
|
||||
"render.children.contrast": "대비",
|
||||
"render.children.copy_image": "복사",
|
||||
"render.children.copy_job": "작업 JSON 복사",
|
||||
"render.children.copy_request": "요청 JSON 복사",
|
||||
"render.children.coverage_error": "커버리지 오차",
|
||||
"render.children.cpu": "CPU 레이 트레이싱",
|
||||
"render.children.denoise": "완성 이미지의 노이즈 줄이기",
|
||||
"render.children.depth": "경로 깊이",
|
||||
"render.children.distortion": "왜곡",
|
||||
"render.children.edge_samples": "모서리 샘플",
|
||||
"render.children.effects_banner": "이 효과에는 GPU 경로 추적이 필요합니다. 열어도 방식은 바뀌지 않습니다.",
|
||||
"render.children.enable_adaptive": "적응형 한도를 편집하려면 독립 파일럿을 활성화하세요.",
|
||||
"render.children.enable_bloom": "강도, 임계값, 반경을 편집하려면 블룸을 활성화하세요.",
|
||||
"render.children.finishing": "마무리",
|
||||
"render.children.flare": "플레어",
|
||||
"render.children.fresnel": "프레넬 계층",
|
||||
"render.children.ghosts": "고스트 링",
|
||||
"render.children.glass": "유리 광 전송",
|
||||
"render.children.go_to": "{editor}(으)로 이동",
|
||||
"render.children.grain": "입자",
|
||||
"render.children.halo": "후광",
|
||||
"render.children.hdr": "HDR",
|
||||
"render.children.keep_master": "원시 선형 마스터 유지",
|
||||
"render.children.last_result": "최근: {number} · {width} × {height} · {phase}",
|
||||
"render.children.lens_effects": "렌즈 효과",
|
||||
"render.children.look_summary": "{tone} · 룩 {count}개",
|
||||
"render.children.looks": "크리에이티브 룩",
|
||||
"render.children.memory": "메모리",
|
||||
"render.children.method": "방식",
|
||||
"render.children.minimum": "최소값",
|
||||
"render.children.needs_cpu": "CPU 레이 트레이싱이 필요합니다. 열어도 방식은 바뀌지 않습니다.",
|
||||
"render.children.nested": "인증된 중첩 유전체",
|
||||
"render.children.not_checked": "검사 안 됨",
|
||||
"render.children.path": "경로 추적",
|
||||
"render.children.pilots": "파일럿 샘플",
|
||||
"render.children.preview": "미리보기 데이터",
|
||||
"render.children.progressive_reason": "샘플 수와 시드를 편집하려면 점진적 모드를 선택하세요.",
|
||||
"render.children.radius": "반경",
|
||||
"render.children.reflect_depth": "반사 깊이",
|
||||
"render.children.reflect_samples": "반사 샘플",
|
||||
"render.children.regrade": "다시 그레이딩",
|
||||
"render.children.relative_error": "상대 오차",
|
||||
"render.children.render": "렌더링",
|
||||
"render.children.render_shot": "샷 렌더링",
|
||||
"render.children.renderer": "렌더러",
|
||||
"render.children.renderers": "렌더러",
|
||||
"render.children.request": "이 요청",
|
||||
"render.children.reset_finishing": "마무리 초기화",
|
||||
"render.children.review_quality": "품질 사양 검토…",
|
||||
"render.children.rgb_gain": "RGB 게인",
|
||||
"render.children.samples": "샘플",
|
||||
"render.children.sampling": "샘플링",
|
||||
"render.children.saturation": "채도",
|
||||
"render.children.scene_summary": "바디 {bodies}개 · 삼각형 {triangles}개",
|
||||
"render.children.seed": "시드",
|
||||
"render.children.sharpening": "선명도",
|
||||
"render.children.single_image": "단일 이미지",
|
||||
"render.children.soft_focus": "소프트 포커스",
|
||||
"render.children.streak": "광선",
|
||||
"render.children.strength": "강도",
|
||||
"render.children.studio": "스튜디오",
|
||||
"render.children.threshold": "임계값",
|
||||
"render.children.tone": "톤",
|
||||
"render.children.under_hood": "내부 정보",
|
||||
"render.children.vignette": "비네트",
|
||||
"render.children.workstation": "워크스테이션",
|
||||
"render.choose_look": "먼저 외관 라이브러리에서 외관을 선택하세요",
|
||||
"render.clear_stage": "Remove saved stage",
|
||||
"render.cpu_budget": "CPU 리소스 프로필",
|
||||
"render.cpu_budget_bodies": "바디 수 상한",
|
||||
@@ -1702,6 +1864,86 @@
|
||||
"render.cpu_budget_workstation": "워크스테이션 (대규모 장면)",
|
||||
"render.effects_gpu_only": "이 효과를 사용하려면 GPU 경로 추적이 필요합니다. 페이지를 바꿔도 렌더러는 자동으로 전환되지 않습니다.",
|
||||
"render.emitted_axis": "방출 축",
|
||||
"render.env_advanced": "고급",
|
||||
"render.env_backdrop": "배경",
|
||||
"render.env_backdrop_pending": "렌더러가 환경 배경 표시와 흐림을 아직 지원하지 않습니다.",
|
||||
"render.env_blur": "흐림",
|
||||
"render.env_change": "변경",
|
||||
"render.env_choose_source": "조명을 편집하기 전에 스튜디오 및 환경에서 환경을 선택하세요.",
|
||||
"render.env_clear": "투명",
|
||||
"render.env_colour": "색상",
|
||||
"render.env_environments": "환경",
|
||||
"render.env_ground": "지면",
|
||||
"render.env_ground_pending": "물리적 지면은 유한한 확산 표면으로 그림자를 받습니다. 그림자만 포착하거나 지면에 반사하는 기능은 아직 지원하지 않습니다.",
|
||||
"render.env_intensity": "강도",
|
||||
"render.env_invalid_edit": "환경 편집 내용이 올바르지 않습니다.",
|
||||
"render.env_physical_ground": "물리적 지면",
|
||||
"render.env_preview_help": "구 예시이며 선택한 환경의 미리보기가 아닙니다.",
|
||||
"render.env_reflection": "반사",
|
||||
"render.env_ring_help": "링을 드래그하여 조명을 회전하세요. Shift를 누르면 15° 간격으로 스냅합니다.",
|
||||
"render.env_rotate": "회전",
|
||||
"render.env_set": "렌더 환경 설정",
|
||||
"render.env_shadow_catcher": "그림자 포착",
|
||||
"render.env_show_environment": "환경 표시",
|
||||
"render.env_source": "소스",
|
||||
"render.env_stage_details": "지면 편집에는 레이 트레이싱과 단일 지면 패널이 필요합니다. 다른 무대 패널은 장면에서 편집하세요.",
|
||||
"render.env_studios": "스튜디오",
|
||||
"render.environment.albedo": "알베도",
|
||||
"render.environment.atmosphere": "대기",
|
||||
"render.environment.backdrop_note": "배경은 카메라에만 보이며 조명, 그림자, 반사에 영향을 주지 않습니다. 투명 출력과 함께 사용할 수 없습니다.",
|
||||
"render.environment.blur_pending": "흐림을 사용할 수 없습니다. 렌더러에 배경 흐림 설정이 없습니다.",
|
||||
"render.environment.builtin": "내장 HDR",
|
||||
"render.environment.check": "파일 확인",
|
||||
"render.environment.checked": "HDR 파일을 확인했습니다. 저장하면 이 데이터가 포함됩니다.",
|
||||
"render.environment.choose": "HDR 선택…",
|
||||
"render.environment.constant": "상수",
|
||||
"render.environment.cyclorama": "사이클로라마",
|
||||
"render.environment.embedded": "이 디자인 안에 저장됨",
|
||||
"render.environment.end": "끝",
|
||||
"render.environment.extinction": "소광 계수",
|
||||
"render.environment.file": "파일",
|
||||
"render.environment.fit": "지면 맞춤 및 저장",
|
||||
"render.environment.floor_wall": "바닥과 벽",
|
||||
"render.environment.gap": "간격",
|
||||
"render.environment.gradient": "그라데이션",
|
||||
"render.environment.gradient_gpu": "그라데이션 배경에는 GPU 경로 추적이 필요합니다.",
|
||||
"render.environment.ground": "지면과 스테이지",
|
||||
"render.environment.hdr": "HDR",
|
||||
"render.environment.hdr_file": "HDR 파일",
|
||||
"render.environment.horizon": "수평선",
|
||||
"render.environment.horizontal": "수평",
|
||||
"render.environment.keep": "유지",
|
||||
"render.environment.lighting_samples": "조명 샘플",
|
||||
"render.environment.margin": "범위 여백",
|
||||
"render.environment.max": "최대 경계",
|
||||
"render.environment.medium": "참여 매질",
|
||||
"render.environment.min": "최소 경계",
|
||||
"render.environment.mode": "모드",
|
||||
"render.environment.needs_gpu": "GPU 경로 추적이 필요합니다.",
|
||||
"render.environment.none": "없음",
|
||||
"render.environment.orientation": "방향과 강도",
|
||||
"render.environment.phase": "위상",
|
||||
"render.environment.primaries": "지정되지 않은 원색을 선형 sRGB로 처리",
|
||||
"render.environment.primaries_gpu": "지정되지 않은 원색 해석에는 GPU 경로 추적이 필요합니다.",
|
||||
"render.environment.radial": "방사형",
|
||||
"render.environment.radial_only": "중심과 반경은 방사형 모드에 적용됩니다.",
|
||||
"render.environment.reflectance": "반사율",
|
||||
"render.environment.remove": "스테이지 제거",
|
||||
"render.environment.remove_confirm": "저장된 스테이지를 제거할까요?",
|
||||
"render.environment.remove_note": "이 샷에서 패시브 패널 {count}개를 제거합니다. 카메라 배경은 유지됩니다.",
|
||||
"render.environment.replace": "기존 스테이지 교체 확인",
|
||||
"render.environment.rotation_hdr": "CPU 광선 추적의 회전에는 HDR 광원이 필요합니다.",
|
||||
"render.environment.samples_cpu": "GPU 조명 샘플은 경로 예산으로 정해집니다. 이 설정에는 CPU 광선 추적이 필요합니다.",
|
||||
"render.environment.saved_panels": "저장된 패널 {count}",
|
||||
"render.environment.sky_ground": "지면",
|
||||
"render.environment.sky_note": "조명용 오리지널 하늘 그라데이션이며 보정된 대기 모델은 아닙니다.",
|
||||
"render.environment.source_raytrace": "환경 광원에는 CPU 또는 GPU 광선 추적이 필요합니다.",
|
||||
"render.environment.stage_raytrace": "물리 스테이지에는 CPU 또는 GPU 광선 추적이 필요합니다.",
|
||||
"render.environment.start": "시작",
|
||||
"render.environment.vertical": "수직",
|
||||
"render.environment.world": "월드",
|
||||
"render.environment.world_pending": "월드 배경을 사용할 수 없습니다. 환경의 카메라 표시를 저장하는 설정이 아직 없습니다.",
|
||||
"render.environment.zenith": "천정",
|
||||
"render.environment_tiles_require_raytrace": "환경에는 CPU 또는 GPU 광선 추적이 필요합니다. 출력 편집기에서 선택하세요.",
|
||||
"render.error_area_samples": "area_samples는 1, 4, 16 또는 64여야 함",
|
||||
"render.error_binding_allocation": "재질 연결을 할당할 수 없음",
|
||||
@@ -1766,14 +2008,40 @@
|
||||
"render.fixed_camera": "카메라",
|
||||
"render.fixed_world": "월드",
|
||||
"render.fold_browser": "브라우저 접기",
|
||||
"render.frame_aspect": "화면 비율",
|
||||
"render.frame_centre_mark": "중심 표시",
|
||||
"render.frame_copy_limit": "사용 가능한 복제 샷 이름이 없습니다",
|
||||
"render.frame_copy_name": "{name} 복사본 {number}",
|
||||
"render.frame_custom": "사용자 지정",
|
||||
"render.frame_distance_unit": " × 크기",
|
||||
"render.frame_duplicate": "복제",
|
||||
"render.frame_exposure": "노출",
|
||||
"render.frame_fov": "시야각",
|
||||
"render.frame_guides": "가이드",
|
||||
"render.frame_invalid_aspect": "잘못된 화면 비율 프리셋",
|
||||
"render.frame_lens": "시야각 {fov}° · 약 {mm} mm",
|
||||
"render.frame_name": "이름",
|
||||
"render.frame_output_size": "출력 크기",
|
||||
"render.frame_photo": "3:2 · 사진",
|
||||
"render.frame_portrait": "4:5 · 세로",
|
||||
"render.frame_presets": "구도 프리셋",
|
||||
"render.frame_presets_pending": "샷 편집기와 함께 제공 예정",
|
||||
"render.frame_projection": "투영",
|
||||
"render.frame_render_shot": "이 샷 렌더링",
|
||||
"render.frame_rule_thirds": "삼분할 법칙",
|
||||
"render.frame_safe_area": "안전 영역",
|
||||
"render.frame_shot_title": "샷 · {name}",
|
||||
"render.frame_square": "1:1 · 정사각형",
|
||||
"render.frame_tall": "9:16 · 세로형",
|
||||
"render.frame_thirds": "삼분할선",
|
||||
"render.frame_wide": "16:9 · 와이드스크린",
|
||||
"render.heading_batch": "일괄 처리",
|
||||
"render.heading_frame": "프레임",
|
||||
"render.heading_lens": "렌즈",
|
||||
"render.heading_results": "결과",
|
||||
"render.heading_shots": "샷",
|
||||
"render.hide_shots_label": "샷 스트립 숨기기",
|
||||
"render.hover_look": "{object} · {look} · 클릭하여 선택",
|
||||
"render.image_cancelled": "렌더링 취소됨",
|
||||
"render.image_cancelling": "취소 중",
|
||||
"render.image_completed": "이미지 내보내기 준비됨",
|
||||
@@ -1880,8 +2148,86 @@
|
||||
"render.library_title": "렌더 리소스 라이브러리",
|
||||
"render.library_uniform_ack": "공간 변화나 고급 효과 없는 균일 근사 사용",
|
||||
"render.library_users": "사용 위치",
|
||||
"render.light_aim": "조준 대상",
|
||||
"render.light_anchor_pending": "조명 좌표계 변경은 아직 지원되지 않습니다.",
|
||||
"render.light_azimuth": "방위각",
|
||||
"render.light_backend_limit": "조명을 편집하려면 CPU 레이 트레이싱이나 명시적인 GPU 스튜디오를 선택하세요. 기존 GPU 스튜디오 조명은 읽기 전용입니다.",
|
||||
"render.light_behaviour": "동작",
|
||||
"render.light_default_fill": "필 라이트",
|
||||
"render.light_default_key": "키 라이트",
|
||||
"render.light_default_number": "조명 {number}",
|
||||
"render.light_default_rim": "림 라이트",
|
||||
"render.light_delete": "삭제",
|
||||
"render.light_distance": "거리",
|
||||
"render.light_duplicate": "복제",
|
||||
"render.light_elevation": "고도각",
|
||||
"render.light_gpu_punctual": "포인트와 스폿 조명은 CPU 레이 트레이싱에서 사용할 수 있습니다.",
|
||||
"render.light_hard_shadow": "이 조명은 단단한 그림자만 지원합니다.",
|
||||
"render.light_intensity": "강도",
|
||||
"render.light_missing": "이 조명이 더 이상 없습니다. 브라우저에서 조명을 선택하세요.",
|
||||
"render.light_place_highlight": "하이라이트로 배치",
|
||||
"render.light_place_pending": "하이라이트 배치는 뷰포트 조명 선택이 필요하며 아직 지원되지 않습니다.",
|
||||
"render.light_position": "위치",
|
||||
"render.light_preview_help": "라이브 뷰에는 그림자가 없으며 영역 조명은 중심 샘플로 근사됩니다. 렌더는 전체 조명 모델을 사용합니다.",
|
||||
"render.light_product_centre": "제품 중심",
|
||||
"render.light_size": "크기",
|
||||
"render.light_softness": "부드러움",
|
||||
"render.light_temperature": "색온도",
|
||||
"render.light_temperature_help": "흑체 색상 근사값이며 선형 RGB로 저장됩니다.",
|
||||
"render.light_type": "유형",
|
||||
"render.light_type_area": "영역",
|
||||
"render.light_type_point": "포인트",
|
||||
"render.light_type_spot": "스폿",
|
||||
"render.light_type_sun": "태양",
|
||||
"render.light_view_only": "솔로와 음소거는 이 뷰와 렌더에만 적용되며 디자인에 저장되지 않습니다.",
|
||||
"render.light_world_origin": "월드 원점",
|
||||
"render.lighting_aim_point": "조준점",
|
||||
"render.lighting_apply": "프리셋 적용",
|
||||
"render.lighting_area_samples": "영역 샘플",
|
||||
"render.lighting_budget": "한도",
|
||||
"render.lighting_budget_help": "개수는 읽기 전용입니다. 조명을 추가, 복제 또는 삭제하세요. 한도는 방식에 따라 정해집니다.",
|
||||
"render.lighting_colour": "색상",
|
||||
"render.lighting_consent": "이 프리셋으로 방향 조명 교체",
|
||||
"render.lighting_custom": "사용자 조명",
|
||||
"render.lighting_custom_help": "사용자 조명을 선택하면 프리셋이 트리의 각 행에서 편집 가능한 조명으로 변환됩니다.",
|
||||
"render.lighting_direction": "방향 X Y Z",
|
||||
"render.lighting_direction_help": "또는 조명 방향을 입력하세요 (X Y Z).",
|
||||
"render.lighting_distance_unit": " × 크기",
|
||||
"render.lighting_edge_u": "변 U 벡터",
|
||||
"render.lighting_edge_v": "변 V 벡터",
|
||||
"render.lighting_falloff": "감쇠",
|
||||
"render.lighting_falloff_help": "강도는 기준 거리에서의 값입니다.",
|
||||
"render.lighting_height": "높이 V",
|
||||
"render.lighting_minimum": "최솟값",
|
||||
"render.lighting_mute": "이 조명 끄기",
|
||||
"render.lighting_point": "점",
|
||||
"render.lighting_preset": "스튜디오 프리셋",
|
||||
"render.lighting_preset_cpu": "방향 조명 프리셋에는 CPU 레이 트레이싱이 필요합니다. GPU는 명시적 태양 및 영역 조명을 사용합니다.",
|
||||
"render.lighting_preset_row": "프리셋",
|
||||
"render.lighting_radiance": "복사휘도",
|
||||
"render.lighting_reference": "기준",
|
||||
"render.lighting_review_help": "방향 조명 목록을 교체합니다. 점 및 영역 조명, 환경, 그림자, 카메라와 다른 샷 설정은 유지합니다.",
|
||||
"render.lighting_review_title": "조명 프리셋 검토",
|
||||
"render.lighting_samples_cpu": "영역 조명 샘플은 CPU 레이 트레이싱에 적용됩니다.",
|
||||
"render.lighting_samples_need_area": "영역 샘플을 설정하려면 CPU 영역 조명을 추가하세요.",
|
||||
"render.lighting_samples_reason": "영역 샘플은 1, 4, 16 또는 64여야 합니다.",
|
||||
"render.lighting_shadow_cpu": "그림자 스위치에는 CPU 레이 트레이싱이 필요합니다. GPU 경로 추적은 항상 그림자를 계산합니다.",
|
||||
"render.lighting_shadows": "그림자 투사",
|
||||
"render.lighting_shadows_section": "그림자 및 샘플링",
|
||||
"render.lighting_shape": "모양",
|
||||
"render.lighting_solo": "이 조명만 표시",
|
||||
"render.lighting_source": "광원",
|
||||
"render.lighting_source_section": "광원",
|
||||
"render.lighting_spot_preserved": "이 점 조명은 유형을 변경할 때까지 저장된 스폿 원뿔을 유지합니다.",
|
||||
"render.lighting_sun_distance": "태양 방향은 거리 및 조준점과 무관합니다.",
|
||||
"render.lighting_unsupported": "지원되지 않음",
|
||||
"render.lighting_used": "{used} / {limit}",
|
||||
"render.lighting_width": "너비 U",
|
||||
"render.lighting_world_position": "월드 X Y Z",
|
||||
"render.lights_fixed_to": "조명 고정 기준",
|
||||
"render.look_applied": "{name} 적용됨",
|
||||
"render.look_material": "재질",
|
||||
"render.look_pasted": "외관 붙여넣음",
|
||||
"render.material_color_replace": "기본 맵으로 바디 색상 교체",
|
||||
"render.material_limits": "최대 128개 바디 설정, 분리된 유리 32개, 코팅 64개, 텍스처 연결 128개. 같은 맵은 메모리를 공유하며 실제 장치 및 전체 메모리 제한은 유지됩니다.",
|
||||
"render.material_metallic_map": "금속성 맵 (선형)",
|
||||
@@ -1894,9 +2240,11 @@
|
||||
"render.output_advanced": "고급",
|
||||
"render.output_backend_ready": "준비 완료",
|
||||
"render.output_check": "확인",
|
||||
"render.output_check_failed": "검사 · 오류",
|
||||
"render.output_check_help": "확인을 실행하면 렌더링을 시작하지 않고 요청을 검토합니다.",
|
||||
"render.output_check_summary": "검사 · 참고 {count}개",
|
||||
"render.output_copy": "복사",
|
||||
"render.output_copy_report": "보고서 복사",
|
||||
"render.output_destination": "저장 위치",
|
||||
"render.output_destination_help": "완성된 이미지를 내보낼 때 대상 파일을 선택합니다.",
|
||||
"render.output_dimensions": "크기",
|
||||
@@ -1906,16 +2254,20 @@
|
||||
"render.output_fit": "맞춤",
|
||||
"render.output_format": "형식",
|
||||
"render.output_format_status": "PNG는 완료된 표시 이미지 그대로입니다. 선택적 GPU EXR은 표시 필터 전 선형 FLOAT32 방사 휘도를 보존합니다. 미리보기 캐시나 다른 작업으로 바꾸어 내보내지 않습니다.",
|
||||
"render.output_grading": "색 보정",
|
||||
"render.output_image": "이미지",
|
||||
"render.output_largest": "{width} × {height} 최대",
|
||||
"render.output_presets_help": "형식, 품질 및 검사 목록은 출력 편집기에 있습니다.",
|
||||
"render.output_quality": "품질",
|
||||
"render.output_quality_waiting": "품질 규약 대기 중",
|
||||
"render.output_ready": "렌더링 준비 완료",
|
||||
"render.output_run_check": "검사 실행",
|
||||
"render.output_size_limit": "{method}: 한 변 최대 {dimension} px, 총 {pixels} 픽셀. 가능한 최대 크기: {width} × {height}.",
|
||||
"render.output_size_ok": "크기 정상 · {width} × {height} px",
|
||||
"render.output_tools_inspector": "출력 검사기에서 크기와 형식을 편집하세요.",
|
||||
"render.output_view_image": "이미지 보기",
|
||||
"render.paint_label": "칠하기",
|
||||
"render.painting_with": "{name}(으)로 칠하는 중",
|
||||
"render.passive_stage": "Render-only stage",
|
||||
"render.passive_stage_help": "Finite passive panels belong only to rendered images. They do not add CAD bodies or mass. Placement is fixed after applying; intersecting product bounds refuse. CPU does not provide diffuse bounce lighting.",
|
||||
"render.perspective": "원근 카메라",
|
||||
@@ -1934,6 +2286,7 @@
|
||||
"render.pick_help": "바디, 면 또는 구성요소를 선택합니다. 빈 공간을 클릭하면 선택이 해제되고 Shift 또는 Ctrl로 추가하거나 전환합니다. 강조 표시는 실시간 제품 뷰에만 나타납니다.",
|
||||
"render.pick_label": "선택",
|
||||
"render.pick_up_label": "가져오기",
|
||||
"render.pick_up_prompt": "외관을 가져올 객체를 클릭하세요",
|
||||
"render.pick_waiting": "제품 선택은 아직 지원되지 않습니다.",
|
||||
"render.preview": "통합 미리보기",
|
||||
"render.preview_help": "래스터 셰이딩과 블렌딩 투명도를 사용합니다. 굴절, HDRI 및 최종 렌더링은 아직 지원하지 않습니다.",
|
||||
@@ -1952,10 +2305,14 @@
|
||||
"render.radial_compare": "비교",
|
||||
"render.radial_fit": "제품 맞추기",
|
||||
"render.radial_save": "샷 저장",
|
||||
"render.recent_looks": "최근 외관",
|
||||
"render.regrade_label": "색상 재조정",
|
||||
"render.reload_settings": "저장된 설정 다시 불러오기",
|
||||
"render.remove_override": "재정의 제거",
|
||||
"render.replace_all": "모두 바꾸기",
|
||||
"render.replace_label": "바꾸기",
|
||||
"render.replace_saved_surface": "Replace an existing saved binding for this target",
|
||||
"render.replace_with": "바꿀 외관",
|
||||
"render.restore_camera": "저장된 카메라 복원",
|
||||
"render.result_actual": "100%",
|
||||
"render.result_actual_size": "100%",
|
||||
@@ -1988,11 +2345,43 @@
|
||||
"render.saved_surface_remove": "Remove saved binding",
|
||||
"render.saved_surfaces": "Saved surface bindings",
|
||||
"render.saved_surfaces_help": "Pinned built-in maps follow the selected occurrence in local millimeters. A replaced or missing target is an error, never an automatic reassignment.",
|
||||
"render.scene_all_shots": "모든 샷 ({count})",
|
||||
"render.scene_batch_reason": "모든 샷에는 아직 지원되지 않는 저장된 샷 렌더링 대기열이 필요합니다.",
|
||||
"render.scene_check_now": "지금 검사",
|
||||
"render.scene_check_passed": "검사 통과 · 참고 {notes}개",
|
||||
"render.scene_check_stale": "검사가 오래됨 · 다시 검사",
|
||||
"render.scene_check_unchecked": "아직 검사하지 않음 · 참고 0개",
|
||||
"render.scene_light_summary": "{environment} · 조명 {lights}개",
|
||||
"render.scene_look_summary": "외관 {looks}개 · 재정의 {overrides}개",
|
||||
"render.scene_open_check": "검사 열기",
|
||||
"render.scene_ready": "렌더링 준비",
|
||||
"render.scene_reminder": "장면은 설계를 보존합니다. 렌더링에서 형상, 엔지니어링 속성 및 CAD는 변경되지 않습니다.",
|
||||
"render.scene_reminders": "알림",
|
||||
"render.scene_renderer_ready": "{renderer} 준비됨",
|
||||
"render.scene_stages": "단계",
|
||||
"render.search_appearances": "외관 {count}개 검색",
|
||||
"render.setup_name": "설정 이름",
|
||||
"render.shell_tab_appearance": "모양",
|
||||
"render.shell_tab_camera": "카메라",
|
||||
"render.shell_tab_scene": "장면",
|
||||
"render.shot_aperture": "조리개",
|
||||
"render.shot_distance": "거리",
|
||||
"render.shot_dof": "피사계 심도",
|
||||
"render.shot_edit_output": "출력에서 편집",
|
||||
"render.shot_exposure_reason": "노출에는 CPU 광선 추적 또는 GPU 경로 추적이 필요합니다.",
|
||||
"render.shot_exposure_section": "노출",
|
||||
"render.shot_focus_distance": "초점 거리",
|
||||
"render.shot_fov_reason": "시야각에는 원근 투영이 필요합니다.",
|
||||
"render.shot_frame_subject": "피사체 맞추기",
|
||||
"render.shot_invalid_camera": "카메라 값은 범위 내의 유한한 수여야 합니다.",
|
||||
"render.shot_lens": "렌즈",
|
||||
"render.shot_lens_enable_reason": "조리개와 초점 거리를 편집하려면 피사계 심도를 켜세요.",
|
||||
"render.shot_lens_gpu_reason": "피사계 심도에는 GPU 경로 추적이 필요합니다.",
|
||||
"render.shot_lens_perspective_reason": "피사계 심도에는 원근 투영이 필요합니다.",
|
||||
"render.shot_look_selection": "선택 항목 바라보기",
|
||||
"render.shot_selection_reason": "바라볼 바디나 면을 선택하세요.",
|
||||
"render.shot_size": "크기",
|
||||
"render.shot_target": "대상",
|
||||
"render.shots_camera_changed": "이 샷을 저장한 후 카메라가 변경되었습니다",
|
||||
"render.shots_name_help": "현재 샷의 고유한 이름을 입력하세요.",
|
||||
"render.shots_no_result": "렌더링 결과 없음",
|
||||
@@ -2012,11 +2401,99 @@
|
||||
"render.size_square": "정사각형",
|
||||
"render.spot_cone": "스폿 원뿔",
|
||||
"render.stage_frame": "구도",
|
||||
"render.stage_layout.appearance_note": "클릭하여 선택 항목에 적용합니다.",
|
||||
"render.stage_layout.studio_note": "클릭하여 적용 전에 검토하세요.",
|
||||
"render.stage_light": "조명",
|
||||
"render.stage_look": "외관",
|
||||
"render.stage_orthographic": "직교 투영",
|
||||
"render.stage_output": "출력",
|
||||
"render.stage_panel_count": "Saved panels",
|
||||
"render.stage_panels.acknowledge": "교체 내용과 제한 사항을 확인했습니다",
|
||||
"render.stage_panels.appearance_note": "클릭하여 선택 항목에 적용합니다. 모델로 끌어 놓으세요. 선택 항목이 없으면 클릭하여 페인트를 시작합니다.",
|
||||
"render.stage_panels.apply": "적용",
|
||||
"render.stage_panels.apply_studio": "스튜디오 적용",
|
||||
"render.stage_panels.badge_blocked": "차단됨",
|
||||
"render.stage_panels.badge_native": "네이티브",
|
||||
"render.stage_panels.badge_projection": "투영",
|
||||
"render.stage_panels.badge_reference": "참조",
|
||||
"render.stage_panels.badge_specification": "사양만",
|
||||
"render.stage_panels.candidate_summary": "후보: 출처가 있는 값 {count}개. 등급과 마감 검토가 필요합니다.",
|
||||
"render.stage_panels.captured_bounds": "캡처한 장면 경계 사용",
|
||||
"render.stage_panels.centre": "중심",
|
||||
"render.stage_panels.depth": "깊이",
|
||||
"render.stage_panels.environments": "환경",
|
||||
"render.stage_panels.extent": "크기",
|
||||
"render.stage_panels.fit_save": "맞춤 및 저장",
|
||||
"render.stage_panels.gpu_required": "GPU 경로 추적 필요",
|
||||
"render.stage_panels.keep": "유지",
|
||||
"render.stage_panels.kept": "유지",
|
||||
"render.stage_panels.kept_fields": "카메라, 샘플링, 이미지 크기, 광학 바인딩, CAD 형상 및 공학 속성.",
|
||||
"render.stage_panels.kept_quality": "방식, 카메라, 조명, 환경, 스테이지, 광학 설정, 노출 및 톤 매핑.",
|
||||
"render.stage_panels.mine": "내 항목",
|
||||
"render.stage_panels.mine_pending": "개인 스튜디오 저장은 아직 지원되지 않습니다.",
|
||||
"render.stage_panels.omits": "생략",
|
||||
"render.stage_panels.paint_pending": "페인트 및 끌어서 할당은 아직 지원되지 않습니다. 외관을 적용할 대상을 선택하세요.",
|
||||
"render.stage_panels.partial_reference": "후보: 출처가 있는 값만 포함합니다. 등급, 상태 및 출처를 검토하세요. 알 수 없는 값은 그대로 유지됩니다.",
|
||||
"render.stage_panels.plane": "평면",
|
||||
"render.stage_panels.prepare_plan": "생성 계획 준비",
|
||||
"render.stage_panels.projects": "투영",
|
||||
"render.stage_panels.quality_ack": "고정 예산과 생략 사항을 확인했습니다",
|
||||
"render.stage_panels.quality_omissions": "적응형 중지 및 오차 목표, 별도 투과 깊이, 러시안 룰렛 규칙, 원시 선형 출력, EXR 마스터 및 수렴 인증.",
|
||||
"render.stage_panels.reference": "참조",
|
||||
"render.stage_panels.references": "참조",
|
||||
"render.stage_panels.remove_optics": "광학 설정 제거",
|
||||
"render.stage_panels.remove_optics_help": "이 샷에 저장된 광학 설정을 제거합니다. 원본 형상은 유지됩니다.",
|
||||
"render.stage_panels.remove_optics_title": "저장된 광학 설정을 제거할까요?",
|
||||
"render.stage_panels.remove_shot": "샷 제거",
|
||||
"render.stage_panels.remove_stage": "스테이지 제거",
|
||||
"render.stage_panels.remove_stage_help": "이 샷에 저장된 수동 패널을 제거합니다. 카메라 배경은 유지됩니다.",
|
||||
"render.stage_panels.remove_stage_title": "저장된 스테이지를 제거할까요?",
|
||||
"render.stage_panels.repeat": "반복",
|
||||
"render.stage_panels.replaces": "교체",
|
||||
"render.stage_panels.replaces_environment": "환경",
|
||||
"render.stage_panels.replaces_maps": "선택한 바디의 임시 맵. 저장된 광학 설정과 충돌할 수 있습니다.",
|
||||
"render.stage_panels.replaces_physical": "없음. 이 계획은 읽기 전용입니다.",
|
||||
"render.stage_panels.replaces_quality": "이미지 크기, 고정 샘플 수, 경로 깊이, 시드 및 노이즈 제거.",
|
||||
"render.stage_panels.replaces_rig": "조명, 환경 및 스테이지",
|
||||
"render.stage_panels.replaces_saved_maps": "선택한 바디에 저장된 표면 맵. 임시 설정과 충돌할 수 있습니다.",
|
||||
"render.stage_panels.replaces_stage": "저장된 바닥 및 수동 스테이지 패널",
|
||||
"render.stage_panels.replaces_studio": "조명, 환경, 노출 및 스테이지",
|
||||
"render.stage_panels.replaces_uniform": "선택한 바디의 불투명 외관. 공간 맵은 균일한 값으로 근사합니다.",
|
||||
"render.stage_panels.review_environment": "환경 검토",
|
||||
"render.stage_panels.review_maps": "GPU 맵 검토",
|
||||
"render.stage_panels.review_physical": "물리 참조 계획",
|
||||
"render.stage_panels.review_quality": "고정 샘플링 예산 사용",
|
||||
"render.stage_panels.review_rig": "조명 리그 맞춤",
|
||||
"render.stage_panels.review_saved_maps": "저장된 맵 검토",
|
||||
"render.stage_panels.review_stage": "바닥 및 스테이지 검토",
|
||||
"render.stage_panels.review_studio": "네이티브 스튜디오 검토",
|
||||
"render.stage_panels.review_uniform": "균일한 외관 검토",
|
||||
"render.stage_panels.rig_summary": "제작된 조명 리그 · 광원 {emitters}개, 카드 {cards}개",
|
||||
"render.stage_panels.rigs": "리그",
|
||||
"render.stage_panels.save_maps": "이 샷에 맵 저장",
|
||||
"render.stage_panels.scope": "범위",
|
||||
"render.stage_panels.search_studios": "스튜디오 검색",
|
||||
"render.stage_panels.search_surfaces": "표면 및 참조 검색",
|
||||
"render.stage_panels.source_note": "제작된 기본 색상 소스 맵. 측정된 재질이 아닙니다.",
|
||||
"render.stage_panels.specifications": "사양 · 읽기 전용",
|
||||
"render.stage_panels.studio_ack": "조명, 환경, 노출 및 스테이지 교체 확인",
|
||||
"render.stage_panels.studio_note": "클릭하여 검토하세요. 확인 후에만 조명, 환경 및 스테이지를 교체합니다. 조명은 계속 편집할 수 있습니다.",
|
||||
"render.stage_panels.studios": "스튜디오",
|
||||
"render.stage_panels.subtitle_environment": "원본 HDR 환경 · 전체 장면",
|
||||
"render.stage_panels.subtitle_maps": "제작된 공간 맵 · 임시 미리 보기",
|
||||
"render.stage_panels.subtitle_physical": "읽기 전용 계획 · 재질 생성 또는 할당 없음",
|
||||
"render.stage_panels.subtitle_quality": "고정 GPU 예산 · 향후 요구 사항 생략",
|
||||
"render.stage_panels.subtitle_rig": "제작된 조명 리그 · 광원 및 수동 카드",
|
||||
"render.stage_panels.subtitle_saved_maps": "제작된 맵 · 이 샷에 저장",
|
||||
"render.stage_panels.subtitle_stage": "물리적 바닥 및 스테이지 · 제품에 맞춤",
|
||||
"render.stage_panels.subtitle_studio": "네이티브 스튜디오 · 전체 장면에 적용",
|
||||
"render.stage_panels.subtitle_uniform": "균일한 근사 · 측정된 재질이 아님",
|
||||
"render.stage_panels.surfaces": "표면",
|
||||
"render.stage_panels.surfaces_references": "표면 및 참조",
|
||||
"render.stage_panels.target": "대상",
|
||||
"render.stage_panels.use_budget": "이 예산 사용",
|
||||
"render.stage_panels.use_maps": "GPU 맵 사용",
|
||||
"render.stage_panels.use_uniform": "균일한 외관 사용",
|
||||
"render.stage_preview_note": "통합 미리 보기 · 직접광",
|
||||
"render.state_completed": "완료된 이미지",
|
||||
"render.state_in_progress": "이미지 생성 중",
|
||||
@@ -2070,6 +2547,13 @@
|
||||
"render.wait_pick_up": "아직 지원되지 않음: 제품 선택 및 모양 샘플링",
|
||||
"render.wait_replace": "아직 지원되지 않음: 모양이 사용된 모든 곳 바꾸기",
|
||||
"render.wait_solo": "아직 지원되지 않음: 조명 표시 및 단독 표시 제어",
|
||||
"render.wear_applies_to": "적용 대상",
|
||||
"render.wear_layer_count": "레이어 {count}개",
|
||||
"render.wear_layer_one": "레이어 {count}개",
|
||||
"render.wear_layers": "레이어",
|
||||
"render.wear_no_layers": "레이어 없음",
|
||||
"render.wear_selected_layer": "선택한 레이어",
|
||||
"render.wear_title": "마모",
|
||||
"sample.bracket.about": "2 mm 판금 규칙을 적용한 베이스 플랜지, 에지 플랜지, 헴",
|
||||
"sample.bracket.name": "판금 브래킷",
|
||||
"sample.enclosure.about": "리프, 나사 보스, 레스트, 스냅핏이 있는 쉘 처리된 박스",
|
||||
@@ -2118,6 +2602,7 @@
|
||||
"settings.display_quality_note": "세밀할수록 곡면과 모서리가 더 매끄럽게 표시되지만 메시 생성 시간이 늘어납니다. 뷰포트만 바뀌며 설계나 내보내기는 바뀌지 않습니다.",
|
||||
"settings.double_click_components": "구성 요소를 두 번 클릭하여 활성화하거나 연결된 구성 요소를 제자리에서 편집",
|
||||
"settings.frame_rate_note": "뷰의 오른쪽 아래에 초당 프레임 수를 표시합니다.",
|
||||
"settings.insert_lists_open_designs": "설계 삽입에서 다른 탭에 열린 설계를 먼저 표시",
|
||||
"settings.measure_axis_distances": "X/Y/Z 거리 표시",
|
||||
"settings.measure_axis_distances_help": "측정 대화상자가 열려 있는 동안 전체 거리와 함께 월드 축 방향 치수와 거리를 표시합니다.",
|
||||
"settings.msaa_applies_on_restart": "안티앨리어싱은 다음에 SolidCraft를 시작할 때 적용됩니다",
|
||||
@@ -2137,6 +2622,10 @@
|
||||
"shortcut.unpin": "고정 해제",
|
||||
"sketch is missing": "스케치가 없습니다",
|
||||
"sketch.degrees_of_freedom": "자유도 {count}개",
|
||||
"sketch.dimension_added_driven": "스케치가 이미 이 치수를 결정하므로 종속(참조) 치수로 추가했습니다",
|
||||
"sketch.dimension_applied": "치수를 적용했습니다",
|
||||
"sketch.dimension_applied_defined": "치수를 적용했습니다. 매개변수 `{name}`을(를) 정의했습니다",
|
||||
"sketch.dimension_applied_renamed": "치수를 적용했습니다. 매개변수 이름을 `{name}`(으)로 지정했습니다",
|
||||
"sketch.dof_left": "남은 자유도 {count}개",
|
||||
"sketch.dof_left_one": "남은 자유도 {count}개",
|
||||
"sketch.draw_curves": "{linetype}(으)로 그리기",
|
||||
@@ -2271,6 +2760,10 @@
|
||||
"ui.3d_mouse_offer": "3D 마우스를 보정하면 바뀌거나 반전된 축이 바로잡히고 속도와 조작감이 맞춰집니다.",
|
||||
"ui.3d_mouse_offer_never": "다시 표시하지 않음",
|
||||
"ui.3d_mouse_offer_swap": "Hidraw(직접 드라이버)로 전환",
|
||||
"ui.3d_mouse_orbit": "궤도 회전",
|
||||
"ui.3d_mouse_orbit_classic": "클래식",
|
||||
"ui.3d_mouse_orbit_tip": "추적: 회전을 시작할 때 뷰 가운데에 있는 모델 부분을 중심으로 3D 마우스가 뷰를 회전하며, 그 점을 희미한 구로 표시합니다. 클래식: 뷰의 중심을 기준으로",
|
||||
"ui.3d_mouse_orbit_traced": "추적",
|
||||
"ui.3d_mouse_reading": "읽은 값",
|
||||
"ui.3d_mouse_reset_axes": "축 지정 초기화",
|
||||
"ui.3d_mouse_reset_view": "뷰 초기화",
|
||||
@@ -2604,6 +3097,15 @@
|
||||
"ui.constant": "상수",
|
||||
"ui.constraints_conflict": "구속 조건 충돌",
|
||||
"ui.construction": "구성선",
|
||||
"ui.construction.angle_hint": "보조 직선: 점 클릭 후 각도 입력 또는 방향 선택",
|
||||
"ui.construction.bisector_hint": "이등분선: 교차하는 두 직선 선택 후 원하는 해 선택",
|
||||
"ui.construction.common_hint": "공통 접선: 두 원/원호 선택 후 원하는 해 선택",
|
||||
"ui.construction.contact_hint": "접선: 원/원호 또는 열린 스플라인/원뿔 곡선 선택 후 접점 선택 (자유 곡선은 끝점만)",
|
||||
"ui.construction.external_hint": "접선: 원 또는 원호, 외부 점, 원하는 해를 차례로 선택",
|
||||
"ui.construction.free_hint": "보조 직선: 두 점 클릭; 마우스 오른쪽 버튼으로 다시 시작",
|
||||
"ui.construction.point_hint": "보조 직선: 통과할 점 클릭",
|
||||
"ui.construction.reference_hint": "보조 직선: 직선 선택 후 점 선택; 마우스 오른쪽 버튼으로 참조 변경",
|
||||
"ui.construction.ribbon_label": "보조선",
|
||||
"ui.context_menu": "컨텍스트 메뉴",
|
||||
"ui.continuity_g0": "G0 꺾임",
|
||||
"ui.continuity_g1": "G1 접선",
|
||||
@@ -2692,6 +3194,14 @@
|
||||
"ui.end_scale": "끝 배율",
|
||||
"ui.entities": "요소",
|
||||
"ui.equal": "동일",
|
||||
"ui.equation_end": "끝",
|
||||
"ui.equation_explicit": "명시적",
|
||||
"ui.equation_form": "형식",
|
||||
"ui.equation_note": "변수는 단위가 없는 수입니다. sin(t)는 라디안으로 읽습니다. 단위가 없는 결과는 디자인 단위입니다.",
|
||||
"ui.equation_parametric": "매개변수식",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "등가 반지름",
|
||||
"ui.expand": "펼치기",
|
||||
"ui.exportDxf": "DXF 내보내기…",
|
||||
@@ -2750,6 +3260,7 @@
|
||||
"ui.heading_design": "디자인",
|
||||
"ui.heading_draft": "구배",
|
||||
"ui.heading_edit": "편집",
|
||||
"ui.heading_equation_curve": "방정식 곡선",
|
||||
"ui.heading_extrude": "돌출",
|
||||
"ui.heading_fillet": "필렛",
|
||||
"ui.heading_finish_editing": "편집 완료",
|
||||
@@ -2821,6 +3332,10 @@
|
||||
"ui.history_marker_tip": "이력 마커: 드래그하여 모델을 되돌립니다. 새 피처는 여기에 추가됩니다",
|
||||
"ui.history_names": "이름",
|
||||
"ui.history_play": "끝까지 재생",
|
||||
"ui.history_play_button_hide": "재생 버튼 숨기기",
|
||||
"ui.history_play_button_show": "재생 버튼 표시",
|
||||
"ui.history_play_finish_action": "기록을 재생하기 전에 현재 작업을 완료하세요",
|
||||
"ui.history_play_roll_back": "재생하기 전에 기록 마커를 이전 단계로 이동하세요",
|
||||
"ui.history_show_names": "이름 표시",
|
||||
"ui.history_title": "기록",
|
||||
"ui.history_toggle_names": "피처 이름 표시/숨기기",
|
||||
@@ -2833,6 +3348,10 @@
|
||||
"ui.import_ellipsis": "가져오기…",
|
||||
"ui.infinite": "무한",
|
||||
"ui.insert": "삽입",
|
||||
"ui.insert_design.browse": "찾아보기…",
|
||||
"ui.insert_design.open_designs": "열린 설계",
|
||||
"ui.insert_design.saved_file": "{name}에 저장되지 않은 변경 사항이 있어 저장된 파일을 삽입했습니다. 저장한 다음 링크 업데이트로 변경 사항을 가져오세요.",
|
||||
"ui.insert_design.unsaved": "저장되지 않은 변경 사항",
|
||||
"ui.inspect": "검사",
|
||||
"ui.intersect": "교차",
|
||||
"ui.isolate": "분리 표시",
|
||||
@@ -2923,6 +3442,7 @@
|
||||
"ui.pan_zoom_orbit": "이동, 확대/축소, 궤도 회전",
|
||||
"ui.parallel": "평행",
|
||||
"ui.parameters": "매개변수",
|
||||
"ui.part_size_needs_a_part": "크기를 바꿀 삽입된 표준 부품(나사, 너트, 와셔 또는 핀)을 선택하십시오. 바디를 키우거나 줄이려면 축척을 사용하십시오.",
|
||||
"ui.part_size_shared": "부품을 다시 빌드하며 추가된 피처는 모두 대체됩니다. 이 구성요소의 모든 인스턴스가 업데이트됩니다.",
|
||||
"ui.paste": "붙여넣기",
|
||||
"ui.path": "경로",
|
||||
@@ -2963,6 +3483,18 @@
|
||||
"ui.project": "투영",
|
||||
"ui.project_face_edges_sketch": "면 모서리를 새 스케치로 투영",
|
||||
"ui.properties": "속성",
|
||||
"ui.properties.copy_matrix": "행렬 복사",
|
||||
"ui.properties.first_moments": "1차 모멘트",
|
||||
"ui.properties.inertia": "관성 모멘트",
|
||||
"ui.properties.inertia_note": "질량 중심 기준, 월드 축 (g·{unit}²)",
|
||||
"ui.properties.inertia_unavailable": "사용할 수 없음: 바디의 메시가 닫혀 있지 않습니다.",
|
||||
"ui.properties.inertia_x": "Ixx, Ixy, Ixz",
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "측정 중…",
|
||||
"ui.properties.measuring_failed": "측정이 끝나기 전에 중단되었습니다.",
|
||||
"ui.properties.principal_axis": "주축 {number}",
|
||||
"ui.properties.principal_moments": "주관성 모멘트",
|
||||
"ui.pull_direction": "빼기 방향",
|
||||
"ui.quality": "품질",
|
||||
"ui.quantity": "수량",
|
||||
@@ -2995,6 +3527,8 @@
|
||||
"ui.restore_defaults": "기본값 복원",
|
||||
"ui.reverse_horizontal_pan_direction": "수평 이동 방향 반전",
|
||||
"ui.reverse_horizontal_pan_tip": "두 손가락 수평 스크롤과 엄지 휠이 반대 방향으로 이동합니다",
|
||||
"ui.reverse_trackpad_orbit_direction": "트랙패드 회전 방향 반전",
|
||||
"ui.reverse_trackpad_orbit_tip": "Shift를 누른 채 두 손가락으로 스크롤하면 반대 방향으로 회전합니다",
|
||||
"ui.reverse_vertical_pan_direction": "수직 이동 방향 반전",
|
||||
"ui.reverse_vertical_pan_tip": "두 손가락 수직 스크롤이 반대 방향으로 이동합니다",
|
||||
"ui.reverse_zoom_direction": "확대/축소 방향 반전",
|
||||
@@ -3018,6 +3552,7 @@
|
||||
"ui.select": "선택",
|
||||
"ui.selectOther": "기타 선택…",
|
||||
"ui.selectTangentChain": "접선 체인 선택",
|
||||
"ui.select_all": "모두 선택",
|
||||
"ui.selection": "선택",
|
||||
"ui.selection_modifiers": "선택 보조 키",
|
||||
"ui.selection_shift_add_only": "Shift+클릭은 추가만 함",
|
||||
@@ -3050,7 +3585,11 @@
|
||||
"ui.sketch": "스케치",
|
||||
"ui.sketch_dimension": "스케치 치수",
|
||||
"ui.sketch_grid": "스케치 격자",
|
||||
"ui.sketch_intersect_geometry": "형상",
|
||||
"ui.sketch_intersect_projection_link": "투영 링크",
|
||||
"ui.sketch_intersect_selection_filter": "선택 필터",
|
||||
"ui.sketch_modifiers": "스케치 보조 키",
|
||||
"ui.sketch_project_geometry": "형상",
|
||||
"ui.sketch_scale": "스케치 축척",
|
||||
"ui.sketches": "스케치",
|
||||
"ui.slice": "슬라이스",
|
||||
@@ -3086,6 +3625,11 @@
|
||||
"ui.symmetric": "대칭",
|
||||
"ui.symmetry": "대칭",
|
||||
"ui.system": "시스템",
|
||||
"ui.tab_assemble": "조립",
|
||||
"ui.tab_manage": "관리",
|
||||
"ui.tab_sheet_metal": "판금",
|
||||
"ui.tab_view": "보기",
|
||||
"ui.tab_weldments": "용접 구조물",
|
||||
"ui.tangent": "접선",
|
||||
"ui.taper_angle": "테이퍼 각도",
|
||||
"ui.tapped": "탭",
|
||||
@@ -3101,6 +3645,7 @@
|
||||
"ui.tip_angle": "선단 각도",
|
||||
"ui.to_object": "객체까지",
|
||||
"ui.tool_direction": "공구 방향",
|
||||
"ui.toolbar_tabs_hidden": "모든 도구 모음 탭이 숨겨져 있습니다. +를 클릭하거나 여기를 마우스 오른쪽 버튼으로 클릭하여 표시하세요.",
|
||||
"ui.top": "상면",
|
||||
"ui.top_diameter": "윗면 지름",
|
||||
"ui.top_radius": "윗면 반지름",
|
||||
@@ -3134,6 +3679,12 @@
|
||||
"ui.view_angles_roll": "롤",
|
||||
"ui.view_angles_yaw": "요",
|
||||
"ui.view_centre": "뷰 중심",
|
||||
"ui.viewport_status_clear": "{name} 끄기",
|
||||
"ui.viewport_status_clear_hint": "{name} 끄기 · Esc",
|
||||
"ui.viewport_status_key": "{name} 범례 표시",
|
||||
"ui.viewport_status_minimum_radius": "최소 반지름",
|
||||
"ui.viewport_status_pairs": "{count}쌍",
|
||||
"ui.viewport_status_stripes": "줄무늬 {count}개",
|
||||
"ui.viewport_theme_follow": "테마 따르기",
|
||||
"ui.visual_shaded_hidden_edges": "음영 처리 및 숨겨진 모서리",
|
||||
"ui.visual_shaded_with_edges": "음영 처리 및 모서리",
|
||||
@@ -3186,6 +3737,9 @@
|
||||
"update.prefs_label": "업데이트",
|
||||
"update.prefs_note": "SolidCraft {version} ({kind})입니다. 확인 시 GitHub에 최신 릴리스만 요청하며 다른 정보는 보내지 않습니다.",
|
||||
"update.prefs_web": "페이지를 새로고침하면 최신 웹 앱을 가져옵니다. 네트워크를 사용할 수 없거나 업데이트 다운로드가 제한 시간 안에 완료되지 않으면 저장된 버전이 열립니다. 진행 중인 다운로드는 다음 새로고침을 위해 계속됩니다.",
|
||||
"update.refresh_checking": "최신 릴리스 확인 중…",
|
||||
"update.refresh_fallback": "새 릴리스를 확인하지 못했습니다. 이전에 찾은 {version}(으)로 업데이트합니다.",
|
||||
"update.refresh_selected": "{version}(으)로 업데이트 중.",
|
||||
"update.release_page": "릴리스 페이지 열기",
|
||||
"update.restart": "지금 다시 시작",
|
||||
"update.restart_later": "나중에",
|
||||
|
||||
@@ -709,6 +709,16 @@
|
||||
"cmd.sheet_refold": "Zegnij ponownie",
|
||||
"cmd.sheet_rules": "Lista reguł blach",
|
||||
"cmd.sheet_unfold": "Rozegnij",
|
||||
"cmd.sketch.construction_line": "Prosta konstrukcyjna",
|
||||
"cmd.sketch.construction_line.angle": "Prosta konstrukcyjna pod kątem",
|
||||
"cmd.sketch.construction_line.bisector": "Dwusieczna kąta",
|
||||
"cmd.sketch.construction_line.horizontal": "Pozioma prosta konstrukcyjna",
|
||||
"cmd.sketch.construction_line.parallel": "Równoległa prosta konstrukcyjna",
|
||||
"cmd.sketch.construction_line.perpendicular": "Prostopadła prosta konstrukcyjna",
|
||||
"cmd.sketch.construction_line.tangent_at": "Styczna w punkcie krzywej",
|
||||
"cmd.sketch.construction_line.tangent_external": "Styczna przez punkt zewnętrzny",
|
||||
"cmd.sketch.construction_line.tangent_two": "Wspólna styczna",
|
||||
"cmd.sketch.construction_line.vertical": "Pionowa prosta konstrukcyjna",
|
||||
"cmd.sketch_arc_center_point": "Łuk ze środka",
|
||||
"cmd.sketch_arc_tangent": "Łuk styczny",
|
||||
"cmd.sketch_arc_three_point": "Łuk przez 3 punkty",
|
||||
@@ -1300,6 +1310,10 @@
|
||||
"shortcut.pin": "Przypnij na górze pola S",
|
||||
"shortcut.unpin": "Odepnij",
|
||||
"sketch.degrees_of_freedom": "Stopnie swobody: {count}",
|
||||
"sketch.dimension_added_driven": "Szkic już określa ten wymiar, więc dodano go jako wymiar sterowany (referencyjny)",
|
||||
"sketch.dimension_applied": "Wymiar zastosowany",
|
||||
"sketch.dimension_applied_defined": "Wymiar zastosowany; zdefiniowano parametr `{name}`",
|
||||
"sketch.dimension_applied_renamed": "Wymiar zastosowany; parametr nazywa się teraz `{name}`",
|
||||
"sketch.dof_left": "Pozostałe stopnie swobody: {count}",
|
||||
"sketch.dof_left_one": "Pozostał {count} stopień swobody",
|
||||
"sketch.draw_curves": "Rysuj jako {linetype}",
|
||||
@@ -1735,6 +1749,7 @@
|
||||
"ui.constant": "Stały",
|
||||
"ui.constraints_conflict": "Konflikt wiązań",
|
||||
"ui.construction": "Konstrukcyjne",
|
||||
"ui.construction.ribbon_label": "Linie pom.",
|
||||
"ui.context_menu": "Menu kontekstowe",
|
||||
"ui.continuity_g0": "G0 załamanie",
|
||||
"ui.continuity_g1": "G1 styczność",
|
||||
@@ -2030,6 +2045,7 @@
|
||||
"ui.pan_zoom_orbit": "Przesuwanie, powiększanie, obracanie",
|
||||
"ui.parallel": "Równoległość",
|
||||
"ui.parameters": "Parametry",
|
||||
"ui.part_size_needs_a_part": "Zaznacz wstawioną część znormalizowaną (śrubę, nakrętkę, podkładkę lub kołek), aby zmienić jej rozmiar. Aby powiększyć lub pomniejszyć bryłę, użyj polecenia Skala.",
|
||||
"ui.part_size_shared": "Przebudowuje część, zastępując wszystkie dodane elementy. Wszystkie wystąpienia tego komponentu zostaną zaktualizowane.",
|
||||
"ui.paste": "Wklej",
|
||||
"ui.path": "Ścieżka",
|
||||
@@ -2113,6 +2129,7 @@
|
||||
"ui.select": "Zaznacz",
|
||||
"ui.selectOther": "Wybierz inny…",
|
||||
"ui.selectTangentChain": "Zaznacz łańcuch styczny",
|
||||
"ui.select_all": "Zaznacz wszystko",
|
||||
"ui.selection": "Zaznaczenie",
|
||||
"ui.selection_modifiers": "Modyfikatory zaznaczania",
|
||||
"ui.selection_shift_add_only": "Shift+kliknięcie tylko dodaje",
|
||||
@@ -2174,6 +2191,10 @@
|
||||
"ui.symmetric": "Symetrycznie",
|
||||
"ui.symmetry": "Symetria",
|
||||
"ui.system": "Systemowy",
|
||||
"ui.tab_assemble": "Złożenie",
|
||||
"ui.tab_manage": "Zarządzanie",
|
||||
"ui.tab_sheet_metal": "Blacha",
|
||||
"ui.tab_view": "Widok",
|
||||
"ui.tangent": "Styczność",
|
||||
"ui.taper_angle": "Kąt pochylenia",
|
||||
"ui.tapped": "Gwintowany",
|
||||
|
||||
@@ -815,6 +815,16 @@
|
||||
"cmd.sheet_refold": "Redobrar",
|
||||
"cmd.sheet_rules": "Listar regras de chapa metálica",
|
||||
"cmd.sheet_unfold": "Desdobrar",
|
||||
"cmd.sketch.construction_line": "Reta de construção",
|
||||
"cmd.sketch.construction_line.angle": "Reta de construção em ângulo",
|
||||
"cmd.sketch.construction_line.bisector": "Bissetriz",
|
||||
"cmd.sketch.construction_line.horizontal": "Reta de construção horizontal",
|
||||
"cmd.sketch.construction_line.parallel": "Reta de construção paralela",
|
||||
"cmd.sketch.construction_line.perpendicular": "Reta de construção perpendicular",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tangente em um ponto da curva",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangente por um ponto externo",
|
||||
"cmd.sketch.construction_line.tangent_two": "Tangente comum",
|
||||
"cmd.sketch.construction_line.vertical": "Reta de construção vertical",
|
||||
"cmd.sketch_arc_center_point": "Arco por ponto central",
|
||||
"cmd.sketch_arc_tangent": "Arco tangente",
|
||||
"cmd.sketch_arc_three_point": "Arco por 3 pontos",
|
||||
@@ -1864,6 +1874,7 @@
|
||||
"ui.constant": "Constante",
|
||||
"ui.constraints_conflict": "Restrições em conflito",
|
||||
"ui.construction": "Construção",
|
||||
"ui.construction.ribbon_label": "Linhas aux.",
|
||||
"ui.context_menu": "Menu de contexto",
|
||||
"ui.continuity_g0": "G0 vinco",
|
||||
"ui.continuity_g1": "G1 tangente",
|
||||
@@ -2161,6 +2172,7 @@
|
||||
"ui.pan_zoom_orbit": "Deslocar, zoom, orbitar",
|
||||
"ui.parallel": "Paralelo",
|
||||
"ui.parameters": "Parâmetros",
|
||||
"ui.part_size_needs_a_part": "Selecione uma peça padrão inserida (um parafuso, uma porca, uma arruela ou um pino) para alterar o tamanho. Para aumentar ou diminuir um corpo, use Escala.",
|
||||
"ui.part_size_shared": "Reconstrói a peça, substituindo quaisquer recursos adicionados. Todas as ocorrências deste componente são atualizadas.",
|
||||
"ui.paste": "Colar",
|
||||
"ui.path": "Caminho",
|
||||
@@ -2243,6 +2255,7 @@
|
||||
"ui.select": "Selecionar",
|
||||
"ui.selectOther": "Selecionar outro…",
|
||||
"ui.selectTangentChain": "Selecionar cadeia tangente",
|
||||
"ui.select_all": "Selecionar tudo",
|
||||
"ui.selection": "Seleção",
|
||||
"ui.selection_modifiers": "Modificadores de seleção",
|
||||
"ui.selection_shift_add_only": "Shift+clique adiciona sem remover",
|
||||
@@ -2304,6 +2317,10 @@
|
||||
"ui.symmetric": "Simétrico",
|
||||
"ui.symmetry": "Simetria",
|
||||
"ui.system": "Sistema",
|
||||
"ui.tab_assemble": "Montar",
|
||||
"ui.tab_manage": "Gerenciar",
|
||||
"ui.tab_sheet_metal": "Chapa Metálica",
|
||||
"ui.tab_view": "Vista",
|
||||
"ui.tangent": "Tangente",
|
||||
"ui.taper_angle": "Ângulo de inclinação",
|
||||
"ui.tapped": "Roscado",
|
||||
|
||||
@@ -7,7 +7,7 @@ pub const DEFAULT_MATERIAL: &str = "Default";
|
||||
pub const DEFAULT_DENSITY: f64 = 1.29;
|
||||
|
||||
/// Physical materials: name and density (g/cm³).
|
||||
pub const MATERIALS: [(&str, f64); 14] = [
|
||||
pub const MATERIALS: &[(&str, f64)] = &[
|
||||
(DEFAULT_MATERIAL, DEFAULT_DENSITY),
|
||||
("Steel", 7.85),
|
||||
("Stainless Steel", 8.0),
|
||||
|
||||
@@ -18,6 +18,8 @@ struct U {
|
||||
depth: vec4<f32>, // x = 1: reversed depth (1 near, 0 far); y, z: the faces' push (`FACE_BIAS`)
|
||||
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
|
||||
product_lights_meta: vec4<f32>, // explicit preview flag and bounded count
|
||||
product_lights: array<vec4<f32>,84>, // position/kind, radiance, axis/cone, attenuation
|
||||
};
|
||||
|
||||
fn reversed() -> bool {
|
||||
@@ -471,6 +473,36 @@ fn shade(i: TOut) -> vec4<f32> {
|
||||
return lit(i, 1.0);
|
||||
}
|
||||
|
||||
fn product_light_unit(v: vec3<f32>) -> vec3<f32> {
|
||||
let scale=max(max(abs(v.x),abs(v.y)),abs(v.z));
|
||||
if scale == 0.0 { return vec3<f32>(0.0,0.0,1.0); }
|
||||
return normalize(v/scale);
|
||||
}
|
||||
|
||||
// Direction and incident radiance for an unshadowed analytic preview sample.
|
||||
fn product_light_sample(k: u32, p: vec3<f32>) -> mat2x3<f32> {
|
||||
let source=u.product_lights[k*4u];
|
||||
let colour=u.product_lights[k*4u+1u];
|
||||
let axis=u.product_lights[k*4u+2u];
|
||||
let falloff=u.product_lights[k*4u+3u];
|
||||
var direction=product_light_unit(source.xyz);
|
||||
var weight=1.0;
|
||||
if source.w > 0.5 {
|
||||
let delta=source.xyz-p;
|
||||
let distance=max(length(delta),falloff.y);
|
||||
direction=product_light_unit(delta);
|
||||
weight=falloff.x/max(distance*distance,0.000001);
|
||||
if source.w == 2.0 {
|
||||
let cosine=dot(product_light_unit(axis.xyz),-direction);
|
||||
var cone=select(0.0,1.0,cosine>=colour.w);
|
||||
if axis.w-colour.w>0.000001 {cone=smoothstep(colour.w,axis.w,cosine);}
|
||||
weight *= cone;
|
||||
}
|
||||
if source.w == 3.0 {weight *= max(dot(product_light_unit(axis.xyz),-direction),0.0);}
|
||||
}
|
||||
return mat2x3<f32>(direction,colour.xyz*weight);
|
||||
}
|
||||
|
||||
fn lit(i: TOut, visibility: f32) -> vec4<f32> {
|
||||
return lit_color(i, visibility, i.c);
|
||||
}
|
||||
@@ -485,6 +517,17 @@ fn lit_color(i: TOut, visibility: f32, base: vec4<f32>) -> vec4<f32> {
|
||||
let v = normalize(u.back.xyz);
|
||||
var n = normalize(i.n);
|
||||
if (dot(n, v) < 0.0) { n = -n; }
|
||||
if u.product_lights_meta.x>0.0 {
|
||||
var radiance=vec3<f32>(0.0);
|
||||
for (var k=0u;k<min(u32(u.product_lights_meta.y),21u);k+=1u) {
|
||||
if u.product_lights[k*4u].w == 4.0 {radiance+=to_linear(base.rgb)*u.product_lights[k*4u+1u].xyz/3.141592653589793;continue;}
|
||||
let sample=product_light_sample(k,i.wp);
|
||||
radiance+=to_linear(base.rgb)*sample[1]*(max(dot(n,sample[0]),0.0)/3.141592653589793);
|
||||
}
|
||||
let mapped=radiance/(vec3<f32>(1.0)+radiance);
|
||||
let encoded=select(mapped*12.92,1.055*pow(mapped,vec3<f32>(1.0/2.4))-vec3<f32>(0.055),mapped>vec3<f32>(0.0031308));
|
||||
return out_color(vec4<f32>(encoded,base.a));
|
||||
}
|
||||
let key = normalize(v * 0.8 + vec3<f32>(-0.3, 0.2, 0.6));
|
||||
let diff = max(dot(n, key), 0.0);
|
||||
let fill = max(dot(n, v), 0.0);
|
||||
|
||||
@@ -175,6 +175,8 @@ impl Tokens {
|
||||
body: Color32::from_rgb(176, 186, 198),
|
||||
body_edge: Color32::from_rgb(40, 44, 52),
|
||||
manipulator: Color32::from_rgb(40, 110, 220),
|
||||
joint_manipulator: Color32::from_rgb(235, 157, 0),
|
||||
joint_axis: Color32::from_rgb(0, 95, 110),
|
||||
preview_add: Color32::from_rgb(112, 160, 226),
|
||||
preview_new: Color32::from_rgb(240, 225, 105),
|
||||
preview_sketch: Color32::from_rgb(32, 190, 96),
|
||||
@@ -193,6 +195,8 @@ impl Tokens {
|
||||
sketch_halo: Color32::from_rgb(240, 243, 247),
|
||||
sketch_point: Color32::BLACK,
|
||||
sketch_locked: Color32::from_rgb(0, 140, 60),
|
||||
// The error red (`error`).
|
||||
sketch_conflict: Color32::from_rgb(214, 54, 54),
|
||||
// Sketch dimensions in a plum of their own, apart from the blue and black curves for
|
||||
// every colour vision mode (#7861).
|
||||
dimension: Color32::from_rgb(130, 42, 110),
|
||||
@@ -343,12 +347,14 @@ impl Tokens {
|
||||
t.selected_bg = Color32::from_rgb(42, 70, 110);
|
||||
t.construction_geom = icon_primary(crate::icon_svg::CONSTRUCTION_PRIMARY[1]);
|
||||
t.error = Color32::from_rgb(240, 100, 96);
|
||||
t.sketch_conflict = t.error;
|
||||
t.warning = Color32::from_rgb(236, 170, 70);
|
||||
t.icon = Color32::from_rgb(208, 214, 226);
|
||||
t.timeline = Color32::from_rgb(33, 37, 45);
|
||||
t.hover = Color32::from_rgb(54, 61, 74);
|
||||
t.hover_edge_halo = Color32::from_rgb(203, 203, 203);
|
||||
t.origin_point = Color32::from_rgb(214, 215, 218);
|
||||
t.joint_axis = Color32::from_rgb(110, 240, 250);
|
||||
t.viewport_top = Color32::from_rgb(46, 52, 64);
|
||||
t.viewport_bottom = Color32::from_rgb(46, 52, 64);
|
||||
t.grid = Color32::from_rgb(59, 65, 76);
|
||||
@@ -413,6 +419,9 @@ impl Tokens {
|
||||
}
|
||||
t.construction_geom = icon_primary(crate::icon_svg::CONSTRUCTION_RED_GREEN[dark as usize]);
|
||||
t.glyph_text = icon_primary(crate::icon_svg::CONSTRAINT_RED_GREEN[dark as usize]);
|
||||
// A deeper red keeps conflicting sketch geometry (#7244) apart from the orange
|
||||
// construction and centerline lines and the crimson lost links for a red-green loss.
|
||||
t.sketch_conflict = Color32::from_rgb(195, 35, 30);
|
||||
t.surface_accent = if dark { Color32::from_rgb(200, 135, 55) } else { Color32::from_rgb(164, 80, 0) };
|
||||
t.mesh_accent = if dark { Color32::from_rgb(190, 175, 70) } else { Color32::from_rgb(130, 103, 0) };
|
||||
t.form_accent = if dark { Color32::from_rgb(165, 135, 220) } else { Color32::from_rgb(115, 73, 205) };
|
||||
@@ -443,6 +452,9 @@ impl Tokens {
|
||||
t.preview_sketch = Color32::from_rgb(125, 180, 105);
|
||||
t.glyph_text = icon_primary(crate::icon_svg::CONSTRAINT_BLUE_YELLOW[dark as usize]);
|
||||
t.construction_geom = icon_primary(crate::icon_svg::CONSTRUCTION_BLUE_YELLOW[dark as usize]);
|
||||
// Conflicting sketch geometry (#7244) apart from the lost links and the construction and
|
||||
// centerline lines for a blue-yellow loss: darker on the light view, lighter on the dark.
|
||||
t.sketch_conflict = if dark { Color32::from_rgb(255, 170, 160) } else { Color32::from_rgb(165, 15, 30) };
|
||||
if dark {
|
||||
t.sketch_locked = Color32::from_rgb(140, 225, 110);
|
||||
t.box_crossing = Color32::from_rgb(240, 110, 170);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 76,
|
||||
"provenance": "Original black-and-white palette",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#ffffff",
|
||||
@@ -91,6 +93,8 @@
|
||||
"icons.highlight": "#000000",
|
||||
"icons.marker_halo": "#000000",
|
||||
"interference": "#ffffff",
|
||||
"joint_axis": "#ffffff",
|
||||
"joint_manipulator": "#ffffff",
|
||||
"logo": [
|
||||
"#ffffff",
|
||||
"#ffffff",
|
||||
@@ -142,6 +146,7 @@
|
||||
"sketch": "#ffffff",
|
||||
"sketch_accent": "#ffffff",
|
||||
"sketch_centerline": "#ffffff",
|
||||
"sketch_conflict": "#ffffff",
|
||||
"sketch_construction": "#ffffff",
|
||||
"sketch_fixed": "#ffffff",
|
||||
"sketch_halo": "#000000",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 75,
|
||||
"provenance": "Original black-and-white palette",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"accent": "#000000",
|
||||
@@ -91,6 +93,8 @@
|
||||
"icons.highlight": "#ffffff",
|
||||
"icons.marker_halo": "#ffffff",
|
||||
"interference": "#000000",
|
||||
"joint_axis": "#000000",
|
||||
"joint_manipulator": "#000000",
|
||||
"logo": [
|
||||
"#000000",
|
||||
"#000000",
|
||||
@@ -142,6 +146,7 @@
|
||||
"sketch": "#000000",
|
||||
"sketch_accent": "#000000",
|
||||
"sketch_centerline": "#000000",
|
||||
"sketch_conflict": "#000000",
|
||||
"sketch_construction": "#000000",
|
||||
"sketch_fixed": "#000000",
|
||||
"sketch_halo": "#ffffff",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 220,
|
||||
"provenance": "Maps the Okibi design system",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"accent": "#c63a00",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 110,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#ffbc48",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 120,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#66ddff",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 200,
|
||||
"provenance": "Original SolidCraft mapping of Catppuccin (MIT palette)",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#cba6f7",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 250,
|
||||
"provenance": "Original mapping of the IBM Color Graphics Adapter palette",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#55ffff",
|
||||
@@ -91,6 +93,8 @@
|
||||
"icons.highlight": "#ffffff",
|
||||
"icons.marker_halo": "#000000cc",
|
||||
"interference": "#ff5555",
|
||||
"joint_axis": "#aaaaaa",
|
||||
"joint_manipulator": "#ffff55",
|
||||
"logo": [
|
||||
"#ffffff",
|
||||
"#55ffff",
|
||||
@@ -142,6 +146,7 @@
|
||||
"sketch": "#55ffff",
|
||||
"sketch_accent": "#ff55ff",
|
||||
"sketch_centerline": "#ffff55",
|
||||
"sketch_conflict": "#ff5555",
|
||||
"sketch_construction": "#aaaaaa",
|
||||
"sketch_fixed": "#ffffff",
|
||||
"sketch_halo": "#000000",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 240,
|
||||
"provenance": "Original warm paper and charcoal palette",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#e8845e",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 230,
|
||||
"provenance": "Original warm paper and charcoal palette",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"accent": "#bf5634",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 90,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"accent": "#007aff",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 180,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#4aa3d8",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 100,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#4dff79",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 20,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Dark Hard",
|
||||
"base": "dark",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 30,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Dark Soft",
|
||||
"base": "dark",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 10,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Dark",
|
||||
"base": "dark",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 50,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Light Hard",
|
||||
"base": "light",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 60,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Light Soft",
|
||||
"base": "light",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 40,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Light",
|
||||
"base": "light",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 170,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#00bfff",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 160,
|
||||
"provenance": "Original SolidCraft mapping of Nord (MIT palette)",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#88c0d0",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 190,
|
||||
"provenance": "Original SolidCraft mapping of Dracula (MIT palette)",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#bd93f9",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 210,
|
||||
"provenance": "Maps the Okibi design system",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#ff7c50",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 130,
|
||||
"provenance": "Original SolidCraft mapping of Atom One Dark (MIT palette)",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"accent": "#61afef",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"order": 80,
|
||||
"provenance": "Original SolidCraft theme",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"accent": "#555599",
|
||||
|
||||