Compare commits

...

33 Commits

Author SHA1 Message Date
0583eb07d5 Remove unused test code to fix console error (#6073) 2025-04-01 03:08:04 +00:00
73694563cf change TyF64 to f64 according to JsonSchema and cleanup docs code (#6081)
* cleanup gen_std

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanup docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix table

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-01 01:02:48 +00:00
bb4ed59191 Fix patterning in module to not fail when importing function from the module (#6082)
* Add failing test

* Update output to show execution error

* Fix circular pattern to not error in isolated or mock mode

* Update output after fix

* Add failing test for pattern linear 2D

* Add failing output

* Fix isolated execution in linear patterns

* Update output after linear fix
2025-03-31 23:46:29 +00:00
566143757f Fix 404 when clicking on the car wheel sample (#6079)
Fixes #6078
2025-03-31 23:09:59 +00:00
822f2ffc73 Add edit flow for Revolve point-and-click (#5951)
* WIP: Add edge and segment selection in point-and-click Helix flow
Fixes #5393

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Working edge based helix edit

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Add utility function for shared code between revolve and helix

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Use updateModelingState in codemod

* A snapshot a day keeps the bugs away! 📷🐛

* Add skip: true for edge helix to be consistent with axis as options

* A snapshot a day keeps the bugs away! 📷🐛

* Add support for sweepEdge and tests

* Lint

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Clean up snapshots

* WIP: Add edit flow for Revolve
Fixes #5504

* A snapshot a day keeps the bugs away! 📷🐛

* Clean up, add edit steps to three e2e tests

* Fix up tests after ccw change

* Use displayName: 'CounterClockWise' cause ccw not cutting it

* Fix tsc

* Remove uneeded return

* Update 2020 snapshots after helix change

* Update 2020 snapshots after helix change

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Another one :djkhaled:

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Move to fromPromise actor, fix test

* A snapshot a day keeps the bugs away! 📷🐛

* Clean up

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* Lint

* Fix third test

* A snapshot a day keeps the bugs away! 📷🐛

* Lint

* Fix edit insert order

* Fix axis, edge cases with new var, edit new var

* Add test case for new variable creation

* Clean up addRevolve with getSafeInsertIndex

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-31 22:13:34 +00:00
eb3ceba497 Minor design tweaks to log in page (#6071)
Bump subheadings, make link buttons primary colored
2025-03-31 15:33:27 -04:00
2c6d0621c9 Add test for #4236: "Fix corner rect panning bug" (#6018)
* add test for rect panning bug

* tweak timeouts

* cleanups, handle both center and corner rectangle

* revert regression that was used for the test

* apply PR feedback
2025-03-31 15:31:22 -04:00
d8e84cb5e3 Change default tolerance value to not depend on units (#6055) 2025-03-31 19:28:15 +00:00
0b1e79871f Bump the patch group across 1 directory with 16 updates (#6068)
Bumps the patch group with 16 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/commands](https://github.com/codemirror/commands) | `6.8.0` | `6.8.1` |
| [@codemirror/lint](https://github.com/codemirror/lint) | `6.8.4` | `6.8.5` |
| [@codemirror/state](https://github.com/codemirror/state) | `6.5.0` | `6.5.2` |
| [@csstools/postcss-oklab-function](https://github.com/csstools/postcss-plugins/tree/HEAD/plugins/postcss-oklab-function) | `4.0.7` | `4.0.8` |
| [@headlessui/tailwindcss](https://github.com/tailwindlabs/headlessui/tree/HEAD/packages/@headlessui-tailwindcss) | `0.2.1` | `0.2.2` |
| [@kittycad/lib](https://github.com/KittyCAD/kittycad.ts) | `2.0.21` | `2.0.23` |
| [chokidar](https://github.com/paulmillr/chokidar) | `4.0.1` | `4.0.3` |
| [electron-updater](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/electron-updater) | `6.6.0` | `6.6.2` |
| [@playwright/test](https://github.com/microsoft/playwright) | `1.51.0` | `1.51.1` |
| [@types/diff](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/diff) | `7.0.1` | `7.0.2` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.13.9` | `22.13.14` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `4.3.1` | `4.3.4` |
| [autoprefixer](https://github.com/postcss/autoprefixer) | `10.4.19` | `10.4.21` |
| [electron-builder](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/electron-builder) | `26.0.7` | `26.0.12` |
| [ws](https://github.com/websockets/ws) | `8.18.0` | `8.18.1` |
| [@types/ws](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ws) | `8.5.13` | `8.18.0` |



Updates `@codemirror/commands` from 6.8.0 to 6.8.1
- [Changelog](https://github.com/codemirror/commands/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/commands/compare/6.8.0...6.8.1)

Updates `@codemirror/lint` from 6.8.4 to 6.8.5
- [Changelog](https://github.com/codemirror/lint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lint/compare/6.8.4...6.8.5)

Updates `@codemirror/state` from 6.5.0 to 6.5.2
- [Changelog](https://github.com/codemirror/state/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/state/compare/6.5.0...6.5.2)

Updates `@csstools/postcss-oklab-function` from 4.0.7 to 4.0.8
- [Changelog](https://github.com/csstools/postcss-plugins/blob/main/plugins/postcss-oklab-function/CHANGELOG.md)
- [Commits](https://github.com/csstools/postcss-plugins/commits/HEAD/plugins/postcss-oklab-function)

Updates `@headlessui/tailwindcss` from 0.2.1 to 0.2.2
- [Release notes](https://github.com/tailwindlabs/headlessui/releases)
- [Changelog](https://github.com/tailwindlabs/headlessui/blob/main/packages/@headlessui-tailwindcss/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/headlessui/commits/@headlessui/tailwindcss@v0.2.2/packages/@headlessui-tailwindcss)

Updates `@kittycad/lib` from 2.0.21 to 2.0.23
- [Release notes](https://github.com/KittyCAD/kittycad.ts/releases)
- [Commits](https://github.com/KittyCAD/kittycad.ts/compare/v2.0.21...v2.0.23)

Updates `chokidar` from 4.0.1 to 4.0.3
- [Release notes](https://github.com/paulmillr/chokidar/releases)
- [Commits](https://github.com/paulmillr/chokidar/compare/4.0.1...4.0.3)

Updates `electron-updater` from 6.6.0 to 6.6.2
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/electron-updater/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/electron-updater@6.6.2/packages/electron-updater)

Updates `@playwright/test` from 1.51.0 to 1.51.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.51.0...v1.51.1)

Updates `@types/diff` from 7.0.1 to 7.0.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/diff)

Updates `@types/node` from 22.13.9 to 22.13.14
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitejs/plugin-react` from 4.3.1 to 4.3.4
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/v4.3.4/packages/plugin-react)

Updates `autoprefixer` from 10.4.19 to 10.4.21
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.19...10.4.21)

Updates `electron-builder` from 26.0.7 to 26.0.12
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/electron-builder/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/v26.0.12/packages/electron-builder)

Updates `ws` from 8.18.0 to 8.18.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.0...8.18.1)

Updates `@types/ws` from 8.5.13 to 8.18.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ws)

---
updated-dependencies:
- dependency-name: "@codemirror/commands"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@codemirror/lint"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@codemirror/state"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@csstools/postcss-oklab-function"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@headlessui/tailwindcss"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@kittycad/lib"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: chokidar
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: electron-updater
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@types/diff"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@vitejs/plugin-react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: autoprefixer
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: electron-builder
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: ws
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch
- dependency-name: "@types/ws"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 18:56:37 +00:00
954fddf578 Show a toast if the user tries to save their work (#6051)
* Show a toast if the user tries to save their work

And store the fact that they've seen it in localStorage so we don't spam
them every time they hit it after they see it.

* Remove any localStorage logic, toast every time
2025-03-31 14:37:04 -04:00
f94f748339 Use waitForExecutionDone in lint errors test (#6070) 2025-03-31 13:43:43 -04:00
e2b7b22ca9 ctx.close in tests when error on execution (#6075)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-31 10:24:42 -07:00
efc8c82d8b BREAKING: KCL @settings are the source of truth for units (#5808) 2025-03-31 10:56:03 -04:00
eac5abba79 Clean up env vars in e2e-tests.yml (#6045)
* pierremtb/adhoc/clean-up-e2e-env-vars-ci

* Add back           VITE_KC_SKIP_AUTH: true for snaps

* Remove VITE_KC_SKIP_AUTH: true, add back token
2025-03-31 09:18:23 -04:00
1956c14b8a auto format kcl samples (#6065)
* recast kcl samples;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* auto format the kcl-samples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-30 17:06:36 +00:00
017fac7041 use deterministic ids in more places (#6064)
* dont redact the ids now that they are deterministic

Signed-off-by: Jess Frazelle <github@jessfraz.com>

pass arouund id generator more

Signed-off-by: Jess Frazelle <github@jessfraz.com>

change the anme space

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates and re-run

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanup old files

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanup old files

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-30 04:23:11 +00:00
0bdc50c78f bump kcl-lib and friends (#6063)
* bump kcl-lib and friends

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* expose

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* relevant files

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* udpates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-29 19:26:20 -07:00
57d78b6094 Move artifact graph out of engine connection (#6062)
* cleanups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cleanups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fmt

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-29 20:25:26 -04:00
db5ce7ba85 Move turns to a submodule of std (#6039)
* Move turns to a submodule of std

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Cache module infos as well as memory; fix a bug with deprecated constants

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-03-30 11:10:44 +13:00
51c16d0048 only rust changes reset scene (#6060)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-29 11:43:42 -07:00
6532b23f1c Bump tar-fs from 2.1.1 to 2.1.2 in /rust/kcl-language-server in the security group (#6056) 2025-03-29 16:35:45 +00:00
49304b9ecd fix context closes (#6058)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-28 20:31:44 -07:00
358b34de4c Fix translate scale & better docs (#6053)
* change translate & scale to be better & docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* autocomplete

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* gen std

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* kcl-samples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-28 21:14:29 +00:00
9973e5fde3 Fix to preserve comments when changing file units (#6052) 2025-03-28 21:07:53 +00:00
36875e05fd Fix .length on undefined WASM error (#6048) 2025-03-28 14:48:47 -04:00
42123383bb Add path argument error to console error whitelist (#6046)
* Add path argument error to console error whitelist

* Lint
2025-03-28 13:50:54 -04:00
ef4c606ed1 Update sweep-related icons to be less detailed, show result (#6047)
* WIP trying out various icons

* Update to use outcome bodies for icons
2025-03-28 16:42:31 +00:00
1ebb73b935 Fix 'originalCode' undefined in a test (#6027) 2025-03-28 12:36:54 -04:00
b57d31c0e7 Fix build:wasm:dev for --dev builds (#6038)
This is useful since it preserves Rust backtraces in WASM.
2025-03-28 08:40:21 -04:00
678ebbc310 Make Helix available in numbered releases (#6024)
* Helix release outside of dev and nightly

* Make length non required on edge mode so we get the edge length by default
2025-03-28 11:25:32 +00:00
cc2efd316c Add more TS lints and fix types (#6037)
* Add as const lint

* Add lint for no implied eval

* Fix incorrect type and add lints

* Add more type lints

* Remove redundant type assertions and add lint

* Fix to turn off incorrect base rules

* Fix yarn lint workflow to wait for build:wasm

* Change so that we don't build:wasm more than once in the workflow
2025-03-28 04:24:24 +00:00
d1f811f91d Boolean create UI (#5906)
* first steps, add to cmd bar etc

* cmdbar working well enough

* mvp

* lint

* fix after rebase

* intersect and union mvps

* add test

* some clean up

* further fix up

* Update src/lang/modifyAst/boolean.ts

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update src/lang/modifyAst/boolean.ts

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* pierre's comments

* tsc

* add comment

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-03-28 03:56:48 +00:00
7ca3afff9f Add CSG operations to the Feature Tree (#6028)
* Add operation tracking for CSG boolean functions

* Add CSG operations to the Feature Tree

* Add just command

* Add union sim test

* Update output with new sim test

* Add CSG subtract test

* Update output from subtract test

* Add intersect sim test

* Update output for intersect test
2025-03-28 09:48:55 +11:00
460 changed files with 26965 additions and 11282 deletions

View File

@ -20,9 +20,20 @@
"plugin:react-hooks/recommended"
],
"rules": {
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-array-delete": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-floating-promises": "error",
"no-implied-eval": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-implied-eval": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"no-unused-vars": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-unused-vars": ["error", {
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
@ -30,6 +41,7 @@
"vars": "all",
"args": "none"
}],
"@typescript-eslint/prefer-as-const": "warn",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",

View File

@ -229,10 +229,6 @@ jobs:
timeout_minutes: 30
max_attempts: 3
env:
CI: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
@ -377,11 +373,7 @@ jobs:
timeout_minutes: 45
max_attempts: 15
env:
CI: true
FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- uses: actions/upload-artifact@v4

View File

@ -28,43 +28,57 @@ jobs:
- run: yarn fmt-check
yarn-build-wasm:
runs-on: ubuntu-22.04
# Build the wasm blob once on the fastest runner.
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- name: Install dependencies
run: yarn install
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with:
tool: wasm-pack
- run: yarn build:wasm
yarn-tsc:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- run: yarn --cwd ./rust/kcl-language-server --modules-folder node_modules install
- uses: Swatinem/rust-cache@v2
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with:
tool: wasm-pack
- run: yarn build:wasm
- run: yarn tsc
- name: Build Wasm
shell: bash
run: yarn build:wasm
yarn-lint:
runs-on: ubuntu-22.04
- uses: actions/upload-artifact@v4
with:
name: prepared-wasm
path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
- uses: actions/upload-artifact@v4
with:
name: prepared-ts-rs-bindings
path: |
rust/kcl-lib/bindings/*
yarn-tsc:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
@ -73,7 +87,53 @@ jobs:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- run: yarn --cwd ./rust/kcl-language-server --modules-folder node_modules install
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn tsc
yarn-lint:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn lint
python-codespell:
@ -91,6 +151,7 @@ jobs:
yarn-unit-test-kcl-samples:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
@ -103,7 +164,22 @@ jobs:
- uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with:
tool: wasm-pack
- run: yarn build:wasm
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
@ -120,6 +196,7 @@ jobs:
yarn-unit-test:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
@ -132,7 +209,22 @@ jobs:
- uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with:
tool: wasm-pack
- run: yarn build:wasm
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}

View File

@ -37,7 +37,7 @@ build-web: public/kcl_wasm_lib_bg.wasm build/index.html
build-desktop: public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES)$(RUST_SOURCES)
yarn build:wasm
yarn build:wasm:dev
build/index.html: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
yarn build:local
@ -99,7 +99,7 @@ test-e2e-web: install build-web ## Run the web e2e tests
.PHONY: test-e2e-desktop
test-e2e-desktop: install build-desktop ## Run the desktop e2e tests
yarn test:playwright:electron --workers=$(E2E_WORKERS) --max-failures=$(E2E_FAILURES) --grep=$(E2E_GREP)
yarn test:playwright:electron --workers=$(E2E_WORKERS) --max-failures=$(E2E_FAILURES) --grep="$(E2E_GREP)"
###############################################################################
# CLEAN

View File

@ -9,13 +9,9 @@ layout: manual
### `std`
- [`HALF_TURN`](/docs/kcl/consts/std-HALF_TURN)
- [`QUARTER_TURN`](/docs/kcl/consts/std-QUARTER_TURN)
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-THREE_QUARTER_TURN)
- [`XY`](/docs/kcl/consts/std-XY)
- [`XZ`](/docs/kcl/consts/std-XZ)
- [`YZ`](/docs/kcl/consts/std-YZ)
- [`ZERO`](/docs/kcl/consts/std-ZERO)
### `std::math`
@ -23,3 +19,10 @@ layout: manual
- [`PI`](/docs/kcl/consts/std-math-PI)
- [`TAU`](/docs/kcl/consts/std-math-TAU)
### `std::turns`
- [`HALF_TURN`](/docs/kcl/consts/std-turns-HALF_TURN)
- [`QUARTER_TURN`](/docs/kcl/consts/std-turns-QUARTER_TURN)
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-turns-THREE_QUARTER_TURN)
- [`ZERO`](/docs/kcl/consts/std-turns-ZERO)

View File

@ -1,15 +0,0 @@
---
title: "std::HALF_TURN"
excerpt: ""
layout: manual
---
```js
std::HALF_TURN: number(deg) = 180deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::QUARTER_TURN: number(deg) = 90deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::THREE_QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::THREE_QUARTER_TURN: number(deg) = 270deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::ZERO"
excerpt: ""
layout: manual
---
```js
std::ZERO: number = 0
```

View File

@ -0,0 +1,15 @@
---
title: "std::turns::HALF_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::HALF_TURN: number(deg) = 180deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::turns::QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::QUARTER_TURN: number(deg) = 90deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::turns::THREE_QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::THREE_QUARTER_TURN: number(deg) = 270deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::turns::ZERO"
excerpt: ""
layout: manual
---
```js
std::turns::ZERO: number = 0
```

View File

@ -23,19 +23,15 @@ layout: manual
* [`tag`](kcl/types/tag)
* **std**
* [`Face`](kcl/types/Face)
* [`HALF_TURN`](kcl/consts/std-HALF_TURN)
* [`Helix`](kcl/types/Helix)
* [`Plane`](kcl/types/Plane)
* [`Point2d`](kcl/types/Point2d)
* [`Point3d`](kcl/types/Point3d)
* [`QUARTER_TURN`](kcl/consts/std-QUARTER_TURN)
* [`Sketch`](kcl/types/Sketch)
* [`Solid`](kcl/types/Solid)
* [`THREE_QUARTER_TURN`](kcl/consts/std-THREE_QUARTER_TURN)
* [`XY`](kcl/consts/std-XY)
* [`XZ`](kcl/consts/std-XZ)
* [`YZ`](kcl/consts/std-YZ)
* [`ZERO`](kcl/consts/std-ZERO)
* [`abs`](kcl/abs)
* [`acos`](kcl/acos)
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
@ -146,3 +142,8 @@ layout: manual
* [`tan`](kcl/std-math-tan)
* **std::sketch**
* [`circle`](kcl/std-sketch-circle)
* **std::turns**
* [`turns::HALF_TURN`](kcl/consts/std-turns-HALF_TURN)
* [`turns::QUARTER_TURN`](kcl/consts/std-turns-QUARTER_TURN)
* [`turns::THREE_QUARTER_TURN`](kcl/consts/std-turns-THREE_QUARTER_TURN)
* [`turns::ZERO`](kcl/consts/std-turns-ZERO)

View File

@ -6,6 +6,10 @@ layout: manual
Rotate a solid or a sketch.
This is really useful for assembling parts together. You can create a part and then rotate it to the correct orientation.
For sketches, you can use this to rotate a sketch and then loft it with another sketch.
### Using Roll, Pitch, and Yaw
When rotating a part in 3D space, "roll," "pitch," and "yaw" refer to the three rotational axes used to describe its orientation: roll is rotation around the longitudinal axis (front-to-back), pitch is rotation around the lateral axis (wing-to-wing), and yaw is rotation around the vertical axis (up-down); essentially, it's like tilting the part on its side (roll), tipping the nose up or down (pitch), and turning it left or right (yaw).
@ -166,7 +170,7 @@ fn square() {
profile001 = square()
profile002 = square()
|> translate(translate = [0, 0, 20])
|> translate(x = 0, y = 0, z = 20)
|> rotate(axis = [0, 0, 1.0], angle = 45)
loft([profile001, profile002])

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,7 @@ circle(@sketch_or_surface: Sketch | Plane | Face, center: Point2d, radius: numbe
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) `|` [`Plane`](/docs/kcl/types/Face) `|` [`Plane`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) OR [`Plane`](/docs/kcl/types/Plane) OR [`Face`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `center` | [`Point2d`](/docs/kcl/types/Point2d) | The center of the circle. | Yes |
| `radius` | [`number`](/docs/kcl/types/number) | The radius of the circle. | Yes |
| [`tag`](/docs/kcl/types/tag) | [`tag`](/docs/kcl/types/tag) | Create a new tag which refers to this circle. | No |

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ An extrude plane.
| `faceId` |[`string`](/docs/kcl/types/string)| The face id for the extrude plane. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
----
@ -48,7 +48,7 @@ An extruded arc.
| `faceId` |[`string`](/docs/kcl/types/string)| The face id for the extrude plane. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
----
@ -68,7 +68,7 @@ Geometry metadata.
| `faceId` |[`string`](/docs/kcl/types/string)| The id for the chamfer surface. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
----
@ -88,7 +88,7 @@ Geometry metadata.
| `faceId` |[`string`](/docs/kcl/types/string)| The id for the fillet surface. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
----

View File

@ -17,6 +17,6 @@ Geometry metadata.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |

View File

@ -17,7 +17,7 @@ A helix.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |[`string`](/docs/kcl/types/string)| The id of the helix. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `revolutions` |[`number`](/docs/kcl/types/number)| Number of revolutions. | No |
| `angleStart` |[`number`](/docs/kcl/types/number)| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |

View File

@ -285,7 +285,7 @@ Data for an imported geometry.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Module`| | No |
| `value` |[`ModuleId`](/docs/kcl/types/ModuleId)| Identifier of a source file. Uses a u32 to keep the size small. | No |
| `value` |`integer`| Identifier of a source file. Uses a u32 to keep the size small. | No |
----

View File

@ -17,6 +17,6 @@ Data for polar coordinates.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line (in degrees). | No |
| `length` |[`TyF64`](/docs/kcl/types/TyF64)| The length of the line. | No |
| `length` |[`number`](/docs/kcl/types/number)| The length of the line. | No |

View File

@ -25,7 +25,7 @@ A sketch type.
|----------|------|-------------|----------|
| `type` |enum: `plane`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the plane. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| Type for a plane. | No |
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the plane. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's X axis be? | No |
@ -49,7 +49,7 @@ A face.
|----------|------|-------------|----------|
| `type` |enum: `face`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the face. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `value` |[`string`](/docs/kcl/types/string)| The tag of the face. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's Y axis be? | No |

View File

@ -1,15 +0,0 @@
---
title: "SourceRange"
excerpt: ""
layout: manual
---
**Type:** `integer` (`uint`)

View File

@ -5,17 +5,11 @@ layout: manual
---
**Type:** `object`
**Type:** [`number`](/docs/kcl/types/number) (`double`)
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `n` |[`number`](/docs/kcl/types/number)| | No |
| `ty` |[`NumericType`](/docs/kcl/types/NumericType)| | No |

View File

@ -85,7 +85,7 @@ async function doBasicSketch(
await page.mouse.click(startXPx, 500 - PUR * 20)
if (openPanes.includes('code')) {
await expect(u.codeLocator)
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -119,10 +119,7 @@ async function doBasicSketch(
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
await expect(
await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)
).toBeLessThan(3)
await expect(await u.getGreatestPixDiff(line1, [0, 0, 255])).toBeLessThan(3)
expect(await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)).toBeLessThan(3)
}
// hold down shift
@ -145,7 +142,7 @@ async function doBasicSketch(
// Open the code pane.
await u.openKclCodePanel()
await expect(u.codeLocator)
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1}, tag = $seg01)

View File

@ -0,0 +1,117 @@
import { test, expect } from './zoo-test'
import fs from 'node:fs/promises'
import path from 'node:path'
test.describe('Point and click for boolean workflows', () => {
// Boolean operations to test
const booleanOperations = [
{
name: 'union',
code: 'union([extrude001, extrude006])',
},
{
name: 'subtract',
code: 'subtract([extrude001], tools = [extrude006])',
},
{
name: 'intersect',
code: 'intersect([extrude001, extrude006])',
},
] as const
for (let i = 0; i < booleanOperations.length; i++) {
const operation = booleanOperations[i]
const operationName = operation.name
const commandName = `Boolean ${
operationName.charAt(0).toUpperCase() + operationName.slice(1)
}`
test(`Create boolean operation -- ${operationName}`, async ({
context,
homePage,
cmdBar,
editor,
toolbar,
scene,
page,
}) => {
const file = await fs.readFile(
path.resolve(
__dirname,
'../../',
'./rust/kcl-lib/e2e/executor/inputs/boolean-setup-with'
),
'utf-8'
)
await context.addInitScript((file) => {
localStorage.setItem('persistCode', file)
}, file)
await homePage.goToModelingScene()
await scene.waitForExecutionDone()
await scene.settled(cmdBar)
// Test coordinates for selection - these might need adjustment based on actual scene layout
const cylinderPoint = { x: 592, y: 174 }
const secondObjectPoint = { x: 683, y: 273 }
// Create mouse helpers for selecting objects
const [clickFirstObject] = scene.makeMouseHelpers(
cylinderPoint.x,
cylinderPoint.y,
{ steps: 10 }
)
const [clickSecondObject] = scene.makeMouseHelpers(
secondObjectPoint.x,
secondObjectPoint.y,
{ steps: 10 }
)
await test.step(`Test ${operationName} operation`, async () => {
// Click the boolean operation button in the toolbar
await toolbar.selectBoolean(operationName)
// Verify command bar is showing the right command
await expect(cmdBar.page.getByTestId('command-name')).toContainText(
commandName
)
// Select first object in the scene, expect there to be a pixel diff from the selection color change
await clickFirstObject({ pixelDiff: 50 })
// For subtract, we need to proceed to the next step before selecting the second object
if (operationName !== 'subtract') {
// should down shift key to select multiple objects
await page.keyboard.down('Shift')
}
// Select second object
await clickSecondObject({ pixelDiff: 50 })
// Confirm the operation in the command bar
await cmdBar.progressCmdBar()
if (operationName === 'union' || operationName === 'intersect') {
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Solids: '2 paths',
},
commandName,
})
} else if (operationName === 'subtract') {
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Tool: '1 path',
Target: '1 path',
},
commandName,
})
}
await cmdBar.submit()
await editor.expectEditor.toContain(operation.code)
})
})
}
})

View File

@ -46,7 +46,7 @@ test.describe(
},
}
const code = `sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
const code = `@settings(defaultLengthUnit = in)sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
await u.openDebugPanel()

View File

@ -251,11 +251,11 @@ test(
])
await Promise.all([
fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
executorInputPath('cylinder-inches.kcl'),
join(routerTemplateDir, 'main.kcl')
),
fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
join(bracketDir, 'main.kcl')
),
])

View File

@ -20,11 +20,11 @@ test(
await Promise.all([fsp.mkdir(bracketDir, { recursive: true })])
await Promise.all([
fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'other.kcl')
),
fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
path.join(bracketDir, 'main.kcl')
),
])
@ -107,7 +107,7 @@ test(
},
{ timeout: 15_000 }
)
.toBeGreaterThan(300_000)
.toBeGreaterThan(30_000)
})
})
@ -187,7 +187,7 @@ test(
},
{ timeout: 15_000 }
)
.toBeGreaterThan(70_000)
.toBeGreaterThan(50_000)
})
})
}

View File

@ -32,26 +32,30 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
// |> close()`)
// |> close()`.replaceAll('\n', '')
)
// uncomment the code
await page.keyboard.down('ControlOrMeta')
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`)
|> close()`.replaceAll('\n', '')
)
})
test('ensure we use the cache, and do not re-execute', async ({
@ -178,13 +182,15 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await page.locator('#code-pane button:first-child').click()
await page.locator('button:has-text("Format code")').click()
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`)
|> close()`.replaceAll('\n', '')
)
})
test('if you click the format button it formats your code and executes so lints are still there', async ({
@ -227,13 +233,15 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await expect(page.locator('.cm-content'))
.toHaveText(`sketch_001 = startSketchOn(XY)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch_001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`)
|> close()`.replaceAll('\n', '')
)
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -471,6 +479,7 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
test('if you write kcl with lint errors you get lints', async ({
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 })
@ -490,10 +499,7 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await page.keyboard.press('ArrowLeft')
await page.keyboard.press('ArrowRight')
// FIXME: lsp errors do not propagate to the frontend until engine is connected and code is executed
// This timeout is to wait for engine connection. LSP and code execution errors should be handled differently
// LSP can emit errors as fast as it waits and show them in the editor
await page.waitForTimeout(10000)
await scene.waitForExecutionDone()
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -815,10 +821,12 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
// there shouldn't be any auto complete options for 'lin' in the comment
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([3.14, 12], %)
|> xLine(%, length = 5) // lin`)
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
// expect there to be no KCL errors
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
@ -888,10 +896,12 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
// there shouldn't be any auto complete options for 'lin' in the comment
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([3.14, 12], %)
|> xLine(%, length = 5) // lin`)
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
})
})
test('Can undo a click and point extrude with ctrl+z', async ({
@ -1206,4 +1216,55 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
})
}
)
test('Rectangle tool panning with middle click', async ({
page,
homePage,
toolbar,
scene,
cmdBar,
editor,
}) => {
await page.setBodyDimensions({ width: 1200, height: 900 })
await homePage.goToModelingScene()
// wait until scene is ready to be interacted with
await scene.connectionEstablished()
await scene.settled(cmdBar)
await page.getByRole('button', { name: 'Start Sketch' }).click()
// select an axis plane
await page.mouse.click(700, 200)
// Needed as we don't yet have a way to get a signal from the engine that the camera has animated to the sketch plane
await page.waitForTimeout(1000)
const middleMousePan = async (
startX: number,
startY: number,
endX: number,
endY: number
) => {
const initialCode = await editor.getCurrentCode()
await page.mouse.click(startX, startY, { button: 'middle' })
await page.mouse.move(endX, endY, {
steps: 10,
})
// We expect the code to be the same, middle mouse click should not modify the code, only do panning
await editor.expectEditor.toBe(initialCode)
}
await test.step(`Verify corner rectangle panning`, async () => {
await page.getByTestId('corner-rectangle').click()
await middleMousePan(800, 500, 900, 600)
})
await test.step(`Verify center rectangle panning`, async () => {
await toolbar.selectCenterRectangle()
await middleMousePan(800, 200, 900, 300)
})
})
})

View File

@ -81,6 +81,13 @@ export class EditorFixture {
expectEditor = {
toContain: this._expectEditorToContain(),
not: { toContain: this._expectEditorToContain(true) },
toBe: async (code: string) => {
const currentCode = await this.getCurrentCode()
return expect(currentCode).toBe(code)
},
}
getCurrentCode = async () => {
return await this.codeContent.innerText()
}
snapshot = async (options?: { timeout?: number; name?: string }) => {
const wasPaneOpen = await this.checkIfPaneIsOpen()

View File

@ -310,7 +310,9 @@ export async function expectPixelColor(
.toBeTruthy()
.catch((cause) => {
throw new Error(
`ExpectPixelColor: expecting ${colour} got ${finalValue}`,
`ExpectPixelColor: point ${JSON.stringify(
coords
)} was expecting ${colour} but got ${finalValue}`,
{ cause }
)
})

View File

@ -181,6 +181,14 @@ export class ToolbarFixture {
).toBeVisible()
await this.page.getByTestId('dropdown-center-rectangle').click()
}
selectBoolean = async (operation: 'union' | 'subtract' | 'intersect') => {
await this.page
.getByRole('button', { name: 'caret down Union: open menu' })
.click()
const operationTestId = `dropdown-boolean-${operation}`
await expect(this.page.getByTestId(operationTestId)).toBeVisible()
await this.page.getByTestId(operationTestId).click()
}
selectCircleThreePoint = async () => {
await this.page

View File

@ -258,14 +258,6 @@ export const isErrorWhitelisted = (exception: Error) => {
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
},
// TODO: fix this error in the code
{
name: 'TypeError',
message: "Cannot read properties of undefined (reading 'length')",
stack: '',
project: 'Google Chrome',
foundInSpec: '', // many tests are impacted by this error
},
// TODO: fix this error in the code
{
name: 'ReferenceError',
message: '_testUtils is not defined',
@ -273,7 +265,6 @@ export const isErrorWhitelisted = (exception: Error) => {
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
},
// TODO: fix this error in the code
{
name: 'TypeError',
message: 'Failed to fetch',
@ -281,21 +272,13 @@ export const isErrorWhitelisted = (exception: Error) => {
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
},
// TODO: fix this error in the code
{
name: 'ReferenceError',
message: 'originalCode is not defined',
stack: '',
name: 'Error',
message: 'The "path" argument must be of type string. Received undefined',
stack:
'Error: The "path" argument must be of type string. Received undefined',
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/onboarding-tests.spec.ts',
},
// TODO: fix this error in the code
{
name: 'ReferenceError',
message: 'createNewVariableCheckbox is not defined',
stack: '',
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/testing-constraints.spec.ts',
foundInSpec: '', // many tests are impacted by this error
},
]

View File

@ -11,7 +11,7 @@ test(
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
join(bracketDir, 'main.kcl')
)
})
@ -51,7 +51,7 @@ test(
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
join(bracketDir, 'main.kcl')
)
})

View File

@ -230,9 +230,9 @@ test.describe('Onboarding tests', () => {
// Override beforeEach test setup
await context.addInitScript(
async ({ settingsKey, settings }) => {
async ({ settingsKey, settings, code }) => {
// Give some initial code, so we can test that it's cleared
localStorage.setItem('persistCode', originalCode)
localStorage.setItem('persistCode', code)
localStorage.setItem(settingsKey, settings)
},
{
@ -240,6 +240,7 @@ test.describe('Onboarding tests', () => {
settings: settingsToToml({
settings: TEST_SETTINGS_ONBOARDING_EXPORT,
}),
code: originalCode,
}
)

View File

@ -137,7 +137,7 @@ test.describe('Point-and-click tests', () => {
await scene.moveCameraTo(cameraPos, cameraTarget)
await test.step('check chamfer selection changes cursor positon', async () => {
await test.step('check chamfer selection changes cursor position', async () => {
await expect(async () => {
// sometimes initial click doesn't register
await clickChamfer()
@ -173,7 +173,7 @@ test.describe('Point-and-click tests', () => {
})
await test.step('Check there is no errors after code created in previous steps executes', async () => {
await editor.expectState({
activeLines: ['sketch001 = startSketchOn(XZ)'],
activeLines: ['@settings(defaultLengthUnit = in)'],
highlightedCode: '',
diagnostics: [],
})
@ -299,7 +299,8 @@ test.describe('Point-and-click tests', () => {
await test.step('verify at the end of the test that final code is what is expected', async () => {
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -369,7 +370,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
})
})
test('Works on chamfers that are non in a pipeExpression can break up multi edges in a chamfer array', async ({
test('Works on chamfers that are not in a pipeExpression can break up multi edges in a chamfer array', async ({
context,
page,
homePage,
@ -418,7 +419,8 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|>close()`,
})
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %)
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -1097,7 +1099,6 @@ openSketch = startSketchOn(XY)
Mode: '',
AngleStart: '',
Revolutions: '',
Length: '',
Radius: '',
CounterClockWise: '',
},
@ -1194,14 +1195,14 @@ openSketch = startSketchOn(XY)
{
selectionType: 'segment',
testPoint: { x: 513, y: 221 },
expectedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedEditedOutput: `helix001 = helix( axis = seg01, radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedOutput: `helix001 = helix( axis = seg01, radius = 1, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedEditedOutput: `helix001 = helix( axis = seg01, radius = 5, revolutions = 20, angleStart = 0, ccw = false,)`,
},
{
selectionType: 'sweepEdge',
testPoint: { x: 564, y: 364 },
expectedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 100, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedEditedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, length = 50, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 1, revolutions = 20, angleStart = 0, ccw = false,)`,
expectedEditedOutput: `helix001 = helix( axis = getOppositeEdge(seg01), radius = 5, revolutions = 20, angleStart = 0, ccw = false,)`,
},
]
helixCases.map(
@ -1244,7 +1245,6 @@ openSketch = startSketchOn(XY)
AngleStart: '',
Mode: '',
CounterClockWise: '',
Length: '',
Radius: '',
Revolutions: '',
},
@ -1261,8 +1261,6 @@ openSketch = startSketchOn(XY)
await cmdBar.progressCmdBar()
await page.keyboard.insertText('1')
await cmdBar.progressCmdBar()
await page.keyboard.insertText('100')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
@ -1271,7 +1269,6 @@ openSketch = startSketchOn(XY)
AngleStart: '0',
Revolutions: '20',
Radius: '1',
Length: '100',
CounterClockWise: '',
},
commandName: 'Helix',
@ -1292,8 +1289,8 @@ openSketch = startSketchOn(XY)
0
)
await operationButton.dblclick()
const initialInput = '100'
const newInput = '50'
const initialInput = '1'
const newInput = '5'
await cmdBar.expectState({
commandName: 'Helix',
stage: 'arguments',
@ -1302,13 +1299,14 @@ openSketch = startSketchOn(XY)
headerArguments: {
AngleStart: '0',
Revolutions: '20',
Radius: '1',
Length: initialInput,
Radius: initialInput,
CounterClockWise: '',
},
highlightedHeaderArg: 'CounterClockWise',
})
await page.keyboard.press('Shift+Backspace')
await page
.getByRole('button', { name: 'radius', exact: false })
.click()
await expect(cmdBar.currentArgumentInput).toBeVisible()
await cmdBar.currentArgumentInput
.locator('.cm-content')
@ -1319,8 +1317,7 @@ openSketch = startSketchOn(XY)
headerArguments: {
AngleStart: '0',
Revolutions: '20',
Radius: '1',
Length: newInput,
Radius: newInput,
CounterClockWise: '',
},
commandName: 'Helix',
@ -1391,7 +1388,6 @@ extrude001 = extrude(profile001, length = 100)
Mode: '',
AngleStart: '',
Revolutions: '',
Length: '',
Radius: '',
CounterClockWise: '',
},
@ -1645,9 +1641,10 @@ loft001 = loft([sketch001, sketch002])
{
targetType: 'circle',
testPoint: { x: 700, y: 250 },
initialCode: `sketch001 = startSketchOn('YZ')
initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
profile001 = circle(sketch001, center = [0, 0], radius = 500)
sketch002 = startSketchOn('XZ')
sketch002 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> xLine(length = -500)
|> tangentialArcTo([-2000, 500], %)`,
@ -1655,7 +1652,8 @@ sketch002 = startSketchOn('XZ')
{
targetType: 'rectangle',
testPoint: { x: 710, y: 255 },
initialCode: `sketch001 = startSketchOn('YZ')
initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
profile001 = startProfileAt([-400, -400], sketch001)
|> angledLine([0, 800], %, $rectangleSegmentA001)
|> angledLine([
@ -1668,7 +1666,7 @@ profile001 = startProfileAt([-400, -400], sketch001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch002 = startSketchOn('XZ')
sketch002 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> xLine(length = -500)
|> tangentialArcTo([-2000, 500], %)`,
@ -1812,7 +1810,8 @@ sketch002 = startSketchOn('XZ')
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(YZ)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
@ -2481,7 +2480,8 @@ extrude001 = extrude(profile001, length = 5)
cmdBar,
}) => {
// Code samples
const initialCode = `sketch001 = startSketchOn(XY)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-12, -6], %)
|> line(end = [0, 12])
|> line(end = [24, 0])
@ -2773,7 +2773,8 @@ extrude001 = extrude(sketch001, length = -12)
toolbar,
}) => {
// Code samples
const initialCode = `sketch001 = startSketchOn(XY)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-12, -6], %)
|> line(end = [0, 12])
|> line(end = [24, 0], tag = $seg02)
@ -2927,7 +2928,8 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(XZ)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 30)
extrude001 = extrude(sketch001, length = 30)
`
@ -3062,7 +3064,8 @@ extrude001 = extrude(sketch001, length = 30)
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(XY)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
|> startProfileAt([-20, 20], %)
|> xLine(length = 40)
|> yLine(length = -60)
@ -3180,7 +3183,8 @@ extrude001 = extrude(sketch001, length = 40)
})
const shellSketchOnFacesCases = [
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100)
|> extrude(length = 100)
@ -3188,7 +3192,8 @@ sketch002 = startSketchOn(sketch001, 'END')
|> circle(center = [0, 0], radius = 50)
|> extrude(length = 50)
`,
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100)
extrude001 = extrude(sketch001, length = 100)
@ -3471,6 +3476,39 @@ segAng(rectangleSegmentA002),
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = 'X')`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
const newAngle = '90'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
test('revolve surface around edge from an extruded solid2d', async ({
context,
@ -3481,26 +3519,22 @@ segAng(rectangleSegmentA002),
toolbar,
cmdBar,
}) => {
const initialCode = `
sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %)
|> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %)
|> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 50)
sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> circle(
center = [-11.34, 10.0],
radius = 8.69
)
|> circle(center = [-11.34, 10.0], radius = 8.69)
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
@ -3518,9 +3552,49 @@ radius = 8.69
const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = getOppositeEdge(rectangleSegmentA001)) `
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = rectangleSegmentA001)`
await editor.expectEditor.toContain(newCodeToFind)
// Edit flow
const newAngle = '180'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await page.getByRole('button', { name: 'Create new variable' }).click()
await expect(page.getByPlaceholder('Variable name')).toHaveValue(
'angle001'
)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain('angle001 = ' + newAngle)
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = angle001')
)
})
test('revolve sketch circle around line segment from startProfileAt sketch', async ({
context,
@ -3531,26 +3605,22 @@ radius = 8.69
toolbar,
cmdBar,
}) => {
const initialCode = `
sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6)
sketch001 = startSketchOn('-XY')
|> startProfileAt([-0.48, 1.25], %)
|> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START')
|> circle(
center = [-0.69, 0.56],
radius = 0.28
)
const initialCode = `sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6)
sketch001 = startSketchOn(-XY)
|> startProfileAt([-0.48, 1.25], %)
|> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START')
|> circle(center = [-0.69, 0.56], radius = 0.28)
`
await context.addInitScript((initialCode) => {
@ -3569,9 +3639,44 @@ radius = 8.69
const lineCodeToSelection = `|> xLine(length = 2.6)`
await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360, axis = seg01)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
const newAngle = '270'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
})
@ -3584,7 +3689,8 @@ radius = 8.69
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(XZ)
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = circle(
sketch001,
center = [0, 0],

View File

@ -87,7 +87,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -124,7 +124,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
const errorDir = path.join(dir, 'broken-code')
@ -162,7 +162,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [110, 110, 110]), {
timeout: 10_000,
})
.toBeLessThan(20)
@ -213,7 +213,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
const emptyDir = path.join(dir, 'empty')
@ -248,7 +248,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -290,7 +290,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
@ -319,7 +319,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -359,7 +359,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
await fsp.copyFile(
@ -393,7 +393,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -443,7 +443,6 @@ test(
await page.getByText('broken-code').click()
// Gotcha: You can not use scene.waitForExecutionDone() since the KCL code is going to fail
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
@ -481,7 +480,7 @@ test.describe('Can export from electron app', () => {
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -513,7 +512,7 @@ test.describe('Can export from electron app', () => {
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -554,7 +553,7 @@ test.describe('Can export from electron app', () => {
},
{ timeout: 15_000 }
)
.toBeGreaterThan(300_000)
.toBeGreaterThan(50_000)
// clean up exported file
await fsp.rm(filepath)
@ -1507,7 +1506,12 @@ test(
await u.waitForPageLoad()
await page.locator('.cm-content').fill(`sketch001 = startSketchOn(XZ)
// The file should be prepopulated with the user's unit settings.
await expect(page.locator('.cm-content')).toHaveText(
'@settings(defaultLengthUnit = in)'
)
await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ')
|> startProfileAt([-87.4, 282.92], %)
|> line(end = [324.07, 27.199], tag = $seg01)
|> line(end = [118.328, -291.754])

View File

@ -4,9 +4,9 @@ import path from 'path'
import * as fsp from 'fs/promises'
import {
getUtils,
executorInputPath,
TEST_COLORS,
TestColor,
executorInputPath,
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
@ -331,7 +331,7 @@ extrude001 = extrude(sketch001, length = 50)
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = mm)
sketch002 = startSketchOn('XY')
sketch002 = startSketchOn(XY)
profile002 = startProfileAt([72.24, -52.05], sketch002)
|> angledLine([0, 181.26], %, $rectangleSegmentA001)
|> angledLine([
@ -582,7 +582,7 @@ extrude002 = extrude(profile002, length = 150)
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -619,6 +619,7 @@ extrude002 = extrude(profile002, length = 150)
test(`View gizmo stays visible even when zoomed out all the way`, async ({
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
@ -632,7 +633,7 @@ extrude002 = extrude(profile002, length = 150)
await test.step(`Load an empty file`, async () => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', '')
localStorage.setItem('persistCode', '@settings(defaultLengthUnit = in)')
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
@ -646,22 +647,31 @@ extrude002 = extrude(profile002, length = 150)
timeout: 5000,
message: 'Plane color is visible',
})
.toBeLessThanOrEqual(15)
.toBeLessThanOrEqual(20)
await expect(scene.startEditSketchBtn).toBeEnabled()
let maxZoomOuts = 10
let middlePixelIsBackgroundColor =
(await middlePixelIsColor(bgColor)) < 10
console.time('pressing control')
await page.keyboard.down('Control')
while (!middlePixelIsBackgroundColor && maxZoomOuts > 0) {
await page.keyboard.down('Control')
await page.mouse.move(600, 460)
await page.mouse.down({ button: 'right' })
await page.mouse.move(600, 50, { steps: 20 })
await page.mouse.up({ button: 'right' })
await page.keyboard.up('Control')
await page.waitForTimeout(100)
await page.mouse.move(650, 460)
console.time('moved to start point')
await page.mouse.down({ button: 'right' })
console.time('moused down')
await page.mouse.move(650, 50, { steps: 20 })
console.time('moved to end point')
await page.waitForTimeout(100)
await page.mouse.up({ button: 'right' })
console.time('moused up')
maxZoomOuts--
middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 10
middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 15
}
await page.keyboard.up('Control')
expect(middlePixelIsBackgroundColor, {
message: 'We should not see the default planes',
@ -678,13 +688,12 @@ extrude002 = extrude(profile002, length = 150)
homePage,
scene,
toolbar,
viewport,
}) => {
await context.folderSetupFn(async (dir) => {
const legoDir = path.join(dir, 'lego')
await fsp.mkdir(legoDir, { recursive: true })
await fsp.copyFile(
executorInputPath('lego.kcl'),
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
path.join(legoDir, 'main.kcl')
)
})
@ -697,11 +706,8 @@ extrude002 = extrude(profile002, length = 150)
await scene.loadingIndicator.waitFor({ state: 'detached' })
})
await test.step(`The part should start loading quickly, not waiting until execution is complete`, async () => {
await scene.expectPixelColor(
[143, 143, 143],
{ x: (viewport?.width ?? 1200) / 2, y: (viewport?.height ?? 500) / 2 },
15
)
// TODO: use the viewport size to pick the center point, but the `viewport` fixture's values were wrong.
await scene.expectPixelColor([116, 116, 116], { x: 500, y: 250 }, 15)
})
})

View File

@ -113,7 +113,8 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([2.61, -4.01], %)
|> xLine(length = 8.73)
|> tangentialArcTo([8.33, -1.31], %)`
@ -159,7 +160,10 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
await page.mouse.click(700, 200)
await expect.poll(u.normalisedEditorCode, { timeout: 1000 })
.toBe(`sketch002 = startSketchOn(XZ)
.toBe(`@settings(defaultLengthUnit = in)
sketch002 = startSketchOn(XZ)
sketch001 = startProfileAt([12.34, -12.34], sketch002)
|> yLine(length = 12.34)
@ -789,7 +793,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
200
)
let codeStr = 'sketch001 = startSketchOn(XY)'
let codeStr =
'@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XY)'
await page.mouse.click(center.x, viewportSize.height * 0.55)
await expect(u.codeLocator).toHaveText(codeStr)
@ -868,7 +873,8 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
await u.openDebugPanel()
const code = `sketch001 = startSketchOn(-XZ)
const code = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(-XZ)
profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
scale * 34.8
)}], sketch001)
@ -898,7 +904,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
await page.mouse.move(700, 200, { steps: 10 })
await page.mouse.click(700, 200, { delay: 200 })
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(-XZ)`
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(-XZ)`
)
let prevContent = await page.locator('.cm-content').innerText()
@ -1426,7 +1432,8 @@ test.describe(`Sketching with offset planes`, () => {
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`offsetPlane001 = offsetPlane(XY, offset = 10)`
`@settings(defaultLengthUnit = in)
offsetPlane001 = offsetPlane(XY, offset = 10)`
)
})
@ -1440,7 +1447,7 @@ test.describe(`Sketching with offset planes`, () => {
await test.step(`Hovering should highlight code`, async () => {
await planeHover()
await editor.expectState({
activeLines: [`offsetPlane001=offsetPlane(XY,offset=10)`],
activeLines: [`@settings(defaultLengthUnit = in)`],
diagnostics: [],
highlightedCode: 'offsetPlane(XY, offset = 10)',
})
@ -1453,7 +1460,7 @@ test.describe(`Sketching with offset planes`, () => {
await expect(toolbar.lineBtn).toBeEnabled()
await editor.expectEditor.toContain('startSketchOn(offsetPlane001)')
await editor.expectState({
activeLines: [`offsetPlane001=offsetPlane(XY,offset=10)`],
activeLines: [`@settings(defaultLengthUnit = in)`],
diagnostics: [],
highlightedCode: '',
})
@ -1604,7 +1611,8 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile002 = startProfileAt([40.68, 87.67], sketch001)
|> xLine(length = 239.17)
profile003 = startProfileAt([206.63, -56.73], sketch001)
@ -2172,7 +2180,8 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.24, 4.54], sketch001)
|> line(end = [-0.41, 6.99])
|> line(end = [8.61, 0.74])
@ -2317,7 +2326,8 @@ profile004 = circleThreePoint(sketch001, p1 = [13.44, -6.8], p2 = [13.39, -2.07]
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.24, 4.54], sketch001)
|> line(end = [-0.41, 6.99])
|> line(end = [8.61, 0.74])
@ -2422,7 +2432,8 @@ profile003 = circle(sketch001, center = [6.92, -4.2], radius = 3.16)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-63.43, 193.08], sketch001)
|> line(end = [168.52, 149.87])
|> line(end = [190.29, -39.18])
@ -2486,7 +2497,11 @@ extrude001 = extrude(profile003, length = 5)
page,
}) => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', `myVar = 5`)
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
myVar = 5`
)
})
await page.setBodyDimensions({ width: 1000, height: 500 })
@ -2533,7 +2548,8 @@ extrude001 = extrude(profile003, length = 5)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([85.19, 338.59], sketch001)
|> line(end = [213.3, -94.52])
|> line(end = [-230.09, -55.34])
@ -2575,7 +2591,8 @@ profile002 = startProfileAt([85.81, 52.55], sketch002)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`thePart = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
thePart = startSketchOn(XZ)
|> startProfileAt([7.53, 10.51], %)
|> line(end = [12.54, 1.83])
|> line(end = [6.65, -6.91])
@ -2636,7 +2653,8 @@ extrude001 = extrude(thePart, length = 75)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.71, -3.66], sketch001)
|> line(end = [2.65, 9.02], tag = $seg02)
|> line(end = [3.73, -9.36], tag = $seg01)
@ -2809,7 +2827,8 @@ extrude003 = extrude(profile011, length = 2.5)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([34, 42.66], sketch001)
|> line(end = [102.65, 151.99])
|> line(end = [76, -138.66])

View File

@ -76,11 +76,11 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({
angle = HALF_TURN,
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLineToY([segAng(seg04, %) + 180, ZERO], %)
|> angledLineToY([segAng(seg04, %) + 180, turns::ZERO], %)
|> angledLineToY({
angle = -bottomAng,
to = -totalHeightHalf - armThick,
@ -88,12 +88,12 @@ part001 = startSketchOn(-XZ)
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01, %))
|> angledLineThatIntersects({
angle = HALF_TURN,
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLineToY([segAng(seg02, %) + 180, -baseHeight], %)
|> xLine(endAbsolute = ZERO)
|> xLine(endAbsolute = turns::ZERO)
|> close()
|> extrude(length = 4)`
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1,5 +1,5 @@
{
"original_source_code": "sketch001 = startSketchOn('XZ')\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn('XY')\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine([0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, $rectangleSegmentB001)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %, $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
"original_source_code": "sketch001 = startSketchOn('XZ')\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn(XY)\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine([0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, $rectangleSegmentB001)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %, $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
"prompt": "make this neon green please, use #39FF14",
"source_ranges": [
{
@ -30,4 +30,4 @@
}
],
"kcl_version": "0.2.48"
}
}

View File

@ -4,7 +4,6 @@ import {
getUtils,
TEST_COLORS,
pollEditorLinesSelectedLength,
executorInputPath,
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { XOR } from 'lib/utils'
@ -81,7 +80,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 79
`@settings(defaultLengthUnit = in)
yo = 79
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4], tag = $seg01)
@ -145,7 +145,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4], tag = $seg01)
@ -159,31 +160,6 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|> xLine(length = segLen(seg_what))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])`
)
const isChecked = await createNewVariableCheckbox.isChecked()
const addVariable = testName === 'Add variable'
XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
(await createNewVariableCheckbox.click())
await page
.getByRole('button', { name: 'Add constraining value' })
.click()
// Wait for the codemod to take effect
await expect(page.locator('.cm-content')).toContainText(`angle: -57,`)
await expect(page.locator('.cm-content')).toContainText(
`offset: ${offset},`
)
await pollEditorLinesSelectedLength(page, 2)
const activeLinesContent = await page.locator('.cm-activeLine').all()
await expect(activeLinesContent[0]).toHaveText(
`|> line(end = [74.36, 130.4], tag = $seg01)`
)
await expect(activeLinesContent[1]).toHaveText(`}, %)`)
// checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
})
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
@ -277,7 +253,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -387,7 +364,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -486,13 +464,13 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
testName: 'Add variable, selecting axis',
addVariable: true,
axisSelect: true,
value: 'QUARTER_TURN - angle001',
value: 'turns::QUARTER_TURN - angle001',
},
{
testName: 'No variable, selecting axis',
addVariable: false,
axisSelect: true,
value: 'QUARTER_TURN - 7',
value: 'turns::QUARTER_TURN - 7',
},
] as const
for (const { testName, addVariable, value, axisSelect } of cases) {
@ -500,7 +478,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -602,7 +581,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -688,7 +668,8 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -768,7 +749,8 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async (customCode) => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -869,7 +851,8 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -935,12 +918,12 @@ part002 = startSketchOn(XZ)
test.describe('Axis & segment - no modal constraints', () => {
const cases = [
{
codeAfter: `|> line(endAbsolute = [154.9, ZERO])`,
codeAfter: `|> line(endAbsolute = [154.9, turns::ZERO])`,
axisClick: { x: 950, y: 250 },
constraintName: 'Snap To X',
},
{
codeAfter: `|> line(endAbsolute = [ZERO, 61.34])`,
codeAfter: `|> line(endAbsolute = [turns::ZERO, 61.34])`,
axisClick: { x: 600, y: 150 },
constraintName: 'Snap To Y',
},
@ -950,7 +933,8 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yo = 5
`@settings(defaultLengthUnit = in)
yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -1117,9 +1101,19 @@ test.describe('Electron constraint tests', () => {
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'test-sample')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('angled_line.kcl'),
path.join(bracketDir, 'main.kcl')
await fsp.writeFile(
path.join(bracketDir, 'main.kcl'),
`@settings(defaultLengthUnit = in)
const part001 = startSketchOn(XY)
|> startProfileAt([4.83, 12.56], %)
|> line(end = [15.1, 2.48])
|> line(end = [3.15, -9.85], tag = $seg01)
|> line(end = [-15.17, -4.1])
|> angledLine([segAng(seg01), 12.35], %)
|> line(end = [-13.02, 10.03])
|> close()
|> extrude(length = 4)`,
'utf-8'
)
})

View File

@ -255,7 +255,7 @@ test.describe(`Testing gizmo, fixture-based`, () => {
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`
`@settings(defaultLengthUnit = in)
const sketch002 = startSketchOn(XZ)
|> startProfileAt([-108.83, -57.48], %)
|> angledLine([0, 105.13], %, $rectangleSegmentA001)

View File

@ -46,7 +46,7 @@ test.describe('Testing in-app sample loading', () => {
page.getByRole('option', {
name,
})
const warningText = page.getByText('Overwrite current file and units?')
const warningText = page.getByText('Overwrite current file with sample?')
const confirmButton = page.getByRole('button', { name: 'Submit command' })
await test.step(`Precondition: check the initial code`, async () => {
@ -110,11 +110,9 @@ test.describe('Testing in-app sample loading', () => {
const commandMethodOption = page.getByRole('option', {
name: 'Overwrite',
})
const newFileWarning = page.getByText(
'Create a new file, overwrite project units?'
)
const newFileWarning = page.getByText('Create a new file from sample?')
const overwriteWarning = page.getByText(
'Overwrite current file and units?'
'Overwrite current file with sample?'
)
const confirmButton = page.getByRole('button', { name: 'Submit command' })
const projectMenuButton = page.getByTestId('project-sidebar-toggle')

View File

@ -210,7 +210,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([5 + 0, 20 + 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -380,7 +381,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`yRel001 = -14
`@settings(defaultLengthUnit = in)
yRel001 = -14
xRel001 = 0.5
angle001 = 3
len001 = 32
@ -459,7 +461,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -590,7 +593,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -751,7 +755,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -831,7 +836,8 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([56.37, 120.33], sketch001)
|> line(end = [162.86, 106.48])
|> arcTo({
@ -957,7 +963,8 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> circle(center = [1 + 0, 0], radius = 8)
`
)
@ -1077,7 +1084,8 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|>startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -1351,7 +1359,8 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
async ({ lineToBeDeleted, extraLine }) => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([5, 6], %)
|> ${lineToBeDeleted}
|> line(end = [-10, -15])
@ -1516,7 +1525,8 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
async ({ lineToBeDeleted }) => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([5, 6], %)
|> ${lineToBeDeleted}
|> line(end = [-10, -15])

View File

@ -68,20 +68,20 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|> xLine(length = ${commonPoints.num1})`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -89,7 +89,7 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -260,7 +260,8 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([-79.26, 95.04], %)
|> line(end = [112.54, 127.64], tag = $seg02)
|> line(end = [170.36, -121.61], tag = $seg01)
@ -528,7 +529,8 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem(
'persistCode',
`part001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
|> startProfileAt([20, 0], %)
|> line(end = [7.13, 4 + 0])
|> angledLine({ angle = 3 + 0, length = 3.14 + 0 }, %)
@ -747,7 +749,8 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
await page.waitForTimeout(200)
await u.removeCurrentCode()
await u.codeLocator.fill(`sketch001 = startSketchOn(XZ)
await u.codeLocator.fill(`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -965,7 +968,8 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
async ({ cases }) => {
localStorage.setItem(
'persistCode',
`yo = 79
`@settings(defaultLengthUnit = in)
yo = 79
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> ${cases[0].expectedCode}
@ -1020,7 +1024,8 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([-79.26, 95.04], %)
|> line(end = [112.54, 127.64])
|> line(end = [170.36, -121.61], tag = $seg01)
@ -1253,7 +1258,7 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)`
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)`
)
await page.waitForTimeout(600)

View File

@ -271,7 +271,7 @@ test.describe('Testing settings', () => {
const bracketDir = join(dir, projectName)
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
executorInputPath('cylinder-inches.kcl'),
join(bracketDir, 'main.kcl')
)
}
@ -699,19 +699,19 @@ test.describe('Testing settings', () => {
name: 'Current units are: ',
})
await gizmo.click()
const button = page.getByRole('button', {
const button = page.locator('ul').getByRole('button', {
name: copy,
exact: true,
})
await button.click()
const toastMessage = page.getByText(
`Set default unit to "${unitOfMeasure}" for this project`
`Updated per-file units to ${unitOfMeasure}`
)
await expect(toastMessage).toBeVisible()
}
await changeUnitOfMeasureInGizmo('in', 'Inches')
await changeUnitOfMeasureInGizmo('ft', 'Feet')
await changeUnitOfMeasureInGizmo('in', 'Inches')
await changeUnitOfMeasureInGizmo('yd', 'Yards')
await changeUnitOfMeasureInGizmo('mm', 'Millimeters')
await changeUnitOfMeasureInGizmo('cm', 'Centimeters')
@ -951,9 +951,9 @@ test.describe('Testing settings', () => {
)
})
await test.step(`Initial units from settings`, async () => {
await test.step(`Initial units from settings are ignored`, async () => {
await homePage.openProject('project-000')
await expect(unitsIndicator).toHaveText('Current units are: in')
await expect(unitsIndicator).toHaveText('Current units are: mm')
})
await test.step(`Manually write inline settings`, async () => {

View File

@ -67,11 +67,11 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({
angle = HALF_TURN,
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLineToY([segAng(seg04) + 180, ZERO], %)
|> angledLineToY([segAng(seg04) + 180, turns::ZERO], %)
|> angledLineToY({
angle = -bottomAng,
to = -totalHeightHalf - armThick,
@ -79,12 +79,12 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01))
|> angledLineThatIntersects({
angle = HALF_TURN,
angle = turns::HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLineToY([segAng(seg02) + 180, -baseHeight], %)
|> xLine(endAbsolute = ZERO)
|> xLine(endAbsolute = turns::ZERO)
|> close()
|> extrude(length = 4)`
)
@ -483,7 +483,8 @@ test('Sketch on face', async ({ page, homePage, scene, cmdBar, toolbar }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn(XZ)
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfileAt([3.29, 7.86], %)
|> line(end = [2.48, 2.44])
|> line(end = [2.66, 1.17])

View File

@ -13,20 +13,20 @@
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.18.6",
"@codemirror/commands": "^6.8.0",
"@codemirror/commands": "^6.8.1",
"@codemirror/language": "^6.11.0",
"@codemirror/lint": "^6.8.4",
"@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.4.1",
"@codemirror/state": "^6.5.2",
"@codemirror/theme-one-dark": "^6.1.2",
"@csstools/postcss-oklab-function": "^4.0.7",
"@csstools/postcss-oklab-function": "^4.0.8",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.19",
"@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "2.0.21",
"@headlessui/tailwindcss": "^0.2.2",
"@kittycad/lib": "2.0.23",
"@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.1",
"@react-hook/resize-observer": "^2.0.1",
@ -37,11 +37,11 @@
"@xstate/react": "^4.1.1",
"bonjour-service": "^1.3.0",
"bson": "^6.10.3",
"chokidar": "^4.0.1",
"chokidar": "^4.0.3",
"codemirror": "^6.0.1",
"decamelize": "^6.0.0",
"diff": "^7.0.0",
"electron-updater": "^6.6.0",
"electron-updater": "^6.6.2",
"fuse.js": "^7.1.0",
"html2canvas-pro": "^1.5.8",
"isomorphic-fetch": "^3.0.0",
@ -94,9 +94,11 @@
"fetch:wasm": "./scripts/get-latest-wasm-bundle.sh",
"fetch:wasm:windows": "./scripts/get-latest-wasm-bundle.ps1",
"fetch:samples": "rm -rf public/kcl-samples* && curl -L -o public/kcl-samples.zip https://github.com/KittyCAD/kcl-samples/archive/refs/heads/achalmers/kw-args-xylineto.zip && unzip -o public/kcl-samples.zip -d public && mv public/kcl-samples-* public/kcl-samples",
"build:wasm-dev": "yarn wasm-prep && (cd rust && wasm-pack build kcl-wasm-lib --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt:generated",
"build:wasm": "./scripts/build-wasm.sh",
"build:wasm:windows": "./scripts/build-wasm.ps1",
"build:wasm-dev": "yarn build:wasm:dev",
"build:wasm:dev": "./scripts/build-wasm-dev.sh",
"build:wasm:dev:windows": "./scripts/build-wasm-dev.ps1",
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./rust/kcl-wasm-lib/pkg/kcl_wasm_lib.js\" || echo \"sed for both mac and linux\"",
"lint-fix": "eslint --fix --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src",
"lint": "eslint --max-warnings 0 --ext .ts --ext .tsx src e2e packages/codemirror-lsp-client/src rust/kcl-language-server/client/src",
@ -162,15 +164,15 @@
"@iarna/toml": "^2.2.5",
"@lezer/generator": "^1.7.2",
"@nabla/vite-plugin-eslint": "^2.0.5",
"@playwright/test": "^1.51.0",
"@playwright/test": "^1.51.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
"@types/diff": "^7.0.1",
"@types/diff": "^7.0.2",
"@types/electron": "^1.6.10",
"@types/isomorphic-fetch": "^0.0.39",
"@types/minimist": "^1.2.5",
"@types/mocha": "^10.0.10",
"@types/node": "^22.13.9",
"@types/node": "^22.13.14",
"@types/pixelmatch": "^5.2.6",
"@types/pngjs": "^6.0.4",
"@types/react": "^18.3.4",
@ -180,13 +182,13 @@
"@types/ua-parser-js": "^0.7.39",
"@types/uuid": "^9.0.8",
"@types/wicg-file-system-access": "^2023.10.5",
"@types/ws": "^8.5.13",
"@vitejs/plugin-react": "^4.3.0",
"@types/ws": "^8.18.0",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/web-worker": "^1.5.0",
"@xstate/cli": "^0.5.17",
"autoprefixer": "^10.4.19",
"autoprefixer": "^10.4.21",
"electron": "^34.1.1",
"electron-builder": "^26.0.6",
"electron-builder": "^26.0.12",
"eslint": "^8.0.1",
"eslint-plugin-css-modules": "^2.12.0",
"eslint-plugin-import": "^2.31.0",
@ -218,7 +220,7 @@
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.1",
"vitest-webgl-canvas-mock": "^1.1.0",
"ws": "^8.17.0",
"ws": "^8.18.1",
"yarn": "^1.22.22"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"

View File

@ -90,7 +90,7 @@ export default class StreamDemuxer extends Queue<Uint8Array> {
}
add(bytes: Uint8Array): void {
const message = Codec.decode(bytes) as vsrpc.Message
const message = Codec.decode<vsrpc.Message>(bytes)
if (this.trace) {
Tracer.server(message)
}

View File

@ -12,7 +12,7 @@ import "car-tire.kcl" as carTire
import lugCount from "globals.kcl"
carRotor
|> translate(translate = [0, 0.5, 0])
|> translate(x = 0, y = 0.5, z = 0)
carWheel
lugNut
|> patternCircular3d(
@ -23,5 +23,5 @@ lugNut
rotateDuplicates = false,
)
brakeCaliper
|> translate(translate = [0, 0.5, 0])
|> translate(x = 0, y = 0.5, z = 0)
carTire

View File

@ -1,6 +1,7 @@
// Dual-Basin Utility Sink
// A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments.
// set units
@settings(defaultLengthUnit = mm)
// globals
@ -12,7 +13,7 @@ profileThickness = 13
metalThickness = 2
blockCount = 3
blockWidth = (tableWidth-profileThickness) / 3
blockWidth = (tableWidth - profileThickness) / 3
blockHeight = tableHeight - metalThickness - 0.5
blockDepth = tableDepth - profileThickness
@ -27,9 +28,9 @@ legHeight = blockHeight - profileThickness
legCount = blockCount + 1
legBody = startProfileAt([0, 0], floorPlane)
|> yLine(length=profileThickness)
|> xLine(length=profileThickness)
|> yLine(length=-profileThickness)
|> yLine(length = profileThickness)
|> xLine(length = profileThickness)
|> yLine(length = -profileThickness)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = legCount, distance = blockWidth)
@ -42,9 +43,9 @@ lowerBeltLengthX = blockWidth - profileThickness
lowerBeltPlane = startSketchOn(offsetPlane(XY, offset = lowerBeltHeightAboveTheFloor))
lowerBeltBodyX = startProfileAt([profileThickness, 0], lowerBeltPlane)
|> yLine(length=profileThickness)
|> xLine(length=lowerBeltLengthX)
|> yLine(length=-profileThickness)
|> yLine(length = profileThickness)
|> xLine(length = lowerBeltLengthX)
|> yLine(length = -profileThickness)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
@ -53,12 +54,12 @@ lowerBeltBodyX = startProfileAt([profileThickness, 0], lowerBeltPlane)
lowerBeltLengthY = blockDepth - profileThickness
lowerBeltBodyY = startProfileAt([0, profileThickness], lowerBeltPlane)
|> yLine(length=lowerBeltLengthY)
|> xLine(length=profileThickness)
|> yLine(length=-lowerBeltLengthY)
|> yLine(length = lowerBeltLengthY)
|> xLine(length = profileThickness)
|> yLine(length = -lowerBeltLengthY)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth - profileThickness)
|> extrude(length = profileThickness)
// pillars
@ -67,9 +68,9 @@ pillarPlane = startSketchOn(offsetPlane(XY, offset = pillarHeightAboveTheFloor))
pillarTotalHeight = blockHeight - profileThickness - pillarHeightAboveTheFloor
pillarBody = startProfileAt([blockSubdivisionWidth, 0], pillarPlane)
|> yLine(length=profileThickness)
|> xLine(length=profileThickness)
|> yLine(length=-profileThickness)
|> yLine(length = profileThickness)
|> xLine(length = profileThickness)
|> yLine(length = -profileThickness)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = blockCount, distance = blockWidth)
@ -80,9 +81,9 @@ pillarBody = startProfileAt([blockSubdivisionWidth, 0], pillarPlane)
upperBeltPlane = startSketchOn(offsetPlane(XY, offset = blockHeight))
upperBeltBodyX = startProfileAt([0, 0], upperBeltPlane)
|> yLine(length=profileThickness)
|> xLine(length=tableWidth)
|> yLine(length=-profileThickness)
|> yLine(length = profileThickness)
|> xLine(length = tableWidth)
|> yLine(length = -profileThickness)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [0, 1], instances = 2, distance = blockDepth)
@ -90,20 +91,20 @@ upperBeltBodyX = startProfileAt([0, 0], upperBeltPlane)
upperBeltLengthY = blockDepth - profileThickness
upperBeltBodyY = startProfileAt([0, profileThickness], upperBeltPlane)
|> yLine(length=upperBeltLengthY)
|> xLine(length=profileThickness)
|> yLine(length=-upperBeltLengthY)
|> yLine(length = upperBeltLengthY)
|> xLine(length = profileThickness)
|> yLine(length = -upperBeltLengthY)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth-profileThickness)
|> patternLinear2d(axis = [1, 0], instances = 2, distance = tableWidth - profileThickness)
|> extrude(length = -profileThickness)
// sink
tableTopPlane = startSketchOn(offsetPlane(XY, offset = tableHeight))
tableTopBody = startProfileAt([0, 0], tableTopPlane)
|> yLine(length=tableDepth)
|> xLine(length=tableWidth)
|> yLine(length=-tableDepth)
|> yLine(length = tableDepth)
|> xLine(length = tableWidth)
|> yLine(length = -tableDepth)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> extrude(length = -metalThickness)
@ -114,59 +115,62 @@ sinkLength = 250
sinkDepth = 200
sinkOffsetFront = 40
sinkOffsetLeft = 350
sinkSpacing = tableWidth - sinkWidth - sinkOffsetLeft*2
sinkSpacing = tableWidth - sinkWidth - (sinkOffsetLeft * 2)
sinkPlaneOutside = startSketchOn(tableTopBody, 'START')
sinkBodyOutside = startProfileAt([-sinkOffsetLeft, sinkOffsetFront], sinkPlaneOutside)
|> yLine(length=sinkLength)
|> xLine(length=-sinkWidth)
|> yLine(length=-sinkLength)
|> yLine(length = sinkLength)
|> xLine(length = -sinkWidth)
|> yLine(length = -sinkLength)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [-1, 0], instances = sinkCount, distance = sinkSpacing)
|> extrude(length = sinkDepth)
sinkPlaneInside = startSketchOn(tableTopBody, 'END')
sinkBodyInside = startProfileAt([sinkOffsetLeft+metalThickness, sinkOffsetFront+metalThickness], sinkPlaneInside)
|> yLine(length=sinkLength-metalThickness*2)
|> xLine(length=sinkWidth-metalThickness*2)
|> yLine(length=-sinkLength+metalThickness*2)
sinkBodyInside = startProfileAt([
sinkOffsetLeft + metalThickness,
sinkOffsetFront + metalThickness
], sinkPlaneInside)
|> yLine(length = sinkLength - (metalThickness * 2))
|> xLine(length = sinkWidth - (metalThickness * 2))
|> yLine(length = -sinkLength + metalThickness * 2)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = sinkCount, distance = sinkSpacing)
|> extrude(length = -sinkDepth)
// door panels
doorGap = 2
doorWidth = blockSubdivisionWidth - profileThickness - doorGap*2
doorStart = profileThickness+doorGap
doorWidth = blockSubdivisionWidth - profileThickness - (doorGap * 2)
doorStart = profileThickness + doorGap
doorHeightAboveTheFloor = pillarHeightAboveTheFloor + doorGap
doorHeight = blockHeight - doorHeightAboveTheFloor - profileThickness - doorGap
doorCount = blockCount * blockSubdivisionCount
doorPlane = startSketchOn(offsetPlane(XY, offset = doorHeightAboveTheFloor))
doorBody = startProfileAt([doorStart, 0], doorPlane)
|> yLine(length=profileThickness)
|> xLine(length=doorWidth)
|> yLine(length=-profileThickness)
|> yLine(length = profileThickness)
|> xLine(length = doorWidth)
|> yLine(length = -profileThickness)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = doorCount, distance = blockSubdivisionWidth)
|> extrude(length = doorHeight)
// side panels
panelWidth = blockDepth - profileThickness - doorGap*2
panelWidth = blockDepth - profileThickness - (doorGap * 2)
panelCount = doorCount + 1
panelSpacing = tableWidth - profileThickness
panelBody = startProfileAt([0, doorStart], doorPlane)
|> yLine(length=panelWidth)
|> xLine(length=profileThickness)
|> yLine(length=-panelWidth)
|> yLine(length = panelWidth)
|> xLine(length = profileThickness)
|> yLine(length = -panelWidth)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
|> patternLinear2d(axis = [1, 0], instances = 2, distance = panelSpacing)
|> extrude(length = doorHeight)
// handle
handleDepth = 40
handleWidth = 120
@ -179,22 +183,25 @@ handleLengthSegmentB = handleWidth - (handleFillet * 2)
handlePlane = startSketchOn(offsetPlane(XY, offset = handleHeightAboveTheFloor))
handleProfilePath = startProfileAt([0 + handleOffset, 0], handlePlane)
|> yLine(length=-handleLengthSegmentA)
|> yLine(length = -handleLengthSegmentA)
|> tangentialArcTo([
handleFillet + handleOffset,
-handleDepth
], %)
|> xLine(length=handleLengthSegmentB)
|> xLine(length = handleLengthSegmentB)
|> tangentialArcTo([
handleOffset + handleWidth,
-handleLengthSegmentA
], %)
|> yLine(length=handleLengthSegmentA)
|> yLine(length = handleLengthSegmentA)
handleSectionPlane = startSketchOn(XZ)
handleProfileSection = circle(
handleSectionPlane,
center = [handleOffset, handleHeightAboveTheFloor],
radius = 2)
center = [
handleOffset,
handleHeightAboveTheFloor
],
radius = 2,
)
handleBody = sweep(handleProfileSection, path = handleProfilePath)
|> patternLinear3d(axis = [1, 0, 0], instances = doorCount, distance = blockSubdivisionWidth)

View File

@ -5,7 +5,7 @@
@settings(defaultLengthUnit = in)
// Define Beam Dimensions
beamLength = 6*ft()
beamLength = 6 * ft()
beamHeight = 4
flangeWidth = 2.663
flangeThickness = 0.293

View File

@ -52,19 +52,22 @@ armPartB = armFn(XZ, armLength, hingeHeight * 2.5 + hingeGap * 2)
// mirror
fn mirrorFn(plane, offsetX, offsetY, altitude, radius, tiefe, gestellR, gestellD) {
armPlane = startSketchOn(offsetPlane(plane, offset = offsetY - (tiefe / 2)))
armPlane = startSketchOn( offsetPlane(plane, offset = offsetY - (tiefe / 2)))
armBody = circle(armPlane, center = [offsetX, altitude], radius = radius)
|> extrude(length = tiefe)
archBody = startProfileAt([offsetX-gestellR, altitude], armPlane)
archBody = startProfileAt([offsetX - gestellR, altitude], armPlane)
|> xLine(length = gestellD)
|> arcTo({
interior = [offsetX, altitude-gestellR],
end = [offsetX+gestellR, altitude]
interior = [offsetX, altitude - gestellR],
end = [offsetX + gestellR, altitude]
}, %)
|> xLine(length = gestellD)
|> arcTo({
interior = [offsetX, altitude-gestellR-gestellD],
interior = [
offsetX,
altitude - gestellR - gestellD
],
end = [profileStartX(%), profileStartY(%)]
}, %)
|> close()
@ -72,4 +75,4 @@ fn mirrorFn(plane, offsetX, offsetY, altitude, radius, tiefe, gestellR, gestellD
return armBody
}
mirror = mirrorFn(XZ, armLength, armLength, hingeHeight * 4 + hingeGap * 3 + mirrorRadius+archToMirrorGap+archThickness, mirrorRadius, mirrorThickness, archRadius, archThickness)
mirror = mirrorFn(XZ, armLength, armLength, hingeHeight * 4 + hingeGap * 3 + mirrorRadius + archToMirrorGap + archThickness, mirrorRadius, mirrorThickness, archRadius, archThickness)

View File

@ -4,7 +4,6 @@
// set units
@settings(defaultLengthUnit = in)
// import constants
import boltDiameter, boltLength, boltHeadLength, boltHeadDiameter, boltHexDrive, boltHexFlatLength, boltThreadLength from "globals.kcl"

View File

@ -1,5 +1,5 @@
// 98017A257 Washer
// washer for the screws in the pipe flange assembly.
// washer for the screws in the pipe flange assembly.
// set units
@settings(defaultLengthUnit = in)

View File

@ -19,27 +19,15 @@ import pipe from "1120t74-pipe.kcl"
flange()
flange()
|> rotate(axis = [0, 1, 0], angle = 180)
|> translate(translate = [
0,
0,
flangeBackHeight * 2 + gasketThickness
])
|> translate(x = 0, y = 0, z = flangeBackHeight * 2 + gasketThickness)
// place gasket between the flanges
gasket()
|> translate(translate = [
0,
0,
-flangeBackHeight - gasketThickness
])
|> translate(x = 0, y = 0, z = -flangeBackHeight - gasketThickness)
// place eight washers (four front, four back)
washer()
|> translate(translate = [
mountingHolePlacementDiameter / 2,
0,
flangeBaseThickness
])
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = flangeBaseThickness)
|> patternCircular3d(
%,
instances = 4,
@ -57,11 +45,7 @@ washer()
// place four bolts
bolt()
|> translate(translate = [
mountingHolePlacementDiameter / 2,
0,
flangeBaseThickness + washerThickness
])
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = flangeBaseThickness + washerThickness)
|> rotate(roll = 90, pitch = 0, yaw = 0)
|> patternCircular3d(
%,
@ -74,11 +58,7 @@ bolt()
// place four hex nuts
hexNut()
|> translate(translate = [
mountingHolePlacementDiameter / 2,
0,
-(flangeBackHeight * 2 + gasketThickness + flangeBaseThickness + washerThickness + hexNutThickness)
])
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = -(flangeBackHeight * 2 + gasketThickness + flangeBaseThickness + washerThickness + hexNutThickness))
|> patternCircular3d(
%,
instances = 4,
@ -98,11 +78,9 @@ pipe()
)
|> translate(
%,
translate = [
0,
0,
flangeBaseThickness + flangeFrontHeight - 0.5
],
x = 0,
y = 0,
z = flangeBaseThickness + flangeFrontHeight - 0.5,
global = true,
)
@ -115,10 +93,8 @@ pipe()
)
|> translate(
%,
translate = [
0,
0,
-(flangeBackHeight * 2 + gasketThickness + flangeBaseThickness + flangeFrontHeight - 0.5)
],
x = 0,
y = 0,
z = -(flangeBackHeight * 2 + gasketThickness + flangeBaseThickness + flangeFrontHeight - 0.5),
global = true,
)

View File

@ -14,7 +14,7 @@ radius = 10
depth = 30
distanceToInsideEdge = slateWidthHalf + templateThickness + templateGap
sketch001 = startSketchOn(XZ)
|> startProfileAt([ZERO, depth + templateGap], %)
|> startProfileAt([0, depth + templateGap], %)
|> xLine(length = slateWidthHalf - radius, tag = $seg01)
|> arc({
angleEnd = 0,
@ -28,7 +28,7 @@ sketch001 = startSketchOn(XZ)
|> yLine(length = templateThickness * 2, tag = $seg08)
|> xLine(endAbsolute = segEndX(seg02) + 0, tag = $seg05)
|> yLine(endAbsolute = segEndY(seg01) + templateThickness, tag = $seg10)
|> xLine(endAbsolute = ZERO, tag = $seg04)
|> xLine(endAbsolute = 0, tag = $seg04)
|> xLine(length = -segLen(seg04))
|> yLine(length = -segLen(seg10))
|> xLine(length = -segLen(seg05))

View File

@ -28,7 +28,7 @@ sketch001 = startSketchOn(XZ)
|> yLine(endAbsolute = -templateGap * 2 - (templateDiameter / 2), tag = $seg05)
|> xLine(endAbsolute = slateWidthHalf + templateThickness, tag = $seg04)
|> yLine(length = -length002, tag = $seg03)
|> xLine(endAbsolute = ZERO, tag = $seg02)
|> xLine(endAbsolute = 0, tag = $seg02)
// |> line(end = [7.78, 11.16])
|> xLine(length = -segLen(seg02))
|> yLine(length = segLen(seg03))

View File

@ -20,37 +20,25 @@ body()
// import the antenna
antenna()
|> translate(translate = [-width / 2 + .45, -0.10, height / 2])
|> translate(x = -width / 2 + .45, y = -0.10, z = height / 2)
// import the case
case()
|> translate(translate = [0, -1, 0])
|> translate(x = 0, y = -1, z = 0)
// import the talk button
talkButton()
|> translate(translate = [width / 2, -thickness / 2, .5])
|> translate(x = width / 2, y = -thickness / 2, z = .5)
// import the frequency knob
knob()
|> translate(translate = [
width / 2 - 0.70,
-thickness / 2,
height / 2
])
|> translate(x = width / 2 - 0.70, y = -thickness / 2, z = height / 2)
// import the buttons
button()
|> translate(translate = [
-(screenWidth / 2 + tolerance),
-1,
screenYPosition
])
|> translate(x = -(screenWidth / 2 + tolerance), y = -1, z = screenYPosition)
button()
|> translate(translate = [
-(screenWidth / 2 + tolerance),
-1,
screenYPosition - buttonHeight - (tolerance * 2)
])
|> translate(x = -(screenWidth / 2 + tolerance), y = -1, z = screenYPosition - buttonHeight - (tolerance * 2))
button()
|> rotate(
%,
@ -59,11 +47,9 @@ button()
yaw = 0,
)
|> translate(
translate = [
screenWidth / 2 + tolerance,
-1,
screenYPosition - buttonHeight
],
x = screenWidth / 2 + tolerance,
y = -1,
z = screenYPosition - buttonHeight,
global = true,
)
button()
@ -74,10 +60,8 @@ button()
yaw = 0,
)
|> translate(
translate = [
screenWidth / 2 + tolerance,
-1,
screenYPosition - (buttonHeight * 2) - (tolerance * 2)
],
x = screenWidth / 2 + tolerance,
y = -1,
z = screenYPosition - (buttonHeight * 2) - (tolerance * 2),
global = true,
)

24
rust/Cargo.lock generated
View File

@ -1780,7 +1780,7 @@ dependencies = [
[[package]]
name = "kcl-bumper"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"anyhow",
"clap",
@ -1791,7 +1791,7 @@ dependencies = [
[[package]]
name = "kcl-derive-docs"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"Inflector",
"anyhow",
@ -1810,7 +1810,7 @@ dependencies = [
[[package]]
name = "kcl-directory-test-macro"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"proc-macro2",
"quote",
@ -1819,7 +1819,7 @@ dependencies = [
[[package]]
name = "kcl-language-server"
version = "0.2.55"
version = "0.2.56"
dependencies = [
"anyhow",
"clap",
@ -1840,7 +1840,7 @@ dependencies = [
[[package]]
name = "kcl-language-server-release"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"anyhow",
"clap",
@ -1860,7 +1860,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.2.55"
version = "0.2.56"
dependencies = [
"anyhow",
"approx 0.5.1",
@ -1928,7 +1928,7 @@ dependencies = [
[[package]]
name = "kcl-python-bindings"
version = "0.3.55"
version = "0.3.56"
dependencies = [
"anyhow",
"kcl-lib",
@ -1943,7 +1943,7 @@ dependencies = [
[[package]]
name = "kcl-test-server"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"anyhow",
"hyper 0.14.32",
@ -1956,7 +1956,7 @@ dependencies = [
[[package]]
name = "kcl-to-core"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"anyhow",
"async-trait",
@ -1970,7 +1970,7 @@ dependencies = [
[[package]]
name = "kcl-wasm-lib"
version = "0.1.55"
version = "0.1.56"
dependencies = [
"bson",
"console_error_panic_hook",
@ -1996,9 +1996,9 @@ dependencies = [
[[package]]
name = "kittycad"
version = "0.3.33"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f6f65645cc07a8f43c34584e4979bf4da16c047cce50c4715fa9381227574d5"
checksum = "0a345fd2a4cb16205f32bd1aa41715045830c59d78c59927fca6580e2a651ac9"
dependencies = [
"anyhow",
"async-trait",

View File

@ -35,7 +35,7 @@ clap = { version = "4.5.31", features = ["derive"] }
dashmap = { version = "6.1.0" }
http = "1"
indexmap = "2.7.0"
kittycad = { version = "0.3.33", default-features = false, features = ["js", "requests"] }
kittycad = { version = "0.3.36", default-features = false, features = ["js", "requests"] }
kittycad-modeling-cmds = { version = "0.2.107", features = ["ts-rs", "websocket"] }
lazy_static = "1.5.0"
miette = "7.5.0"

View File

@ -43,6 +43,10 @@ overwrite-sim-test test_name:
EXPECTORATE=overwrite TWENTY_TWENTY=overwrite {{cita}} -p kcl-lib --no-quiet -- tests::{{test_name}}::kcl_test_execute
EXPECTORATE=overwrite {{cita}} -p kcl-lib --no-quiet -- simulation_tests::{{test_name}}::test_after_engine
# Regenerate all the simulation test output.
redo-sim-tests:
EXPECTORATE=overwrite TWENTY_TWENTY=overwrite {{cita}} -p kcl-lib --no-quiet -- simulation_tests
test:
export RUST_BRACKTRACE="full" && cargo nextest run --workspace --no-fail-fast

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-bumper"
version = "0.1.55"
version = "0.1.56"
edition = "2021"
repository = "https://github.com/KittyCAD/modeling-api"
rust-version = "1.76"

View File

@ -1,7 +1,7 @@
[package]
name = "kcl-derive-docs"
description = "A tool for generating documentation from Rust derive macros"
version = "0.1.55"
version = "0.1.56"
edition = "2021"
license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -329,7 +329,7 @@ fn do_stdlib_inner(
let camel_case_arg_name = to_camel_case(&arg_name);
if ty_string != "ExecState" && ty_string != "Args" {
let schema = quote! {
#docs_crate::cleanup_number_tuples_root(generator.root_schema_for::<#ty_ident>())
generator.root_schema_for::<#ty_ident>()
};
arg_types.push(quote! {
#docs_crate::StdLibFnArg {
@ -394,7 +394,7 @@ fn do_stdlib_inner(
let return_type = if !ret_ty_string.is_empty() || ret_ty_string != "()" {
let ret_ty_string = rust_type_to_openapi_type(&ret_ty_string);
quote! {
let schema = #docs_crate::cleanup_number_tuples_root(generator.root_schema_for::<#return_type_inner>());
let schema = generator.root_schema_for::<#return_type_inner>();
Some(#docs_crate::StdLibFnArg {
name: "".to_string(),
type_: #ret_ty_string.to_string(),
@ -816,7 +816,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
async fn #test_name() -> miette::Result<()> {
let code = #code_block;
// Note, `crate` must be kcl_lib
let result = match crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm, None).await {
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,

View File

@ -31,13 +31,7 @@ mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_someFn0() -> miette::Result<()> {
let code = "someFn()";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -108,7 +102,7 @@ impl crate::docs::StdLibFn for SomeFn {
vec![crate::docs::StdLibFnArg {
name: "data".to_string(),
type_: "Foo".to_string(),
schema: crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<Foo>()),
schema: generator.root_schema_for::<Foo>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -120,7 +114,7 @@ impl crate::docs::StdLibFn for SomeFn {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<i32>());
let schema = generator.root_schema_for::<i32>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "i32".to_string(),

View File

@ -31,13 +31,7 @@ mod test_examples_someFn {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_someFn0() -> miette::Result<()> {
let code = "someFn()";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -108,7 +102,7 @@ impl crate::docs::StdLibFn for SomeFn {
vec![crate::docs::StdLibFnArg {
name: "data".to_string(),
type_: "string".to_string(),
schema: crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<str>()),
schema: generator.root_schema_for::<str>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -120,7 +114,7 @@ impl crate::docs::StdLibFn for SomeFn {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<i32>());
let schema = generator.root_schema_for::<i32>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "i32".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show0() -> miette::Result<()> {
let code = "This is another code block.\nyes sirrr.\nshow";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,9 +103,7 @@ impl crate::docs::StdLibFn for Show {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "[number]".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<[f64; 2usize]>(),
),
schema: generator.root_schema_for::<[f64; 2usize]>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -123,7 +115,7 @@ impl crate::docs::StdLibFn for Show {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>());
let schema = generator.root_schema_for::<f64>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "number".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show0() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nshow";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,7 +103,7 @@ impl crate::docs::StdLibFn for Show {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "number".to_string(),
schema: crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>()),
schema: generator.root_schema_for::<f64>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -121,7 +115,7 @@ impl crate::docs::StdLibFn for Show {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>());
let schema = generator.root_schema_for::<f64>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "number".to_string(),

View File

@ -33,13 +33,7 @@ mod test_examples_my_func {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_my_func0() -> miette::Result<()> {
let code = "This is another code block.\nyes sirrr.\nmyFunc";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -110,9 +104,7 @@ impl crate::docs::StdLibFn for MyFunc {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
),
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
required: false,
label_required: true,
description: String::new().to_string(),
@ -124,8 +116,7 @@ impl crate::docs::StdLibFn for MyFunc {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema =
crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<Vec<Sketch>>());
let schema = generator.root_schema_for::<Vec<Sketch>>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[Sketch]".to_string(),

View File

@ -33,13 +33,7 @@ mod test_examples_line_to {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_line_to0() -> miette::Result<()> {
let code = "This is another code block.\nyes sirrr.\nlineTo";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -111,9 +105,7 @@ impl crate::docs::StdLibFn for LineTo {
crate::docs::StdLibFnArg {
name: "data".to_string(),
type_: "LineToData".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<LineToData>(),
),
schema: generator.root_schema_for::<LineToData>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -122,9 +114,7 @@ impl crate::docs::StdLibFn for LineTo {
crate::docs::StdLibFnArg {
name: "sketch".to_string(),
type_: "Sketch".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Sketch>(),
),
schema: generator.root_schema_for::<Sketch>(),
required: true,
label_required: true,
description: "the sketch you're adding the line to".to_string(),
@ -137,7 +127,7 @@ impl crate::docs::StdLibFn for LineTo {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<Sketch>());
let schema = generator.root_schema_for::<Sketch>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "Sketch".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_min {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_min0() -> miette::Result<()> {
let code = "This is another code block.\nyes sirrr.\nmin";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,9 +103,7 @@ impl crate::docs::StdLibFn for Min {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "[number]".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Vec<f64>>(),
),
schema: generator.root_schema_for::<Vec<f64>>(),
required: true,
label_required: true,
description: String::new().to_string(),
@ -123,7 +115,7 @@ impl crate::docs::StdLibFn for Min {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>());
let schema = generator.root_schema_for::<f64>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "number".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_show0() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nshow";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,9 +103,7 @@ impl crate::docs::StdLibFn for Show {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "number".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Option<f64>>(),
),
schema: generator.root_schema_for::<Option<f64>>(),
required: false,
label_required: true,
description: String::new().to_string(),
@ -123,7 +115,7 @@ impl crate::docs::StdLibFn for Show {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>());
let schema = generator.root_schema_for::<f64>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "number".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_import0() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nimport";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,9 +103,7 @@ impl crate::docs::StdLibFn for Import {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
),
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
required: false,
label_required: true,
description: String::new().to_string(),
@ -123,7 +115,7 @@ impl crate::docs::StdLibFn for Import {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<f64>());
let schema = generator.root_schema_for::<f64>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "number".to_string(),

View File

@ -32,13 +32,7 @@ mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_import0() -> miette::Result<()> {
let code = "This is code.\nIt does other shit.\nimport";
let result = match crate::test_server::execute_and_snapshot(
code,
crate::settings::types::UnitLength::Mm,
None,
)
.await
{
let result = match crate::test_server::execute_and_snapshot(code, None).await {
Err(crate::errors::ExecError::Kcl(e)) => {
return Err(miette::Report::new(crate::errors::Report {
error: e.error,
@ -109,9 +103,7 @@ impl crate::docs::StdLibFn for Import {
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: crate::docs::cleanup_number_tuples_root(
generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
),
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
required: false,
label_required: true,
description: String::new().to_string(),
@ -123,8 +115,7 @@ impl crate::docs::StdLibFn for Import {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema =
crate::docs::cleanup_number_tuples_root(generator.root_schema_for::<Vec<Sketch>>());
let schema = generator.root_schema_for::<Vec<Sketch>>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[Sketch]".to_string(),

Some files were not shown because too many files have changed in this diff Show More