Compare commits

...

87 Commits

Author SHA1 Message Date
d8cc57b843 Cut release v0.17.0 (#1866) 2024-03-25 09:51:17 -04:00
e76db4a621 remove function that's only used once (#1889) 2024-03-25 04:48:51 +00:00
027e947bd5 make setupSketch more composable instead of a monster function (#1879)
* make setupSketch more composable instead of monster function

* clean up
2024-03-25 15:20:43 +11:00
0983dcca22 Add batch support to current KCL implementation (#1871)
* wip

* wip

* updates

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

* more batch shit

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

* fixes

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

* push up mods

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

* go back to batch id

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

* add unlocks back

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

* remove logging

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

* port to wasm

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

* use a trait

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

* updates

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

* snapshojts

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

* artifact map fix

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

* cleanup

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

* remove the blur

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

* hacks on hacks

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

* artifact map clean up

* tweak

* fix so extrudes work

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

* start of id to source range infra

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

* basic map to ids and source ranges

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

* make typescript happy

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

* flush at end of exxecute

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

* small thing for flush

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

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

* trigger ci

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: 49lf <ircsurfer33@gmail.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-23 22:45:55 +00:00
846fc99bbc change KCL Samples link (#1869) 2024-03-22 13:25:59 -07:00
c258ede25c Bump @testing-library/user-event from 14.5.1 to 14.5.2 (#1859)
Bumps [@testing-library/user-event](https://github.com/testing-library/user-event) from 14.5.1 to 14.5.2.
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/user-event/compare/v14.5.1...v14.5.2)

---
updated-dependencies:
- dependency-name: "@testing-library/user-event"
  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-03-22 20:22:26 +00:00
4cc1b3d5ed Bump happy-dom from 14.2.0 to 14.3.1 (#1861)
Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 14.2.0 to 14.3.1.
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v14.2.0...v14.3.1)

---
updated-dependencies:
- dependency-name: happy-dom
  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-03-22 13:00:04 -07:00
be0dd1512d Bump @codemirror/autocomplete from 6.10.2 to 6.15.0 (#1862)
Bumps [@codemirror/autocomplete](https://github.com/codemirror/autocomplete) from 6.10.2 to 6.15.0.
- [Changelog](https://github.com/codemirror/autocomplete/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/autocomplete/compare/6.10.2...6.15.0)

---
updated-dependencies:
- dependency-name: "@codemirror/autocomplete"
  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-03-22 12:59:55 -07:00
a5156c3f5d Add *.zoo.dev origins to Tauri HTTP scopes (#1868) 2024-03-22 19:26:52 +00:00
8038b5d7a3 Make engine background color driven by theme setting (#1842)
* Bump ts lib

* Make engine background color driven by theme setting

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

* Force snapshots to dark mode, fix theme init

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

* Don't assume we have engineCommandManager in CameraControls,
because for some reason it's being loaded before engineConnection in test environments?

* Merge branch 'main' into change-bg-color

* Replace optional chaining with this.engineCommandManager

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

* Okay now all snapshot tests are actually in dark mode

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

* trigger ci

---------

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-03-22 09:35:07 -04:00
54b234360e robustening for autocomplete test (#1864) 2024-03-22 07:10:49 +00:00
465d933d53 circular dependencies refactor (#1863)
* circular dependencies refactor

* clean up
2024-03-22 05:55:30 +00:00
ccd0c619a6 Grackle: integrate source ranges (#1852)
Insert KCL source ranges into the KCVM instructions.
2024-03-22 05:16:27 +00:00
7b570bf525 add parsing of types to functions (#1844)
* add parsing of types to functions

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

* add array

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

* fix clippy

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

* add objects

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>

* updates

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>

* add return types

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

* fix

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-22 00:14:30 +00:00
44d1c29801 set token when fetching user (#1851)
* set token when fetching user

* clean up
2024-03-21 16:32:41 -07:00
0e916cfd5b SketchOnFace UI (#1664)
* always enter edit mode

* initial blocking of extra code-mirror updates

* dry out code

* rejig selections

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

* clean up

* stream clean up

* update export

* sketch mode can be entered and exited for extrude faces

But has bugs

* startSketchOn working in some cases, editsketch animation working but not orientation of instersection plane etc

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

This reverts commit 406fca4c55.

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

* remove comment

* add sketch on face e2e test

* tweenCamToNegYAxis should respect reduced motion

* initial sketch on face working with test

* remove temporary toolbar button and xState flow

* un-used vars

* snapshot test tweak

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

* type tidy up

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

This reverts commit c39b8ebf95.

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

This reverts commit fecf6f490a.

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

* rename

* sketch on sketch on sketch

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

* typo

* startSketchOn Endcaps

end works, start is weird still

* clear selections for entity_ids that are not recognised

* fix sketch on end cap of second order extrustion

* tiny clean up

* fix sketch on close segment/face

* clean up 'lastCodeMirrorSelectionUpdatedFromScene'

* add code mode test for sketchOnExtrudedFace

* make end cap selection more robust

* update js artifacts for extrudes

* update kcl docs

* clean up

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-22 10:23:04 +11:00
e773e932b0 better error lsp server (#1850)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-21 22:14:55 +00:00
2d39fd32ce Revert "Bump @lezer/javascript from 1.4.9 to 1.4.13 (#1812)" (#1849)
This reverts commit 3e4ce44dc9.
2024-03-21 22:07:27 +00:00
5a585a6c2d Grackle: Fix a clippy lint (#1848) 2024-03-21 16:49:10 -05:00
c09d6ee6bd Bump KCVM, integrating InstructionKind (#1847) 2024-03-21 21:17:48 +00:00
09b55259ab Up cam throttle (#1843)
up cam throttle
2024-03-21 20:53:58 +00:00
68b61c9832 Fix new lints from rust 1.77 (#1845) 2024-03-21 15:41:26 -05:00
469ca94437 Bump react-router-dom from 6.14.2 to 6.22.3 (#1837)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.14.2 to 6.22.3.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.22.3/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  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-03-21 12:10:00 -07:00
1d3850b46a Bump tailwindcss from 3.3.6 to 3.4.1 (#1835) 2024-03-21 18:46:47 +00:00
0358343285 Bump vite-tsconfig-paths from 4.3.1 to 4.3.2 (#1838) 2024-03-21 07:06:44 +00:00
38b0603fa2 Bump @types/node from 16.18.39 to 18.19.26 (#1834) 2024-03-20 23:45:27 -07:00
e48a8b6c5d Bump @wdio/local-runner from 8.24.3 to 8.35.1 (#1833) 2024-03-20 23:45:17 -07:00
73e573b251 Bump @tauri-apps/api from 1.5.1 to 1.5.3 (#1830) 2024-03-20 23:45:08 -07:00
793409d53d Bump @types/uuid from 9.0.4 to 9.0.8 (#1832) 2024-03-20 23:44:57 -07:00
3e9ab16c4b Bump ts-node from 10.9.1 to 10.9.2 (#1831) 2024-03-20 23:44:48 -07:00
ab226bc86f Bump eslint from 8.53.0 to 8.57.0 (#1826) 2024-03-20 22:55:58 -07:00
97677e4474 Bump typescript from 5.3.2 to 5.4.3 (#1829) 2024-03-20 22:55:42 -07:00
37fbc8c9ab Bump zustand from 4.4.5 to 4.5.2 (#1827) 2024-03-20 22:55:32 -07:00
29d61da552 Bump @types/debounce-promise from 3.1.8 to 3.1.9 (#1823) 2024-03-21 05:34:27 +00:00
ad2f669ec6 Bump autoprefixer from 10.4.14 to 10.4.19 (#1821) 2024-03-21 05:29:39 +00:00
d66aad8b5d Bump @headlessui/react from 1.7.17 to 1.7.18 (#1822) 2024-03-21 05:27:10 +00:00
d8b8710a0d Bump react-hotkeys-hook from 4.4.1 to 4.5.0 (#1824) 2024-03-20 22:24:35 -07:00
8f8ba2dca5 Bump happy-dom from 10.8.0 to 14.2.0 (#1820) 2024-03-20 22:23:32 -07:00
970b0abb54 Bump @tauri-apps/cli from 1.5.6 to 1.5.11 (#1817) 2024-03-21 05:00:39 +00:00
06b464816f Bump husky from 8.0.3 to 9.0.11 (#1819) 2024-03-21 04:40:51 +00:00
08f7bb2811 Bump vite from 5.1.3 to 5.2.2 (#1816) 2024-03-21 04:40:08 +00:00
197df9f25d Bump @uiw/react-codemirror from 4.21.20 to 4.21.24 (#1818) 2024-03-21 04:39:55 +00:00
4d387dfaf7 Bump @types/crypto-js from 4.1.1 to 4.2.2 (#1813) 2024-03-20 21:21:11 -07:00
912b97bea5 Bump @types/react-dom from 18.2.7 to 18.2.22 (#1814) 2024-03-21 04:17:33 +00:00
3e4ce44dc9 Bump @lezer/javascript from 1.4.9 to 1.4.13 (#1812) 2024-03-21 04:14:51 +00:00
c2058a05fa Bump vitest from 1.3.1 to 1.4.0 (#1811) 2024-03-21 04:13:57 +00:00
7a57965690 Bump clap from 4.5.2 to 4.5.3 in /src/wasm-lib (#1805)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.2 to 4.5.3.
- [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/v4.5.2...v4.5.3)

---
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-03-21 03:57:58 +00:00
c5b115ba97 Bump tauri-plugin-fs-extra from 160498d to 8cd4a39 in /src-tauri (#1809) 2024-03-21 03:53:13 +00:00
90057c2dda add regression test for angletomatch (#1806) 2024-03-21 03:44:52 +00:00
f3e59690d6 Bump async-trait from 0.1.77 to 0.1.78 in /src/wasm-lib (#1807)
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.77 to 0.1.78.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.77...0.1.78)

---
updated-dependencies:
- dependency-name: async-trait
  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-03-21 03:39:46 +00:00
9642a44a02 Bump actions/checkout from 3 to 4 (#1803)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  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-03-21 03:33:24 +00:00
252c7651ac Bump actions/github-script from 6 to 7 (#1804)
Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/github-script
  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-03-21 03:33:09 +00:00
79edcf3826 Bump @wdio/mocha-framework from 8.24.3 to 8.35.0 (#1798)
Bumps [@wdio/mocha-framework](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-mocha-framework) from 8.24.3 to 8.35.0.
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/v8.35.0/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v8.35.0/packages/wdio-mocha-framework)

---
updated-dependencies:
- dependency-name: "@wdio/mocha-framework"
  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-03-21 03:19:52 +00:00
b05ac3a05f fix angleToMatchLengthXY (#1765)
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-03-21 03:14:32 +00:00
1d01ba454b Bump openapitor from 72dcf45 to 8512cea in /src/wasm-lib (#1796)
Bumps [openapitor](https://github.com/KittyCAD/kittycad.rs) from `72dcf45` to `8512cea`.
- [Release notes](https://github.com/KittyCAD/kittycad.rs/releases)
- [Commits](72dcf4573b...8512ceae8e)

---
updated-dependencies:
- dependency-name: openapitor
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-21 03:05:03 +00:00
bf1d6963fe Bump @types/wicg-file-system-access from 2020.9.6 to 2023.10.5 (#1795)
Bumps [@types/wicg-file-system-access](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/wicg-file-system-access) from 2020.9.6 to 2023.10.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/wicg-file-system-access)

---
updated-dependencies:
- dependency-name: "@types/wicg-file-system-access"
  dependency-type: direct:development
  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-03-20 19:59:48 -07:00
176ee63cb9 Bump web-vitals from 3.5.0 to 3.5.2 (#1797)
Bumps [web-vitals](https://github.com/GoogleChrome/web-vitals) from 3.5.0 to 3.5.2.
- [Changelog](https://github.com/GoogleChrome/web-vitals/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GoogleChrome/web-vitals/compare/v3.5.0...v3.5.2)

---
updated-dependencies:
- dependency-name: web-vitals
  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-03-20 19:57:00 -07:00
1ae8059c2b Bump @wdio/spec-reporter from 8.24.2 to 8.32.4 (#1799)
Bumps [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter) from 8.24.2 to 8.32.4.
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/v8.32.4/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v8.32.4/packages/wdio-spec-reporter)

---
updated-dependencies:
- dependency-name: "@wdio/spec-reporter"
  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-03-20 19:52:47 -07:00
93f406d005 Bump @types/react from 18.2.41 to 18.2.67 (#1800)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.41 to 18.2.67.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  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-03-20 19:44:47 -07:00
e97833f0ed Bump kittycad-execution-plan from 494225a to 80998de in /src/wasm-lib (#1801)
Bump kittycad-execution-plan in /src/wasm-lib

Bumps [kittycad-execution-plan](https://github.com/KittyCAD/modeling-api) from `494225a` to `80998de`.
- [Commits](494225aaac...80998dea69)

---
updated-dependencies:
- dependency-name: kittycad-execution-plan
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 19:44:25 -07:00
35417dd8a6 Bump syn from 2.0.52 to 2.0.53 in /src/wasm-lib (#1793)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.52 to 2.0.53.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.52...2.0.53)

---
updated-dependencies:
- dependency-name: syn
  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-03-20 19:35:28 -07:00
cf0560dcfb fix dependabot perms (#1792)
add dependabot to playwright

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-21 00:48:08 +00:00
3659946653 ignore test_copilot_lsp_completions til new model deployed (#1791)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-20 17:40:46 -07:00
156c51484a Bump async-recursion from 1.0.5 to 1.1.0 in /src/wasm-lib (#1775)
Bumps [async-recursion](https://github.com/dcchut/async-recursion) from 1.0.5 to 1.1.0.
- [Release notes](https://github.com/dcchut/async-recursion/releases)
- [Commits](https://github.com/dcchut/async-recursion/compare/v1.0.5...v1.1.0)

---
updated-dependencies:
- dependency-name: async-recursion
  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-03-20 17:07:49 -07:00
dc8dd4bc72 Bump uuid from 1.7.0 to 1.8.0 in /src/wasm-lib (#1776)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.7.0...1.8.0)

---
updated-dependencies:
- dependency-name: uuid
  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-03-20 17:07:15 -07:00
335add67bd Bump thiserror from 1.0.57 to 1.0.58 in /src/wasm-lib (#1778)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.57 to 1.0.58.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.57...1.0.58)

---
updated-dependencies:
- dependency-name: thiserror
  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-03-20 17:06:42 -07:00
231794a69d Bump tauri-plugin-fs-extra from 6db4320 to 160498d in /src-tauri (#1779)
Bumps [tauri-plugin-fs-extra](https://github.com/tauri-apps/plugins-workspace) from `6db4320` to `160498d`.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](6db4320e98...160498dae5)

---
updated-dependencies:
- dependency-name: tauri-plugin-fs-extra
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 17:05:43 -07:00
8e5a6bc6fc bump kittycad.rs (#1784)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-20 15:39:33 -07:00
4f82121105 Add tangentialArcTo to grackle stdlib (#1731)
* Add tangentialArcTo to grackle stdlib

* Clean up test
2024-03-20 14:54:28 -04:00
46358b41a2 Bind all unary, binary and constants to KCL (#1781) 2024-03-20 13:12:43 -04:00
59274b76bf Add onboarding check workflow (#1764)
* add workflow

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

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-20 08:28:55 -07:00
d11d363f19 Cut release v0.16.0 (#1763) 2024-03-20 08:44:09 -04:00
f22ad7c4e7 Fix file route resolution to restor file switching (#1768)
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-03-20 11:39:57 +11:00
1913519f68 Revert "Add ping pong health, remove a timeout interval, fix up netwo… (#1771)
Revert "Add ping pong health, remove a timeout interval, fix up network events (#1555)"

This reverts commit 61d7950ca3.

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-03-20 11:39:49 +11:00
4b9d4fd45b Bump mio in fuzz tests (#1773) 2024-03-19 19:30:47 -05:00
78e6816b06 Always run cargo clippy in CI (#1772)
It's now a required job before merge is allowed. Unfortunately GitHub now blocks any non-Rust PR, because they require cargo clippy but don't trigger it to run.

Solution is simple, just always run cargo clippy, so it can pass, so that merge is allowed.
2024-03-20 11:02:49 +11:00
6607ea1663 Bump tauri-plugin-fs-extra from d95a1b3 to 6db4320 in /src-tauri (#1756)
Bumps [tauri-plugin-fs-extra](https://github.com/tauri-apps/plugins-workspace) from `d95a1b3` to `6db4320`.
- [Release notes](https://github.com/tauri-apps/plugins-workspace/releases)
- [Commits](d95a1b382f...6db4320e98)

---
updated-dependencies:
- dependency-name: tauri-plugin-fs-extra
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-19 15:53:07 -07:00
644a8ef3ca Remove cargo build CI job (#1767)
We shouldn't actually need `cargo build` CI checks. Because we're not building any binaries. Just `cargo check` should be enough. WASM builds are tested elsewhere.
2024-03-19 21:38:21 +00:00
e3e132c0d5 Fix cargo warnings (#1766)
CI is currently broken [logs here](https://github.com/KittyCAD/modeling-app/actions/runs/8349085118/job/22852456873?pr=1765#step:9:1046). Trying to fix.

OK I've fixed it. Process to fix was:

1. Revert be3fed8427 ("Add support for line, xLine, yLine, xLineTo, yLineTo (#1754)")
2. Restore that commit without any of its changes to Cargo.lock (it had, IMO, a lot of unnecessary changes)
3. `cargo update -p kittycad-execution-plan` (redoing only the necessary changes)
2024-03-19 21:19:57 +00:00
be3fed8427 Add support for line, xLine, yLine, xLineTo, yLineTo (#1754)
* Add support for line, xLine, yLine, xLineTo, yLineTo

* Fix minor memory misalignment

* Address PR comments
2024-03-19 12:11:45 -04:00
cefa6f85fe tag changes followup (#1747)
* tag changes followup

* fmt
2024-03-17 18:24:03 +11:00
47ff4623bd updating example kcl back to bracket with updated changes (#1743)
* updating example kcl

* parantheses error

* fix recast bug (#1746)

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

* minor fix

* adding comment to kcl

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-03-15 23:10:34 -07:00
69ff651201 fix recast bug (#1746)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-15 20:18:34 -07:00
788ae5dbab update starting example (#1742)
update starting example
2024-03-15 16:05:26 -07:00
816870253e Make tag last optional param everywhere (#1739)
* Make tag last optional param

* Update all test assertions with correct tag format

* Format ts

* Some progress on tests and code mods

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

* More sketch fixes

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

* Only 1 test left

* Clean up console.log

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

* Fix last ts test

* Clean up fmt

* Fix clippy too

* Update docs and fix small oversight on angled lines

* Fix more rust tests

* Make typescript happy

* Fmt

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-03-15 17:03:42 -04:00
4987965731 better copilot test (#1741)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-03-15 13:07:02 -07:00
042ceb42fd Update cargo-test.yml (#1740) 2024-03-15 19:44:41 +00:00
216 changed files with 9945 additions and 7436 deletions

View File

@ -1,3 +1,3 @@
[codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey
skip: **/target,node_modules,build,**/Cargo.lock

View File

@ -1,50 +0,0 @@
on:
push:
branches:
- main
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-build.yml
pull_request:
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-build.yml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: cargo build
jobs:
cargobuild:
name: cargo build
runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib']
steps:
- uses: actions/checkout@v4
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: install dependencies
if: matrix.dir == 'src-tauri'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Run cargo build
run: |
cd "${{ matrix.dir }}"
cargo build --all
shell: bash

View File

@ -9,12 +9,6 @@ on:
- '**.rs'
- .github/workflows/cargo-clippy.yml
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- '**.rs'
- .github/workflows/cargo-build.yml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

View File

@ -3,7 +3,7 @@ on:
branches:
- main
paths:
- src/wasm-lib/**.rs'
- 'src/wasm-lib/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
@ -11,7 +11,7 @@ on:
pull_request:
paths:
- src/wasm-lib/**.rs'
- 'src/wasm-lib/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'

36
.github/workflows/check-exampleKcl.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Check Onboarding KCL
on:
pull_request:
types: [opened, synchronize]
paths:
- 'src/lib/exampleKcl.ts'
permissions:
contents: read
issues: write
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
const issue_number = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
// Post a comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: message,
});

View File

@ -9,6 +9,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
jobs:
playwright-ubuntu:
timeout-minutes: 60

View File

@ -17,7 +17,7 @@ angleToMatchLengthX(segment_name: string, to: number, sketch_group: SketchGroup)
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [1, 3.82], tag: 'seg01' }, %)
|> line([1, 3.82], %, 'seg01')
|> angledLineToX([
-angleToMatchLengthX('seg01', 10, %),
5
@ -69,6 +69,8 @@ const part001 = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ angleToMatchLengthY(segment_name: string, to: number, sketch_group: SketchGroup)
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [1, 3.82], tag: 'seg01' }, %)
|> line([1, 3.82], %, 'seg01')
|> angledLineToX([
-angleToMatchLengthY('seg01', 10, %),
5
@ -69,6 +69,8 @@ const part001 = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line.
```js
angledLine(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
angledLine(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ angledLine(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> angledLine({ angle: 45, length: 10, tag: "edge1" }, %)
|> angledLine({ angle: 45, length: 10 }, %, "edge1")
|> line([10, 10], %)
|> line([0, 10], %)
|> close(%, "edge2")
@ -33,8 +33,6 @@ startSketchOn('XY')
angle: number,
// The length of the line.
length: number,
// The tag.
tag: string,
} |
[number, number]
```
@ -78,6 +76,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -202,6 +202,7 @@ startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -245,6 +246,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line of a given x length.
```js
angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ angledLineOfXLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGr
```js
startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> angledLineOfXLength({ angle: 45, length: 10, tag: "edge1" }, %)
|> angledLineOfXLength({ angle: 45, length: 10 }, %, "edge1")
|> line([10, 10], %)
|> line([0, 10], %)
|> close(%, "edge2")
@ -33,8 +33,6 @@ startSketchOn('XZ')
angle: number,
// The length of the line.
length: number,
// The tag.
tag: string,
} |
[number, number]
```
@ -78,6 +76,8 @@ startSketchOn('XZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -202,6 +202,7 @@ startSketchOn('XZ')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -245,6 +246,8 @@ startSketchOn('XZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line of a given y length.
```js
angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGroup
angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ angledLineOfYLength(data: AngledLineData, sketch_group: SketchGroup) -> SketchGr
```js
startSketchOn('YZ')
|> startProfileAt([0, 0], %)
|> angledLineOfYLength({ angle: 45, length: 10, tag: "edge1" }, %)
|> angledLineOfYLength({ angle: 45, length: 10 }, %, "edge1")
|> line([10, 10], %)
|> line([0, 10], %)
|> close(%, "edge2")
@ -34,8 +34,6 @@ startSketchOn('YZ')
angle: number,
// The length of the line.
length: number,
// The tag.
tag: string,
} |
[number, number]
```
@ -79,6 +77,8 @@ startSketchOn('YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -203,6 +203,7 @@ startSketchOn('YZ')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -246,6 +247,8 @@ startSketchOn('YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line that intersects with a given line.
```js
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: SketchGroup) -> SketchGroup
angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,14 +17,13 @@ angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: Sketc
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> lineTo({ to: [2, 2], tag: "yo" }, %)
|> lineTo([2, 2], %, "yo")
|> lineTo([3, 1], %)
|> angledLineThatIntersects({
angle: 180,
intersectTag: 'yo',
offset: 12,
tag: "yo2"
}, %)
offset: 12
}, %, "yo2")
|> line([4, 0], %)
|> close(%, "yo3")
|> extrude(10, %)
@ -41,8 +40,6 @@ const part001 = startSketchOn('XY')
intersectTag: string,
// The offset from the intersecting line.
offset: number,
// The tag.
tag: string,
}
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
@ -85,6 +82,8 @@ const part001 = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -209,6 +208,7 @@ const part001 = startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -252,6 +252,8 @@ const part001 = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line to a given x coordinate.
```js
angledLineToX(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
angledLineToX(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ angledLineToX(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> angledLineToX({ angle: 45, to: 10, tag: "edge1" }, %)
|> angledLineToX({ angle: 45, to: 10 }, %, "edge1")
|> line([10, 10], %)
|> line([0, 10], %)
|> close(%, "edge2")
@ -32,12 +32,9 @@ startSketchOn('XY')
{
// The angle of the line.
angle: number,
// The tag.
tag: string,
// The point to draw to.
to: number,
} |
[number, number]
}
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
@ -79,6 +76,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -203,6 +202,7 @@ startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -246,6 +246,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an angled line to a given y coordinate.
```js
angledLineToY(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
angledLineToY(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ angledLineToY(data: AngledLineToData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> angledLineToY({ angle: 45, to: 10, tag: "edge1" }, %)
|> angledLineToY({ angle: 45, to: 10 }, %, "edge1")
|> line([10, 10], %)
|> line([0, 10], %)
|> close(%, "edge2")
@ -31,12 +31,9 @@ startSketchOn('XY')
{
// The angle of the line.
angle: number,
// The tag.
tag: string,
// The point to draw to.
to: number,
} |
[number, number]
}
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
@ -78,6 +75,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -202,6 +201,7 @@ startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -245,6 +245,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw an arc.
```js
arc(data: ArcData, sketch_group: SketchGroup) -> SketchGroup
arc(data: ArcData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -20,9 +20,8 @@ startSketchOn('-YZ')
|> arc({
angle_start: 0,
angle_end: 360,
radius: 10,
tag: "edge1"
}, %)
radius: 10
}, %, "edge1")
|> extrude(10, %)
```
@ -37,16 +36,12 @@ startSketchOn('-YZ')
angle_start: number,
// The radius.
radius: number,
// The tag.
tag: string,
} |
{
// The center.
center: [number, number],
// The radius.
radius: number,
// The tag.
tag: string,
// The to point.
to: [number, number],
}
@ -91,6 +86,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -215,6 +212,7 @@ startSketchOn('-YZ')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -258,6 +256,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a bezier curve.
```js
bezierCurve(data: BezierData, sketch_group: SketchGroup) -> SketchGroup
bezierCurve(data: BezierData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -20,9 +20,8 @@ startSketchOn('XY')
|> bezierCurve({
to: [10, 10],
control1: [5, 0],
control2: [5, 10],
tag: "edge1"
}, %)
control2: [5, 10]
}, %, "edge1")
|> close(%)
|> extrude(10, %)
```
@ -36,8 +35,6 @@ startSketchOn('XY')
control1: [number, number],
// The second control point.
control2: [number, number],
// The tag.
tag: string,
// The to point.
to: [number, number],
}
@ -82,6 +79,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -206,6 +205,7 @@ startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -249,6 +249,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -71,6 +71,8 @@ const rectangle = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -135,6 +137,8 @@ const rectangle = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -302,6 +306,8 @@ const rectangle = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -72,6 +72,8 @@ startSketchOn('YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -240,6 +242,8 @@ startSketchOn('YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -67,6 +67,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,9 +17,9 @@ fillet(data: FilletData, extrude_group: ExtrudeGroup) -> ExtrudeGroup
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [0, 10], tag: "thing" }, %)
|> line([0, 10], %, "thing")
|> line([10, 0], %)
|> line({ to: [0, -10], tag: "thing2" }, %)
|> line([0, -10], %, "thing2")
|> close(%)
|> extrude(10, %)
|> fillet({ radius: 2, tags: ["thing", "thing2"] }, %)

View File

@ -19,7 +19,7 @@ const box = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line({ to: [0, -10], tag: "surface" }, %)
|> line([0, -10], %, "surface")
|> close(%)
|> extrude(5, %)

View File

@ -17,9 +17,9 @@ getNextAdjacentEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [0, 10], tag: "thing" }, %)
|> line({ to: [10, 0], tag: "thing1" }, %)
|> line({ to: [0, -10], tag: "thing2" }, %)
|> line([0, 10], %, "thing")
|> line([10, 0], %, "thing1")
|> line([0, -10], %, "thing2")
|> close(%)
|> extrude(10, %)
|> fillet({

View File

@ -17,9 +17,9 @@ getOppositeEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [0, 10], tag: "thing" }, %)
|> line([0, 10], %, "thing")
|> line([10, 0], %)
|> line({ to: [0, -10], tag: "thing2" }, %)
|> line([0, -10], %, "thing2")
|> close(%)
|> extrude(10, %)
|> fillet({

View File

@ -17,9 +17,9 @@ getPreviousAdjacentEdge(tag: String, extrude_group: ExtrudeGroup) -> Uuid
```js
const part001 = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line({ to: [0, 10], tag: "thing" }, %)
|> line({ to: [10, 0], tag: "thing1" }, %)
|> line({ to: [0, -10], tag: "thing2" }, %)
|> line([0, 10], %, "thing")
|> line([10, 0], %, "thing1")
|> line([0, -10], %, "thing2")
|> close(%)
|> extrude(10, %)
|> fillet({

View File

@ -68,6 +68,8 @@ const square = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -236,6 +238,8 @@ const square = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -403,6 +407,8 @@ const square = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ lastSegX(sketch_group: SketchGroup) -> number
```js
startSketchOn("YZ")
|> startProfileAt([0, 0], %)
|> line({ to: [5, 0], tag: "thing" }, %)
|> line([5, 0], %, "thing")
|> line([5, 5], %)
|> line([0, lastSegX(%)], %)
|> close(%)
@ -66,6 +66,8 @@ startSketchOn("YZ")
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ lastSegY(sketch_group: SketchGroup) -> number
```js
startSketchOn("YZ")
|> startProfileAt([0, 0], %)
|> line({ to: [5, 0], tag: "thing" }, %)
|> line([5, 0], %, "thing")
|> line([5, 5], %)
|> line([0, lastSegY(%)], %)
|> close(%)
@ -66,6 +66,8 @@ startSketchOn("YZ")
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line.
```js
line(data: LineData, sketch_group: SketchGroup) -> SketchGroup
line(delta: [number], sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -18,23 +18,14 @@ line(data: LineData, sketch_group: SketchGroup) -> SketchGroup
startSketchOn('-XY')
|> startProfileAt([0, 0], %)
|> line([10, 10], %)
|> line({ to: [20, 10], tag: "edge1" }, %)
|> line([20, 10], %, "edge1")
|> close(%, "edge2")
|> extrude(10, %)
```
### Arguments
* `data`: `LineData` - Data to draw a line. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: [number, number],
} |
[number, number]
```
* `delta`: `[number]` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -75,6 +66,8 @@ startSketchOn('-XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -199,6 +192,7 @@ startSketchOn('-XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -242,6 +236,8 @@ startSketchOn('-XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line to a point.
```js
lineTo(data: LineToData, sketch_group: SketchGroup) -> SketchGroup
lineTo(to: [number], sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -18,18 +18,9 @@ lineTo(data: LineToData, sketch_group: SketchGroup) -> SketchGroup
fn rectShape = (pos, w, l) => {
const rr = startSketchOn('YZ')
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|> lineTo({
to: [pos[0] + w / 2, pos[1] - (l / 2)],
tag: "edge1"
}, %)
|> lineTo({
to: [pos[0] + w / 2, pos[1] + l / 2],
tag: "edge2"
}, %)
|> lineTo({
to: [pos[0] - (w / 2), pos[1] + l / 2],
tag: "edge3"
}, %)
|> lineTo([pos[0] + w / 2, pos[1] - (l / 2)], %, "edge1")
|> lineTo([pos[0] + w / 2, pos[1] + l / 2], %, "edge2")
|> lineTo([pos[0] - (w / 2), pos[1] + l / 2], %, "edge3")
|> close(%, "edge4")
return rr
}
@ -40,16 +31,7 @@ const part = rectShape([0, 0], 20, 20)
### Arguments
* `data`: `LineToData` - Data to draw a line to a point. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: [number, number],
} |
[number, number]
```
* `to`: `[number]` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -90,6 +72,8 @@ const part = rectShape([0, 0], 20, 20)
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -214,6 +198,7 @@ const part = rectShape([0, 0], 20, 20)
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -257,6 +242,8 @@ const part = rectShape([0, 0], 20, 20)
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -80,6 +80,8 @@ const part = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -77,6 +77,8 @@ const part = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -18,7 +18,7 @@ segAng(segment_name: string, sketch_group: SketchGroup) -> number
const part001 = startSketchOn('XY')
|> startProfileAt([4.83, 12.56], %)
|> line([15.1, 2.48], %)
|> line({ to: [3.15, -9.85], tag: 'seg01' }, %)
|> line([3.15, -9.85], %, 'seg01')
|> line([-15.17, -4.1], %)
|> angledLine([segAng('seg01', %), 12.35], %)
|> line([-13.02, 10.03], %)
@ -69,6 +69,8 @@ const part001 = startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ segEndX(segment_name: string, sketch_group: SketchGroup) -> number
```js
startSketchOn("YZ")
|> startProfileAt([0, 0], %)
|> line({ to: [5, 0], tag: "thing" }, %)
|> line([5, 0], %, "thing")
|> line([5, 5], %)
|> line([segEndX("thing", %), 5], %)
|> close(%)
@ -67,6 +67,8 @@ startSketchOn("YZ")
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ segEndY(segment_name: string, sketch_group: SketchGroup) -> number
```js
startSketchOn("YZ")
|> startProfileAt([0, 0], %)
|> line({ to: [5, 0], tag: "thing" }, %)
|> line([5, 0], %, "thing")
|> line([5, 5], %)
|> line([segEndY("thing", %), 5], %)
|> close(%)
@ -67,6 +67,8 @@ startSketchOn("YZ")
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ segLen(segment_name: string, sketch_group: SketchGroup) -> number
```js
startSketchOn("YZ")
|> startProfileAt([0, 0], %)
|> line({ to: [5, 0], tag: "thing" }, %)
|> line([5, 0], %, "thing")
|> line([5, 5], %)
|> line([0, segLen("thing", %)], %)
|> close(%)
@ -67,6 +67,8 @@ startSketchOn("YZ")
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Start a profile at a given point.
```js
startProfileAt(data: LineData, sketch_surface: SketchSurface) -> SketchGroup
startProfileAt(to: [number], sketch_surface: SketchSurface, tag?: String) -> SketchGroup
```
### Examples
@ -22,16 +22,7 @@ startSketchOn('XY')
### Arguments
* `data`: `LineData` - Data to draw a line. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: [number, number],
} |
[number, number]
```
* `to`: `[number]` (REQUIRED)
* `sketch_surface`: `SketchSurface` - A sketch group type. (REQUIRED)
```js
{
@ -66,6 +57,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -93,6 +86,7 @@ startSketchOn('XY')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -136,6 +130,8 @@ startSketchOn('XY')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Start a sketch at a given point on the 'XY' plane.
```js
startSketchAt(data: LineData) -> SketchGroup
startSketchAt(data: [number]) -> SketchGroup
```
### Examples
@ -21,16 +21,7 @@ startSketchAt([0, 0])
### Arguments
* `data`: `LineData` - Data to draw a line. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: [number, number],
} |
[number, number]
```
* `data`: `[number]` (REQUIRED)
### Returns
@ -74,6 +65,8 @@ startSketchAt([0, 0])
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -18,7 +18,7 @@ startSketchOn(data: SketchData, tag?: SketchOnFaceTag) -> SketchSurface
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([10, 10], %)
|> line({ to: [20, 10], tag: "edge1" }, %)
|> line([20, 10], %, "edge1")
|> close(%, "edge2")
```
@ -40,7 +40,7 @@ const box = cube([0, 0], 20)
const part001 = startSketchOn(box, "start")
|> startProfileAt([0, 0], %)
|> line([10, 10], %)
|> line({ to: [20, 10], tag: "edge1" }, %)
|> line([20, 10], %, "edge1")
|> close(%)
|> extrude(20, %)
```
@ -254,6 +254,8 @@ string
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ Draw an arc.
```js
tangentialArc(data: TangentialArcData, sketch_group: SketchGroup) -> SketchGroup
tangentialArc(data: TangentialArcData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,8 +17,8 @@ tangentialArc(data: TangentialArcData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('-YZ')
|> startProfileAt([0, 0], %)
|> line({ to: [10, 10], tag: "edge0" }, %)
|> tangentialArc({ radius: 10, offset: 90, tag: "edge1" }, %)
|> line([10, 10], %, "edge1")
|> tangentialArc({ radius: 10, offset: 90 }, %, "edge1")
|> close(%)
|> extrude(10, %)
```
@ -33,12 +33,6 @@ startSketchOn('-YZ')
// Radius of the arc. Not to be confused with Raiders of the Lost Ark.
radius: number,
} |
{
// The tag.
tag: string,
// Where the arc should end. Must lie in the same plane as the current path pen position. Must not be colinear with current path pen position.
to: [number, number],
} |
[number, number]
```
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
@ -81,6 +75,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -205,6 +201,7 @@ startSketchOn('-YZ')
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -248,6 +245,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -17,7 +17,7 @@ tangentialArcTo(to: [number], sketch_group: SketchGroup, tag?: String) -> Sketch
```js
startSketchOn('-YZ')
|> startProfileAt([0, 0], %)
|> line({ to: [10, 10], tag: "edge0" }, %)
|> line([10, 10], %, "edge0")
|> tangentialArcTo([10, 0], %)
|> close(%)
```
@ -65,6 +65,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -233,6 +235,8 @@ startSketchOn('-YZ')
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line on the x-axis.
```js
xLine(data: AxisLineData, sketch_group: SketchGroup) -> SketchGroup
xLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -25,16 +25,7 @@ startSketchOn('YZ')
### Arguments
* `data`: `AxisLineData` - Data to draw a line on an axis. (REQUIRED)
```js
{
// The length of the line.
length: number,
// The tag.
tag: string,
} |
number
```
* `length`: `number` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -75,6 +66,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -199,6 +192,7 @@ number
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -242,6 +236,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line to a point on the x-axis.
```js
xLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
xLineTo(to: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ xLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> xLineTo({ to: 10, tag: "edge1" }, %)
|> xLineTo(10, %, "edge1")
|> line([10, 10], %)
|> close(%, "edge2")
|> extrude(10, %)
@ -25,16 +25,7 @@ startSketchOn('XY')
### Arguments
* `data`: `AxisLineToData` - Data to draw a line to a point on an axis. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: number,
} |
number
```
* `to`: `number` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -75,6 +66,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -199,6 +192,7 @@ number
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -242,6 +236,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line on the y-axis.
```js
yLine(data: AxisLineData, sketch_group: SketchGroup) -> SketchGroup
yLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -25,16 +25,7 @@ startSketchOn('XY')
### Arguments
* `data`: `AxisLineData` - Data to draw a line on an axis. (REQUIRED)
```js
{
// The length of the line.
length: number,
// The tag.
tag: string,
} |
number
```
* `length`: `number` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -75,6 +66,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -199,6 +192,7 @@ number
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -242,6 +236,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

View File

@ -9,7 +9,7 @@ Draw a line to a point on the y-axis.
```js
yLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
yLineTo(to: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
```
### Examples
@ -17,7 +17,7 @@ yLineTo(data: AxisLineToData, sketch_group: SketchGroup) -> SketchGroup
```js
startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> yLineTo({ to: 10, tag: "edge1" }, %)
|> yLineTo(10, %, "edge1")
|> line([10, 10], %)
|> close(%, "edge2")
|> extrude(10, %)
@ -26,16 +26,7 @@ startSketchOn('XZ')
### Arguments
* `data`: `AxisLineToData` - Data to draw a line to a point on an axis. (REQUIRED)
```js
{
// The tag.
tag: string,
// The to point.
to: number,
} |
number
```
* `to`: `number` (REQUIRED)
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
```js
{
@ -76,6 +67,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.
@ -200,6 +193,7 @@ number
},
}
```
* `tag`: `String` (OPTIONAL)
### Returns
@ -243,6 +237,8 @@ number
},
} |
{
// the face id the sketch is on
faceId: uuid,
// The id of the face.
id: uuid,
// The original sketch group id of the object we are sketching on.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -20,6 +20,8 @@ const commonPoints = {
startAt: '[9.06, -12.22]',
num1: 9.14,
num2: 18.2,
// num1: 9.64,
// num2: 19.19,
}
test.beforeEach(async ({ context, page }) => {
@ -76,6 +78,7 @@ test('Basic sketch', async ({ page }) => {
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('-XZ')`
)
await u.closeDebugPanel()
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
@ -86,7 +89,6 @@ test('Basic sketch', async ({ page }) => {
|> startProfileAt(${commonPoints.startAt}, %)`)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
@ -130,7 +132,7 @@ test('Basic sketch', async ({ page }) => {
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line({ to: [${commonPoints.num1}, 0], tag: 'seg01' }, %)
|> line([${commonPoints.num1}, 0], %, 'seg01')
|> line([0, ${commonPoints.num1}], %)
|> angledLine([180, segLen('seg01', %)], %)`)
})
@ -472,8 +474,18 @@ test('Auto complete works', async ({ page }) => {
const u = getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
const lspStartPromise = page.waitForEvent('console', async (message) => {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if (message.text().includes('start kcl lsp')) {
await new Promise((resolve) => setTimeout(resolve, 200))
return true
}
return false
})
await page.goto('/')
await u.waitForAuthSkipAppStart()
await lspStartPromise
// this test might be brittle as we add and remove functions
// but should also be easy to update.
@ -625,7 +637,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
const emptySpaceClick = () =>
page.mouse.click(728, 343).then(() => page.waitForTimeout(100))
const topHorzSegmentClick = () =>
page.mouse.click(709, 289).then(() => page.waitForTimeout(100))
page.mouse.click(709, 290).then(() => page.waitForTimeout(100))
const bottomHorzSegmentClick = () =>
page.mouse.click(767, 396).then(() => page.waitForTimeout(100))
@ -640,13 +652,12 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await page.waitForTimeout(700) // wait for animation
const startXPx = 600
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
@ -727,13 +738,18 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await emptySpaceClick()
// select segment in editor than another segment in scene and check there are two cursors
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
await page.waitForTimeout(300)
await page.keyboard.down('Shift')
await expect(page.locator('.cm-cursor')).toHaveCount(1)
// TODO change this back to shift click in the scene, not cmd click in the editor
await bottomHorzSegmentClick()
await page.keyboard.up('Shift')
await expect(page.locator('.cm-cursor')).toHaveCount(1)
await page.keyboard.down(process.platform === 'linux' ? 'Control' : 'Meta')
await page.waitForTimeout(100)
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
await expect(page.locator('.cm-cursor')).toHaveCount(2)
await page.waitForTimeout(500)
await page.keyboard.up(process.platform === 'linux' ? 'Control' : 'Meta')
// clear selection by clicking on nothing
await emptySpaceClick()
@ -918,13 +934,13 @@ test('Can add multiple sketches', async ({ page }) => {
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
const startXPx = 600
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
@ -1372,10 +1388,129 @@ test('Snap to close works (at any scale)', async ({ page }) => {
) => `const part001 = startSketchOn('XZ')
|> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %)
|> line([${roundOff(scale * 175.36)}, 0], %)
|> line([0, -${roundOff(scale * 175.37) + fudge}], %)
|> line([0, -${roundOff(scale * 175.36) + fudge}], %)
|> close(%)`
await doSnapAtDifferentScales([0, 100, 100], codeTemplate(0.01, 0.01))
await doSnapAtDifferentScales([0, 10000, 10000], codeTemplate())
})
test('Sketch on face', async ({ page, context }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('-XZ')
|> startProfileAt([3.29, 7.86], %)
|> line([2.48, 2.44], %)
|> line([2.66, 1.17], %)
|> line([3.75, 0.46], %)
|> line([4.99, -0.46], %)
|> line([3.3, -2.12], %)
|> line([2.16, -3.33], %)
|> line([0.85, -3.08], %)
|> line([-0.18, -3.36], %)
|> line([-3.86, -2.73], %)
|> line([-17.67, 0.85], %)
|> close(%)
|> extrude(5 + 7, %)`
)
})
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await page.getByRole('button', { name: 'Start Sketch' }).click()
let previousCodeContent = await page.locator('.cm-content').innerText()
await page.mouse.click(793, 133)
const firstClickPosition = [612, 238]
const secondClickPosition = [661, 242]
const thirdClickPosition = [609, 267]
await page.waitForTimeout(300)
await page.mouse.click(firstClickPosition[0], firstClickPosition[1])
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await page.mouse.click(secondClickPosition[0], secondClickPosition[1])
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await page.mouse.click(thirdClickPosition[0], thirdClickPosition[1])
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await page.mouse.click(firstClickPosition[0], firstClickPosition[1])
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await expect(page.locator('.cm-content'))
.toContainText(`const part002 = startSketchOn(part001, 'seg01')
|> startProfileAt([1.03, 1.03], %)
|> line([4.18, -0.35], %)
|> line([-4.44, -2.13], %)
|> close(%)`)
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.updateCamPosition([1049, 239, 686])
await u.closeDebugPanel()
await page.getByText('startProfileAt([1.03, 1.03], %)').click()
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(200)
const pointToDragFirst = [691, 237]
await page.mouse.move(pointToDragFirst[0], pointToDragFirst[1])
await page.mouse.down()
await page.mouse.move(pointToDragFirst[0] - 20, pointToDragFirst[1], {
steps: 5,
})
await page.mouse.up()
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await expect(page.locator('.cm-content'))
.toContainText(`const part002 = startSketchOn(part001, 'seg01')
|> startProfileAt([1.03, 1.03], %)
|> line([2.81, -0.33], %)
|> line([-4.44, -2.13], %)
|> close(%)`)
// exit sketch
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
await page.getByText('startProfileAt([1.03, 1.03], %)').click()
await expect(page.getByRole('button', { name: 'Extrude' })).not.toBeDisabled()
await page.getByRole('button', { name: 'Extrude' }).click()
await expect(page.getByTestId('command-bar')).toBeVisible()
await page.keyboard.press('Enter')
await expect(page.getByText('Confirm Extrude')).toBeVisible()
await page.keyboard.press('Enter')
await expect(page.locator('.cm-content'))
.toContainText(`const part002 = startSketchOn(part001, 'seg01')
|> startProfileAt([1.03, 1.03], %)
|> line([2.81, -0.33], %)
|> line([-4.44, -2.13], %)
|> close(%)
|> extrude(5 + 7, %)`)
})

View File

@ -22,7 +22,7 @@ test.beforeEach(async ({ context, page }) => {
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
theme: 'dark',
unitSystem: 'imperial',
})
)
@ -55,10 +55,9 @@ const part001 = startSketchOn('-XZ')
|> angledLineToY({
angle: topAng,
to: totalHeightHalf,
tag: 'seg04'
}, %)
|> xLineTo({ to: totalLen, tag: 'seg03' }, %)
|> yLine({ length: -armThick, tag: 'seg01' }, %)
}, %, 'seg04')
|> xLineTo(totalLen, %, 'seg03')
|> yLine(-armThick, %, 'seg01')
|> angledLineThatIntersects({
angle: HALF_TURN,
offset: -armThick,
@ -68,8 +67,7 @@ const part001 = startSketchOn('-XZ')
|> angledLineToY({
angle: -bottomAng,
to: -totalHeightHalf - armThick,
tag: 'seg02'
}, %)
}, %, 'seg02')
|> xLineTo(segEndX('seg03', %) + 0, %)
|> yLine(-segLen('seg01', %), %)
|> angledLineThatIntersects({
@ -399,7 +397,7 @@ test('Draft segments should look right', async ({ page, context }) => {
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
theme: 'dark',
unitSystem: 'imperial',
})
)
@ -477,7 +475,7 @@ test('Client side scene scale should match engine scale inch', async ({
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
theme: 'dark',
unitSystem: 'imperial',
})
)
@ -577,7 +575,7 @@ test('Client side scene scale should match engine scale mm', async ({
onboardingStatus: 'dismissed',
showDebugPanel: true,
textWrapping: 'On',
theme: 'system',
theme: 'dark',
unitSystem: 'metric',
})
)
@ -614,7 +612,7 @@ test('Client side scene scale should match engine scale mm', async ({
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.33], %)`)
|> startProfileAt([230.03, -310.32], %)`)
await page.waitForTimeout(100)
await u.closeDebugPanel()
@ -624,7 +622,7 @@ test('Client side scene scale should match engine scale mm', async ({
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.33], %)
|> startProfileAt([230.03, -310.32], %)
|> line([232.2, 0], %)`)
await page.getByRole('button', { name: 'Tangential Arc' }).click()
@ -634,7 +632,7 @@ test('Client side scene scale should match engine scale mm', async ({
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.33], %)
|> startProfileAt([230.03, -310.32], %)
|> line([232.2, 0], %)
|> tangentialArcTo([694.43, -78.12], %)`)
@ -660,3 +658,48 @@ test('Client side scene scale should match engine scale mm', async ({
maxDiffPixels: 100,
})
})
test('Sketch on face with none z-up', async ({ page, context }) => {
const u = getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('-XZ')
|> startProfileAt([1.4, 2.47], %)
|> line({ to: [9.31, 10.55], tag: 'seg01' }, %)
|> line([11.91, -10.42], %)
|> close(%)
|> extrude(5 + 7, %)
const part002 = startSketchOn(part001, 'seg01')
|> startProfileAt([-2.89, 1.82], %)
|> line([4.68, 3.05], %)
|> line({ to: [0, -7.79], tag: 'seg02' }, %)
|> close(%)
|> extrude(5 + 7, %)
`
)
})
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await page.getByRole('button', { name: 'Start Sketch' }).click()
let previousCodeContent = await page.locator('.cm-content').innerText()
// click at 641, 135
await page.mouse.click(641, 135)
await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent)
previousCodeContent = await page.locator('.cm-content').innerText()
await page.waitForTimeout(300)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
})
await page.waitForTimeout(200)
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,30 +1,30 @@
{
"name": "untitled-app",
"version": "0.15.6",
"version": "0.17.0",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.10.2",
"@codemirror/autocomplete": "^6.15.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.17",
"@headlessui/react": "^1.7.18",
"@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.55",
"@kittycad/lib": "^0.1.0",
"@lezer/javascript": "^1.4.9",
"@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6",
"@replit/codemirror-interact": "^6.3.0",
"@tauri-apps/api": "^1.5.1",
"@tauri-apps/api": "^1.5.3",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.1",
"@testing-library/user-event": "^14.5.2",
"@ts-stack/markdown": "^1.5.0",
"@tweenjs/tween.js": "^23.1.1",
"@types/node": "^16.7.13",
"@types/react": "^18.2.41",
"@types/react-dom": "^18.0.0",
"@uiw/react-codemirror": "^4.21.20",
"@types/node": "^18.19.26",
"@types/react": "^18.2.67",
"@types/react-dom": "^18.2.22",
"@uiw/react-codemirror": "^4.21.24",
"@xstate/inspect": "^0.8.0",
"@xstate/react": "^3.2.2",
"crypto-js": "^4.2.0",
@ -39,27 +39,27 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-hotkeys-hook": "^4.4.1",
"react-hotkeys-hook": "^4.5.0",
"react-json-view": "^1.21.3",
"react-modal": "^3.16.1",
"react-modal-promise": "^1.0.2",
"react-router-dom": "^6.14.2",
"react-router-dom": "^6.22.3",
"sketch-helpers": "^0.0.4",
"swr": "^2.2.2",
"tauri-plugin-fs-extra-api": "https://github.com/tauri-apps/tauri-plugin-fs-extra#v1",
"three": "^0.160.0",
"toml": "^3.0.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2",
"ts-node": "^10.9.2",
"typescript": "^5.4.3",
"uuid": "^9.0.1",
"vitest": "^1.3.1",
"vitest": "^1.4.0",
"vscode-jsonrpc": "^8.1.0",
"vscode-languageserver-protocol": "^3.17.5",
"wasm-pack": "^0.12.1",
"web-vitals": "^3.5.0",
"web-vitals": "^3.5.2",
"ws": "^8.13.0",
"xstate": "^4.38.2",
"zustand": "^4.4.5"
"zustand": "^4.5.2"
},
"scripts": {
"start": "vite",
@ -110,41 +110,41 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.23.3",
"@playwright/test": "^1.39.0",
"@tauri-apps/cli": "^1.5.6",
"@types/crypto-js": "^4.1.1",
"@types/debounce-promise": "^3.1.8",
"@tauri-apps/cli": "^1.5.11",
"@types/crypto-js": "^4.2.2",
"@types/debounce-promise": "^3.1.9",
"@types/pixelmatch": "^5.2.6",
"@types/pngjs": "^6.0.4",
"@types/react-modal": "^3.16.3",
"@types/three": "^0.160.0",
"@types/uuid": "^9.0.4",
"@types/uuid": "^9.0.8",
"@types/wait-on": "^5.3.4",
"@types/wicg-file-system-access": "^2020.9.6",
"@types/wicg-file-system-access": "^2023.10.5",
"@types/ws": "^8.5.5",
"@vitejs/plugin-react": "^4.2.1",
"@wdio/cli": "^8.24.3",
"@wdio/globals": "^8.24.3",
"@wdio/local-runner": "^8.24.3",
"@wdio/mocha-framework": "^8.24.3",
"@wdio/spec-reporter": "^8.24.2",
"@wdio/local-runner": "^8.35.1",
"@wdio/mocha-framework": "^8.35.0",
"@wdio/spec-reporter": "^8.32.4",
"@xstate/cli": "^0.5.17",
"autoprefixer": "^10.4.13",
"eslint": "^8.53.0",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-css-modules": "^2.12.0",
"happy-dom": "^10.8.0",
"husky": "^8.0.3",
"happy-dom": "^14.3.1",
"husky": "^9.0.11",
"pixelmatch": "^5.3.0",
"pngjs": "^7.0.0",
"postcss": "^8.4.31",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.8.0",
"setimmediate": "^1.0.5",
"tailwindcss": "^3.3.6",
"vite": "^5.1.3",
"tailwindcss": "^3.4.1",
"vite": "^5.2.2",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-package-version": "^1.1.0",
"vite-tsconfig-paths": "^4.3.1",
"vite-tsconfig-paths": "^4.3.2",
"vitest-webgl-canvas-mock": "^1.1.0",
"wait-on": "^7.2.0",
"yarn": "^1.22.19"

6
src-tauri/Cargo.lock generated
View File

@ -1664,9 +1664,9 @@ dependencies = [
[[package]]
name = "kittycad"
version = "0.2.60"
version = "0.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aa5906d0730bd90f6b3331fe57c04951d00743169a29ee96408767b4060605"
checksum = "949555aa013e1cefa68f59671cfe96602a459c903376c53a410aebf3831d291f"
dependencies = [
"anyhow",
"async-trait",
@ -3876,7 +3876,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs-extra"
version = "0.0.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#d95a1b382f512a0be748e7a89e0f8fc4278010e2"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#8cd4a39864986ae3600be9f23d089afd3988c43a"
dependencies = [
"log",
"serde",

View File

@ -16,7 +16,7 @@ tauri-build = { version = "1.5.1", features = [] }
[dependencies]
anyhow = "1"
kittycad = "0.2.60"
kittycad = "0.2.61"
oauth2 = "4.4.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@ -7,7 +7,7 @@
},
"package": {
"productName": "zoo-modeling-app",
"version": "0.15.6"
"version": "0.17.0"
},
"tauri": {
"allowlist": {
@ -34,8 +34,11 @@
"request": true,
"scope": [
"https://dev.kittycad.io/*",
"https://dev.zoo.dev/*",
"https://kittycad.io/*",
"https://api.dev.kittycad.io/*"
"https://zoo.dev/*",
"https://api.dev.kittycad.io/*",
"https://api.dev.zoo.dev/*"
]
},
"os": {

View File

@ -28,7 +28,7 @@ import { CodeMenu } from 'components/CodeMenu'
import { TextEditor } from 'components/TextEditor'
import { Themes, getSystemTheme } from 'lib/theme'
import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
import { engineCommandManager } from './lang/std/engineConnection'
import { engineCommandManager } from 'lib/singletons'
import { useModelingContext } from 'hooks/useModelingContext'
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
import { isTauri } from 'lib/isTauri'

View File

@ -28,7 +28,7 @@ import {
import { CommandBarProvider } from 'components/CommandBar/CommandBarProvider'
import SettingsAuthProvider from 'components/SettingsAuthProvider'
import LspProvider from 'components/LspProvider'
import { KclContextProvider } from 'lang/KclSingleton'
import { KclContextProvider } from 'lang/KclProvider'
export const BROWSER_FILE_NAME = 'new'
@ -59,6 +59,7 @@ const router = createBrowserRouter([
{
loader: fileLoader,
id: paths.FILE,
path: paths.FILE + '/:id',
element: (
<Auth>
<FileMachineProvider>
@ -74,8 +75,11 @@ const router = createBrowserRouter([
),
children: [
{
path: paths.FILE + '/:id',
loader: onboardingRedirectLoader,
index: true,
element: <></>,
},
{
children: [
{
path: makeUrlPathRelative(paths.SETTINGS),

View File

@ -1,12 +1,12 @@
import { WheelEvent, useRef, useMemo } from 'react'
import { isCursorInSketchCommandRange } from 'lang/util'
import { engineCommandManager } from './lang/std/engineConnection'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { useModelingContext } from 'hooks/useModelingContext'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { ActionButton } from 'components/ActionButton'
import usePlatform from 'hooks/usePlatform'
import { isSingleCursorInPipe } from 'lang/queryAst'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { useKclContext } from 'lang/KclProvider'
import {
NetworkHealthState,
useNetworkStatus,

View File

@ -19,7 +19,7 @@ import {
import {
EngineCommand,
Subscription,
engineCommandManager,
EngineCommandManager,
} from 'lang/std/engineConnection'
import { v4 as uuidv4 } from 'uuid'
import { deg2Rad } from 'lib/utils2d'
@ -34,10 +34,6 @@ const tempQuaternion = new Quaternion() // just used for maths
type interactionType = 'pan' | 'rotate' | 'zoom'
const throttledEngCmd = throttle((cmd: EngineCommand) => {
engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 15)
interface ThreeCamValues {
position: Vector3
quaternion: Quaternion
@ -62,68 +58,8 @@ export type ReactCameraProperties =
const lastCmdDelay = 50
const throttledUpdateEngineCamera = throttle((threeValues: ThreeCamValues) => {
const cmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
...convertThreeCamValuesToEngineCam(threeValues),
},
}
engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 15)
let lastPerspectiveCmd: EngineCommand | null = null
let lastPerspectiveCmdTime: number = Date.now()
let lastPerspectiveCmdTimeoutId: number | null = null
const sendLastPerspectiveReliableChannel = () => {
if (
lastPerspectiveCmd &&
Date.now() - lastPerspectiveCmdTime >= lastCmdDelay
) {
engineCommandManager.sendSceneCommand(lastPerspectiveCmd, true)
lastPerspectiveCmdTime = Date.now()
}
}
const throttledUpdateEngineFov = throttle(
(vals: {
position: Vector3
quaternion: Quaternion
zoom: number
fov: number
target: Vector3
}) => {
const cmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_perspective_settings',
...convertThreeCamValuesToEngineCam({
...vals,
isPerspective: true,
}),
fov_y: vals.fov,
...calculateNearFarFromFOV(vals.fov),
},
}
engineCommandManager.sendSceneCommand(cmd)
lastPerspectiveCmd = cmd
lastPerspectiveCmdTime = Date.now()
if (lastPerspectiveCmdTimeoutId !== null) {
clearTimeout(lastPerspectiveCmdTimeoutId)
}
lastPerspectiveCmdTimeoutId = setTimeout(
sendLastPerspectiveReliableChannel,
lastCmdDelay
) as any as number
},
1000 / 30
)
export class CameraControls {
engineCommandManager: EngineCommandManager
syncDirection: 'clientToEngine' | 'engineToClient' = 'engineToClient'
camera: PerspectiveCamera | OrthographicCamera
target: Vector3
@ -213,7 +149,77 @@ export class CameraControls {
this.update(true)
}
constructor(isOrtho = false, domElement: HTMLCanvasElement) {
throttledEngCmd = throttle((cmd: EngineCommand) => {
this.engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 30)
throttledUpdateEngineCamera = throttle((threeValues: ThreeCamValues) => {
const cmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
...convertThreeCamValuesToEngineCam(threeValues),
},
}
this.engineCommandManager.sendSceneCommand(cmd)
}, 1000 / 15)
lastPerspectiveCmd: EngineCommand | null = null
lastPerspectiveCmdTime: number = Date.now()
lastPerspectiveCmdTimeoutId: number | null = null
sendLastPerspectiveReliableChannel = () => {
if (
this.lastPerspectiveCmd &&
Date.now() - this.lastPerspectiveCmdTime >= lastCmdDelay
) {
this.engineCommandManager.sendSceneCommand(this.lastPerspectiveCmd, true)
this.lastPerspectiveCmdTime = Date.now()
}
}
throttledUpdateEngineFov = throttle(
(vals: {
position: Vector3
quaternion: Quaternion
zoom: number
fov: number
target: Vector3
}) => {
const cmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_perspective_settings',
...convertThreeCamValuesToEngineCam({
...vals,
isPerspective: true,
}),
fov_y: vals.fov,
...calculateNearFarFromFOV(vals.fov),
},
}
this.engineCommandManager.sendSceneCommand(cmd)
this.lastPerspectiveCmd = cmd
this.lastPerspectiveCmdTime = Date.now()
if (this.lastPerspectiveCmdTimeoutId !== null) {
clearTimeout(this.lastPerspectiveCmdTimeoutId)
}
this.lastPerspectiveCmdTimeoutId = setTimeout(
this.sendLastPerspectiveReliableChannel,
lastCmdDelay
) as any as number
},
1000 / 30
)
constructor(
isOrtho = false,
domElement: HTMLCanvasElement,
engineCommandManager: EngineCommandManager
) {
this.engineCommandManager = engineCommandManager
this.camera = isOrtho ? new OrthographicCamera() : new PerspectiveCamera()
this.camera.up.set(0, 0, 1)
this.camera.far = 20000
@ -259,15 +265,15 @@ export class CameraControls {
this.onCameraChange()
}
setTimeout(() => {
engineCommandManager.subscribeTo({
this.engineCommandManager.subscribeTo({
event: 'camera_drag_end',
callback: cb,
})
engineCommandManager.subscribeTo({
this.engineCommandManager.subscribeTo({
event: 'default_camera_zoom',
callback: cb,
})
engineCommandManager.subscribeTo({
this.engineCommandManager.subscribeTo({
event: 'default_camera_get_settings',
callback: cb,
})
@ -310,7 +316,7 @@ export class CameraControls {
this.handleStart()
if (this.syncDirection === 'engineToClient') {
void engineCommandManager.sendSceneCommand({
void this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_start',
@ -334,7 +340,7 @@ export class CameraControls {
if (interaction === 'none') return
if (this.syncDirection === 'engineToClient') {
throttledEngCmd({
this.throttledEngCmd({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_move',
@ -377,7 +383,7 @@ export class CameraControls {
if (this.syncDirection === 'engineToClient') {
const interaction = this.getInteractionType(event)
if (interaction === 'none') return
void engineCommandManager.sendSceneCommand({
void this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_end',
@ -401,7 +407,7 @@ export class CameraControls {
this.handleEnd()
return
}
throttledEngCmd({
this.throttledEngCmd({
type: 'modeling_cmd_req',
cmd: {
type: 'default_camera_zoom',
@ -425,6 +431,7 @@ export class CameraControls {
if (this.camera instanceof OrthographicCamera) return
const { x: px, y: py, z: pz } = this.camera.position
const { x: qx, y: qy, z: qz, w: qw } = this.camera.quaternion
const oldCamUp = this.camera.up.clone()
const aspect = window.innerWidth / window.innerHeight
this.lastPerspectiveFov = this.camera.fov
const { z_near, z_far } = calculateNearFarFromFOV(this.lastPerspectiveFov)
@ -436,7 +443,8 @@ export class CameraControls {
z_near,
z_far
)
this.camera.up.set(0, 0, 1)
this.camera.up.copy(oldCamUp)
this.camera.layers.enable(SKETCH_LAYER)
if (DEBUG_SHOW_INTERSECTION_PLANE)
this.camera.layers.enable(INTERSECTION_PLANE_LAYER)
@ -447,7 +455,7 @@ export class CameraControls {
this.camera.quaternion.set(qx, qy, qz, qw)
this.camera.updateProjectionMatrix()
engineCommandManager.sendSceneCommand({
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
@ -458,13 +466,14 @@ export class CameraControls {
}
private createPerspectiveCamera = () => {
const { z_near, z_far } = calculateNearFarFromFOV(this.lastPerspectiveFov)
const previousCamUp = this.camera.up.clone()
this.camera = new PerspectiveCamera(
this.lastPerspectiveFov,
window.innerWidth / window.innerHeight,
z_near,
z_far
)
this.camera.up.set(0, 0, 1)
this.camera.up.copy(previousCamUp)
this.camera.layers.enable(SKETCH_LAYER)
if (DEBUG_SHOW_INTERSECTION_PLANE)
this.camera.layers.enable(INTERSECTION_PLANE_LAYER)
@ -490,7 +499,7 @@ export class CameraControls {
}
usePerspectiveCamera = () => {
this._usePerspectiveCamera()
engineCommandManager.sendSceneCommand({
this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
@ -558,7 +567,7 @@ export class CameraControls {
this.camera.near = z_near
this.camera.far = z_far
throttledUpdateEngineFov({
this.throttledUpdateEngineFov({
fov: newFov,
position: newPosition,
quaternion: this.camera.quaternion,
@ -618,7 +627,7 @@ export class CameraControls {
didChange = true
}
this.safeLookAtTarget()
this.safeLookAtTarget(this.camera.up)
// Update the camera's matrices
this.camera.updateMatrixWorld()
@ -683,48 +692,48 @@ export class CameraControls {
targetAngle = -Math.PI / 2,
duration = 500
): Promise<void> {
// should tween the camera so that it has an xPosition of 0, and forcing it's yPosition to be negative
// zPosition should stay the same
const xyRadius = Math.sqrt(
(this.target.x - this.camera.position.x) ** 2 +
(this.target.y - this.camera.position.y) ** 2
)
const xyAngle = Math.atan2(
this.camera.position.y - this.target.y,
this.camera.position.x - this.target.x
)
this._isCamMovingCallback(true, true)
return new Promise((resolve) => {
// should tween the camera so that it has an xPosition of 0, and forcing it's yPosition to be negative
// zPosition should stay the same
const xyRadius = Math.sqrt(
(this.target.x - this.camera.position.x) ** 2 +
(this.target.y - this.camera.position.y) ** 2
)
const xyAngle = Math.atan2(
this.camera.position.y - this.target.y,
this.camera.position.x - this.target.x
)
const camAtTime = (obj: { angle: number }) => {
const x = xyRadius * Math.cos(obj.angle)
const y = xyRadius * Math.sin(obj.angle)
this.camera.position.set(
this.target.x + x,
this.target.y + y,
this.camera.position.z
)
this.update()
this.onCameraChange()
}
const onComplete = (obj: { angle: number }) => {
camAtTime(obj)
this._isCamMovingCallback(false, true)
// resolve after a couple of frames
requestAnimationFrame(() => {
requestAnimationFrame(() => resolve())
})
}
this._isCamMovingCallback(true, true)
if (isReducedMotion()) {
onComplete({ angle: targetAngle })
return
}
new TWEEN.Tween({ angle: xyAngle })
.to({ angle: targetAngle }, duration)
.onUpdate((obj) => {
const x = xyRadius * Math.cos(obj.angle)
const y = xyRadius * Math.sin(obj.angle)
this.camera.position.set(
this.target.x + x,
this.target.y + y,
this.camera.position.z
)
this.update()
this.onCameraChange()
})
.onComplete((obj) => {
const x = xyRadius * Math.cos(obj.angle)
const y = xyRadius * Math.sin(obj.angle)
this.camera.position.set(
this.target.x + x,
this.target.y + y,
this.camera.position.z
)
this.update()
this.onCameraChange()
this._isCamMovingCallback(false, true)
// resolve after a couple of frames
requestAnimationFrame(() => {
requestAnimationFrame(() => resolve())
})
})
.onUpdate(camAtTime)
.onComplete(onComplete)
.start()
})
}
@ -778,6 +787,8 @@ export class CameraControls {
targetQuaternion,
animationProgress
)
const up = new Vector3(0, 0, 1).applyQuaternion(currentQ)
this.camera.up.copy(up)
const currentTarget = tempVec.lerpVectors(
initialTarget,
targetPosition,
@ -802,7 +813,7 @@ export class CameraControls {
const onComplete = async () => {
if (isReducedMotion() && toOrthographic) {
cameraAtTime(0.99)
cameraAtTime(0.9999)
this.useOrthographicCamera()
} else if (toOrthographic) {
await this.animateToOrthographic()
@ -863,37 +874,40 @@ export class CameraControls {
animateFovChange() // Start the animation
})
animateToPerspective = () =>
animateToPerspective = (targetCamUp = new Vector3(0, 0, 1)) =>
new Promise((resolve) => {
if (this.syncDirection === 'engineToClient')
if (this.syncDirection === 'engineToClient') {
console.warn(
'animate To Perspective not design to work with engineToClient syncDirection.'
)
}
this.isFovAnimationInProgress = true
// Immediately set the camera to perspective with a very low FOV
const targetFov = this.fovBeforeOrtho // Target FOV for perspective
this.lastPerspectiveFov = 4
let currentFov = 4
this.camera.updateProjectionMatrix()
const fovAnimationStep = (targetFov - currentFov) / FRAMES_TO_ANIMATE_IN
const initialCameraUp = this.camera.up.clone()
this.usePerspectiveCamera()
const tempVec = new Vector3()
const animateFovChange = () => {
if (this.camera instanceof OrthographicCamera) return
if (this.camera.fov < targetFov) {
// Increase the FOV
currentFov = Math.min(currentFov + fovAnimationStep, targetFov)
// this.camera.fov = currentFov
this.camera.updateProjectionMatrix()
this.dollyZoom(currentFov)
requestAnimationFrame(animateFovChange) // Continue the animation
} else {
// Set the flag to false as the FOV animation is complete
this.isFovAnimationInProgress = false
resolve(true)
}
const cameraAtTime = (t: number) => {
currentFov =
this.lastPerspectiveFov + (targetFov - this.lastPerspectiveFov) * t
const currentUp = tempVec.lerpVectors(initialCameraUp, targetCamUp, t)
this.camera.up.copy(currentUp)
this.dollyZoom(currentFov)
}
animateFovChange() // Start the animation
const onComplete = () => {
this.isFovAnimationInProgress = false
resolve(true)
}
new TWEEN.Tween({ t: 0 })
.to({ t: 1 }, isReducedMotion() ? 50 : FRAMES_TO_ANIMATE_IN * 16) // Assuming 60fps, hence 16ms per frame
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(({ t }) => cameraAtTime(t))
.onComplete(onComplete)
.start()
})
reactCameraPropertiesCallback: (a: ReactCameraProperties) => void = () => {}
@ -916,7 +930,7 @@ export class CameraControls {
}
if (this.syncDirection === 'clientToEngine' || forceUpdate)
throttledUpdateEngineCamera({
this.throttledUpdateEngineCamera({
quaternion: this.camera.quaternion,
position: this.camera.position,
zoom: this.camera.zoom,

View File

@ -4,9 +4,10 @@ import { useModelingContext } from 'hooks/useModelingContext'
import { cameraMouseDragGuards } from 'lib/cameraControls'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useStore } from 'useStore'
import { DEBUG_SHOW_BOTH_SCENES, sceneInfra } from './sceneInfra'
import { DEBUG_SHOW_BOTH_SCENES } from './sceneInfra'
import { ReactCameraProperties } from './CameraControls'
import { throttle } from 'lib/utils'
import { sceneInfra } from 'lib/singletons'
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false)

View File

@ -40,3 +40,12 @@ export function isQuaternionVertical(q: Quaternion) {
// no x or y components means it's vertical
return compareVec2Epsilon2([v.x, v.y], [0, 0])
}
export function quaternionFromUpNForward(up: Vector3, forward: Vector3) {
const dummyCam = new PerspectiveCamera()
dummyCam.up.copy(up)
dummyCam.position.copy(forward)
dummyCam.lookAt(0, 0, 0)
dummyCam.updateMatrix()
return dummyCam.quaternion.clone()
}

View File

@ -5,7 +5,6 @@ import {
Group,
Intersection,
LineCurve3,
Matrix4,
Mesh,
MeshBasicMaterial,
Object3D,
@ -29,7 +28,6 @@ import {
INTERSECTION_PLANE_LAYER,
OnMouseEnterLeaveArgs,
RAYCASTABLE_PLANE,
sceneInfra,
SKETCH_GROUP_SEGMENTS,
SKETCH_LAYER,
X_AXIS,
@ -37,7 +35,7 @@ import {
Y_AXIS,
YZ_PLANE,
} from './sceneInfra'
import { isQuaternionVertical } from './helpers'
import { isQuaternionVertical, quaternionFromUpNForward } from './helpers'
import {
CallExpression,
getTangentialArcToInfo,
@ -53,10 +51,9 @@ import {
VariableDeclaration,
VariableDeclarator,
} from 'lang/wasm'
import { kclManager } from 'lang/KclSingleton'
import { engineCommandManager, kclManager, sceneInfra } from 'lib/singletons'
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
import { executeAst } from 'useStore'
import { engineCommandManager } from 'lang/std/engineConnection'
import { executeAst, useStore } from 'useStore'
import {
createArcGeometry,
dashedStraight,
@ -70,16 +67,23 @@ import {
changeSketchArguments,
updateStartProfileAtArgs,
} from 'lang/std/sketch'
import { isReducedMotion, throttle } from 'lib/utils'
import { throttle } from 'lib/utils'
import {
createArrayExpression,
createCallExpressionStdLib,
createLiteral,
createPipeSubstitution,
} from 'lang/modifyAst'
import { getEventForSegmentSelection } from 'lib/selections'
import {
getEventForSegmentSelection,
sendSelectEventToEngine,
} from 'lib/selections'
import { getTangentPointFromPreviousArc } from 'lib/utils2d'
import { createGridHelper, orthoScale, perspScale } from './helpers'
import { Models } from '@kittycad/lib'
import { v4 as uuidv4 } from 'uuid'
import { SketchDetails } from 'machines/modelingMachine'
import { EngineCommandManager } from 'lang/std/engineConnection'
type DraftSegment = 'line' | 'tangentialArcTo'
@ -95,14 +99,16 @@ export const PROFILE_START = 'profile-start'
// This singleton Class is responsible for all of the things the user sees and interacts with.
// That mostly mean sketch elements.
// Cameras, controls, raycasters, etc are handled by sceneInfra
class SceneEntities {
export class SceneEntities {
engineCommandManager: EngineCommandManager
scene: Scene
sceneProgramMemory: ProgramMemory = { root: {}, return: null }
activeSegments: { [key: string]: Group } = {}
intersectionPlane: Mesh | null = null
axisGroup: Group | null = null
currentSketchQuaternion: Quaternion | null = null
constructor() {
constructor(engineCommandManager: EngineCommandManager) {
this.engineCommandManager = engineCommandManager
this.scene = sceneInfra?.scene
sceneInfra?.camControls.subscribeToCamChange(this.onCamChange)
}
@ -164,7 +170,7 @@ class SceneEntities {
console.warn('createIntersectionPlane called when it already exists')
return
}
const hundredM = 1000000
const hundredM = 100_0000
const planeGeometry = new PlaneGeometry(hundredM, hundredM)
const planeMaterial = new MeshBasicMaterial({
color: 0xff0000,
@ -178,7 +184,12 @@ class SceneEntities {
this.intersectionPlane.layers.set(INTERSECTION_PLANE_LAYER)
this.scene.add(this.intersectionPlane)
}
createSketchAxis(sketchPathToNode: PathToNode) {
createSketchAxis(
sketchPathToNode: PathToNode,
forward: [number, number, number],
up: [number, number, number],
sketchPosition?: [number, number, number]
) {
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
const baseXColor = 0x000055
const baseYColor = 0x550000
@ -238,14 +249,12 @@ class SceneEntities {
child.layers.set(SKETCH_LAYER)
})
const quat = quaternionFromSketchGroup(
sketchGroupFromPathToNode({
pathToNode: sketchPathToNode,
ast: kclManager.ast,
programMemory: kclManager.programMemory,
})
const quat = quaternionFromUpNForward(
new Vector3(...up),
new Vector3(...forward)
)
this.axisGroup.setRotationFromQuaternion(quat)
sketchPosition && this.axisGroup.position.set(...sketchPosition)
this.scene.add(this.axisGroup)
}
removeIntersectionPlane() {
@ -255,27 +264,33 @@ class SceneEntities {
async setupSketch({
sketchPathToNode,
ast,
// is draft line assumes the last segment is a draft line, and mods it as the user moves the mouse
draftSegment,
forward,
up,
position,
maybeModdedAst,
draftExpressionsIndices,
}: {
sketchPathToNode: PathToNode
ast?: Program
draftSegment?: DraftSegment
}) {
maybeModdedAst: Program
draftExpressionsIndices?: { start: number; end: number }
forward: [number, number, number]
up: [number, number, number]
position?: [number, number, number]
}): Promise<{
truncatedAst: Program
programMemoryOverride: ProgramMemory
sketchGroup: SketchGroup
variableDeclarationName: string
}> {
sceneInfra.resetMouseListeners()
this.createIntersectionPlane()
const { truncatedAst, programMemoryOverride, variableDeclarationName } =
this.prepareTruncatedMemoryAndAst(
sketchPathToNode || [],
kclManager.ast,
draftSegment
)
this.prepareTruncatedMemoryAndAst(sketchPathToNode || [], maybeModdedAst)
const { programMemory } = await executeAst({
ast: truncatedAst,
useFakeExecutor: true,
engineCommandManager,
engineCommandManager: this.engineCommandManager,
programMemoryOverride,
})
const sketchGroup = sketchGroupFromPathToNode({
@ -283,9 +298,16 @@ class SceneEntities {
ast: kclManager.ast,
programMemory,
})
if (!Array.isArray(sketchGroup?.value)) return
if (!Array.isArray(sketchGroup?.value))
return {
truncatedAst,
programMemoryOverride,
sketchGroup,
variableDeclarationName,
}
this.sceneProgramMemory = programMemory
const group = new Group()
position && group.position.set(...position)
group.userData = {
type: SKETCH_GROUP_SEGMENTS,
pathToNode: sketchPathToNode,
@ -325,7 +347,10 @@ class SceneEntities {
kclManager.ast,
segment.__geoMeta.sourceRange
)
if (draftSegment && (sketchGroup.value[index - 1] || sketchGroup.start)) {
if (
draftExpressionsIndices &&
(sketchGroup.value[index - 1] || sketchGroup.start)
) {
const previousSegment =
sketchGroup.value[index - 1] || sketchGroup.start
const previousSegmentPathToNode = getNodePathFromSourceRange(
@ -340,7 +365,9 @@ class SceneEntities {
segPathToNode[1][0] = bodyIndex
}
const isDraftSegment =
draftSegment && index === sketchGroup.value.length - 1
draftExpressionsIndices &&
index <= draftExpressionsIndices.end &&
index >= draftExpressionsIndices.start
let seg
const callExpName = getNodeFromPath<CallExpression>(
kclManager.ast,
@ -377,122 +404,182 @@ class SceneEntities {
this.activeSegments[JSON.stringify(segPathToNode)] = seg
})
this.currentSketchQuaternion = quaternionFromSketchGroup(sketchGroup)
this.currentSketchQuaternion = quaternionFromUpNForward(
new Vector3(...up),
new Vector3(...forward)
)
group.setRotationFromQuaternion(this.currentSketchQuaternion)
this.intersectionPlane &&
this.intersectionPlane.setRotationFromQuaternion(
this.currentSketchQuaternion
)
this.intersectionPlane &&
position &&
this.intersectionPlane.position.set(...position)
this.scene.add(group)
if (!draftSegment) {
sceneInfra.setCallbacks({
onDrag: ({ selected, intersectionPoint, mouseEvent, intersects }) => {
if (mouseEvent.which !== 1) return
this.onDragSegment({
object: selected,
intersection2d: intersectionPoint.twoD,
intersects,
sketchPathToNode,
})
},
onMove: () => {},
onClick: (args) => {
if (args?.mouseEvent.which !== 1) return
if (!args || !args.selected) {
sceneInfra.modelingSend({
type: 'Set selection',
data: {
selectionType: 'singleCodeCursor',
},
})
return
}
const { selected } = args
const event = getEventForSegmentSelection(selected)
if (!event) return
sceneInfra.modelingSend(event)
},
...mouseEnterLeaveCallbacks(),
})
} else {
sceneInfra.setCallbacks({
onClick: async (args) => {
if (!args) return
if (args.mouseEvent.which !== 1) return
const { intersectionPoint } = args
let intersection2d = intersectionPoint?.twoD
const profileStart = args.intersects
.map(({ object }) => getParentGroup(object, [PROFILE_START]))
.find((a) => a?.name === PROFILE_START)
let modifiedAst
if (profileStart) {
modifiedAst = addCloseToPipe({
node: kclManager.ast,
programMemory: kclManager.programMemory,
pathToNode: sketchPathToNode,
})
} else if (intersection2d) {
const lastSegment = sketchGroup.value.slice(-1)[0]
modifiedAst = addNewSketchLn({
node: kclManager.ast,
programMemory: kclManager.programMemory,
to: [intersection2d.x, intersection2d.y],
from: [lastSegment.to[0], lastSegment.to[1]],
fnName:
lastSegment.type === 'TangentialArcTo'
? 'tangentialArcTo'
: 'line',
pathToNode: sketchPathToNode,
}).modifiedAst
} else {
// return early as we didn't modify the ast
return
}
kclManager.executeAstMock(modifiedAst, { updates: 'code' })
await this.tearDownSketch({ removeAxis: false })
this.setupSketch({ sketchPathToNode, draftSegment })
},
onMove: (args) => {
this.onDragSegment({
intersection2d: args.intersectionPoint.twoD,
object: Object.values(this.activeSegments).slice(-1)[0],
intersects: args.intersects,
sketchPathToNode,
draftInfo: {
draftSegment,
truncatedAst,
programMemoryOverride,
variableDeclarationName,
},
})
},
...mouseEnterLeaveCallbacks(),
})
}
sceneInfra.camControls.enableRotate = false
return {
truncatedAst,
programMemoryOverride,
sketchGroup,
variableDeclarationName,
}
}
updateAstAndRejigSketch = async (
sketchPathToNode: PathToNode,
modifiedAst: Program
modifiedAst: Program,
forward: [number, number, number],
up: [number, number, number],
origin: [number, number, number]
) => {
await kclManager.updateAst(modifiedAst, false)
await this.tearDownSketch({ removeAxis: false })
this.setupSketch({ sketchPathToNode })
await this.setupSketch({
sketchPathToNode,
forward,
up,
position: origin,
maybeModdedAst: kclManager.ast,
})
this.setupSketchIdleCallbacks(sketchPathToNode)
}
setUpDraftArc = async (sketchPathToNode: PathToNode) => {
await this.tearDownSketch({ removeAxis: false })
await new Promise((resolve) => setTimeout(resolve, 100))
this.setupSketch({ sketchPathToNode, draftSegment: 'tangentialArcTo' })
setUpDraftSegment = async (
sketchPathToNode: PathToNode,
forward: [number, number, number],
up: [number, number, number],
origin: [number, number, number],
segmentName: 'line' | 'tangentialArcTo' = 'line',
shouldTearDown = true
) => {
const _ast = JSON.parse(JSON.stringify(kclManager.ast))
const variableDeclarationName =
getNodeFromPath<VariableDeclaration>(
_ast,
sketchPathToNode || [],
'VariableDeclaration'
)?.node?.declarations?.[0]?.id?.name || ''
const sg = kclManager.programMemory.root[
variableDeclarationName
] as SketchGroup
const lastSeg = sg.value.slice(-1)[0] || sg.start
const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1`
let modifiedAst = addNewSketchLn({
node: kclManager.ast,
programMemory: kclManager.programMemory,
to: [lastSeg.to[0], lastSeg.to[1]],
from: [lastSeg.to[0], lastSeg.to[1]],
fnName: segmentName,
pathToNode: sketchPathToNode,
}).modifiedAst
modifiedAst = parse(recast(modifiedAst))
const draftExpressionsIndices = { start: index, end: index }
if (shouldTearDown) await this.tearDownSketch({ removeAxis: false })
const { truncatedAst, programMemoryOverride, sketchGroup } =
await this.setupSketch({
sketchPathToNode,
forward,
up,
position: origin,
maybeModdedAst: modifiedAst,
draftExpressionsIndices,
})
sceneInfra.setCallbacks({
onClick: async (args) => {
if (!args) return
if (args.mouseEvent.which !== 1) return
const { intersectionPoint } = args
let intersection2d = intersectionPoint?.twoD
const profileStart = args.intersects
.map(({ object }) => getParentGroup(object, [PROFILE_START]))
.find((a) => a?.name === PROFILE_START)
let modifiedAst
if (profileStart) {
modifiedAst = addCloseToPipe({
node: kclManager.ast,
programMemory: kclManager.programMemory,
pathToNode: sketchPathToNode,
})
} else if (intersection2d) {
const lastSegment = sketchGroup.value.slice(-1)[0]
modifiedAst = addNewSketchLn({
node: kclManager.ast,
programMemory: kclManager.programMemory,
to: [intersection2d.x, intersection2d.y],
from: [lastSegment.to[0], lastSegment.to[1]],
fnName:
lastSegment.type === 'TangentialArcTo'
? 'tangentialArcTo'
: 'line',
pathToNode: sketchPathToNode,
}).modifiedAst
} else {
// return early as we didn't modify the ast
return
}
await kclManager.executeAstMock(modifiedAst, { updates: 'code' })
this.setUpDraftSegment(
sketchPathToNode,
forward,
up,
origin,
segmentName
)
},
onMove: (args) => {
this.onDragSegment({
intersection2d: args.intersectionPoint.twoD,
object: Object.values(this.activeSegments).slice(-1)[0],
intersects: args.intersects,
sketchPathToNode,
draftInfo: {
truncatedAst,
programMemoryOverride,
variableDeclarationName,
},
})
},
...mouseEnterLeaveCallbacks(),
})
}
setUpDraftLine = async (sketchPathToNode: PathToNode) => {
await this.tearDownSketch({ removeAxis: false })
await new Promise((resolve) => setTimeout(resolve, 100))
this.setupSketch({ sketchPathToNode, draftSegment: 'line' })
setupSketchIdleCallbacks = (pathToNode: PathToNode) => {
sceneInfra.setCallbacks({
onDrag: ({ selected, intersectionPoint, mouseEvent, intersects }) => {
if (mouseEvent.which !== 1) return
this.onDragSegment({
object: selected,
intersection2d: intersectionPoint.twoD,
intersects,
sketchPathToNode: pathToNode,
})
},
onMove: () => {},
onClick: (args) => {
if (args?.mouseEvent.which !== 1) return
if (!args || !args.selected) {
sceneInfra.modelingSend({
type: 'Set selection',
data: {
selectionType: 'singleCodeCursor',
},
})
return
}
const { selected } = args
const event = getEventForSegmentSelection(selected)
if (!event) return
sceneInfra.modelingSend(event)
},
...mouseEnterLeaveCallbacks(),
})
}
onDraftLineMouseMove = () => {}
prepareTruncatedMemoryAndAst = (
sketchPathToNode: PathToNode,
ast?: Program,
@ -516,7 +603,6 @@ class SceneEntities {
sketchPathToNode: PathToNode
intersects: Intersection<Object3D<Object3DEventMap>>[]
draftInfo?: {
draftSegment: DraftSegment
truncatedAst: Program
programMemoryOverride: ProgramMemory
variableDeclarationName: string
@ -595,7 +681,7 @@ class SceneEntities {
const { programMemory } = await executeAst({
ast: truncatedAst,
useFakeExecutor: true,
engineCommandManager: engineCommandManager,
engineCommandManager: this.engineCommandManager,
programMemoryOverride,
})
this.sceneProgramMemory = programMemory
@ -785,10 +871,10 @@ class SceneEntities {
}
}
async animateAfterSketch() {
if (isReducedMotion()) {
sceneInfra.camControls.usePerspectiveCamera()
return
}
// if (isReducedMotion()) {
// sceneInfra.camControls.usePerspectiveCamera()
// return
// }
await sceneInfra.camControls.animateToPerspective()
}
removeSketchGrid() {
@ -853,26 +939,81 @@ class SceneEntities {
const type: DefaultPlane = selected.userData.type
selected.material.color = defaultPlaneColor(type)
},
onClick: (args) => {
onClick: async (args) => {
const checkExtrudeFaceClick = async (): Promise<boolean> => {
const { streamDimensions } = useStore.getState()
const { entity_id } = await sendSelectEventToEngine(
args?.mouseEvent,
document.getElementById('video-stream') as HTMLVideoElement,
streamDimensions
)
if (!entity_id) return false
const artifact = this.engineCommandManager.artifactMap[entity_id]
if (artifact?.commandType !== 'solid3d_get_extrusion_face_info')
return false
const faceInfo: Models['FaceIsPlanar_type'] = (
await this.engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'face_is_planar',
object_id: entity_id,
},
})
)?.data?.data
if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis)
return false
const { z_axis, origin, y_axis } = faceInfo
const pathToNode = getNodePathFromSourceRange(
kclManager.ast,
artifact.range
)
sceneInfra.modelingSend({
type: 'Select default plane',
data: {
type: 'extrudeFace',
zAxis: [z_axis.x, z_axis.y, z_axis.z],
yAxis: [y_axis.x, y_axis.y, y_axis.z],
position: [origin.x, origin.y, origin.z].map(
(num) => num / sceneInfra._baseUnitMultiplier
) as [number, number, number],
extrudeSegmentPathToNode: pathToNode,
cap:
artifact?.additionalData?.type === 'cap'
? artifact.additionalData.info
: 'none',
},
})
return true
}
if (await checkExtrudeFaceClick()) return
if (!args || !args.intersects?.[0]) return
if (args.mouseEvent.which !== 1) return
const { intersects } = args
const type = intersects?.[0].object.name || ''
const posNorm = Number(intersects?.[0]?.normal?.z) > 0
let planeString: DefaultPlaneStr = posNorm ? 'XY' : '-XY'
let normal: [number, number, number] = posNorm ? [0, 0, 1] : [0, 0, -1]
let zAxis: [number, number, number] = posNorm ? [0, 0, 1] : [0, 0, -1]
let yAxis: [number, number, number] = [0, 1, 0]
if (type === YZ_PLANE) {
planeString = posNorm ? 'YZ' : '-YZ'
normal = posNorm ? [1, 0, 0] : [-1, 0, 0]
zAxis = posNorm ? [1, 0, 0] : [-1, 0, 0]
yAxis = [0, 0, 1]
} else if (type === XZ_PLANE) {
planeString = posNorm ? 'XZ' : '-XZ'
normal = posNorm ? [0, 1, 0] : [0, -1, 0]
zAxis = posNorm ? [0, 1, 0] : [0, -1, 0]
yAxis = [0, 0, 1]
}
sceneInfra.modelingSend({
type: 'Select default plane',
data: {
type: 'defaultPlane',
plane: planeString,
normal,
zAxis,
yAxis,
},
})
},
@ -882,8 +1023,6 @@ class SceneEntities {
export type DefaultPlaneStr = 'XY' | 'XZ' | 'YZ' | '-XY' | '-XZ' | '-YZ'
export const sceneEntitiesManager = new SceneEntities()
// calculations/pure-functions/easy to test so no excuse not to
function prepareTruncatedMemoryAndAst(
@ -1005,30 +1144,6 @@ export function sketchGroupFromPathToNode({
return programMemory.root[varDec?.id?.name || ''] as SketchGroup
}
export function quaternionFromSketchGroup(
sketchGroup: SketchGroup
): Quaternion {
// TODO figure what is happening in the executor that it's some times returning
// [x,y,z] and sometimes {x,y,z}
if (!sketchGroup?.zAxis) {
// sometimes sketchGroup is undefined,
// I don't quiet understand the circumstances yet
// and it's very intermittent so leaving this here for now
console.log('no zAxis', sketchGroup)
console.trace('no zAxis')
}
const zAxisVec = massageFormats(sketchGroup?.zAxis)
const yAxisVec = massageFormats(sketchGroup?.yAxis)
const xAxisVec = new Vector3().crossVectors(yAxisVec, zAxisVec).normalize()
let yAxisVecNormalized = yAxisVec.clone().normalize()
let zAxisVecNormalized = zAxisVec.clone().normalize()
let rotationMatrix = new Matrix4()
rotationMatrix.makeBasis(xAxisVec, yAxisVecNormalized, zAxisVecNormalized)
return new Quaternion().setFromRotationMatrix(rotationMatrix)
}
function colorSegment(object: any, color: number) {
const segmentHead = getParentGroup(object, [ARROWHEAD, PROFILE_START])
if (segmentHead) {
@ -1063,10 +1178,68 @@ export function getSketchQuaternion(
programMemory: kclManager.programMemory,
})
const zAxis = sketchGroup?.zAxis || sketchNormalBackUp
return getQuaternionFromZAxis(massageFormats(zAxis))
}
export async function getSketchOrientationDetails(
sketchPathToNode: PathToNode
): Promise<{
quat: Quaternion
sketchDetails: SketchDetails
}> {
const sketchGroup = sketchGroupFromPathToNode({
pathToNode: sketchPathToNode,
ast: kclManager.ast,
programMemory: kclManager.programMemory,
})
if (sketchGroup.on.type === 'plane') {
const zAxis = sketchGroup?.zAxis
return {
quat: getQuaternionFromZAxis(massageFormats(zAxis)),
sketchDetails: {
sketchPathToNode,
zAxis: [zAxis.x, zAxis.y, zAxis.z],
yAxis: [sketchGroup.yAxis.x, sketchGroup.yAxis.y, sketchGroup.yAxis.z],
origin: [0, 0, 0],
},
}
}
if (sketchGroup.on.type === 'face') {
const faceInfo: Models['FaceIsPlanar_type'] = (
await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'face_is_planar',
object_id: sketchGroup.on.faceId,
},
})
)?.data?.data
if (!faceInfo?.origin || !faceInfo?.z_axis || !faceInfo?.y_axis)
throw new Error('faceInfo')
const { z_axis, y_axis, origin } = faceInfo
const quaternion = quaternionFromUpNForward(
new Vector3(y_axis.x, y_axis.y, y_axis.z),
new Vector3(z_axis.x, z_axis.y, z_axis.z)
)
return {
quat: quaternion,
sketchDetails: {
sketchPathToNode,
zAxis: [z_axis.x, z_axis.y, z_axis.z],
yAxis: [y_axis.x, y_axis.y, y_axis.z],
origin: [origin.x, origin.y, origin.z],
},
}
}
throw new Error(
'sketchGroup.on.type not recognized, has a new type been added?'
)
}
export function getQuaternionFromZAxis(zAxis: Vector3): Quaternion {
const dummyCam = new PerspectiveCamera()
dummyCam.up.set(0, 0, 1)
const _zAxis = massageFormats(zAxis)
dummyCam.position.copy(_zAxis)
dummyCam.position.copy(zAxis)
dummyCam.lookAt(0, 0, 0)
dummyCam.updateMatrix()
const quaternion = dummyCam.quaternion.clone()
@ -1075,7 +1248,7 @@ export function getSketchQuaternion(
// because vertical quaternions are a gimbal lock, for the orbit controls
// it's best to set them explicitly to the vertical position with a known good camera up
if (isVert && _zAxis.z < 0) {
if (isVert && zAxis.z < 0) {
quaternion.set(0, 1, 0, 0)
} else if (isVert) {
quaternion.set(0, 0, 0, 1)

View File

@ -27,6 +27,7 @@ import { Axis } from 'lib/selections'
import { type BaseUnit } from 'lib/settings/settingsTypes'
import { SETTINGS_PERSIST_KEY } from 'lib/constants'
import { CameraControls } from './CameraControls'
import { EngineCommandManager } from 'lang/std/engineConnection'
type SendType = ReturnType<typeof useModelingContext>['send']
@ -37,8 +38,10 @@ export const ZOOM_MAGIC_NUMBER = 63.5
export const INTERSECTION_PLANE_LAYER = 1
export const SKETCH_LAYER = 2
export const DEBUG_SHOW_INTERSECTION_PLANE = false
export const DEBUG_SHOW_BOTH_SCENES = false
// redundant types so that it can be changed temporarily but CI will catch the wrong type
export const DEBUG_SHOW_INTERSECTION_PLANE: false = false
export const DEBUG_SHOW_BOTH_SCENES: false = false
export const RAYCASTABLE_PLANE = 'raycastable-plane'
export const DEFAULT_PLANES = 'default-planes'
@ -84,7 +87,7 @@ interface OnMoveCallbackArgs {
// This singleton class is responsible for all of the under the hood setup for the client side scene.
// That is the cameras and switching between them, raycasters for click mouse events and their abstractions (onClick etc), setting up controls.
// Anything that added the the scene for the user to interact with is probably in SceneEntities.ts
class SceneInfra {
export class SceneInfra {
static instance: SceneInfra
scene: Scene
renderer: WebGLRenderer
@ -97,13 +100,13 @@ class SceneInfra {
_baseUnitMultiplier = 1
onDragCallback: (arg: OnDragCallbackArgs) => void = () => {}
onMoveCallback: (arg: OnMoveCallbackArgs) => void = () => {}
onClickCallback: (arg?: OnClickCallbackArgs) => void = () => {}
onClickCallback: (arg: OnClickCallbackArgs) => void = () => {}
onMouseEnter: (arg: OnMouseEnterLeaveArgs) => void = () => {}
onMouseLeave: (arg: OnMouseEnterLeaveArgs) => void = () => {}
setCallbacks = (callbacks: {
onDrag?: (arg: OnDragCallbackArgs) => void
onMove?: (arg: OnMoveCallbackArgs) => void
onClick?: (arg?: OnClickCallbackArgs) => void
onClick?: (arg: OnClickCallbackArgs) => void
onMouseEnter?: (arg: OnMouseEnterLeaveArgs) => void
onMouseLeave?: (arg: OnMouseEnterLeaveArgs) => void
}) => {
@ -124,7 +127,7 @@ class SceneInfra {
)
}
resetMouseListeners = () => {
sceneInfra.setCallbacks({
this.setCallbacks({
onDrag: () => {},
onMove: () => {},
onClick: () => {},
@ -153,7 +156,7 @@ class SceneInfra {
} | null = null
mouseDownVector: null | Vector2 = null
constructor() {
constructor(engineCommandManager: EngineCommandManager) {
// SCENE
this.scene = new Scene()
this.scene.background = new Color(0x000000)
@ -176,7 +179,11 @@ class SceneInfra {
const x = Math.cos(ang) * length
const y = Math.sin(ang) * length
this.camControls = new CameraControls(false, this.renderer.domElement)
this.camControls = new CameraControls(
false,
this.renderer.domElement,
engineCommandManager
)
this.camControls.subscribeToCamChange(() => this.onCameraChange())
this.camControls.camera.layers.enable(SKETCH_LAYER)
this.camControls.camera.position.set(0, -x, y)
@ -219,9 +226,9 @@ class SceneInfra {
?.getObjectByName('gridHelper')
planesGroup &&
planesGroup.scale.set(
scale / sceneInfra._baseUnitMultiplier,
scale / sceneInfra._baseUnitMultiplier,
scale / sceneInfra._baseUnitMultiplier
scale / this._baseUnitMultiplier,
scale / this._baseUnitMultiplier,
scale / this._baseUnitMultiplier
)
axisGroup?.name === 'gridHelper' && axisGroup.scale.set(scale, scale, scale)
}
@ -253,7 +260,7 @@ class SceneInfra {
} | null => {
this.planeRaycaster.setFromCamera(
this.currentMouseVector,
sceneInfra.camControls.camera
this.camControls.camera
)
const planeIntersects = this.planeRaycaster.intersectObjects(
this.scene.children,
@ -272,16 +279,19 @@ class SceneInfra {
let transformedPoint = intersectPoint.clone()
if (transformedPoint) {
transformedPoint.applyQuaternion(inversePlaneQuaternion)
transformedPoint?.sub(
new Vector3(...planePosition).applyQuaternion(inversePlaneQuaternion)
)
}
const twoD = new Vector2(
// I think the intersection plane doesn't get scale when nearly everything else does, maybe that should change
transformedPoint.x / this._baseUnitMultiplier,
transformedPoint.y / this._baseUnitMultiplier
) // z should be 0
const planePositionCorrected = new Vector3(
...planePosition
).applyQuaternion(inversePlaneQuaternion)
twoD.sub(new Vector2(...planePositionCorrected))
return {
twoD: new Vector2(
transformedPoint.x / this._baseUnitMultiplier,
transformedPoint.y / this._baseUnitMultiplier
), // z should be 0
twoD,
threeD: intersectPoint.divideScalar(this._baseUnitMultiplier),
intersection: planeIntersects[0],
}
@ -464,7 +474,7 @@ class SceneInfra {
intersects,
})
} else {
this.onClickCallback()
this.onClickCallback({ mouseEvent, intersects })
}
// Clear the selected state whether it was dragged or not
this.selected = null
@ -478,7 +488,7 @@ class SceneInfra {
intersects,
})
} else {
this.onClickCallback()
this.onClickCallback({ mouseEvent, intersects })
}
}
showDefaultPlanes() {
@ -522,9 +532,9 @@ class SceneInfra {
this.camControls.target
)
planesGroup.scale.set(
sceneScale / sceneInfra._baseUnitMultiplier,
sceneScale / sceneInfra._baseUnitMultiplier,
sceneScale / sceneInfra._baseUnitMultiplier
sceneScale / this._baseUnitMultiplier,
sceneScale / this._baseUnitMultiplier,
sceneScale / this._baseUnitMultiplier
)
this.scene.add(planesGroup)
}
@ -535,7 +545,7 @@ class SceneInfra {
if (planesGroup) this.scene.remove(planesGroup)
}
updateOtherSelectionColors = (otherSelections: Axis[]) => {
const axisGroup = sceneInfra.scene.children.find(
const axisGroup = this.scene.children.find(
({ userData }) => userData?.type === AXIS_GROUP
)
const axisMap: { [key: string]: Axis } = {
@ -557,8 +567,6 @@ class SceneInfra {
}
}
export const sceneInfra = new SceneInfra()
export function getSceneScale(
camera: PerspectiveCamera | OrthographicCamera,
target: Vector3

View File

@ -1,5 +1,5 @@
import { useModelingContext } from 'hooks/useModelingContext'
import { kclManager } from 'lang/KclSingleton'
import { kclManager } from 'lib/singletons'
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
import { useEffect, useRef, useState } from 'react'
import { useStore } from 'useStore'

View File

@ -7,8 +7,8 @@ import {
findUniqueName,
} from '../lang/modifyAst'
import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { useKclContext } from 'lang/KclProvider'
import { useModelingContext } from 'hooks/useModelingContext'
import { executeAst } from 'useStore'

View File

@ -1,6 +1,5 @@
import { useState, useEffect } from 'react'
import { sceneInfra } from '../clientSideScene/sceneInfra'
import { engineCommandManager } from 'lang/std/engineConnection'
import { engineCommandManager, sceneInfra } from 'lib/singletons'
import { throttle, isReducedMotion } from 'lib/utils'
const updateDollyZoom = throttle(

View File

@ -6,7 +6,7 @@ import styles from './CodeMenu.module.css'
import { useConvertToVariable } from 'hooks/useToolbarGuards'
import { editorShortcutMeta } from './TextEditor'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { kclManager } from 'lang/KclSingleton'
import { kclManager } from 'lib/singletons'
export const CodeMenu = ({ children }: PropsWithChildren) => {
const { enable: convertToVarEnabled, handleClick: handleConvertToVarClick } =
@ -77,7 +77,7 @@ export const CodeMenu = ({ children }: PropsWithChildren) => {
<Menu.Item>
<a
className={styles.button}
href="https://github.com/KittyCAD/kcl-samples"
href="https://zoo.dev/docs/kcl-samples"
target="_blank"
rel="noopener noreferrer"
>

View File

@ -1,6 +1,6 @@
import { useSelector } from '@xstate/react'
import { useCommandsContext } from 'hooks/useCommandsContext'
import { useKclContext } from 'lang/KclSingleton'
import { useKclContext } from 'lang/KclProvider'
import { CommandArgument } from 'lib/commandTypes'
import {
ResolvedSelectionType,

View File

@ -1,4 +1,5 @@
import { CommandLog, engineCommandManager } from 'lang/std/engineConnection'
import { CommandLog } from 'lang/std/engineConnection'
import { engineCommandManager } from 'lib/singletons'
import { useState, useEffect } from 'react'
function useEngineCommands(): [CommandLog[], () => void] {

View File

@ -13,7 +13,7 @@ import { useHotkeys } from 'react-hotkeys-hook'
import styles from './FileTree.module.css'
import { FILE_EXT, sortProject } from 'lib/tauriFS'
import { CustomIcon } from './CustomIcon'
import { kclManager } from 'lang/KclSingleton'
import { kclManager } from 'lib/singletons'
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
import { useLspContext } from './LspProvider'

View File

@ -2,7 +2,7 @@ import ReactJson from 'react-json-view'
import { useEffect } from 'react'
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { Themes } from '../lib/theme'
import { useKclContext } from 'lang/KclSingleton'
import { useKclContext } from 'lang/KclProvider'
const ReactJsonTypeHack = ReactJson as any

View File

@ -38,7 +38,26 @@ describe('processMemory', () => {
myVar: 5,
myFn: undefined,
otherVar: 3,
theExtrude: [],
theExtrude: [
{
type: 'extrudePlane',
position: [0, 0, 0],
rotation: [0, 0, 0, 1],
faceId: expect.any(String),
name: '',
id: expect.any(String),
sourceRange: [170, 194],
},
{
type: 'extrudePlane',
position: [0, 0, 0],
rotation: [0, 0, 0, 1],
faceId: expect.any(String),
name: '',
id: expect.any(String),
sourceRange: [202, 230],
},
],
theSketch: [
{ type: 'ToPoint', to: [-3.35, 0.17], from: [0, 0], name: '' },
{ type: 'ToPoint', to: [0.98, 5.16], from: [-3.35, 0.17], name: '' },

View File

@ -3,7 +3,7 @@ import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useMemo } from 'react'
import { ProgramMemory, Path, ExtrudeSurface } from '../lang/wasm'
import { Themes } from '../lib/theme'
import { useKclContext } from 'lang/KclSingleton'
import { useKclContext } from 'lang/KclProvider'
interface MemoryPanelProps extends CollapsiblePanelProps {
theme?: Exclude<Themes, Themes.System>

View File

@ -12,8 +12,8 @@ import { SetSelections, modelingMachine } from 'machines/modelingMachine'
import { useSetupEngineManager } from 'hooks/useSetupEngineManager'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { isCursorInSketchCommandRange } from 'lang/util'
import { engineCommandManager } from 'lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons'
import { useKclContext } from 'lang/KclProvider'
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
import {
angleBetweenInfo,
@ -23,9 +23,9 @@ import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
import { pathMapToSelections } from 'lang/util'
import { useStore } from 'useStore'
import {
Selections,
canExtrudeSelection,
handleSelectionBatch,
handleSelectionWithShift,
isSelectionLastLine,
isSketchPipe,
} from 'lib/selections'
@ -33,15 +33,20 @@ import { applyConstraintIntersect } from './Toolbar/Intersect'
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
import useStateMachineCommands from 'hooks/useStateMachineCommands'
import { modelingMachineConfig } from 'lib/commandBarConfigs/modelingCommandConfig'
import { sceneInfra } from 'clientSideScene/sceneInfra'
import { getSketchQuaternion } from 'clientSideScene/sceneEntities'
import { startSketchOnDefault } from 'lang/modifyAst'
import { Program } from 'lang/wasm'
import { isSingleCursorInPipe } from 'lang/queryAst'
import {
getSketchOrientationDetails,
getSketchQuaternion,
} from 'clientSideScene/sceneEntities'
import { sketchOnExtrudedFace, startSketchOnDefault } from 'lang/modifyAst'
import { Program, parse } from 'lang/wasm'
import { getNodePathFromSourceRange, isSingleCursorInPipe } from 'lang/queryAst'
import { TEST } from 'env'
import { exportFromEngine } from 'lib/exportFromEngine'
import { Models } from '@kittycad/lib/dist/types/src'
import toast from 'react-hot-toast'
import { EditorSelection } from '@uiw/react-codemirror'
import { Vector3 } from 'three'
import { quaternionFromUpNForward } from 'clientSideScene/helpers'
type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>
@ -61,17 +66,23 @@ export const ModelingMachineProvider = ({
const {
auth,
settings: {
context: { baseUnit },
context: { baseUnit, theme },
},
} = useSettingsAuthContext()
const { code } = useKclContext()
const token = auth?.context?.token
const streamRef = useRef<HTMLDivElement>(null)
useSetupEngineManager(streamRef, token)
useSetupEngineManager(streamRef, token, theme)
const { isShiftDown, editorView } = useStore((s) => ({
const {
isShiftDown,
editorView,
setLastCodeMirrorSelectionUpdatedFromScene,
} = useStore((s) => ({
isShiftDown: s.isShiftDown,
editorView: s.editorView,
setLastCodeMirrorSelectionUpdatedFromScene:
s.setLastCodeMirrorSelectionUpdatedFromScene,
}))
// Settings machine setup
@ -92,92 +103,98 @@ export const ModelingMachineProvider = ({
{
actions: {
'sketch exit execute': () => {
kclManager.executeAst()
try {
kclManager.executeAst(parse(kclManager.code))
} catch (e) {
kclManager.executeAst()
}
},
'Set selection': assign(({ selectionRanges }, event) => {
if (event.type !== 'Set selection') return {} // this was needed for ts after adding 'Set selection' action to on done modal events
const setSelections = event.data
if (!editorView) return {}
if (setSelections.selectionType === 'mirrorCodeMirrorSelections')
return { selectionRanges: setSelections.selection }
else if (setSelections.selectionType === 'otherSelection') {
const {
codeMirrorSelection,
selectionRangeTypeMap,
otherSelections,
} = handleSelectionWithShift({
otherSelection: setSelections.selection,
currentSelections: selectionRanges,
isShiftDown,
})
setTimeout(() => {
editorView.dispatch({
selection: codeMirrorSelection,
})
})
return {
selectionRangeTypeMap,
selectionRanges: {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections,
},
}
} else if (setSelections.selectionType === 'singleCodeCursor') {
// This DOES NOT set the `selectionRanges` in xstate context
// instead it updates/dispatches to the editor, which in turn updates the xstate context
// I've found this the best way to deal with the editor without causing an infinite loop
// and really we want the editor to be in charge of cursor positions and for `selectionRanges` mirror it
// because we want to respect the user manually placing the cursor too.
// for more details on how selections see `src/lib/selections.ts`.
const {
codeMirrorSelection,
selectionRangeTypeMap,
otherSelections,
} = handleSelectionWithShift({
codeSelection: setSelections.selection,
currentSelections: selectionRanges,
isShiftDown,
})
if (codeMirrorSelection) {
setTimeout(() => {
editorView.dispatch({
selection: codeMirrorSelection,
})
})
}
if (!setSelections.selection) {
return {
selectionRangeTypeMap,
selectionRanges: {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections,
},
const dispatchSelection = (selection?: EditorSelection) => {
if (!selection) return // TODO less of hack for the below please
setLastCodeMirrorSelectionUpdatedFromScene(Date.now())
setTimeout(() => editorView.dispatch({ selection }))
}
let selections: Selections = {
codeBasedSelections: [],
otherSelections: [],
}
if (setSelections.selectionType === 'singleCodeCursor') {
if (!setSelections.selection && isShiftDown) {
} else if (!setSelections.selection && !isShiftDown) {
selections = {
codeBasedSelections: [],
otherSelections: [],
}
} else if (setSelections.selection && !isShiftDown) {
selections = {
codeBasedSelections: [setSelections.selection],
otherSelections: [],
}
} else if (setSelections.selection && isShiftDown) {
selections = {
codeBasedSelections: [
...selectionRanges.codeBasedSelections,
setSelections.selection,
],
otherSelections: selectionRanges.otherSelections,
}
}
const {
engineEvents,
codeMirrorSelection,
updateSceneObjectColors,
} = handleSelectionBatch({
selections,
})
codeMirrorSelection && dispatchSelection(codeMirrorSelection)
engineEvents &&
engineEvents.forEach((event) =>
engineCommandManager.sendSceneCommand(event)
)
updateSceneObjectColors()
return {
selectionRangeTypeMap,
selectionRanges: {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections,
},
selectionRanges: selections,
}
}
// This DOES NOT set the `selectionRanges` in xstate context
// same as comment above
const { codeMirrorSelection, selectionRangeTypeMap } =
handleSelectionBatch({
selections: setSelections.selection,
})
if (codeMirrorSelection) {
setTimeout(() => {
editorView.dispatch({
selection: codeMirrorSelection,
})
})
if (setSelections.selectionType === 'mirrorCodeMirrorSelections') {
return {
selectionRanges: setSelections.selection,
}
}
return { selectionRangeTypeMap }
if (setSelections.selectionType === 'otherSelection') {
if (isShiftDown) {
selections = {
codeBasedSelections: selectionRanges.codeBasedSelections,
otherSelections: [setSelections.selection],
}
} else {
selections = {
codeBasedSelections: [],
otherSelections: [setSelections.selection],
}
}
const { engineEvents, updateSceneObjectColors } =
handleSelectionBatch({
selections,
})
engineEvents &&
engineEvents.forEach((event) =>
engineCommandManager.sendSceneCommand(event)
)
updateSceneObjectColors()
return {
selectionRanges: selections,
}
}
return {}
}),
'Engine export': (_, event) => {
if (event.type !== 'Export' || TEST) return
@ -255,10 +272,10 @@ export const ModelingMachineProvider = ({
kclManager.kclErrors.length === 0 && kclManager.ast.body.length > 0,
},
services: {
'AST-undo-startSketchOn': async ({ sketchPathToNode }) => {
if (!sketchPathToNode) return
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
if (!sketchDetails) return
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
const varDecIndex = sketchPathToNode[1][0]
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
// remove body item at varDecIndex
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
await kclManager.executeAstMock(newAst, { updates: 'code' })
@ -267,28 +284,69 @@ export const ModelingMachineProvider = ({
onDrag: () => {},
})
},
'animate-to-face': async (_, { data: { plane, normal } }) => {
'animate-to-face': async (_, { data }) => {
if (data.type === 'extrudeFace') {
const { modifiedAst, pathToNode: pathToNewSketchNode } =
sketchOnExtrudedFace(
kclManager.ast,
data.extrudeSegmentPathToNode,
kclManager.programMemory,
data.cap
)
await kclManager.executeAstMock(modifiedAst, { updates: 'code' })
const forward = new Vector3(...data.zAxis)
const up = new Vector3(...data.yAxis)
let target = new Vector3(...data.position).multiplyScalar(
sceneInfra._baseUnitMultiplier
)
const quaternion = quaternionFromUpNForward(up, forward)
await sceneInfra.camControls.tweenCameraToQuaternion(
quaternion,
target
)
return {
sketchPathToNode: pathToNewSketchNode,
zAxis: data.zAxis,
yAxis: data.yAxis,
origin: data.position,
}
}
const { modifiedAst, pathToNode } = startSketchOnDefault(
kclManager.ast,
plane
data.plane
)
await kclManager.updateAst(modifiedAst, false)
const quaternion = getSketchQuaternion(pathToNode, normal)
await sceneInfra.camControls.tweenCameraToQuaternion(quaternion)
const quat = await getSketchQuaternion(pathToNode, data.zAxis)
await sceneInfra.camControls.tweenCameraToQuaternion(quat)
return {
sketchPathToNode: pathToNode,
sketchNormalBackUp: normal,
zAxis: data.zAxis,
yAxis: data.yAxis,
origin: [0, 0, 0],
}
},
'animate-to-sketch': async ({
sketchPathToNode,
sketchNormalBackUp,
}) => {
const quaternion = getSketchQuaternion(
sketchPathToNode || [],
sketchNormalBackUp
'animate-to-sketch': async ({ selectionRanges }) => {
const sourceRange = selectionRanges.codeBasedSelections[0].range
const sketchPathToNode = getNodePathFromSourceRange(
kclManager.ast,
sourceRange
)
await sceneInfra.camControls.tweenCameraToQuaternion(quaternion)
const info = await getSketchOrientationDetails(sketchPathToNode || [])
await sceneInfra.camControls.tweenCameraToQuaternion(
info.quat,
new Vector3(...info.sketchDetails.origin)
)
return {
sketchPathToNode: sketchPathToNode || [],
zAxis: info.sketchDetails.zAxis || null,
yAxis: info.sketchDetails.yAxis || null,
origin: info.sketchDetails.origin.map(
(a) => a / sceneInfra._baseUnitMultiplier
) as [number, number, number],
}
},
'Get horizontal info': async ({
selectionRanges,

View File

@ -30,7 +30,7 @@ describe('NetworkHealthIndicator tests', () => {
fireEvent.click(screen.getByTestId('network-toggle'))
expect(screen.getByTestId('network')).toHaveTextContent(
NETWORK_HEALTH_TEXT[NetworkHealthState.Issue]
NETWORK_HEALTH_TEXT[NetworkHealthState.Ok]
)
})

View File

@ -5,13 +5,12 @@ import {
ConnectingType,
ConnectingTypeGroup,
DisconnectingType,
engineCommandManager,
EngineCommandManagerEvents,
EngineConnectionEvents,
EngineConnectionState,
EngineConnectionStateType,
ErrorType,
initialConnectingTypeGroupState,
} from '../lang/std/engineConnection'
import { engineCommandManager } from '../lib/singletons'
import Tooltip from './Tooltip'
export enum NetworkHealthState {
@ -82,35 +81,37 @@ const overallConnectionStateIcon: Record<
}
export function useNetworkStatus() {
const [steps, setSteps] = useState(
structuredClone(initialConnectingTypeGroupState)
)
const [steps, setSteps] = useState(initialConnectingTypeGroupState)
const [internetConnected, setInternetConnected] = useState<boolean>(true)
const [overallState, setOverallState] = useState<NetworkHealthState>(
NetworkHealthState.Disconnected
NetworkHealthState.Ok
)
const [pingPongHealth, setPingPongHealth] = useState<'OK' | 'BAD'>('BAD')
const [hasCopied, setHasCopied] = useState<boolean>(false)
const [error, setError] = useState<ErrorType | undefined>(undefined)
const hasIssue = (i: [ConnectingType, boolean | undefined]) =>
i[1] === undefined ? i[1] : !i[1]
const issues: Record<ConnectingTypeGroup, boolean> = {
[ConnectingTypeGroup.WebSocket]: steps[ConnectingTypeGroup.WebSocket].some(
(a: [ConnectingType, boolean | undefined]) => a[1] === false
),
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].some(
(a: [ConnectingType, boolean | undefined]) => a[1] === false
),
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].some(
(a: [ConnectingType, boolean | undefined]) => a[1] === false
),
}
const [issues, setIssues] = useState<
Record<ConnectingTypeGroup, boolean | undefined>
>({
[ConnectingTypeGroup.WebSocket]: undefined,
[ConnectingTypeGroup.ICE]: undefined,
[ConnectingTypeGroup.WebRTC]: undefined,
})
const hasIssues: boolean =
issues[ConnectingTypeGroup.WebSocket] ||
issues[ConnectingTypeGroup.ICE] ||
issues[ConnectingTypeGroup.WebRTC]
const [hasIssues, setHasIssues] = useState<boolean | undefined>(undefined)
useEffect(() => {
setOverallState(
!internetConnected
? NetworkHealthState.Disconnected
: hasIssues || hasIssues === undefined
: hasIssues
? NetworkHealthState.Issue
: NetworkHealthState.Ok
)
@ -133,59 +134,19 @@ export function useNetworkStatus() {
}, [])
useEffect(() => {
console.log(pingPongHealth)
}, [pingPongHealth])
useEffect(() => {
const issues = {
[ConnectingTypeGroup.WebSocket]: steps[
ConnectingTypeGroup.WebSocket
].reduce(
(acc: boolean | undefined, a) =>
acc === true || acc === undefined ? acc : hasIssue(a),
false
),
[ConnectingTypeGroup.ICE]: steps[ConnectingTypeGroup.ICE].reduce(
(acc: boolean | undefined, a) =>
acc === true || acc === undefined ? acc : hasIssue(a),
false
),
[ConnectingTypeGroup.WebRTC]: steps[ConnectingTypeGroup.WebRTC].reduce(
(acc: boolean | undefined, a) =>
acc === true || acc === undefined ? acc : hasIssue(a),
false
),
}
setIssues(issues)
}, [steps])
useEffect(() => {
setHasIssues(
issues[ConnectingTypeGroup.WebSocket] ||
issues[ConnectingTypeGroup.ICE] ||
issues[ConnectingTypeGroup.WebRTC]
)
}, [issues])
useEffect(() => {
const onPingPongChange = ({ detail: state }: CustomEvent) => {
setPingPongHealth(state)
}
const onConnectionStateChange = ({
detail: engineConnectionState,
}: CustomEvent) => {
setSteps((steps) => {
let nextSteps = structuredClone(steps)
engineCommandManager.onConnectionStateChange(
(engineConnectionState: EngineConnectionState) => {
let hasSetAStep = false
if (
engineConnectionState.type === EngineConnectionStateType.Connecting
) {
const groups = Object.values(nextSteps)
const groups = Object.values(steps)
for (let group of groups) {
for (let step of group) {
if (step[0] !== engineConnectionState.value.type) continue
step[1] = true
hasSetAStep = true
}
}
}
@ -193,7 +154,7 @@ export function useNetworkStatus() {
if (
engineConnectionState.type === EngineConnectionStateType.Disconnecting
) {
const groups = Object.values(nextSteps)
const groups = Object.values(steps)
for (let group of groups) {
for (let step of group) {
if (
@ -204,6 +165,7 @@ export function useNetworkStatus() {
?.type === step[0]
) {
step[1] = false
hasSetAStep = true
}
}
}
@ -214,50 +176,11 @@ export function useNetworkStatus() {
}
}
// Reset the state of all steps if we have disconnected.
if (
engineConnectionState.type === EngineConnectionStateType.Disconnected
) {
return structuredClone(initialConnectingTypeGroupState)
if (hasSetAStep) {
setSteps(steps)
}
return nextSteps
})
}
const onEngineAvailable = ({ detail: engineConnection }: CustomEvent) => {
engineConnection.addEventListener(
EngineConnectionEvents.PingPongChanged,
onPingPongChange as EventListener
)
engineConnection.addEventListener(
EngineConnectionEvents.ConnectionStateChanged,
onConnectionStateChange as EventListener
)
}
engineCommandManager.addEventListener(
EngineCommandManagerEvents.EngineAvailable,
onEngineAvailable as EventListener
}
)
return () => {
engineCommandManager.removeEventListener(
EngineCommandManagerEvents.EngineAvailable,
onEngineAvailable as EventListener
)
// When the component is unmounted these should be assigned, but it's possible
// the component mounts and unmounts before engine is available.
engineCommandManager.engineConnection?.addEventListener(
EngineConnectionEvents.PingPongChanged,
onPingPongChange as EventListener
)
engineCommandManager.engineConnection?.addEventListener(
EngineConnectionEvents.ConnectionStateChanged,
onConnectionStateChange as EventListener
)
}
}, [])
return {
@ -269,7 +192,6 @@ export function useNetworkStatus() {
error,
setHasCopied,
hasCopied,
pingPongHealth,
}
}
@ -334,18 +256,18 @@ export const NetworkHealthIndicator = () => {
size="lg"
icon={
hasIssueToIcon[
String(issues[name as ConnectingTypeGroup])
issues[name as ConnectingTypeGroup].toString()
]
}
iconClassName={
hasIssueToIconColors[
String(issues[name as ConnectingTypeGroup])
issues[name as ConnectingTypeGroup].toString()
].icon
}
bgClassName={
'rounded-sm ' +
hasIssueToIconColors[
String(issues[name as ConnectingTypeGroup])
issues[name as ConnectingTypeGroup].toString()
].bg
}
/>

View File

@ -11,7 +11,7 @@ import {
validateSettings,
} from 'lib/settings/settingsUtils'
import { toast } from 'react-hot-toast'
import { setThemeClass, Themes } from 'lib/theme'
import { getThemeColorForEngine, setThemeClass, Themes } from 'lib/theme'
import {
AnyStateMachine,
ContextFrom,
@ -22,8 +22,8 @@ import {
import { isTauri } from 'lib/isTauri'
import { settingsCommandBarConfig } from 'lib/commandBarConfigs/settingsCommandConfig'
import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig'
import { sceneInfra } from 'clientSideScene/sceneInfra'
import { kclManager } from 'lang/KclSingleton'
import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons'
import { v4 as uuidv4 } from 'uuid'
type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>
@ -96,6 +96,16 @@ export const SettingsAuthProviderBase = ({
: context.baseUnit
sceneInfra.baseUnit = newBaseUnit
},
setEngineTheme: (context) => {
engineCommandManager.sendSceneCommand({
cmd_id: uuidv4(),
type: 'modeling_cmd_req',
cmd: {
type: 'set_background_color',
color: getThemeColorForEngine(context.theme),
},
})
},
toastSuccess: (context, event) => {
const truncatedNewValue =
'data' in event && event.data instanceof Object
@ -147,7 +157,6 @@ export const SettingsAuthProviderBase = ({
actions: {
goToSignInPage: () => {
navigate(paths.SIGN_IN)
logout()
},
goToIndexPage: () => {

View File

@ -1,15 +1,13 @@
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useStore } from '../useStore'
import { getNormalisedCoordinates } from '../lib/utils'
import Loading from './Loading'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Models } from '@kittycad/lib'
import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from 'hooks/useModelingContext'
import { useKclContext } from 'lang/KclSingleton'
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
import { NetworkHealthState, useNetworkStatus } from './NetworkHealthIndicator'
import { butName } from 'lib/cameraControls'
import { sendSelectEventToEngine } from 'lib/selections'
export const Stream = ({ className = '' }: { className?: string }) => {
const [isLoading, setIsLoading] = useState(true)
@ -30,9 +28,7 @@ export const Stream = ({ className = '' }: { className?: string }) => {
}))
const { settings } = useSettingsAuthContext()
const { state } = useModelingContext()
const { isExecuting } = useKclContext()
const { overallState } = useNetworkStatus()
const isNetworkOkay = overallState === NetworkHealthState.Ok
useEffect(() => {
@ -61,50 +57,14 @@ export const Stream = ({ className = '' }: { className?: string }) => {
setClickCoords({ x, y })
}
const handleMouseUp: MouseEventHandler<HTMLDivElement> = ({
clientX,
clientY,
ctrlKey,
}) => {
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
if (!videoRef.current) return
setButtonDownInStream(undefined)
if (state.matches('Sketch')) return
if (state.matches('Sketch no face')) return
const { x, y } = getNormalisedCoordinates({
clientX,
clientY,
el: videoRef.current,
...streamDimensions,
})
const newCmdId = uuidv4()
const interaction = ctrlKey ? 'pan' : 'rotate'
const command: Models['WebSocketRequest_type'] = {
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_end',
interaction,
window: { x, y },
},
cmd_id: newCmdId,
}
if (!didDragInStream) {
command.cmd = {
type: 'select_with_point',
selected_at_window: { x, y },
selection_type: 'add',
}
engineCommandManager.sendSceneCommand(command)
} else if (didDragInStream) {
command.cmd = {
type: 'handle_mouse_drag_end',
window: { x, y },
}
void engineCommandManager.sendSceneCommand(command)
} else {
engineCommandManager.sendSceneCommand(command)
if (!didDragInStream && butName(e).left) {
sendSelectEventToEngine(e, videoRef.current, streamDimensions)
}
setDidDragInStream(false)
@ -141,9 +101,10 @@ export const Stream = ({ className = '' }: { className?: string }) => {
controls={false}
onPlay={() => setIsLoading(false)}
onMouseMoveCapture={handleMouseMove}
className={`w-full cursor-pointer h-full ${isExecuting && 'blur-md'}`}
className="w-full cursor-pointer h-full"
disablePictureInPicture
style={{ transitionDuration: '200ms', transitionProperty: 'filter' }}
id="video-stream"
/>
<ClientSideScene cameraControls={settings.context?.cameraControls} />
{!isNetworkOkay && !isLoading && (

View File

@ -3,6 +3,7 @@ import ReactCodeMirror, {
Extension,
ViewUpdate,
keymap,
SelectionRange,
} from '@uiw/react-codemirror'
import { TEST } from 'env'
import { useCommandsContext } from 'hooks/useCommandsContext'
@ -19,10 +20,9 @@ import { kclErrToDiagnostic } from 'lang/errors'
import { CSSRuleObject } from 'tailwindcss/types/config'
import { useModelingContext } from 'hooks/useModelingContext'
import interact from '@replit/codemirror-interact'
import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSingleton'
import { engineCommandManager, sceneInfra, kclManager } from 'lib/singletons'
import { useKclContext } from 'lang/KclProvider'
import { ModelingMachineEvent } from 'machines/modelingMachine'
import { sceneInfra } from 'clientSideScene/sceneInfra'
import { NetworkHealthState, useNetworkStatus } from './NetworkHealthIndicator'
import { useHotkeys } from 'react-hotkeys-hook'
import { useLspContext } from './LspProvider'
@ -75,7 +75,7 @@ export const TextEditor = ({
})
const {
context: { selectionRanges, selectionRangeTypeMap },
context: { selectionRanges },
send,
state,
} = useModelingContext()
@ -91,10 +91,27 @@ export const TextEditor = ({
if (isNetworkOkay) kclManager.setCodeAndExecute(newCode)
else kclManager.setCode(newCode)
} //, []);
const lastSelection = useRef('')
const onUpdate = (viewUpdate: ViewUpdate) => {
if (!editorView) {
setEditorView(viewUpdate.view)
}
const selString = stringifyRanges(
viewUpdate?.state?.selection?.ranges || []
)
if (selString === lastSelection.current) {
// onUpdate is noisy and is fired a lot by extensions
// since we're only interested in selections changes we can ignore most of these.
return
}
lastSelection.current = selString
if (
// TODO find a less lazy way of getting the last
Date.now() - useStore.getState().lastCodeMirrorSelectionUpdatedFromScene <
150
)
return // update triggered by scene selection
if (sceneInfra.selected) return // mid drag
const ignoreEvents: ModelingMachineEvent['type'][] = [
'Equip Line tool',
@ -104,7 +121,6 @@ export const TextEditor = ({
const eventInfo = processCodeMirrorRanges({
codeMirrorRanges: viewUpdate.state.selection.ranges,
selectionRanges,
selectionRangeTypeMap,
isShiftDown,
})
if (!eventInfo) return
@ -226,3 +242,7 @@ export const TextEditor = ({
</div>
)
}
function stringifyRanges(ranges: readonly SelectionRange[]): string {
return ranges.map(({ to, from }) => `${to}->${from}`).join('&')
}

View File

@ -11,7 +11,7 @@ import {
getTransformInfos,
PathToNodeMap,
} from '../../lang/std/sketchcombos'
import { kclManager } from 'lang/KclSingleton'
import { kclManager } from 'lib/singletons'
export function equalAngleInfo({
selectionRanges,

View File

@ -11,7 +11,7 @@ import {
getTransformInfos,
PathToNodeMap,
} from '../../lang/std/sketchcombos'
import { kclManager } from 'lang/KclSingleton'
import { kclManager } from 'lib/singletons'
export function setEqualLengthInfo({
selectionRanges,

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