Compare commits

...

115 Commits

Author SHA1 Message Date
9860294eb1 Release kcl kcl-0.2.18 2024-09-23 11:35:42 -04:00
1c393bfa84 Add E2E regression test that the gizmo remains at far zooms (#3923)
* Add E2E regression test that the gizmo remains at far zooms

* Tweak test's plane color, it's slightly different in CI
2024-09-23 10:33:47 -04:00
95ea1427bc Show device token while signing in (#3935)
* Show user code while logging in

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* @jtran feedback

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 5ba9e4351a.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-09-23 10:17:56 -04:00
f1b0e40388 Circle function and UI tool (#3860)
* circle

* fix another example

* fix bad comment

* toPoint fix

* cargo fmt

* resolve most of the tests

* fix last test

* missed circle in bracket

* remove console error

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* trigger ci

* remove three dot menu for circle

* make sure circle can be extruded

* fix up after merge

* add extrude test for circle

* clean up

* typo

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 03f8eeb542.

* update docs again

* cmd bar test serialisation improvements

* tiny clean up

* fix after: Replace kittycad crate with kittycad-modeling-cmds

* fmt

* rename fix

* Update src/lib/toolbar.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

* add another error to list

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* image updates

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)"

This reverts commit 505bb20bea.

* update markdown

* skip un reproducable windows test failure

* rust review

* leave issue todo comment

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-09-23 07:42:51 -05:00
max
7848d63177 add multiple selections support for focusPath (#3944) 2024-09-23 08:07:31 +02:00
619b059ae1 Bump vite from 5.4.3 to 5.4.6 (#3911) 2024-09-22 02:06:09 +00:00
429fc3eb1b Release KCL 0.2.17 (#3945) 2024-09-21 16:02:25 -05:00
615f661cbb Bump express from 4.19.2 to 4.21.0 (#3929) 2024-09-21 11:26:37 -04:00
6e0675cfda Cut release v0.25.3 (#3942) 2024-09-21 23:31:00 +10:00
3e79b90884 Use kittycad-modeling-cmds from crates.io (#3939) 2024-09-20 16:33:38 -05:00
5a0a635995 No more empty outputs from modeling API (#3931)
* WIP: No more empty outputs from modeling API

Part of https://github.com/KittyCAD/modeling-api/issues/518

* Remove unused import

* Keep Empty in the API

* Fix TS type error due to upgrade to ts_rs 10.0.0

* Fix warning about unused use

* Fix more type errors from ts_rs upgrade

* De-flake settings override desktop test

* Update export test file sizes

---------

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
2024-09-20 16:28:52 -05:00
93d9b10e11 Bump bson from 2.12.0 to 2.13.0 in /src/wasm-lib (#3933)
Bumps [bson](https://github.com/mongodb/bson-rust) from 2.12.0 to 2.13.0.
- [Release notes](https://github.com/mongodb/bson-rust/releases)
- [Commits](https://github.com/mongodb/bson-rust/compare/v2.12.0...v2.13.0)

---
updated-dependencies:
- dependency-name: bson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-20 10:21:11 -07:00
166487433c Bump ts-rs from 9.0.1 to 10.0.0 in /src/wasm-lib (#3934)
Bumps [ts-rs](https://github.com/Aleph-Alpha/ts-rs) from 9.0.1 to 10.0.0.
- [Release notes](https://github.com/Aleph-Alpha/ts-rs/releases)
- [Changelog](https://github.com/Aleph-Alpha/ts-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Aleph-Alpha/ts-rs/compare/v9.0.1...v10.0.0)

---
updated-dependencies:
- dependency-name: ts-rs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-20 10:20:42 -07:00
5512f99997 Add a test step to confirm the solid bg of the settings dialog (#3927) 2024-09-20 12:04:36 -04:00
01cc9e751b implement from for unit length (#3932)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-19 17:24:09 -07:00
bfac6b7dc8 bump the world (kcl-lib) (#3930)
* bump the world

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit e095d2a990.

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-19 16:31:32 -07:00
d1f9a02ffa fix dumb ass logic bug with edge cuts, actually extends edge cuts array versus overwriting it lolz (#3928)
* dumb ass logic bug with edge cuts

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

* change order

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 1ad9eb315e.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)"

This reverts commit 4004c9c1db.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 57d0d05d06.

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-19 14:50:36 -07:00
d8236dd8da Fix zoom callback on camera controls (#3924) 2024-09-19 21:26:27 +00:00
dabf256e2b change to index map, re-fmt, and fillet face id (#3926)
* change to index map, re-fmt, and fillet face id

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

* fixes

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-19 21:06:29 +00:00
4285e81001 Nadro/2833/zoom level increase when swapping sketch modes (#3854)
* fix: fixing logic around setting the perspective and position of perspective camera when leaving sketch mode

* fix: typo

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 60b12ffc54.

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)"

This reverts commit 9ab973c6c4.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* remove unused vars

* fix: fixed the positions of the mouse clicks since the zoom level has changed?

* fix: updating test to make it work with my new zoom level

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-09-19 14:39:32 -05:00
370375c328 Should we bump power precedence? (#3900)
* Should we bump power predecence

* add test

* fix stupid test name
2024-09-19 19:31:41 +10:00
9f22882c68 Add tests that verify folder deletion behavior (#3719)
* Move file tree deletion tests into file-tree.spect.ts

* Move other file tree tests into file-tree.spec.ts

* Add tests that prove we show a deletion confirmation for folders

* Fix lint warning
2024-09-19 15:15:02 +10:00
db5331d9b9 Rename UserVal::set to new to be clearer (#3913) 2024-09-19 00:23:19 +00:00
5cc92f0162 Replace kittycad crate with kittycad-modeling-cmds (#3909)
lib.rs/kittycad-modeling-cmds is the source of our Modeling API. It gets included in our backend APIs, and those APIs generate OpenAPI specs which are read by `openapitor` which generates the lib.rs/kittycad crate. So basically, our modeling app is using the _generated code_ instead of the _handwritten code_.

This sucks -- if you add a new field to the modeling-api crate, you have to merge PRs to the engine, api-deux, and kittycad.rs before finally you can get the new field into the modeling-app. I was pretty embarrased when @mlfarrell asked how to get a new field into the modeling app and had to explain this whole bullshit cycle. Let's fix it.

Switching to use the kittycad-modeling-cmds (aka kcmc) crate directly should speed up our dev cycle.
2024-09-18 17:04:04 -05:00
2978e80226 Bump vite from 5.4.2 to 5.4.3 (#3788)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.2 to 5.4.3.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.3/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-09-18 14:22:00 +10:00
4a74c60150 Shell two at once from the same sketch on face (#3908)
* shell two at once from the same obhject

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-17 18:49:08 -07:00
00fa40bbc9 Bug fix: make dismiss during export not fire success toast (#3882)
* Bug fix: make dismiss during export not fire success toast

* Fix export fail test, since this failure errors early now

* Remove throttling from send side

* Move toast.loading out to when first engine command is sent, so it is shown immediately

* Use shared, named constants for toast messages

* Hook up a couple other error toasts to the `pendingExport.toastId`
2024-09-17 19:06:06 -04:00
max
62b78840b6 Fix canExtrudeSelectionItem and getSelectionType for multiple selections (#3884)
* fix isSketchPipe in canExtrudeSelectionItem

* fix count in getSelectionType

used to count only same type as first selection
2024-09-17 22:32:07 +02:00
f828c36e58 renaming extrude to sweep to generalize the command (#3773)
* fix: just a one liner? forcing a revolve to be an extrude artifact

* fix: first step in renaming ExtrusionArtifact to SweepArtifact

* fix: renaming extrusion to sweep for a few things? need to do another pass

* fix: cleaning up comments, fixing unit tests for new key names

* fix: unit test update

* fix: removing TODO comments that are not needed

* fix: renaming more extrude/extrusion values to sweep

* fix: test:nowatch -u to update the vitests

* Look at this (photo)Graph *in the voice of Nickelback*

* fix: removing TODOs

* fix: forgot to update the extrudeEdge string in other files

* chore: adding e2e test to see if users can sketch on revolved face

* fix: removing garbage string

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-17 13:22:53 -05:00
8c5b146c94 Nadro/3716/mvp revolve (#3728)
* chore: Implemented a executeAst interrupt to stop processing a KCL program

* fix: added a catch since this promise was not being caught

* fix: fmt formatting, need to fix some tsc errors next.

* fix: fixing tsc errors

* fix: cleaning up comment

* fix: only rejecting pending modeling commands

* fix: adding constant for rejection message, adding rejection in WASM send command

* fix: tsc, lint, fmt checks

* feat: first pass over revolve with basic hard coded X axis

* fix: updated revolve status for DEV only

* fix: adding some TODOs to warn others about the Revolve MVP

* fix: fmt, lint, tsc checks

* fix: codespell got me

* fix: xstate v5 upgrade

* fix: removing this fix for a different PR. Not needed for initial MVP

* fix: renaming extrude function to sweep since it fixes extrude and revolve now

* fix: updating selection logic to support revolve

* fix: renaming extrude to sweep since it adds revolve

* fix: swapping as for type in function parameters

* fix: updated from object destruct to structuredClone

* fix: addressing PR comments

* fix: one other typo for return value of revolve
2024-09-17 08:29:52 -05:00
61c7d9844d Make light theme borders more contrasting, update sidebar icons (#3883)
* Make light theme borders more contrasting

* Update icons in sidebar

* fix disabled styles on ActionIcon

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Update src/components/CustomIcon.tsx

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* trigger CI

* fmt

* Update "Make" button test locator to be more specific

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-09-16 17:12:54 -04:00
8d48c17395 Fix: Opposite adjacent edge selection (#3896)
* fix opposite adjacent edge selection

* make test more robust
2024-09-17 05:38:58 +10:00
0ff820d4da Unify execution state into a single struct (#3877)
* Add ExecState that combines ProgramMemory and DynamicState

* Remove unneeded clones

* Add exec_state parameter to all KCL stdlib functions

* Move pipe value into ExecState

* Add test for pipe substitution not leaking into function calls

* KCL: Better message on assertEqual function

Also add a new no-visual test for performance testing.

* Fix new array module to use ExecState

---------

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2024-09-16 19:10:33 +00:00
c4ff1c2ef1 Update types.md for constants (#3899)
Update types.md
2024-09-16 11:50:59 -07:00
b6aba2f29c Bump once_cell from 1.19.0 to 1.20.0 in /src/wasm-lib (#3889)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.19.0 to 1.20.0.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.19.0...v1.20.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 11:34:58 -07:00
7467f7ea50 Bump pyo3 from 0.22.2 to 0.22.3 in /src/wasm-lib (#3890)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.22.2 to 0.22.3.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/v0.22.3/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.22.2...v0.22.3)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 11:34:36 -07:00
0c6d3e0ccf Bump pretty_assertions from 1.4.0 to 1.4.1 in /src/wasm-lib (#3893)
Bumps [pretty_assertions](https://github.com/rust-pretty-assertions/rust-pretty-assertions) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/rust-pretty-assertions/rust-pretty-assertions/releases)
- [Changelog](https://github.com/rust-pretty-assertions/rust-pretty-assertions/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-pretty-assertions/rust-pretty-assertions/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: pretty_assertions
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 11:34:22 -07:00
e82917ea01 Bump anyhow from 1.0.88 to 1.0.89 in /src/wasm-lib (#3892)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.88 to 1.0.89.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.88...1.0.89)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 11:32:54 -07:00
857c1aad3d Bump tokio-tungstenite from 0.23.1 to 0.24.0 in /src/wasm-lib (#3891)
Bumps [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) from 0.23.1 to 0.24.0.
- [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md)
- [Commits](https://github.com/snapview/tokio-tungstenite/commits/v0.24.0)

---
updated-dependencies:
- dependency-name: tokio-tungstenite
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 11:31:55 -07:00
dc73acb1b1 KCL: Better message on assertEqual function (#3898)
Also add a new no-visual test for performance testing.
2024-09-16 11:43:49 -05:00
8602e937d3 Cut release v0.25.2 (#3879)
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2024-09-16 11:45:13 -04:00
a2133d8317 Add updater-test back after electron migration (#3873)
* Add updater-test back after electron migration
Fixes #3871

* Separate updater-test files more

* Push dummy 0.999.999 version to updater-test

* Push 0.255.255

* Revert dummy push commits

* Clean up
2024-09-16 04:58:30 -04:00
39ce0da3e5 Fail playwright tests when console errors exists (#3345)
* initial console error whitelist

* add testInfo to the beforeEach

* set  COLLECT_CONSOLE_ERRORS

* add more console errors

* temporarily  set max_retrys to 0 instead of 4

* more console errors

* revert max retries back to 4

* add 'necessary' to complete sentence

* tweak env var name

* update whitelist

* test disabling flag

* update whitelist

* lint + enable for chrome only

* re-enabled on CI

* re-order whitelist

* create failOnConsoleErrors

* try update list

* add more to list

* tweak list again

* tweak again<

* tweak again

* tweak

* testInfo

* increase timeout

---------

Co-authored-by: ryanrosello-og <ry@zoo.dev>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-09-16 07:32:33 +10:00
f235a950b0 KCL stdlib reduce function (#3881)
Adds an `arrayReduce` function to KCL stdlib. Right now, it can only reduce SketchGroup values because my implementation of higher-order KCL functions sucks. But we will generalize it in the future to be able to reduce any type.

This simplifies sketching polygons, e.g.

```
fn decagon = (radius) => {
  let step = (1/10) * tau()
  let sketch = startSketchAt([
    (cos(0) * radius), 
    (sin(0) * radius),
  ])
  return arrayReduce([1..10], sketch, (i, sg) => {
      let x = cos(step * i) * radius
      let y = sin(step * i) * radius
      return lineTo([x, y], sg)
  })
}
```

Part of #3842
2024-09-14 00:10:17 -04:00
3cd3e1af72 Bug fix: make "phantom side panes" get properly cleared (#3878)
* Write a failing test

* Make `openPanes` get cleared of any hidden panes

* Grrr fmt
2024-09-13 14:49:33 -04:00
8c6266e94b Bump bson from 2.11.0 to 2.12.0 in /src/wasm-lib (#3869)
Bumps [bson](https://github.com/mongodb/bson-rust) from 2.11.0 to 2.12.0.
- [Release notes](https://github.com/mongodb/bson-rust/releases)
- [Commits](https://github.com/mongodb/bson-rust/compare/v2.11.0...v2.12.0)

---
updated-dependencies:
- dependency-name: bson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 09:42:02 -07:00
755a6016c7 Bump insta from 1.38.0 to 1.40.0 in /src/wasm-lib (#3840)
Bumps [insta](https://github.com/mitsuhiko/insta) from 1.38.0 to 1.40.0.
- [Release notes](https://github.com/mitsuhiko/insta/releases)
- [Changelog](https://github.com/mitsuhiko/insta/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mitsuhiko/insta/compare/1.38.0...1.40.0)

---
updated-dependencies:
- dependency-name: insta
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 09:41:38 -07:00
1cbbefba97 Update Onboarding Bracket (#3874)
* Update Onboarding Bracket

* update KCL header

* update text to go to last character in onboarding code and delete for error reporting

* update allowable tensile stress

* Update test

* fix text

* run prettier

* Make error message in tooltip not matter

* Image asset path needs to be relative on desktop

---------

Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-09-13 11:24:31 -04:00
8610d606f4 Refactor clientSide scene (#3859)
* refactor clientSide scene

* start consolidate threejs segment funcitons

* rename stuff

* first pass of integrating threejs segment create and update into one

* reduce create segment complexity

* add color back in

* use input

* fix comment

* feedback changes
2024-09-13 21:14:14 +10:00
728e87a627 Remove most of modelingMachine.context.store (#3867) 2024-09-12 22:06:50 -04:00
772034af68 Sketch on face of chamfer now works, added an example (#3876)
* sketch on face of chamfer example

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

* sketch on face of chamfer example

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

* make pretty

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-12 16:13:11 -07:00
957a9ca4fe bump kittycad.rs (#3875)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-12 14:23:54 -07:00
max
472eb2bafe AST mod for Multi-Edge Fillets (#3724)
* test

* test + selection loop

* wipe as

* multi body multi fillet test

* make eslint happy again

* as fatality

* Revert "make eslint happy again"

This reverts commit 21a966b9b0.

* lint error fix
2024-09-12 21:45:26 +02:00
88216d4c76 Bump serde from 1.0.209 to 1.0.210 in /src/wasm-lib (#3838)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.209 to 1.0.210.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.209...v1.0.210)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-12 12:14:12 -07:00
8b1e4d6708 Bump anyhow from 1.0.86 to 1.0.88 in /src/wasm-lib (#3868)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.86 to 1.0.88.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.86...1.0.88)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-12 09:13:07 -07:00
769c3ec785 Remove double upload workaround for 0.25.1 release (#3870) 2024-09-12 05:18:37 -04:00
1c4179a9db Use Inter 4.0 as sans-serif font (#3857)
* Use Inter 4.0 as sans-serif font

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Host the Inter font locally

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Re-run CI

* Just use the variable font, it's the future

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Re-run CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-11 16:57:54 -04:00
292f89859f Make settings reset button only reset current level (#3855)
* Update test to expect new behavior (failing)

* Update behavior to match new test expectations

* Make reset button more clear

* Fix eslint issue

* Fix up separate test that relied on old reset logic
2024-09-11 09:39:10 -04:00
a00800bddc add more shell samples (#3861)
* add more shell sampels

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-10 19:50:34 -07:00
78ceba6d20 fixing the position and display of the segment labels during sketch mode (#3796)
* bug: fixing the position and display of the segment labels during sketch mode

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* fix: minor visual tweaks

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* fix: adding border styling

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* feat: aligned the text to the slope of the line drawn

* fix: tsc, lint, fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* fix: linter warnings for unused variable

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-10 16:22:16 -05:00
6776a350af Update KNOWN-ISSUES.md 2024-09-10 13:19:49 -07:00
dd75f06f77 Add linting to codemirror-lsp-client (#3850) 2024-09-10 20:18:31 +00:00
394872d84e remove debug log (#3853) 2024-09-10 20:09:39 +00:00
f9eef6397f Do not read in the "theme" setting at the project level (#3845)
* Do not read in the "theme" setting at the project level

* Add a couple unit tests
2024-09-10 15:15:20 -04:00
900bac999c Bugfix: update sketch mode colors on theme change (#3849)
* Update client-side scene mesh base colors properly

* Add E2E test

* Remove use of `as`
2024-09-10 13:30:39 -04:00
5b2738f826 Fixing bug in convertThreeCamValuesToEngineCam (#3806)
fix: we need the up of the camera, not a hard coded up
2024-09-10 11:45:32 -05:00
dab96577a7 fix: users shouldn't have to press down arrow twice to select an option (#3809)
* fix: users shouldn't have to press down arrow twice to select an option

* add regression test for cmd bar arrow

* tweak
2024-09-10 02:10:14 +00:00
25443eba31 internal: Add lints for promises (#3733)
* Add lints for floating and misued promises

* Add logging async errors in main

* Add async error catch in test-utils

* Change any to unknown

* Trap promise errors and ignore more await warnings

* Add more ignores and toSync helper

* Fix more lint warnings

* Add more ignores and fixes

* Add more reject reporting

* Add accepting arbitrary parameters to toSync()

* Fix more lints

* Revert unintentional change to non-arrow function

* Revert unintentional change to use arrow function

* Fix new warnings in main with auto updater

* Fix formatting

* Change lints to error

This is what the recommended type checked rules do.

* Fix to properly report promise rejections

* Fix formatting

* Fix formatting

* Remove unused import

* Remove unused convenience function

* Move type helpers

* Fix to not return promise when caller doesn't expect it

* Add ignores to lsp code
2024-09-10 08:17:45 +10:00
0a72d7a39a Remove ill-advised CSS added during #3794 (#3844) 2024-09-09 17:23:01 -04:00
5f8d4f8294 Migrate to XState v5 (#3735)
* migrate settingsMachine

* Guard events with properties instead

* migrate settingsMachine

* Migrate auth machine

* Migrate file machine

* Migrate depracated types

* Migrate home machine

* Migrate command bar machine

* Version fixes

* Migrate command bar machine

* Migrate modeling machine

* Migrate types, state.can, state.matches and state.nextEvents

* Fix syntax

* Pass in modelingState into editor manager instead of modeling event

* Fix issue with missing command bar provider

* Fix state transition

* Fix type issue in Home

* Make sure no guards rely on event type

* Fix up command bar submission logic

* Home machine tweaks to get things running

* Fix AST fillet function args

* Handle "Set selection" when it is called by actor onDone

* Remove unused imports

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Fix injectin project to the fileTree machine

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 4b43ff69d1.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Re-run CI

* Restore success toasts on file/folder deletion

* Replace casting with guarding against event.type

* Remove console.log

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Replace all instances of event casting with guards against event.type

---------

Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-09-09 12:59:36 -04:00
max
7c2cfba0ac Extract updateAstAndFocus from Main Function (#3832)
refactor: pull out updateAst and focus
2024-09-09 12:15:16 +02:00
5ee43bda22 Move recast functions to new unparser module (#3824)
This just moves code.  Nothing else was changed.
2024-09-07 12:51:35 -04:00
a1b6bbac7e Replace msi with exe/nsis in download endpoint generation (#3828) 2024-09-06 20:42:47 -04:00
e61516f3c3 Cut release v0.25.1 (#3807)
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-09-06 20:02:14 -04:00
e2eeec37ad Don't paste in code for "Closing settings modal should..." test (#3827) 2024-09-06 18:15:13 -04:00
d7fcc128aa KCL: Break face-analyzing map into its own function (#3792) 2024-09-06 17:02:04 -05:00
cf266b17c1 Batch extrudes (#3764)
Adds a new KCL executor benchmark which builds a `10` wide by `n` tall lego, with varying `n`. The benchmark runs a n = 1, 2, 3 etc build, so we can get an idea of how the speed changes with size. 

This change improves execution speed by 25-36% depending on how many bumps there are. Tested by:

* Rust unit tests
* Open up modeling app, sketch a square, use the command palette to extrude it
* Open up the Bambu printer "poop chute" model, it all extrudes and works fine

Also fixes a bug: extrude, loft, revolve all trigger a GetExtrusionFaceInfo command. Due to a bug, the GetExtrusionFaceInfo command reused the Command ID from the previous extrude/loft/revolve. Fixed that.
2024-09-06 16:55:24 -05:00
b3a1796da9 Move cursor with large files (#3825)
* Make code editor go zoom again (reason: parsing is slow)

* Never build wasm bundle in dev mode

---------

Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-09-06 14:52:52 -07:00
39b9a6b2c4 Get playwright green (#3823)
* Fix "Text-to-CAD functionality" electron test

* Make "Closing settings modal should go back..." test not run order-dependent

* Seeing if paneOpen is part of the run order-dependent story

* Fix mistake in selector for text-to-cad test

* Add resiliency to a couple flakes

---------

Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-09-06 17:14:02 -04:00
6ba4fa305c Fix double locator issue with text-to-cad test (#3816) 2024-09-06 15:24:59 -04:00
1d043899c8 Bump dashmap from 6.0.1 to 6.1.0 in /src/wasm-lib (#3820)
Bumps [dashmap](https://github.com/xacrimon/dashmap) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/xacrimon/dashmap/releases)
- [Commits](https://github.com/xacrimon/dashmap/compare/v6.0.1...v6.1.0)

---
updated-dependencies:
- dependency-name: dashmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-06 10:07:51 -07:00
cb8a087d89 Bump winnow (#3822) 2024-09-06 09:42:11 -05:00
f2eb7b57b8 Update offset plane test images (#3821)
Update offset plane tests
2024-09-06 08:40:29 -05:00
eba653930f Update loft docs + images (#3815) 2024-09-06 07:21:08 -05:00
3deb5c689a The electron-builder updater on 0.25.0 is pointing to the wrong directory (#3818)
Contributes to fixing #3817
2024-09-05 23:22:48 -04:00
11ebe11111 Remove "circle reveal" animation on load of sign-in page (#3802)
* Remove "circle reveal" animation on load of sign-in page

* Remove CSS selector that broke text rendering when OS was dark and app theme is light
2024-09-05 18:59:20 -07:00
9538ffb8ec remove tauri shit (#3812)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-05 18:05:19 -07:00
55d1da226f default to 2 in lofts (#3813)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-05 17:29:07 -07:00
2bfde64bf1 add loft example (#3810)
* add loft example

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

* add docs in between

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-05 16:18:03 -07:00
7cb9a2efd9 Revert "Update package.json to remove tauri dep" (#3811)
Revert "Update package.json to remove tauri dep (#3804)"

This reverts commit dbc5f7b11f.
2024-09-05 15:42:50 -07:00
57e85d7fd0 Upgrade to rust 1.81.0 (#3797)
* Upgrade to rust 1.81.0

* Fix new clippy warnings upgrading to 1.81.0
2024-09-05 21:44:57 +00:00
ca4a442cce Mark Loft as "KCL only" in toolbar, add a link to docs (#3798) 2024-09-05 20:48:03 +00:00
46eef39d53 Set BASE_URL so auth works against dev (#3793)
* Set BASE_URL so auth works against dev

* RM setBaseUrl as it didn't do anything

---------

Co-authored-by: 49fl <ircsurfer33@gmail.com>
2024-09-05 20:36:13 +00:00
dbc5f7b11f Update package.json to remove tauri dep (#3804)
* Update package.json

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-05 13:14:31 -07:00
6797331c9d Bump clap from 4.5.16 to 4.5.17 in /src/wasm-lib (#3782)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.16 to 4.5.17.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.16...clap_complete-v4.5.17)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 13:14:06 -07:00
cc80a2da3d Bump serde_json from 1.0.127 to 1.0.128 in /src/wasm-lib (#3783)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.127 to 1.0.128.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/1.0.127...1.0.128)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 12:41:35 -07:00
54fb9c903a Add no-drag to Toolbar tooltips in Desktop, open links in default browser (#3800)
Fixes #3781
2024-09-05 19:20:51 +00:00
e63597458a Add an Electron app drag handle to sign-in page (#3795)
* Add Electron app drag handle to sign-in page

* Don't assign drag regions in web from JSX, results in dev-only console errors about unsupported style values
2024-09-05 12:18:32 -07:00
e15c38fa23 Fix flash of white background in electron dark mode (#3794) 2024-09-05 11:33:41 -07:00
906ca65611 chore: Implemented electron playwright test to swap between a small cube and large lego (#3732)
* chore: Implemented electron playwright test to swap between a small cube and large lego

* fix: updating comment

* fix: added debug panel and execution done calls

* fix: yarn tsc, fmt, lint

* fix: updating lint warnings

* fix: removing testing line of code that hangs forever :(

* fix: trying a longer timeout

* fix: narrowing the scope to not get multiple elements

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-09-05 10:19:07 -07:00
805b9f48e5 KCL: small refactors to Extrude (#3768)
- Make post-extrude code more functional
 - impl Copy for Point3d
2024-09-04 23:27:12 -05:00
a762d741a5 Generate download endpoint with linux links (#3778) 2024-09-04 20:03:55 -07:00
4b8ca7f61f Double click multiple windows fixes (#3777)
* better way of doing on file open

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>

* cleanuer

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>
2024-09-05 02:18:33 +00:00
31b0a8af12 Cut release v0.25.0 (#3750)
* Cut release v0.25.0

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

---------

Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-09-04 21:33:22 -04:00
74b4cb9e08 quit macos all close (#3775)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-04 15:47:04 -07:00
e7c6dd3698 fix macos double click (#3774)
* fixmacos

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

* fix

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

* updates

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>
2024-09-04 15:32:34 -07:00
aa9abbe83f Loft (#3681)
* add loft

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

* add offsetPlane as well

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

* fix offset

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

* change to 2

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

* updates

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

* updates

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

* fixes

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

* fixes

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

* fixes

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

* add-docs

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-04 14:34:33 -07:00
b19f3bbdb0 chore: added new command log for export done (#3770) 2024-09-04 14:03:21 -07:00
892e856471 fix export logic (#3769)
* fix export logic

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

* updates

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

* fixes

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-04 13:12:16 -07:00
84fae12cdd Bump react-hotkeys-hook from 4.5.0 to 4.5.1 (#3759)
Bumps [react-hotkeys-hook](https://github.com/JohannesKlauss/react-keymap-hook) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/JohannesKlauss/react-keymap-hook/releases)
- [Changelog](https://github.com/JohannesKlauss/react-hotkeys-hook/blob/main/CHANGELOG.md)
- [Commits](https://github.com/JohannesKlauss/react-keymap-hook/compare/v4.5.0...v4.5.1)

---
updated-dependencies:
- dependency-name: react-hotkeys-hook
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-09-04 12:37:51 -07:00
3d67781039 File associations (#3765)
* do windows

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

* info.plist conversion

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

* fixes

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-09-04 12:03:44 -07:00
114c3a2580 Bump eslint-plugin-import from 2.29.1 to 2.30.0 (#3761)
Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.29.1 to 2.30.0.
- [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
- [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.29.1...v2.30.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-import
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 11:29:52 -07:00
02b4aa0476 Bump google-github-actions/upload-cloud-storage from 2.1.1 to 2.2.0 (#3762)
Bumps [google-github-actions/upload-cloud-storage](https://github.com/google-github-actions/upload-cloud-storage) from 2.1.1 to 2.2.0.
- [Release notes](https://github.com/google-github-actions/upload-cloud-storage/releases)
- [Changelog](https://github.com/google-github-actions/upload-cloud-storage/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google-github-actions/upload-cloud-storage/compare/v2.1.1...v2.2.0)

---
updated-dependencies:
- dependency-name: google-github-actions/upload-cloud-storage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 11:29:21 -07:00
57f4e1b79c internal: Add ArtifactId type (#3752)
* Add ArtifactId type

* Use ArtifactId type in more places

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-09-04 11:49:13 -04:00
35f9b82a65 Set a default initial directory, handle an existing settings file with no project directory (#3734)
* Fix the project directory setting assignment from file

* Fix default project directory value initialization

* Add a couple tests for loading the app without project directory settings

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* trigger CI

* Object merging logic was bad, blew away other app settings if they existed

* Update silly little export file size expectation numbers

* Make rename timeout in test way shorter

* Fix silly little test issues

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-09-04 11:30:09 -04:00
389 changed files with 58319 additions and 14434 deletions

View File

@ -2,7 +2,9 @@ NODE_ENV=development
DEV=true DEV=true
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
VITE_KC_SKIP_AUTH=false VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000 VITE_KC_CONNECTION_TIMEOUT_MS=5000
VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local" # ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!
#VITE_KC_DEV_TOKEN="your token from dev.zoo.dev should go in .env.development.local"

View File

@ -13,6 +13,8 @@
"plugin:css-modules/recommended" "plugin:css-modules/recommended"
], ],
"rules": { "rules": {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"semi": [ "semi": [
"error", "error",
"never" "never"
@ -24,7 +26,6 @@
{ {
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure "files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"rules": { "rules": {
"@typescript-eslint/no-floating-promises": "warn",
"suggest-no-throw/suggest-no-throw": "off", "suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off", "testing-library/prefer-screen-queries": "off",
"jest/valid-expect": "off" "jest/valid-expect": "off"

View File

@ -44,7 +44,7 @@ jobs:
# TODO: see if we can fetch from main instead if no diff at src/wasm-lib # TODO: see if we can fetch from main instead if no diff at src/wasm-lib
- name: Run build:wasm - name: Run build:wasm
run: "yarn build:wasm${{ env.BUILD_RELEASE == 'true' && '-dev' || ''}}" run: "yarn build:wasm"
- name: Set nightly version - name: Set nightly version
if: github.event_name == 'schedule' if: github.event_name == 'schedule'
@ -52,7 +52,6 @@ jobs:
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
# TODO: see if we need to inject updater nightly URL here https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json # TODO: see if we need to inject updater nightly URL here https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json
# TODO: see if we ned to add updater test URL here https://dl.zoo.dev/releases/modeling-app/updater-test/last_update.json
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
with: with:
@ -64,6 +63,17 @@ jobs:
- id: export_version - id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT" run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
- name: Prepare electron-builder.yml file for updater test
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/updater-test"' electron-builder.yml
- uses: actions/upload-artifact@v3
with:
name: prepared-files-updater-test
path: |
electron-builder.yml
build-apps: build-apps:
needs: [prepare-files] needs: [prepare-files]
@ -81,8 +91,6 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
CSC_FOR_PULL_REQUEST: true CSC_FOR_PULL_REQUEST: true
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
VERSION: ${{ github.event_name == 'schedule' && needs.prepare-files.outputs.version || format('v{0}', needs.prepare-files.outputs.version) }} VERSION: ${{ github.event_name == 'schedule' && needs.prepare-files.outputs.version || format('v{0}', needs.prepare-files.outputs.version) }}
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }} VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
WINDOWS_CERTIFICATE_THUMBPRINT: F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D WINDOWS_CERTIFICATE_THUMBPRINT: F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D
@ -142,41 +150,36 @@ jobs:
- name: List artifacts in out/ - name: List artifacts in out/
run: ls -R out run: ls -R out
- name: Prepare the tauri update bundles (macOS)
if: ${{ env.BUILD_RELEASE && matrix.os == 'macos-14' }}
run: |
for ARCH in arm64 x64; do
TAURI_DIR=out/tauri/$VERSION/macos
TEMP_DIR=temp/$ARCH
mkdir -p $TAURI_DIR
mkdir -p $TEMP_DIR
unzip out/*-$ARCH-mac.zip -d $TEMP_DIR
tar -czvf "$TAURI_DIR/Zoo Modeling App-$ARCH.app.tar.gz" -C $TEMP_DIR "Zoo Modeling App.app"
yarn tauri signer sign "$TAURI_DIR/Zoo Modeling App-$ARCH.app.tar.gz"
done
ls -R out
- name: Prepare the tauri update bundles (Windows)
if: ${{ env.BUILD_RELEASE && matrix.os == 'windows-2022' }}
run: |
$env:TAURI_DIR="out/tauri/${env:VERSION}/nsis"
mkdir -p ${env:TAURI_DIR}
$env:OUT_FILE="${env:TAURI_DIR}/Zoo Modeling App_${env:VERSION_NO_V}_x64-setup.nsis.zip"
7z a -mm=Copy "${env:OUT_FILE}" ./out/*-x64-win.exe
yarn tauri signer sign "${env:OUT_FILE}"
ls -R out
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
with: with:
name: out-${{ matrix.os }} name: out-${{ matrix.os }}
path: | path: |
out/Zoo*.* out/Zoo*.*
out/latest*.yml out/latest*.yml
out/tauri
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back # TODO: add the 'Build for Mac TestFlight (nightly)' stage back
# TODO: add the updater tests back - uses: actions/download-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }}
name: prepared-files-updater-test
- name: Copy updated electron-builder.yml file for updater test
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
ls -R prepared-files-updater-test
cp prepared-files-updater-test/electron-builder.yml electron-builder.yml
- name: Build the app (updater-test)
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: yarn electron-builder --config ${{ env.BUILD_RELEASE && '--publish always' || '' }}
- uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }}
with:
name: updater-test-${{ matrix.os }}
path: |
out/Zoo*.*
out/latest*.yml
publish-apps-release: publish-apps-release:
@ -192,8 +195,6 @@ jobs:
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Non-release build, commit {0}', github.sha) }} NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Non-release build, commit {0}', github.sha) }}
BUCKET_DIR: ${{ github.event_name == 'schedule' && 'dl.kittycad.io/releases/modeling-app/nightly' || 'dl.kittycad.io/releases/modeling-app' }} BUCKET_DIR: ${{ github.event_name == 'schedule' && 'dl.kittycad.io/releases/modeling-app/nightly' || 'dl.kittycad.io/releases/modeling-app' }}
WEBSITE_DIR: ${{ github.event_name == 'schedule' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }} WEBSITE_DIR: ${{ github.event_name == 'schedule' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
BUCKET_DIR_TAURI: 'dl.kittycad.io/releases/modeling-app/tauri-compat'
WEBSITE_DIR_TAURI: 'dl.zoo.dev/releases/modeling-app/tauri-compat'
URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }} URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -212,7 +213,7 @@ jobs:
with: with:
name: out-ubuntu-22.04 name: out-ubuntu-22.04
path: out path: out
- name: Generate the download static endpoint - name: Generate the download static endpoint
run: | run: |
RELEASE_DIR=https://${WEBSITE_DIR} RELEASE_DIR=https://${WEBSITE_DIR}
@ -222,8 +223,10 @@ jobs:
--arg notes "${NOTES}" \ --arg notes "${NOTES}" \
--arg mac_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-mac.dmg" \ --arg mac_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-mac.dmg" \
--arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \ --arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \
--arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.msi" \ --arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.exe" \
--arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.msi" \ --arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.exe" \
--arg linux_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-linux.AppImage" \
--arg linux_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x86_64-linux.AppImage" \
'{ '{
"version": $version, "version": $version,
"pub_date": $pub_date, "pub_date": $pub_date,
@ -235,54 +238,22 @@ jobs:
"dmg-x64": { "dmg-x64": {
"url": $mac_x64_url "url": $mac_x64_url
}, },
"msi-arm64": { "exe-arm64": {
"url": $windows_arm64_url "url": $windows_arm64_url
}, },
"msi-x64": { "exe-x64": {
"url": $windows_x64_url "url": $windows_x64_url
},
"appimage-arm64": {
"url": $linux_arm64_url
},
"appimage-x64": {
"url": $linux_x64_url
} }
} }
}' > last_download.json }' > last_download.json
cat last_download.json cat last_download.json
- name: Generate the update static endpoint for tauri
run: |
TAURI_DIR=out/tauri/$VERSION
MAC_ARM64_SIG=`cat $TAURI_DIR/macos/*-arm64.app.tar.gz.sig`
MAC_X64_SIG=`cat $TAURI_DIR/macos/*-x64.app.tar.gz.sig`
WINDOWS_SIG=`cat $TAURI_DIR/nsis/*.nsis.zip.sig`
RELEASE_DIR=https://${WEBSITE_DIR_TAURI}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg mac_arm64_sig "$MAC_ARM64_SIG" \
--arg mac_arm64_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}-arm64.app.tar.gz" \
--arg mac_x64_sig "$MAC_X64_SIG" \
--arg mac_x64_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}-x64.app.tar.gz" \
--arg windows_sig "$WINDOWS_SIG" \
--arg windows_url "$RELEASE_DIR/nsis/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64-setup.nsis.zip" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"darwin-x86_64": {
"signature": $mac_x64_sig,
"url": $mac_x64_url
},
"darwin-aarch64": {
"signature": $mac_arm64_sig,
"url": $mac_arm64_url
},
"windows-x86_64": {
"signature": $windows_sig,
"url": $windows_url
}
}
}' > last_update.json
cat last_update.json
- name: List artifacts - name: List artifacts
run: "ls -R out" run: "ls -R out"
@ -310,7 +281,7 @@ jobs:
path: out path: out
glob: 'latest*' glob: 'latest*'
parent: false parent: false
destination: ${{ env.BUCKET_DIR }} destination: ${{ env.BUCKET_DIR }}
- name: Upload download endpoint to public bucket - name: Upload download endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.2.0 uses: google-github-actions/upload-cloud-storage@v2.2.0
@ -318,20 +289,6 @@ jobs:
path: last_download.json path: last_download.json
destination: ${{ env.BUCKET_DIR }} destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to public bucket for tauri
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: "out/tauri/${{ env.VERSION }}"
glob: '*/Zoo*'
parent: false
destination: ${{ env.BUCKET_DIR_TAURI }}/${{ env.VERSION }}
- name: Upload update endpoint to public bucket for tauri
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: last_update.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to Github - name: Upload release files to Github
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2

View File

@ -45,7 +45,7 @@ jobs:
- run: yarn xstate:typegen - run: yarn xstate:typegen
- run: yarn tsc - run: yarn tsc
- name: Lint - name: Lint
run: yarn eslint --max-warnings 0 src e2e run: yarn eslint --max-warnings 0 src e2e packages/codemirror-lsp-client
check-typos: check-typos:

View File

@ -28,6 +28,7 @@ jobs:
dir: ['src/wasm-lib'] dir: ['src/wasm-lib']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: taiki-e/install-action@just
- name: Install latest rust - name: Install latest rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -41,7 +42,7 @@ jobs:
- name: Run clippy - name: Run clippy
run: | run: |
cd "${{ matrix.dir }}" cd "${{ matrix.dir }}"
cargo clippy --all --tests --benches -- -D warnings just lint
# If this fails, run "cargo check" to update Cargo.lock, # If this fails, run "cargo check" to update Cargo.lock,
# then add Cargo.lock to the PR. # then add Cargo.lock to the PR.
- name: Check Cargo.lock doesn't need updating - name: Check Cargo.lock doesn't need updating

View File

@ -34,7 +34,7 @@ jobs:
- 'src/wasm-lib/**' - 'src/wasm-lib/**'
playwright-chrome: playwright-chrome:
timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 40 }} timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 50 }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -232,6 +232,7 @@ jobs:
exit 0 exit 0
env: env:
CI: true CI: true
FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true VITE_KC_SKIP_AUTH: true
@ -262,7 +263,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-14] os: [ubuntu-latest, windows-latest, macos-14]
timeout-minutes: 40 timeout-minutes: 60
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
needs: check-rust-changes needs: check-rust-changes
steps: steps:
@ -410,6 +411,7 @@ jobs:
exit 0 exit 0
env: env:
CI: true CI: true
FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true VITE_KC_SKIP_AUTH: true

View File

@ -351,25 +351,6 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
</details> </details>
### Tauri e2e tests
#### Windows (local only until the CI edge version mismatch is fixed)
```
yarn install
yarn build:wasm-dev
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
yarn vite build --mode development
yarn tauri build --debug -b
$env:KITTYCAD_API_TOKEN="<YOUR_KITTYCAD_API_TOKEN>"
$env:VITE_KC_API_BASE_URL="https://api.dev.zoo.dev"
$env:E2E_TAURI_ENABLED="true"
$env:TS_NODE_COMPILER_OPTIONS='{"module": "commonjs"}'
$env:E2E_APPLICATION=".\src-tauri\target\debug\Zoo Modeling App.exe"
Stop-Process -Name msedgedriver
yarn wdio run wdio.conf.ts
```
## KCL ## KCL
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl). For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).

View File

@ -22,8 +22,3 @@ once fixed in engine will just start working here with no language changes.
- **Chamfers**: Chamfers cannot intersect, you will get an error. Only simple - **Chamfers**: Chamfers cannot intersect, you will get an error. Only simple
chamfer cases work currently. chamfer cases work currently.
Sketching on the chamfered face does not currently work.
- **Shell**: Shell sometimes does not work when arcs or fillets are involved.
We are tracking the engine side bug on this.

View File

@ -270,6 +270,26 @@ const extrusion = extrude(5, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -479,6 +499,26 @@ const extrusion = extrude(5, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -274,6 +274,26 @@ const extrusion = extrude(5, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -483,6 +503,26 @@ const extrusion = extrude(5, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -189,6 +189,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -398,6 +418,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -609,6 +649,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -818,6 +878,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -188,6 +188,26 @@ const extrusion = extrude(10, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -397,6 +417,26 @@ const extrusion = extrude(10, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -608,6 +648,26 @@ const extrusion = extrude(10, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -817,6 +877,26 @@ const extrusion = extrude(10, sketch001)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -190,6 +190,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -399,6 +419,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -610,6 +650,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -819,6 +879,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -282,6 +282,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -491,6 +511,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -702,6 +742,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -911,6 +971,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -187,6 +187,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -396,6 +416,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -607,6 +647,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -816,6 +876,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -187,6 +187,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -396,6 +416,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -607,6 +647,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -816,6 +876,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -200,6 +200,26 @@ const exampleSketch = startSketchOn('XZ')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -409,6 +429,26 @@ const exampleSketch = startSketchOn('XZ')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -620,6 +660,26 @@ const exampleSketch = startSketchOn('XZ')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -829,6 +889,26 @@ const exampleSketch = startSketchOn('XZ')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

938
docs/kcl/arrayReduce.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -193,6 +193,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -402,6 +422,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -613,6 +653,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -822,6 +882,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because one or more lines are too long

View File

@ -9,14 +9,14 @@ Construct a 2-dimensional circle, of the specified radius, centered at
the provided (x, y) origin point. the provided (x, y) origin point.
```js ```js
circle(center: [number], radius: number, sketch_surface_or_group: SketchSurfaceOrGroup, tag?: TagDeclarator) -> SketchGroup circle(data: CircleData, sketch_surface_or_group: SketchSurfaceOrGroup, tag?: TagDeclarator) -> SketchGroup
``` ```
### Examples ### Examples
```js ```js
const exampleSketch = startSketchOn("-XZ") const exampleSketch = startSketchOn("-XZ")
|> circle([0, 0], 10, %) |> circle({ center: [0, 0], radius: 10 }, %)
const example = extrude(5, exampleSketch) const example = extrude(5, exampleSketch)
``` ```
@ -30,7 +30,7 @@ const exampleSketch = startSketchOn("XZ")
|> line([0, 30], %) |> line([0, 30], %)
|> line([-30, 0], %) |> line([-30, 0], %)
|> close(%) |> close(%)
|> hole(circle([0, 15], 5, %), %) |> hole(circle({ center: [0, 15], radius: 5 }, %), %)
const example = extrude(5, exampleSketch) const example = extrude(5, exampleSketch)
``` ```
@ -39,8 +39,15 @@ const example = extrude(5, exampleSketch)
### Arguments ### Arguments
* `center`: `[number]` (REQUIRED) * `data`: `CircleData` - Data for drawing an circle (REQUIRED)
* `radius`: `number` (REQUIRED) ```js
{
// The center of the circle.
center: [number, number],
// The circle radius
radius: number,
}
```
* `sketch_surface_or_group`: `SketchSurfaceOrGroup` - A sketch surface or a sketch group. (REQUIRED) * `sketch_surface_or_group`: `SketchSurfaceOrGroup` - A sketch surface or a sketch group. (REQUIRED)
```js ```js
{ {
@ -186,6 +193,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -562,6 +589,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -773,6 +820,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -982,6 +1049,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -188,6 +188,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -397,6 +417,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -608,6 +648,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -817,6 +877,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because one or more lines are too long

View File

@ -213,6 +213,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -423,6 +443,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -753,6 +793,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -445,6 +445,26 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -849,6 +869,26 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@ helix(data: HelixData, extrude_group: ExtrudeGroup) -> ExtrudeGroup
```js ```js
const part001 = startSketchOn('XY') const part001 = startSketchOn('XY')
|> circle([5, 5], 10, %) |> circle({ center: [5, 5], radius: 10 }, %)
|> extrude(10, %) |> extrude(10, %)
|> helix({ |> helix({
angleStart: 0, angleStart: 0,
@ -316,6 +316,26 @@ const part001 = startSketchOn('XY')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -711,6 +731,26 @@ const part001 = startSketchOn('XY')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -21,8 +21,8 @@ const exampleSketch = startSketchOn('XY')
|> line([5, 0], %) |> line([5, 0], %)
|> line([0, -5], %) |> line([0, -5], %)
|> close(%) |> close(%)
|> hole(circle([1, 1], .25, %), %) |> hole(circle({ center: [1, 1], radius: .25 }, %), %)
|> hole(circle([1, 4], .25, %), %) |> hole(circle({ center: [1, 4], radius: .25 }, %), %)
const example = extrude(1, exampleSketch) const example = extrude(1, exampleSketch)
``` ```
@ -41,7 +41,7 @@ fn squareHoleSketch = () => {
} }
const exampleSketch = startSketchOn('-XZ') const exampleSketch = startSketchOn('-XZ')
|> circle([0, 0], 3, %) |> circle({ center: [0, 0], radius: 3 }, %)
|> hole(squareHoleSketch(), %) |> hole(squareHoleSketch(), %)
const example = extrude(1, exampleSketch) const example = extrude(1, exampleSketch)
``` ```
@ -199,6 +199,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -409,6 +429,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -611,6 +651,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -820,6 +880,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -1022,6 +1102,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -1231,6 +1331,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,7 @@ layout: manual
* [`angledLineToX`](kcl/angledLineToX) * [`angledLineToX`](kcl/angledLineToX)
* [`angledLineToY`](kcl/angledLineToY) * [`angledLineToY`](kcl/angledLineToY)
* [`arc`](kcl/arc) * [`arc`](kcl/arc)
* [`arrayReduce`](kcl/arrayReduce)
* [`asin`](kcl/asin) * [`asin`](kcl/asin)
* [`assert`](kcl/assert) * [`assert`](kcl/assert)
* [`assertEqual`](kcl/assertEqual) * [`assertEqual`](kcl/assertEqual)
@ -56,6 +57,7 @@ layout: manual
* [`line`](kcl/line) * [`line`](kcl/line)
* [`lineTo`](kcl/lineTo) * [`lineTo`](kcl/lineTo)
* [`ln`](kcl/ln) * [`ln`](kcl/ln)
* [`loft`](kcl/loft)
* [`log`](kcl/log) * [`log`](kcl/log)
* [`log10`](kcl/log10) * [`log10`](kcl/log10)
* [`log2`](kcl/log2) * [`log2`](kcl/log2)
@ -63,6 +65,7 @@ layout: manual
* [`max`](kcl/max) * [`max`](kcl/max)
* [`min`](kcl/min) * [`min`](kcl/min)
* [`mm`](kcl/mm) * [`mm`](kcl/mm)
* [`offsetPlane`](kcl/offsetPlane)
* [`patternCircular2d`](kcl/patternCircular2d) * [`patternCircular2d`](kcl/patternCircular2d)
* [`patternCircular3d`](kcl/patternCircular3d) * [`patternCircular3d`](kcl/patternCircular3d)
* [`patternLinear2d`](kcl/patternLinear2d) * [`patternLinear2d`](kcl/patternLinear2d)

View File

@ -21,7 +21,7 @@ int(num: number) -> i64
```js ```js
const sketch001 = startSketchOn('XZ') const sketch001 = startSketchOn('XZ')
|> circle([0, 0], 2, %) |> circle({ center: [0, 0], radius: 2 }, %)
const extrude001 = extrude(5, sketch001) const extrude001 = extrude(5, sketch001)
const pattern01 = patternTransform(int(ceil(5 / 2)), (id) => { const pattern01 = patternTransform(int(ceil(5 / 2)), (id) => {

View File

@ -179,6 +179,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -388,6 +408,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -179,6 +179,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -388,6 +408,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -192,6 +192,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -401,6 +421,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -612,6 +652,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -821,6 +881,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -179,6 +179,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -388,6 +408,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -599,6 +639,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -808,6 +868,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

536
docs/kcl/loft.md Normal file

File diff suppressed because one or more lines are too long

138
docs/kcl/offsetPlane.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -197,6 +197,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -407,6 +427,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -16,7 +16,7 @@ patternCircular3d(data: CircularPattern3dData, extrude_group_set: ExtrudeGroupSe
```js ```js
const exampleSketch = startSketchOn('XZ') const exampleSketch = startSketchOn('XZ')
|> circle([0, 0], 1, %) |> circle({ center: [0, 0], radius: 1 }, %)
const example = extrude(-5, exampleSketch) const example = extrude(-5, exampleSketch)
|> patternCircular3d({ |> patternCircular3d({
@ -321,6 +321,26 @@ const example = extrude(-5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -16,7 +16,7 @@ patternLinear2d(data: LinearPattern2dData, sketch_group_set: SketchGroupSet) ->
```js ```js
const exampleSketch = startSketchOn('XZ') const exampleSketch = startSketchOn('XZ')
|> circle([0, 0], 1, %) |> circle({ center: [0, 0], radius: 1 }, %)
|> patternLinear2d({ |> patternLinear2d({
axis: [1, 0], axis: [1, 0],
repetitions: 6, repetitions: 6,
@ -190,6 +190,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -400,6 +420,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -319,6 +319,26 @@ const example = extrude(1, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -32,7 +32,7 @@ fn transform = (replicaId) => {
fn layer = () => { fn layer = () => {
return startSketchOn("XY") return startSketchOn("XY")
// or some other plane idk // or some other plane idk
|> circle([0, 0], 1, %, $tag1) |> circle({ center: [0, 0], radius: 1 }, %, $tag1)
|> extrude(h, %) |> extrude(h, %)
} }
// The vase is 100 layers tall. // The vase is 100 layers tall.
@ -321,6 +321,26 @@ let vase = layer()
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -22,7 +22,10 @@ pi() -> number
const circumference = 70 const circumference = 70
const exampleSketch = startSketchOn("XZ") const exampleSketch = startSketchOn("XZ")
|> circle([0, 0], circumference / (2 * pi()), %) |> circle({
center: [0, 0],
radius: circumference / (2 * pi())
}, %)
const example = extrude(5, exampleSketch) const example = extrude(5, exampleSketch)
``` ```

View File

@ -180,6 +180,26 @@ const sketch001 = startSketchOn('XY')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -389,6 +409,26 @@ const sketch001 = startSketchOn('XY')
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -258,6 +258,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -561,6 +581,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -770,6 +810,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -205,6 +205,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -414,6 +434,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -327,6 +327,26 @@ const a1 = startSketchOn({
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -743,6 +763,26 @@ const a1 = startSketchOn({
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

File diff suppressed because it is too large Load Diff

View File

@ -188,6 +188,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -397,6 +417,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -608,6 +648,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -817,6 +877,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -179,6 +179,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -388,6 +408,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -599,6 +639,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -808,6 +868,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -179,6 +179,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -388,6 +408,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -599,6 +639,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -808,6 +868,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -13,14 +13,16 @@ arrays can hold objects and vice versa.
`true` or `false` work when defining values. `true` or `false` work when defining values.
## Variable declaration ## Constant declaration
Variables are defined with the `let` keyword like so: Constants are defined with the `let` keyword like so:
``` ```
let myBool = false let myBool = false
``` ```
Currently you cannot redeclare a constant.
## Array ## Array
An array is defined with `[]` braces. What is inside the brackets can An array is defined with `[]` braces. What is inside the brackets can

View File

@ -182,6 +182,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -391,6 +411,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -602,6 +642,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -811,6 +871,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -182,6 +182,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -391,6 +411,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -602,6 +642,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -811,6 +871,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -180,6 +180,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -389,6 +409,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -600,6 +640,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -809,6 +869,26 @@ const example = extrude(10, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -178,6 +178,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -387,6 +407,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -598,6 +638,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],
@ -807,6 +867,26 @@ const example = extrude(5, exampleSketch)
to: [number, number], to: [number, number],
type: "TangentialArc", type: "TangentialArc",
} | } |
{
// arc's direction
ccw: bool,
// the arc's center
center: [number, number],
// The from point.
from: [number, number],
// the arc's radius
radius: number,
// The tag of the path.
tag: {
digest: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number],
end: number,
start: number,
value: string,
},
// The to point.
to: [number, number],
type: "Circle",
} |
{ {
// The from point. // The from point.
from: [number, number], from: [number, number],

View File

@ -0,0 +1,216 @@
import type { Page, Locator } from '@playwright/test'
import { expect, test as base } from '@playwright/test'
import { getUtils, setup, tearDown } from './test-utils'
import fsp from 'fs/promises'
import { join } from 'path'
type CmdBarSerilised =
| {
stage: 'commandBarClosed'
// TODO no more properties needed but needs to be implemented in _serialiseCmdBar
}
| {
stage: 'pickCommand'
// TODO this will need more properties when implemented in _serialiseCmdBar
}
| {
stage: 'arguments'
currentArgKey: string
currentArgValue: string
headerArguments: Record<string, string>
highlightedHeaderArg: string
commandName: string
}
| {
stage: 'review'
headerArguments: Record<string, string>
commandName: string
}
export class AuthenticatedApp {
private readonly codeContent: Locator
private readonly extrudeButton: Locator
constructor(public readonly page: Page) {
this.codeContent = page.locator('.cm-content')
this.extrudeButton = page.getByTestId('extrude')
}
async initialise(code = '') {
const u = await getUtils(this.page)
await this.page.addInitScript(async (code) => {
localStorage.setItem('persistCode', code)
;(window as any).playwrightSkipFilePicker = true
}, code)
await this.page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
}
getInputFile = (fileName: string) => {
return fsp.readFile(
join('src', 'wasm-lib', 'tests', 'executor', 'inputs', fileName),
'utf-8'
)
}
makeMouseHelpers = (x: number, y: number) => [
() => this.page.mouse.click(x, y),
() => this.page.mouse.move(x, y),
]
/** Likely no where, there's a chance it will click something in the scene, depending what you have in the scene.
*
* Expects the viewPort to be 1000x500 */
clickNoWhere = () => this.page.mouse.click(998, 60)
// Toolbars
expectExtrudeButtonToBeDisabled = async () =>
await expect(this.extrudeButton).toBeDisabled()
expectExtrudeButtonToBeEnabled = async () =>
await expect(this.extrudeButton).not.toBeDisabled()
clickExtrudeButton = async () => await this.extrudeButton.click()
private _serialiseCmdBar = async (): Promise<CmdBarSerilised> => {
const reviewForm = await this.page.locator('#review-form')
const getHeaderArgs = async () => {
const inputs = await this.page.getByTestId('cmd-bar-input-tab').all()
const entries = await Promise.all(
inputs.map((input) => {
const key = input
.locator('[data-test-name="arg-name"]')
.innerText()
.then((a) => a.trim())
const value = input
.getByTestId('header-arg-value')
.innerText()
.then((a) => a.trim())
return Promise.all([key, value])
})
)
return Object.fromEntries(entries)
}
const getCommandName = () =>
this.page.getByTestId('command-name').textContent()
if (await reviewForm.isVisible()) {
const [headerArguments, commandName] = await Promise.all([
getHeaderArgs(),
getCommandName(),
])
return {
stage: 'review',
headerArguments,
commandName: commandName || '',
}
}
const [
currentArgKey,
currentArgValue,
headerArguments,
highlightedHeaderArg,
commandName,
] = await Promise.all([
this.page.getByTestId('cmd-bar-arg-name').textContent(),
this.page.getByTestId('cmd-bar-arg-value').textContent(),
getHeaderArgs(),
this.page
.locator('[data-is-current-arg="true"]')
.locator('[data-test-name="arg-name"]')
.textContent(),
getCommandName(),
])
return {
stage: 'arguments',
currentArgKey: currentArgKey || '',
currentArgValue: currentArgValue || '',
headerArguments,
highlightedHeaderArg: highlightedHeaderArg || '',
commandName: commandName || '',
}
}
expectCmdBarToBe = async (expected: CmdBarSerilised) => {
return expect.poll(() => this._serialiseCmdBar()).toEqual(expected)
}
progressCmdBar = async () => {
if (Math.random() > 0.5) {
const arrowButton = this.page.getByRole('button', {
name: 'arrow right Continue',
})
if (await arrowButton.isVisible()) {
await arrowButton.click()
} else {
await this.page
.getByRole('button', { name: 'checkmark Submit command' })
.click()
}
} else {
await this.page.keyboard.press('Enter')
}
}
expectCodeHighlightedToBe = async (code: string) =>
await expect
.poll(async () => {
const texts = (
await this.page.getByTestId('hover-highlight').allInnerTexts()
).map((s) => s.replace(/\s+/g, '').trim())
return texts.join('')
})
.toBe(code.replace(/\s+/g, '').trim())
expectActiveLinesToBe = async (lines: Array<string>) => {
await expect
.poll(async () => {
return (await this.page.locator('.cm-activeLine').allInnerTexts()).map(
(l) => l.trim()
)
})
.toEqual(lines.map((l) => l.trim()))
}
private _expectEditorToContain =
(not = false) =>
(
code: string,
{
shouldNormalise = false,
timeout = 5_000,
}: { shouldNormalise?: boolean; timeout?: number } = {}
) => {
if (!shouldNormalise) {
const expectStart = expect(this.codeContent)
if (not) {
return expectStart.not.toContainText(code, { timeout })
}
return expectStart.toContainText(code, { timeout })
}
const normalisedCode = code.replaceAll(/\s+/g, ' ').trim()
const expectStart = expect.poll(() => this.codeContent.textContent(), {
timeout,
})
if (not) {
return expectStart.not.toContain(normalisedCode)
}
return expectStart.toContain(normalisedCode)
}
expectEditor = {
toContain: this._expectEditorToContain(),
not: { toContain: this._expectEditorToContain(true) },
}
}
export const test = base.extend<{
app: AuthenticatedApp
}>({
app: async ({ page }, use) => {
const authenticatedApp = new AuthenticatedApp(page)
await use(authenticatedApp)
},
})
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
export { expect } from '@playwright/test'

View File

@ -8,8 +8,8 @@ import {
PERSIST_MODELING_CONTEXT, PERSIST_MODELING_CONTEXT,
} from './test-utils' } from './test-utils'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {

View File

@ -3,8 +3,8 @@ import { getUtils, setup, tearDown } from './test-utils'
import { EngineCommand } from 'lang/std/artifactGraph' import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {

View File

@ -12,8 +12,8 @@ import { bracket } from 'lib/exampleKcl'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates' import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates'
import fsp from 'fs/promises' import fsp from 'fs/promises'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
@ -65,6 +65,8 @@ const extrude001 = extrude(5, sketch001)`
test('Opening and closing the code pane will consistently show error diagnostics', async ({ test('Opening and closing the code pane will consistently show error diagnostics', async ({
page, page,
}) => { }) => {
await page.goto('http://localhost:3000')
const u = await getUtils(page) const u = await getUtils(page)
// Load the app with the working starter code // Load the app with the working starter code
@ -90,7 +92,7 @@ const extrude001 = extrude(5, sketch001)`
// Delete a character to break the KCL // Delete a character to break the KCL
await u.openKclCodePanel() await u.openKclCodePanel()
await page.getByText('extrude(').click() await page.getByText('thickness, bracketLeg1Sketch)').click()
await page.keyboard.press('Backspace') await page.keyboard.press('Backspace')
// Ensure that a badge appears on the button // Ensure that a badge appears on the button
@ -101,7 +103,7 @@ const extrude001 = extrude(5, sketch001)`
// error text on hover // error text on hover
await page.hover('.cm-lint-marker-error') await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible() await expect(page.locator('.cm-tooltip').first()).toBeVisible()
// Close the code pane // Close the code pane
await codePaneButton.click() await codePaneButton.click()
@ -124,7 +126,7 @@ const extrude001 = extrude(5, sketch001)`
// error text on hover // error text on hover
await page.hover('.cm-lint-marker-error') await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible() await expect(page.locator('.cm-tooltip').first()).toBeVisible()
}) })
test('When error is not in view you can click the badge to scroll to it', async ({ test('When error is not in view you can click the badge to scroll to it', async ({
@ -271,10 +273,7 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
}) })
// If they're open by default, we're not actually testing anything. // If they're open by default, we're not actually testing anything.
@ -302,16 +301,7 @@ test(
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
}) })
await test.step('All panes opened before should be visible', async () => { await test.step('All panes opened before should be visible', async () => {

View File

@ -3,8 +3,8 @@ import { test, expect } from '@playwright/test'
import { getUtils, setup, tearDown } from './test-utils' import { getUtils, setup, tearDown } from './test-utils'
import { KCL_DEFAULT_LENGTH } from 'lib/constants' import { KCL_DEFAULT_LENGTH } from 'lib/constants'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {

View File

@ -1,8 +1,8 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
import { getUtils, setup, tearDown } from './test-utils' import { getUtils, setup, tearDown } from './test-utils'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {

View File

@ -104,7 +104,7 @@ test(
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(477481) .toBe(482669)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')

View File

@ -2,8 +2,8 @@ import { test, expect } from '@playwright/test'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { getUtils, setup, tearDown } from './test-utils' import { getUtils, setup, tearDown } from './test-utils'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
@ -558,7 +558,7 @@ test.describe('Editor tests', () => {
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.keyboard.type(`const extrusion = startSketchOn('XY') await page.keyboard.type(`const extrusion = startSketchOn('XY')
|> circle([0, 0], dia/2, %) |> circle({ center: [0, 0], radius: dia/2 }, %)
|> hole(squareHole(length, width, height), %) |> hole(squareHole(length, width, height), %)
|> extrude(height, %)`) |> extrude(height, %)`)

View File

@ -1,9 +1,18 @@
import { test, expect } from '@playwright/test' import { test, expect } from '@playwright/test'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import { getUtils, setup, setupElectron, tearDown } from './test-utils' import * as fs from 'fs'
import {
executorInputPath,
getUtils,
setup,
setupElectron,
tearDown,
} from './test-utils'
import { join } from 'path'
import { FILE_EXT } from 'lib/constants'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
@ -108,11 +117,11 @@ test.describe('when using the file tree to', () => {
async ({ browser: _ }, testInfo) => { async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({ const { electronApp, page } = await setupElectron({
testInfo, testInfo,
folderSetupFn: async () => {},
}) })
const { const {
panesOpen, openKclCodePanel,
openFilePanel,
createAndSelectProject, createAndSelectProject,
pasteCodeInEditor, pasteCodeInEditor,
createNewFileAndSelect, createNewFileAndSelect,
@ -124,9 +133,9 @@ test.describe('when using the file tree to', () => {
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log) page.on('console', console.log)
await panesOpen(['files', 'code'])
await createAndSelectProject('project-000') await createAndSelectProject('project-000')
await openKclCodePanel()
await openFilePanel()
// File the main.kcl with contents // File the main.kcl with contents
const kclCube = await fsp.readFile( const kclCube = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cube.kcl', 'src/wasm-lib/tests/executor/inputs/cube.kcl',
@ -150,6 +159,7 @@ test.describe('when using the file tree to', () => {
await selectFile(kcl1) await selectFile(kcl1)
await editorTextMatches(kclCube) await editorTextMatches(kclCube)
}) })
await page.waitForTimeout(500)
await test.step(`Postcondition: ${kcl2} still exists with the original content`, async () => { await test.step(`Postcondition: ${kcl2} still exists with the original content`, async () => {
await selectFile(kcl2) await selectFile(kcl2)
@ -201,4 +211,659 @@ test.describe('when using the file tree to', () => {
await electronApp.close() await electronApp.close()
} }
) )
test(
'loading small file, then large, then back to small',
{
tag: '@electron',
},
async ({ browser: _ }, testInfo) => {
const { page } = await setupElectron({
testInfo,
})
const {
panesOpen,
createAndSelectProject,
pasteCodeInEditor,
createNewFile,
openDebugPanel,
closeDebugPanel,
expectCmdLog,
} = await getUtils(page, test)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await panesOpen(['files', 'code'])
await createAndSelectProject('project-000')
// Create a small file
const kclCube = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cube.kcl',
'utf-8'
)
// pasted into main.kcl
await pasteCodeInEditor(kclCube)
// Create a large lego file
await createNewFile('lego')
const legoFile = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'lego.kcl' }),
})
await expect(legoFile).toBeVisible({ timeout: 60_000 })
await legoFile.click()
const kclLego = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/lego.kcl',
'utf-8'
)
await pasteCodeInEditor(kclLego)
const mainFile = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'main.kcl' }),
})
// Open settings and enable the debug panel
await page
.getByRole('link', {
name: 'settings Settings',
})
.click()
await page.locator('#showDebugPanel').getByText('OffOn').click()
await page.getByTestId('settings-close-button').click()
await test.step('swap between small and large files', async () => {
await openDebugPanel()
// Previously created a file so we need to start back at main.kcl
await mainFile.click()
await expectCmdLog('[data-message-type="execution-done"]', 60_000)
// Click the large file
await legoFile.click()
// Once it is building, click back to the smaller file
await mainFile.click()
await expectCmdLog('[data-message-type="execution-done"]', 60_000)
await closeDebugPanel()
})
}
)
})
test.describe('Renaming in the file tree', () => {
test(
'A file you have open',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'fileToRename.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const checkUnRenamedFS = () => {
const filePath = join(dir, 'Test Project', 'fileToRename.kcl')
return fs.existsSync(filePath)
}
const newFileName = 'newFileName'
const checkRenamedFS = () => {
const filePath = join(dir, 'Test Project', `${newFileName}.kcl`)
return fs.existsSync(filePath)
}
const fileToRename = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
const renamedFile = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'newFileName.kcl' }) })
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const renameInput = page.getByPlaceholder('fileToRename.kcl')
const codeLocator = page.locator('.cm-content')
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
await u.openFilePanel()
await expect(fileToRename).toBeVisible()
expect(checkUnRenamedFS()).toBeTruthy()
expect(checkRenamedFS()).toBeFalsy()
await fileToRename.click()
await expect(projectMenuButton).toContainText('fileToRename.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('circle(')
await u.closeKclCodePanel()
})
await test.step('Rename the file', async () => {
await fileToRename.click({ button: 'right' })
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFileName)
await page.keyboard.press('Enter')
})
await test.step('Verify the file is renamed', async () => {
await expect(fileToRename).not.toBeAttached()
await expect(renamedFile).toBeVisible()
expect(checkUnRenamedFS()).toBeFalsy()
expect(checkRenamedFS()).toBeTruthy()
})
await test.step('Verify we navigated', async () => {
await expect(projectMenuButton).toContainText(newFileName + FILE_EXT)
const url = page.url()
expect(url).toContain(newFileName)
await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
await expect(projectMenuButton).not.toContainText('main.kcl')
expect(url).not.toContain('fileToRename.kcl')
expect(url).not.toContain('main.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('circle(')
})
await electronApp.close()
}
)
test(
'A file you do not have open',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'fileToRename.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const newFileName = 'newFileName'
const checkUnRenamedFS = () => {
const filePath = join(dir, 'Test Project', 'fileToRename.kcl')
return fs.existsSync(filePath)
}
const checkRenamedFS = () => {
const filePath = join(dir, 'Test Project', `${newFileName}.kcl`)
return fs.existsSync(filePath)
}
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const fileToRename = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
const renamedFile = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: newFileName + FILE_EXT }),
})
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const renameInput = page.getByPlaceholder('fileToRename.kcl')
const codeLocator = page.locator('.cm-content')
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
await u.openFilePanel()
await expect(fileToRename).toBeVisible()
expect(checkUnRenamedFS()).toBeTruthy()
expect(checkRenamedFS()).toBeFalsy()
})
await test.step('Rename the file', async () => {
await fileToRename.click({ button: 'right' })
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFileName)
await page.keyboard.press('Enter')
})
await test.step('Verify the file is renamed', async () => {
await expect(fileToRename).not.toBeAttached()
await expect(renamedFile).toBeVisible()
expect(checkUnRenamedFS()).toBeFalsy()
expect(checkRenamedFS()).toBeTruthy()
})
await test.step('Verify we have not navigated', async () => {
await expect(projectMenuButton).toContainText('main.kcl')
await expect(projectMenuButton).not.toContainText(
newFileName + FILE_EXT
)
await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain(newFileName)
expect(url).not.toContain('fileToRename.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('fillet(')
})
await electronApp.close()
}
)
test(
`A folder you're not inside`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToRename = page.getByRole('button', {
name: 'folderToRename',
})
const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const originalFolderName = 'folderToRename'
const renameInput = page.getByPlaceholder(originalFolderName)
const newFolderName = 'newFolderName'
const checkUnRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', originalFolderName)
return fs.existsSync(folderPath)
}
const checkRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', newFolderName)
return fs.existsSync(folderPath)
}
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await u.openFilePanel()
await expect(folderToRename).toBeVisible()
expect(checkUnRenamedFolderFS()).toBeTruthy()
expect(checkRenamedFolderFS()).toBeFalsy()
})
await test.step('Rename the folder', async () => {
await folderToRename.click({ button: 'right' })
await expect(renameMenuItem).toBeVisible()
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFolderName)
await page.keyboard.press('Enter')
})
await test.step('Verify the folder is renamed, and no navigation occurred', async () => {
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await expect(projectMenuButton).toContainText('main.kcl')
await expect(renamedFolder).toBeVisible()
await expect(folderToRename).not.toBeAttached()
expect(checkUnRenamedFolderFS()).toBeFalsy()
expect(checkRenamedFolderFS()).toBeTruthy()
})
await electronApp.close()
}
)
test(
`A folder you are inside`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToRename = page.getByRole('button', {
name: 'folderToRename',
})
const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
const fileWithinFolder = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
})
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const originalFolderName = 'folderToRename'
const renameInput = page.getByPlaceholder(originalFolderName)
const newFolderName = 'newFolderName'
const checkUnRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', originalFolderName)
return fs.existsSync(folderPath)
}
const checkRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', newFolderName)
return fs.existsSync(folderPath)
}
await test.step('Open project and navigate into folder', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await u.openFilePanel()
await expect(folderToRename).toBeVisible()
await folderToRename.click()
await expect(fileWithinFolder).toBeVisible()
await fileWithinFolder.click()
await expect(projectMenuButton).toContainText('someFileWithin.kcl')
const newUrl = page.url()
expect(newUrl).toContain('folderToRename')
expect(newUrl).toContain('someFileWithin.kcl')
expect(newUrl).not.toContain('main.kcl')
expect(checkUnRenamedFolderFS()).toBeTruthy()
expect(checkRenamedFolderFS()).toBeFalsy()
})
await test.step('Rename the folder', async () => {
await page.waitForTimeout(60000)
await folderToRename.click({ button: 'right' })
await expect(renameMenuItem).toBeVisible()
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFolderName)
await page.keyboard.press('Enter')
})
await test.step('Verify the folder is renamed, and navigated to new path', async () => {
const urlSnippet = encodeURIComponent(
join(newFolderName, 'someFileWithin.kcl')
)
await page.waitForURL(new RegExp(urlSnippet))
await expect(projectMenuButton).toContainText('someFileWithin.kcl')
await expect(renamedFolder).toBeVisible()
await expect(folderToRename).not.toBeAttached()
// URL is synchronous, so we check the other stuff first
const url = page.url()
expect(url).not.toContain('main.kcl')
expect(url).toContain(newFolderName)
expect(url).toContain('someFileWithin.kcl')
expect(checkUnRenamedFolderFS()).toBeFalsy()
expect(checkRenamedFolderFS()).toBeTruthy()
})
await electronApp.close()
}
)
})
test.describe('Deleting items from the file pane', () => {
test(
`delete file when main.kcl exists, navigate to main.kcl`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const testDir = join(dir, 'testProject')
await fsp.mkdir(testDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(testDir, 'main.kcl')
)
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(testDir, 'fileToDelete.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectCard = page.getByText('testProject')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const fileToDelete = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToDelete.kcl' }) })
const deleteMenuItem = page.getByRole('button', { name: 'Delete' })
const deleteConfirmation = page.getByTestId('delete-confirmation')
await test.step('Open project and navigate to fileToDelete.kcl', async () => {
await projectCard.click()
await u.waitForPageLoad()
await u.openFilePanel()
await fileToDelete.click()
await u.waitForPageLoad()
await u.openKclCodePanel()
await expect(u.codeLocator).toContainText('getOppositeEdge(thing)')
await u.closeKclCodePanel()
})
await test.step('Delete fileToDelete.kcl', async () => {
await fileToDelete.click({ button: 'right' })
await expect(deleteMenuItem).toBeVisible()
await deleteMenuItem.click()
await expect(deleteConfirmation).toBeVisible()
await deleteConfirmation.click()
})
await test.step('Check deletion and navigation', async () => {
await u.waitForPageLoad()
await expect(fileToDelete).not.toBeVisible()
await u.closeFilePanel()
await u.openKclCodePanel()
await expect(u.codeLocator).toContainText('circle(')
await expect(projectMenuButton).toContainText('main.kcl')
})
await electronApp.close()
}
)
test.fixme(
'TODO - delete file we have open when main.kcl does not exist',
async () => {}
)
test(
`Delete folder we are not in, don't navigate`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToDelete'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToDelete', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectCard = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToDelete = page.getByRole('button', {
name: 'folderToDelete',
})
const deleteMenuItem = page.getByRole('button', { name: 'Delete' })
const deleteConfirmation = page.getByTestId('delete-confirmation')
await test.step('Open project and open project pane', async () => {
await projectCard.click()
await u.waitForPageLoad()
await expect(projectMenuButton).toContainText('main.kcl')
await u.closeKclCodePanel()
await u.openFilePanel()
})
await test.step('Delete folderToDelete', async () => {
await folderToDelete.click({ button: 'right' })
await expect(deleteMenuItem).toBeVisible()
await deleteMenuItem.click()
await expect(deleteConfirmation).toBeVisible()
await deleteConfirmation.click()
})
await test.step('Check deletion and no navigation', async () => {
await expect(folderToDelete).not.toBeAttached()
await expect(projectMenuButton).toContainText('main.kcl')
})
await electronApp.close()
}
)
test(
`Delete folder we are in, navigate to main.kcl`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToDelete'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToDelete', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectCard = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToDelete = page.getByRole('button', {
name: 'folderToDelete',
})
const fileWithinFolder = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
})
const deleteMenuItem = page.getByRole('button', { name: 'Delete' })
const deleteConfirmation = page.getByTestId('delete-confirmation')
await test.step('Open project and navigate into folderToDelete', async () => {
await projectCard.click()
await u.waitForPageLoad()
await expect(projectMenuButton).toContainText('main.kcl')
await u.closeKclCodePanel()
await u.openFilePanel()
await folderToDelete.click()
await expect(fileWithinFolder).toBeVisible()
await fileWithinFolder.click()
await expect(projectMenuButton).toContainText('someFileWithin.kcl')
})
await test.step('Delete folderToDelete', async () => {
await folderToDelete.click({ button: 'right' })
await expect(deleteMenuItem).toBeVisible()
await deleteMenuItem.click()
await expect(deleteConfirmation).toBeVisible()
await deleteConfirmation.click()
})
await test.step('Check deletion and navigation to main.kcl', async () => {
await expect(folderToDelete).not.toBeAttached()
await expect(fileWithinFolder).not.toBeAttached()
await expect(projectMenuButton).toContainText('main.kcl')
})
await electronApp.close()
}
)
test.fixme('TODO - delete folder we are in, with no main.kcl', async () => {})
}) })

View File

@ -0,0 +1,270 @@
export const isErrorWhitelisted = (exception: Error) => {
// due to the way webkit/Google Chrome report errors, it was necessary
// to whitelist similar errors separately for each project
let whitelist: {
name: string
message: string
stack: string
foundInSpec: string
project: 'webkit' | 'Google Chrome'
}[] = [
{
name: '',
message: 'undefined',
stack: '',
foundInSpec: `e2e/playwright/sketch-tests.spec.ts Existing sketch with bad code delete user's code`,
project: 'Google Chrome',
},
{
name: '"{"kind"',
message:
'"engine","sourceRanges":[[0,0]],"msg":"Failed to get string from response from engine: `JsValue(undefined)`"}"',
stack: '',
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
project: 'Google Chrome',
},
{
name: '',
message: 'false',
stack: '',
foundInSpec: 'e2e/playwright/testing-segment-overlays.spec.ts',
project: 'Google Chrome',
},
{
name: '{"kind"',
// eslint-disable-next-line no-useless-escape
message: 'no connection to send on',
stack: '',
foundInSpec: 'e2e/playwright/various.spec.ts',
project: 'Google Chrome',
},
{
name: '',
message: 'sketchGroup not found',
stack: '',
foundInSpec:
'e2e/playwright/testing-selections.spec.ts Deselecting line tool should mean nothing happens on click',
project: 'Google Chrome',
},
{
name: 'engine error',
message:
'[{"error_code":"bad_request","message":"Cannot set the camera position with these values"}]',
stack: '',
foundInSpec:
'e2e/playwright/can-create-sketches-on-all-planes-and-their-back-sides.spec.ts XY',
project: 'Google Chrome',
},
{
name: '',
message: 'no connection to send on',
stack: '',
foundInSpec:
'e2e/playwright/can-create-sketches-on-all-planes-and-their-back-sides.spec.ts XY',
project: 'Google Chrome',
},
{
name: 'RangeError',
message: 'Position 160 is out of range for changeset of length 0',
stack: `RangeError: Position 160 is out of range for changeset of length 0
at _ChangeSet.mapPos (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:756:13)
at findSharedChunks (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:3045:49)
at _RangeSet.compare (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:2840:24)
at findChangedDeco (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:3320:12)
at DocView.update (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:2774:20)
at _EditorView.update (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:7056:30)
at DOMObserver.flush (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:6621:17)
at MutationObserver.<anonymous> (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:6322:14)`,
foundInSpec: 'e2e/playwright/editor-tests.spec.ts fold gutters work',
project: 'Google Chrome',
},
{
name: 'RangeError',
message: 'Selection points outside of document',
stack: `RangeError: Selection points outside of document
+ at checkSelection (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:1453:13)
+ at new _Transaction (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:2014:7)
+ at _Transaction.create (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:2022:12)
+ at resolveTransaction (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:2155:24)
+ at _EditorState.update (http://localhost:3000/node_modules/.vite/deps/chunk-3BHLKIA4.js?v=412eae63:2281:12)
+ at _EditorView.dispatch (http://localhost:3000/node_modules/.vite/deps/chunk-IZYF444B.js?v=412eae63:6988:148)
+ at EditorManager.selectRange (http://localhost:3000/src/editor/manager.ts:182:22)
+ at AST extrude (http://localhost:3000/src/machines/modelingMachine.ts:828:25)`,
foundInSpec: 'e2e/playwright/editor-tests.spec.ts',
project: 'Google Chrome',
},
{
name: 'Unhandled Promise Rejection',
message: "TypeError: null is not an object (evaluating 'sg.value')",
stack: `Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'sg.value')
at unknown (http://localhost:3000/src/clientSideScene/sceneEntities.ts:466:23)
at unknown (http://localhost:3000/src/clientSideScene/sceneEntities.ts:454:32)
at set up draft line without teardown (http://localhost:3000/src/machines/modelingMachine.ts:983:47)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1877:24)
at handleAction (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1064:26)
at processBlock (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1087:36)
at map ([native code]:0:0)
at resolveActions (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1109:49)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:3639:37)
at provide (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1117:18)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:2452:30)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1831:43)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1659:17)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1643:19)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=0de2e74f:1829:33)
at unknown (http://localhost:3000/src/clientSideScene/sceneEntities.ts:263:19)`,
foundInSpec: `e2e/playwright/testing-camera-movement.spec.ts Zoom should be consistent when exiting or entering sketches`,
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: 'false',
stack: `Unhandled Promise Rejection: false
at unknown (http://localhost:3000/src/clientSideScene/ClientSideSceneComp.tsx:455:78)`,
foundInSpec: `e2e/playwright/testing-segment-overlays.spec.ts line-[tagOutsideSketch]`,
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: `TypeError: null is not an object (evaluating 'programMemory.get(variableDeclarationName).value')`,
stack: ` + stack:Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'programMemory.get(variableDeclarationName).value')
+ at unknown (http://localhost:3000/src/machines/modelingMachine.ts:911:49)`,
foundInSpec: `e2e/playwright/can-create-sketches-on-all-planes-and-their-back-sides.spec.ts`,
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: `null is not an object (evaluating 'programMemory.get(variableDeclarationName).value')`,
stack: `Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'programMemory.get(variableDeclarationName).value')
at unknown (http://localhost:3000/src/machines/modelingMachine.ts:911:49)`,
foundInSpec: `e2e/playwright/testing-camera-movement.spec.ts Zoom should be consistent when exiting or entering sketches`,
project: 'webkit',
},
{
name: 'TypeError',
message: `null is not an object (evaluating 'gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision')`,
stack: `TypeError: null is not an object (evaluating 'gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision')
at getMaxPrecision (http://localhost:3000/node_modules/.vite/deps/chunk-DEEFU7IG.js?v=d328572b:9557:71)
at WebGLCapabilities (http://localhost:3000/node_modules/.vite/deps/chunk-DEEFU7IG.js?v=d328572b:9570:39)
at initGLContext (http://localhost:3000/node_modules/.vite/deps/chunk-DEEFU7IG.js?v=d328572b:16993:43)
at WebGLRenderer (http://localhost:3000/node_modules/.vite/deps/chunk-DEEFU7IG.js?v=d328572b:17024:18)
at SceneInfra (http://localhost:3000/src/clientSideScene/sceneInfra.ts:185:38)
at module code (http://localhost:3000/src/lib/singletons.ts:14:41)`,
foundInSpec: `e2e/playwright/testing-segment-overlays.spec.ts angledLineToX`,
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message:
'{"kind":"engine","sourceRanges":[[0,0]],"msg":"Failed to get string from response from engine: `JsValue(undefined)`"}',
stack: `Unhandled Promise Rejection: {"kind":"engine","sourceRanges":[[0,0]],"msg":"Failed to get string from response from engine: \`JsValue(undefined)\`"}
at unknown (http://localhost:3000/src/lang/std/engineConnection.ts:1245:26)`,
foundInSpec:
'e2e/playwright/onboarding-tests.spec.ts Click through each onboarding step',
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: 'undefined',
stack: '',
foundInSpec: `e2e/playwright/sketch-tests.spec.ts Existing sketch with bad code delete user's code`,
project: 'webkit',
},
{
name: 'Fetch API cannot load https',
message: '/api.dev.zoo.dev/logout due to access control checks.',
stack: `Fetch API cannot load https://api.dev.zoo.dev/logout due to access control checks.
at goToSignInPage (http://localhost:3000/src/components/SettingsAuthProvider.tsx:229:15)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1877:24)
at handleAction (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1064:26)
at processBlock (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1087:36)
at map (:1:11)
at resolveActions (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1109:49)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:3639:37)
at provide (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1117:18)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:2452:30)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1831:43)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1659:17)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1643:19)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:1829:33)
at unknown (http://localhost:3000/node_modules/.vite/deps/chunk-6FRHHHSJ.js?v=d328572b:2601:23)`,
foundInSpec:
'e2e/playwright/testing-selections.spec.ts Solids should be select and deletable',
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: 'ReferenceError: Cannot access uninitialized variable.',
stack: `Unhandled Promise Rejection: ReferenceError: Cannot access uninitialized variable.
at setDiagnosticsForCurrentErrors (http://localhost:3000/src/lang/KclSingleton.ts:90:18)
at kclErrors (http://localhost:3000/src/lang/KclSingleton.ts:82:40)
at safeParse (http://localhost:3000/src/lang/KclSingleton.ts:150:9)
at unknown (http://localhost:3000/src/lang/KclSingleton.ts:113:32)`,
foundInSpec:
'e2e/playwright/testing-segment-overlays.spec.ts angledLineToX',
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message: 'sketchGroup not found',
stack: `Unhandled Promise Rejection: sketchGroup not found
at unknown (http://localhost:3000/src/machines/modelingMachine.ts:911:49)`,
foundInSpec:
'e2e/playwright/testing-selections.spec.ts Deselecting line tool should mean nothing happens on click',
project: 'webkit',
},
{
name: 'Unhandled Promise Rejection',
message:
'engine error: [{"error_code":"bad_request","message":"Cannot set the camera position with these values"}]',
stack:
'Unhandled Promise Rejection: engine error: [{"error_code":"bad_request","message":"Cannot set the camera position with these values"}]',
foundInSpec:
'e2e/playwright/testing-camera-movement.spec.ts Zoom should be consistent when exiting or entering sketches',
project: 'webkit',
},
{
name: 'SecurityError',
stack: `SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
at <anonymous>:13:5
at <anonymous>:18:5
at <anonymous>:19:7`,
message: `Failed to read the 'localStorage' property from 'Window': Access is denied for this document.`,
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/basic-sketch.spec.ts',
},
{
name: ' - internal_engine',
stack: `
`,
message: `Nothing to export`,
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/regression-tests.spec.ts',
},
{
name: 'SyntaxError',
stack: `SyntaxError: Unexpected end of JSON input
at crossPlatformFetch (http://localhost:3000/src/lib/crossPlatformFetch.ts:34:31)
at async sendTelemetry (http://localhost:3000/src/lib/textToCad.ts:179:3)`,
message: `Unexpected end of JSON input`,
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/text-to-cad-tests.spec.ts',
},
{
name: '{"kind"',
stack: ``,
message: `engine","sourceRanges":[[0,0]],"msg":"Failed to wait for promise from engine: JsValue(\\"Force interrupt, executionIsStale, new AST requested\\")"}`,
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/testing-settings.spec.ts',
},
]
const cleanString = (str: string) => str.replace(/[`"]/g, '')
const foundItem = whitelist.find(
(item) =>
cleanString(exception.name) === cleanString(item.name) &&
cleanString(exception.message).includes(cleanString(item.message))
)
return foundItem !== undefined
}

View File

@ -38,7 +38,7 @@ test(
await expect(page.getByText(notFoundText).first()).not.toBeVisible() await expect(page.getByText(notFoundText).first()).not.toBeVisible()
// Find the make button // Find the make button
const makeButton = page.getByRole('button', { name: 'Make' }) const makeButton = page.getByRole('button', { name: 'Make part' })
// Make sure the button is visible but disabled // Make sure the button is visible but disabled
await expect(makeButton).toBeVisible() await expect(makeButton).toBeVisible()
await expect(makeButton).toBeDisabled() await expect(makeButton).toBeDisabled()

View File

@ -0,0 +1,55 @@
import { test } from './authenticatedAppFixture'
// test file is for testing point an click code gen functionality that's not sketch mode related
test('verify extruding circle works', async ({ app }) => {
test.skip(
process.platform === 'win32',
'Fails on windows in CI, can not be replicated locally on windows.'
)
const file = await app.getInputFile('test-circle-extrude.kcl')
await app.initialise(file)
const [clickCircle, moveToCircle] = app.makeMouseHelpers(582, 217)
await test.step('because there is sweepable geometry, verify extrude is enable when nothing is selected', async () => {
await app.clickNoWhere()
await app.expectExtrudeButtonToBeEnabled()
})
await test.step('check code model connection works and that button is still enable once circle is selected ', async () => {
await moveToCircle()
const circleSnippet =
'circle({ center: [318.33, 168.1], radius: 182.8 }, %)'
await app.expectCodeHighlightedToBe(circleSnippet)
await clickCircle()
await app.expectActiveLinesToBe([circleSnippet.slice(-5)])
await app.expectExtrudeButtonToBeEnabled()
})
await test.step('do extrude flow and check extrude code is added to editor', async () => {
await app.clickExtrudeButton()
await app.expectCmdBarToBe({
stage: 'arguments',
currentArgKey: 'distance',
currentArgValue: '5',
headerArguments: { Selection: '1 face', Distance: '' },
highlightedHeaderArg: 'distance',
commandName: 'Extrude',
})
await app.progressCmdBar()
const expectString = 'const extrude001 = extrude(5, sketch001)'
await app.expectEditor.not.toContain(expectString)
await app.expectCmdBarToBe({
stage: 'review',
headerArguments: { Selection: '1 face', Distance: '5' },
commandName: 'Extrude',
})
await app.progressCmdBar()
await app.expectEditor.toContain(expectString)
})
})

View File

@ -12,7 +12,6 @@ import {
import fsp from 'fs/promises' import fsp from 'fs/promises'
import fs from 'fs' import fs from 'fs'
import { join } from 'path' import { join } from 'path'
import { FILE_EXT } from 'lib/constants'
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo) await tearDown(page, testInfo)
@ -147,9 +146,6 @@ test.describe('Can export from electron app', () => {
const u = await getUtils(page) const u = await getUtils(page)
page.on('console', console.log) page.on('console', console.log)
await electronApp.context().addInitScript(async () => {
;(window as any).playwrightSkipFilePicker = true
})
const pointOnModel = { x: 630, y: 280 } const pointOnModel = { x: 630, y: 280 }
@ -207,7 +203,7 @@ test.describe('Can export from electron app', () => {
}, },
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBe(477481) .toBe(482669)
// clean up output.gltf // clean up output.gltf
await fsp.rm('output.gltf') await fsp.rm('output.gltf')
@ -938,16 +934,7 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -972,16 +959,7 @@ test(
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached() await u.waitForPageLoad()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most // gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color) // user way we can verify it (pixel color)
@ -1392,455 +1370,6 @@ test(
} }
) )
test.describe('Renaming in the file tree', () => {
test(
'A file you have open',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'fileToRename.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const checkUnRenamedFS = () => {
const filePath = join(dir, 'Test Project', 'fileToRename.kcl')
return fs.existsSync(filePath)
}
const newFileName = 'newFileName'
const checkRenamedFS = () => {
const filePath = join(dir, 'Test Project', `${newFileName}.kcl`)
return fs.existsSync(filePath)
}
const fileToRename = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
const renamedFile = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'newFileName.kcl' }) })
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const renameInput = page.getByPlaceholder('fileToRename.kcl')
const codeLocator = page.locator('.cm-content')
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
await u.openFilePanel()
await expect(fileToRename).toBeVisible()
expect(checkUnRenamedFS()).toBeTruthy()
expect(checkRenamedFS()).toBeFalsy()
await fileToRename.click()
await expect(projectMenuButton).toContainText('fileToRename.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('circle(')
await u.closeKclCodePanel()
})
await test.step('Rename the file', async () => {
await fileToRename.click({ button: 'right' })
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFileName)
await page.keyboard.press('Enter')
})
await test.step('Verify the file is renamed', async () => {
await expect(fileToRename).not.toBeAttached()
await expect(renamedFile).toBeVisible()
expect(checkUnRenamedFS()).toBeFalsy()
expect(checkRenamedFS()).toBeTruthy()
})
await test.step('Verify we navigated', async () => {
await expect(projectMenuButton).toContainText(newFileName + FILE_EXT)
const url = page.url()
expect(url).toContain(newFileName)
await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
await expect(projectMenuButton).not.toContainText('main.kcl')
expect(url).not.toContain('fileToRename.kcl')
expect(url).not.toContain('main.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('circle(')
})
await electronApp.close()
}
)
test(
'A file you do not have open',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'fileToRename.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const newFileName = 'newFileName'
const checkUnRenamedFS = () => {
const filePath = join(dir, 'Test Project', 'fileToRename.kcl')
return fs.existsSync(filePath)
}
const checkRenamedFS = () => {
const filePath = join(dir, 'Test Project', `${newFileName}.kcl`)
return fs.existsSync(filePath)
}
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const fileToRename = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
const renamedFile = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: newFileName + FILE_EXT }),
})
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const renameInput = page.getByPlaceholder('fileToRename.kcl')
const codeLocator = page.locator('.cm-content')
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
await u.openFilePanel()
await expect(fileToRename).toBeVisible()
expect(checkUnRenamedFS()).toBeTruthy()
expect(checkRenamedFS()).toBeFalsy()
})
await test.step('Rename the file', async () => {
await fileToRename.click({ button: 'right' })
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFileName)
await page.keyboard.press('Enter')
})
await test.step('Verify the file is renamed', async () => {
await expect(fileToRename).not.toBeAttached()
await expect(renamedFile).toBeVisible()
expect(checkUnRenamedFS()).toBeFalsy()
expect(checkRenamedFS()).toBeTruthy()
})
await test.step('Verify we have not navigated', async () => {
await expect(projectMenuButton).toContainText('main.kcl')
await expect(projectMenuButton).not.toContainText(
newFileName + FILE_EXT
)
await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain(newFileName)
expect(url).not.toContain('fileToRename.kcl')
await u.openKclCodePanel()
await expect(codeLocator).toContainText('fillet(')
})
await electronApp.close()
}
)
test(
`A folder you're not inside`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToRename = page.getByRole('button', {
name: 'folderToRename',
})
const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const originalFolderName = 'folderToRename'
const renameInput = page.getByPlaceholder(originalFolderName)
const newFolderName = 'newFolderName'
const checkUnRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', originalFolderName)
return fs.existsSync(folderPath)
}
const checkRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', newFolderName)
return fs.existsSync(folderPath)
}
await test.step('Open project and file pane', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await u.openFilePanel()
await expect(folderToRename).toBeVisible()
expect(checkUnRenamedFolderFS()).toBeTruthy()
expect(checkRenamedFolderFS()).toBeFalsy()
})
await test.step('Rename the folder', async () => {
await folderToRename.click({ button: 'right' })
await expect(renameMenuItem).toBeVisible()
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFolderName)
await page.keyboard.press('Enter')
})
await test.step('Verify the folder is renamed, and no navigation occurred', async () => {
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await expect(projectMenuButton).toContainText('main.kcl')
await expect(renamedFolder).toBeVisible()
await expect(folderToRename).not.toBeAttached()
expect(checkUnRenamedFolderFS()).toBeFalsy()
expect(checkRenamedFolderFS()).toBeTruthy()
})
await electronApp.close()
}
)
test(
`A folder you are inside`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page, dir } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
recursive: true,
})
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(dir, 'Test Project', 'main.kcl')
)
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectLink = page.getByText('Test Project')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const folderToRename = page.getByRole('button', {
name: 'folderToRename',
})
const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
const fileWithinFolder = page.getByRole('listitem').filter({
has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
})
const renameMenuItem = page.getByRole('button', { name: 'Rename' })
const originalFolderName = 'folderToRename'
const renameInput = page.getByPlaceholder(originalFolderName)
const newFolderName = 'newFolderName'
const checkUnRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', originalFolderName)
return fs.existsSync(folderPath)
}
const checkRenamedFolderFS = () => {
const folderPath = join(dir, 'Test Project', newFolderName)
return fs.existsSync(folderPath)
}
await test.step('Open project and navigate into folder', async () => {
await expect(projectLink).toBeVisible()
await projectLink.click()
await expect(projectMenuButton).toBeVisible()
await expect(projectMenuButton).toContainText('main.kcl')
const url = page.url()
expect(url).toContain('main.kcl')
expect(url).not.toContain('folderToRename')
await u.openFilePanel()
await expect(folderToRename).toBeVisible()
await folderToRename.click()
await expect(fileWithinFolder).toBeVisible()
await fileWithinFolder.click()
await expect(projectMenuButton).toContainText('someFileWithin.kcl')
const newUrl = page.url()
expect(newUrl).toContain('folderToRename')
expect(newUrl).toContain('someFileWithin.kcl')
expect(newUrl).not.toContain('main.kcl')
expect(checkUnRenamedFolderFS()).toBeTruthy()
expect(checkRenamedFolderFS()).toBeFalsy()
})
await test.step('Rename the folder', async () => {
await page.waitForTimeout(60000)
await folderToRename.click({ button: 'right' })
await expect(renameMenuItem).toBeVisible()
await renameMenuItem.click()
await expect(renameInput).toBeVisible()
await renameInput.fill(newFolderName)
await page.keyboard.press('Enter')
})
await test.step('Verify the folder is renamed, and navigated to new path', async () => {
const urlSnippet = encodeURIComponent(
join(newFolderName, 'someFileWithin.kcl')
)
await page.waitForURL(new RegExp(urlSnippet))
await expect(projectMenuButton).toContainText('someFileWithin.kcl')
await expect(renamedFolder).toBeVisible()
await expect(folderToRename).not.toBeAttached()
// URL is synchronous, so we check the other stuff first
const url = page.url()
expect(url).not.toContain('main.kcl')
expect(url).toContain(newFolderName)
expect(url).toContain('someFileWithin.kcl')
expect(checkUnRenamedFolderFS()).toBeFalsy()
expect(checkRenamedFolderFS()).toBeTruthy()
})
await electronApp.close()
}
)
})
test.describe('Deleting files from the file pane', () => {
test(
`when main.kcl exists, navigate to main.kcl`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const testDir = join(dir, 'testProject')
await fsp.mkdir(testDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder.kcl'),
join(testDir, 'main.kcl')
)
await fsp.copyFile(
executorInputPath('basic_fillet_cube_end.kcl'),
join(testDir, 'fileToDelete.kcl')
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// Constants and locators
const projectCard = page.getByText('testProject')
const projectMenuButton = page.getByTestId('project-sidebar-toggle')
const fileToDelete = page
.getByRole('listitem')
.filter({ has: page.getByRole('button', { name: 'fileToDelete.kcl' }) })
const deleteMenuItem = page.getByRole('button', { name: 'Delete' })
const deleteConfirmation = page.getByTestId('delete-confirmation')
await test.step('Open project and navigate to fileToDelete.kcl', async () => {
await projectCard.click()
await u.waitForPageLoad()
await u.openFilePanel()
await fileToDelete.click()
await u.waitForPageLoad()
await u.openKclCodePanel()
await expect(u.codeLocator).toContainText('getOppositeEdge(thing)')
await u.closeKclCodePanel()
})
await test.step('Delete fileToDelete.kcl', async () => {
await fileToDelete.click({ button: 'right' })
await expect(deleteMenuItem).toBeVisible()
await deleteMenuItem.click()
await expect(deleteConfirmation).toBeVisible()
await deleteConfirmation.click()
})
await test.step('Check deletion and navigation', async () => {
await u.waitForPageLoad()
await expect(fileToDelete).not.toBeVisible()
await u.closeFilePanel()
await u.openKclCodePanel()
await expect(u.codeLocator).toContainText('circle(')
await expect(projectMenuButton).toContainText('main.kcl')
})
await electronApp.close()
}
)
test.fixme('TODO - when main.kcl does not exist', async () => {})
})
test( test(
'Original project name persist after onboarding', 'Original project name persist after onboarding',
{ tag: '@electron' }, { tag: '@electron' },

View File

@ -11,8 +11,8 @@ import {
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates' import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
@ -54,6 +54,67 @@ const sketch001 = startSketchAt([-0, -0])
const crypticErrorText = `ApiError` const crypticErrorText = `ApiError`
await expect(page.getByText(crypticErrorText).first()).toBeVisible() await expect(page.getByText(crypticErrorText).first()).toBeVisible()
}) })
test('user should not have to press down twice in cmdbar', async ({
page,
}) => {
// because the model has `line([0,0]..` it is valid code, but the model is invalid
// regression test for https://github.com/KittyCAD/modeling-app/issues/3251
// Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch2 = startSketchOn("XY")
const sketch001 = startSketchAt([-0, -0])
|> line([0, 0], %)
|> line([-4.84, -5.29], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/')
await u.waitForPageLoad()
await test.step('Check arrow down works', async () => {
await page.getByTestId('command-bar-open-button').click()
await page
.getByRole('option', { name: 'floppy disk arrow Export' })
.click()
// press arrow down key twice
await page.keyboard.press('ArrowDown')
await page.waitForTimeout(100)
await page.keyboard.press('ArrowDown')
// STL is the third option, which makes sense for two arrow downs
await expect(page.locator('[data-headlessui-state="active"]')).toHaveText(
'STL'
)
await page.keyboard.press('Escape')
await page.waitForTimeout(200)
await page.keyboard.press('Escape')
await page.waitForTimeout(200)
})
await test.step('Check arrow up works', async () => {
// theme in test is dark, which is the second option, which means we can test arrow up
await page.getByTestId('command-bar-open-button').click()
await page.getByText('The overall appearance of the').click()
await page.keyboard.press('ArrowUp')
await page.waitForTimeout(100)
await expect(page.locator('[data-headlessui-state="active"]')).toHaveText(
'light'
)
})
})
test('executes on load', async ({ page }) => { test('executes on load', async ({ page }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
@ -285,10 +346,7 @@ const sketch001 = startSketchAt([-0, -0])
// Find the toast. // Find the toast.
// Look out for the toast message // Look out for the toast message
const exportingToastMessage = page.getByText(`Exporting...`) const exportingToastMessage = page.getByText(`Exporting...`)
await expect(exportingToastMessage).toBeVisible()
const errorToastMessage = page.getByText(`Error while exporting`) const errorToastMessage = page.getByText(`Error while exporting`)
await expect(errorToastMessage).toBeVisible()
const engineErrorToastMessage = page.getByText(`Nothing to export`) const engineErrorToastMessage = page.getByText(`Nothing to export`)
await expect(engineErrorToastMessage).toBeVisible() await expect(engineErrorToastMessage).toBeVisible()
@ -479,6 +537,61 @@ const sketch001 = startSketchAt([-0, -0])
await electronApp.close() await electronApp.close()
} }
) )
test(`View gizmo stays visible even when zoomed out all the way`, async ({
page,
}) => {
const u = await getUtils(page)
// Constants and locators
const planeColor: [number, number, number] = [170, 220, 170]
const bgColor: [number, number, number] = [27, 27, 27]
const middlePixelIsColor = async (color: [number, number, number]) => {
return u.getGreatestPixDiff({ x: 600, y: 250 }, color)
}
const gizmo = page.locator('[aria-label*=gizmo]')
await test.step(`Load an empty file`, async () => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', '')
})
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.closeKclCodePanel()
})
await test.step(`Zoom out until you can't see the default planes`, async () => {
await expect
.poll(async () => middlePixelIsColor(planeColor), {
timeout: 5000,
message: 'Plane color is visible',
})
.toBeLessThan(15)
let maxZoomOuts = 10
let middlePixelIsBackgroundColor =
(await middlePixelIsColor(bgColor)) < 10
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)
maxZoomOuts--
middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 10
}
expect(middlePixelIsBackgroundColor, {
message: 'We no longer the default planes',
}).toBeTruthy()
})
await test.step(`Check that the gizmo is still visible`, async () => {
await expect(gizmo).toBeVisible()
})
})
}) })
async function clickExportButton(page: Page) { async function clickExportButton(page: Page) {

View File

@ -9,8 +9,8 @@ import {
} from './test-utils' } from './test-utils'
import { uuidv4, roundOff } from 'lib/utils' import { uuidv4, roundOff } from 'lib/utils'
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page) await setup(context, page, testInfo)
}) })
test.afterEach(async ({ page }, testInfo) => { test.afterEach(async ({ page }, testInfo) => {
@ -40,7 +40,7 @@ test.describe('Sketch tests', () => {
const screwRadius = 3 const screwRadius = 3
const wireRadius = 2 const wireRadius = 2
const wireOffset = 0.5 const wireOffset = 0.5
const screwHole = startSketchOn('XY') const screwHole = startSketchOn('XY')
${startProfileAt1} ${startProfileAt1}
|> arc({ |> arc({
@ -48,7 +48,7 @@ test.describe('Sketch tests', () => {
angle_start: 0, angle_start: 0,
angle_end: 360 angle_end: 360
}, %) }, %)
const part001 = startSketchOn('XY') const part001 = startSketchOn('XY')
${startProfileAt2} ${startProfileAt2}
|> xLine(width * .5, %) |> xLine(width * .5, %)
@ -57,7 +57,7 @@ test.describe('Sketch tests', () => {
|> close(%) |> close(%)
|> hole(screwHole, %) |> hole(screwHole, %)
|> extrude(thickness, %) |> extrude(thickness, %)
const part002 = startSketchOn('-XZ') const part002 = startSketchOn('-XZ')
${startProfileAt3} ${startProfileAt3}
|> xLine(width / 4, %) |> xLine(width / 4, %)
@ -149,14 +149,16 @@ test.describe('Sketch tests', () => {
await page.getByRole('button', { name: 'line Line', exact: true }).click() await page.getByRole('button', { name: 'line Line', exact: true }).click()
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.mouse.click(700, 200) await expect(async () => {
await page.mouse.click(700, 200)
await expect.poll(u.normalisedEditorCode) await expect.poll(u.normalisedEditorCode, { timeout: 1000 })
.toBe(`const sketch001 = startSketchOn('XZ') .toBe(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([12.34, -12.34], %) |> startProfileAt([12.34, -12.34], %)
|> line([-12.34, 12.34], %) |> line([-12.34, 12.34], %)
`) `)
}).toPass({ timeout: 40_000, intervals: [1_000] })
}) })
test('Can exit selection of face', async ({ page }) => { test('Can exit selection of face', async ({ page }) => {
// Load the app with the code panes // Load the app with the code panes
@ -344,6 +346,92 @@ test.describe('Sketch tests', () => {
}) })
}) })
test('Can edit a circle center and radius by dragging its handles', async ({
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> circle({ center: [4.61, -5.01], radius: 8 }, %)`
)
})
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await page.waitForTimeout(100)
await u.openAndClearDebugPanel()
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 },
},
})
await page.waitForTimeout(100)
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
await page.waitForTimeout(100)
const startPX = [667, 325]
const dragPX = 40
await page
.getByText('circle({ center: [4.61, -5.01], radius: 8 }, %)')
.click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText()
await expect(page.getByTestId('segment-overlay')).toHaveCount(1)
await test.step('drag circle center handle', async () => {
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0], y: startPX[1] },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] - dragPX },
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
})
await test.step('drag circle radius handle', async () => {
await page.waitForTimeout(100)
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX * 2, y: lineEnd.y + dragPX },
})
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
})
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> circle({ center: [7.26, -2.37], radius: 11.44 }, %)
`)
})
test('Can edit a sketch that has been extruded in the same pipe', async ({ test('Can edit a sketch that has been extruded in the same pipe', async ({
page, page,
}) => { }) => {
@ -618,19 +706,19 @@ test.describe('Sketch tests', () => {
await u.closeDebugPanel() await u.closeDebugPanel()
await click00r(30, 0) await click00r(30, 0)
codeStr += ` |> startProfileAt([1.53, 0], %)` codeStr += ` |> startProfileAt([2.03, 0], %)`
await expect(u.codeLocator).toHaveText(codeStr) await expect(u.codeLocator).toHaveText(codeStr)
await click00r(30, 0) await click00r(30, 0)
codeStr += ` |> line([1.53, 0], %)` codeStr += ` |> line([2.04, 0], %)`
await expect(u.codeLocator).toHaveText(codeStr) await expect(u.codeLocator).toHaveText(codeStr)
await click00r(0, 30) await click00r(0, 30)
codeStr += ` |> line([0, -1.53], %)` codeStr += ` |> line([0, -2.03], %)`
await expect(u.codeLocator).toHaveText(codeStr) await expect(u.codeLocator).toHaveText(codeStr)
await click00r(-30, 0) await click00r(-30, 0)
codeStr += ` |> line([-1.53, 0], %)` codeStr += ` |> line([-2.04, 0], %)`
await expect(u.codeLocator).toHaveText(codeStr) await expect(u.codeLocator).toHaveText(codeStr)
await click00r(undefined, undefined) await click00r(undefined, undefined)
@ -954,4 +1042,68 @@ const sketch002 = startSketchOn(extrude001, 'END')
await u.getGreatestPixDiff(XYPlanePoint, noPlanesColor) await u.getGreatestPixDiff(XYPlanePoint, noPlanesColor)
).toBeLessThan(3) ).toBeLessThan(3)
}) })
test('Can attempt to sketch on revolved face', async ({
page,
browserName,
}) => {
test.skip(
browserName === 'webkit',
'Skip on Safari until `window.tearDown` is working there'
)
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const lugHeadLength = 0.25
const lugDiameter = 0.5
const lugLength = 2
fn lug = (origin, length, diameter, plane) => {
const lugSketch = startSketchOn(plane)
|> startProfileAt([origin[0] + lugDiameter / 2, origin[1]], %)
|> angledLineOfYLength({ angle: 60, length: lugHeadLength }, %)
|> xLineTo(0 + .001, %)
|> yLineTo(0, %)
|> close(%)
|> revolve({ axis: "Y" }, %)
return lugSketch
}
lug([0, 0], 10, .5, "XY")`
)
})
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
/***
* Test Plan
* Start the sketch mode
* Click the middle of the screen which should click the top face that is revolved
* Wait till you see the line tool be enabled
* Wait till you see the exit sketch enabled
*
* This is supposed to test that you are allowed to go into sketch mode to sketch on a revolved face
*/
await page.getByRole('button', { name: 'Start Sketch' }).click()
await expect(async () => {
await page.mouse.click(600, 250)
await page.waitForTimeout(1000)
await expect(
page.getByRole('button', { name: 'Exit Sketch' })
).toBeVisible()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).toHaveAttribute('aria-pressed', 'true')
}).toPass({ timeout: 40_000, intervals: [1_000] })
})
}) })

View File

@ -532,6 +532,64 @@ test(
}) })
} }
) )
test(
'Draft circle should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
)
// select a plane
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const sketch001 = startSketchOn('XZ')`
)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
await u.closeDebugPanel()
const startXPx = 600
// Equip the rectangle tool
// await page.getByRole('button', { name: 'line Line', exact: true }).click()
await page.getByTestId('circle-center').click()
// Draw the rectangle
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 10, { steps: 5 })
// Ensure the draft rectangle looks the same as it usually does
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
await expect(page.locator('.cm-content')).toHaveText(
`const sketch001 = startSketchOn('XZ')
|> circle({ center: [14.44, -2.44], radius: 1 }, %)`
)
}
)
test.describe( test.describe(
'Client side scene scale should match engine scale', 'Client side scene scale should match engine scale',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 43 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: 48 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 30 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: 48 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 46 KiB

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