Compare commits

...

21 Commits

Author SHA1 Message Date
2f51763df9 Cut release v0.24.0 (#2972)
* Cut release v0.24.0

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-09 10:29:08 -04:00
7c4bf8d793 fix when you comment out it should re-execute (#2975)
* fix when you comment out it should re-execute

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

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

* updates

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

* updates

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

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

* copilot being a little shit

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

* fix

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

* fix

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

* fmt

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

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

* fix

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

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

* updates

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

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

* updates

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

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

* turn copilot off

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

* updates

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

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

* fix for realisesi

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

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

* remove footguns

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2024-07-08 21:07:15 -07:00
4747cdcab6 Bump syn from 2.0.69 to 2.0.70 in /src/wasm-lib (#2981)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.69 to 2.0.70.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.69...2.0.70)

---
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-07-08 20:36:30 -07:00
de73f335fe Bump uuid from 1.9.1 to 1.10.0 in /src/wasm-lib (#2980)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.9.1 to 1.10.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.9.1...1.10.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-07-08 20:36:19 -07:00
a62004da82 Bump clap from 4.5.7 to 4.5.9 in /src/wasm-lib (#2979)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.7 to 4.5.9.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.7...v4.5.9)

---
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-07-08 20:35:54 -07:00
92e0da1f8d playwright fixmes 😭 (#2977)
* add fixmes 😭

* fmt
2024-07-09 11:11:32 +10:00
a111473658 Uses the grammar marijn made :) (#2967)
* Add a Lezer KCL grammar

* fmt

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

* make tsc happy

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

* turn off semantic tokens in favor of grammar

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

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

* fixups

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

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

* empty

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Marijn Haverbeke <marijn@haverbeke.berlin>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-08 16:47:30 -07:00
7cfed9bff4 Add a timeout instead of insta teardown on window hide (#2970)
* Add a timeout instead of insta teardown on window hide

* Close sketch mode on teardown
2024-07-09 07:58:09 +10:00
a30bd185d8 Allow modify sketch when extrude on end of pipe expr (#2960) 2024-07-09 07:57:37 +10:00
e8cae630a1 remove all z_near far params in engine calls, enable ssao again (#2956)
* remove all z_near far params in engine calls, enable ssao again

* fmt
2024-07-09 06:53:33 +10:00
74ec749560 Add segment length indicators to straight segments in sketch mode (#2935)
* Rough impl of line lengths, still duplicating

* Make sure the labels get cleared along with the rest of the sketch

* Show current units in segment length indicators

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

* Re-run CI after snapshots

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

* Re-run CI

* Make sure `close` segments get insert segment handles

* Skip engine connection tests on Safari with a todo

* Fmt

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-08 16:41:00 -04:00
ebdaf59d1c Bump pyo3 from 0.22.0 to 0.22.1 in /src/wasm-lib (#2949) 2024-07-08 12:44:55 -07:00
cd68414d54 Bump async-trait from 0.1.80 to 0.1.81 in /src/wasm-lib (#2948) 2024-07-08 12:44:43 -07:00
c8238ff04a Bump syn from 2.0.68 to 2.0.69 in /src/wasm-lib (#2947)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.68 to 2.0.69.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.68...2.0.69)

---
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-07-08 10:00:23 -07:00
8089369108 Bump serde from 1.0.203 to 1.0.204 in /src/wasm-lib (#2946)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.203 to 1.0.204.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.203...v1.0.204)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 10:00:13 -07:00
8ebe78c664 Lf94/eco mode save the planet (#2940)
* Trigger shutdown operations after each test

* Idle mode states

* Don't show the reconnect when coming back from tab
2024-07-07 10:10:52 -07:00
a85c1a9375 Scoped tags (#2941)
* start of scoped tags

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

* add the tags to the sketch group context

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

* scoped tags

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

* update docs

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

* fix tests

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>

* scoped

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

* updates

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-07-05 16:53:13 -07:00
5701616f3e Add a current default unit indicator with menu to switch (#2937)
* Add a units indicator with a menu to switch default units

* Add a playwright test, add a SR label

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

* Re-run CI

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

* Re-run CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-05 18:40:43 -04:00
846acaba2f fix bug with order of operations (#2938)
* fix bug with order of operations

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-07-05 15:37:30 -07:00
0a524d42f6 Bump kittycad.rs (#2936)
* update kittycad.rs

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

* tauri bump

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-05 12:39:58 -07:00
fe28527ef9 update docs (#2933)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-05 10:44:29 -07:00
129 changed files with 7328 additions and 462 deletions

View File

@ -121,6 +121,9 @@ const extrusion = extrude(5, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -282,6 +285,9 @@ const extrusion = extrude(5, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -125,6 +125,9 @@ const extrusion = extrude(5, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -286,6 +289,9 @@ const extrusion = extrude(5, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -126,6 +126,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -287,6 +290,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -476,6 +482,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -637,6 +646,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -125,6 +125,9 @@ const extrusion = extrude(10, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -286,6 +289,9 @@ const extrusion = extrude(10, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -475,6 +481,9 @@ const extrusion = extrude(10, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -636,6 +645,9 @@ const extrusion = extrude(10, sketch001)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

File diff suppressed because one or more lines are too long

View File

@ -133,6 +133,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -294,6 +297,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -483,6 +489,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -644,6 +653,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -124,6 +124,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -285,6 +288,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -474,6 +480,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -635,6 +644,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -124,6 +124,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -285,6 +288,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -474,6 +480,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -635,6 +644,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -135,6 +135,9 @@ const exampleSketch = startSketchOn('XZ')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -296,6 +299,9 @@ const exampleSketch = startSketchOn('XZ')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -485,6 +491,9 @@ const exampleSketch = startSketchOn('XZ')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -646,6 +655,9 @@ const exampleSketch = startSketchOn('XZ')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -130,6 +130,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -291,6 +294,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -480,6 +486,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -641,6 +650,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -225,6 +225,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -532,6 +535,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -123,6 +123,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -410,6 +413,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -599,6 +605,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -760,6 +769,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -125,6 +125,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -286,6 +289,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -475,6 +481,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -636,6 +645,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -150,6 +150,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -311,6 +314,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
type: "sketchGroup", type: "sketchGroup",
// The paths in the sketch group. // The paths in the sketch group.
@ -580,6 +586,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -225,6 +225,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -524,6 +527,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -215,6 +215,9 @@ const revolution = startSketchOn(box, "revolveAxis")
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -211,6 +211,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -211,6 +211,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -213,6 +213,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -213,6 +213,9 @@ const part001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -512,6 +515,9 @@ const part001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -136,6 +136,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -297,6 +300,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
type: "sketchGroup", type: "sketchGroup",
// The paths in the sketch group. // The paths in the sketch group.
@ -479,6 +485,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -640,6 +649,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -821,6 +833,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -982,6 +997,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -129,6 +129,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -290,6 +293,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -479,6 +485,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -640,6 +649,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -466,6 +472,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -627,6 +636,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -134,6 +134,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -295,6 +298,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
type: "sketchGroup", type: "sketchGroup",
// The paths in the sketch group. // The paths in the sketch group.

View File

@ -217,6 +217,9 @@ const example = extrude(-5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -127,6 +127,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -288,6 +291,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
type: "sketchGroup", type: "sketchGroup",
// The paths in the sketch group. // The paths in the sketch group.

View File

@ -215,6 +215,9 @@ const example = extrude(1, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -217,6 +217,9 @@ let vase = layer()
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -117,6 +117,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -278,6 +281,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -112,6 +112,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -273,6 +276,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -111,6 +111,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -272,6 +275,9 @@ const sketch001 = startSketchOn('XY')
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -247,6 +247,9 @@ uuid |
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -408,6 +411,9 @@ uuid |
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -673,6 +679,9 @@ uuid |
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -124,6 +124,9 @@ const example = extrude(4, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -285,6 +288,9 @@ const example = extrude(4, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -122,6 +122,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -283,6 +286,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -123,6 +123,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -284,6 +287,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -121,6 +121,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -282,6 +285,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -213,6 +213,9 @@ shell({ faces: ['end'], thickness: 0.25 }, firstSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -512,6 +515,9 @@ shell({ faces: ['end'], thickness: 0.25 }, firstSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -195,6 +195,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -442,6 +445,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -603,6 +609,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -142,6 +142,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -303,6 +306,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -264,6 +264,9 @@ const a1 = startSketchOn({
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -539,6 +542,9 @@ const a1 = startSketchOn({
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

File diff suppressed because it is too large Load Diff

View File

@ -125,6 +125,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -286,6 +289,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -475,6 +481,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -636,6 +645,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -116,6 +116,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -277,6 +280,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -466,6 +472,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -627,6 +636,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -74,6 +74,107 @@ You can nest expressions in parenthesis as well:
let myMathExpression = 3 + (1 * 2 / (3 - 7)) let myMathExpression = 3 + (1 * 2 / (3 - 7))
``` ```
Please if you find any issues using any of the above expressions or syntax ## Tags
Tags are used to give a name (tag) to a specific path.
### Tag Declaration
The syntax for declaring a tag is `$myTag` you would use it in the following
way:
```
startSketchOn('XZ')
|> startProfileAt(origin, %)
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001, %) - 90,
196.99
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001, %),
-segLen(rectangleSegmentA001, %)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
```
### Tag Identifier
As per the example above you can use the tag identifier to get a reference to the
tagged object. The syntax for this is `myTag`.
In the example above we use the tag identifier to get the angle of the segment
`segAng(rectangleSegmentA001, %)`.
### Tag Scope
Tags are scoped globally if in the root context meaning in this example you can
use the tag `rectangleSegmentA001` in any function or expression in the file.
However if the code was written like this:
```
fn rect = (origin) => {
return startSketchOn('XZ')
|> startProfileAt(origin, %)
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001, %) - 90,
196.99
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001, %),
-segLen(rectangleSegmentA001, %)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
}
rect([0, 0])
rect([20, 0])
```
Those tags would only be available in the `rect` function and not globally.
However you likely want to use those tags somewhere outside the `rect` function.
Tags are accessible through the sketch group they are declared in.
For example the following code works.
```
fn rect = (origin) => {
return startSketchOn('XZ')
|> startProfileAt(origin, %)
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001, %) - 90,
196.99
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001, %),
-segLen(rectangleSegmentA001, %)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
}
rect([0, 0])
const myRect = rect([20, 0])
myRect
|> extrude(10, %)
|> fillet({radius: 0.5, tags: [myRect.tags.rectangleSegmentA001]}, %)
```
See how we use the tag `rectangleSegmentA001` in the `fillet` function outside
the `rect` function. This is because the `rect` function is returning the
sketch group that contains the tags.
---
If you find any issues using any of the above expressions or syntax,
please file an issue with the `ast` label on the [modeling-app please file an issue with the `ast` label on the [modeling-app
repo](https://github.com/KittyCAD/modeling-app/issues/new). repo](https://github.com/KittyCAD/modeling-app/issues/new).

View File

@ -119,6 +119,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -280,6 +283,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -469,6 +475,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -630,6 +639,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -119,6 +119,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -280,6 +283,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -469,6 +475,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -630,6 +639,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -117,6 +117,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -278,6 +281,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -467,6 +473,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -628,6 +637,9 @@ const example = extrude(10, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -115,6 +115,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -276,6 +279,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -465,6 +471,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
@ -626,6 +635,9 @@ const example = extrude(5, exampleSketch)
}, },
// The to point. // The to point.
to: [number, number], to: [number, number],
},
// Tag identifiers that have been declared in this sketch group.
tags: {
}, },
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{

View File

@ -52,7 +52,24 @@ const commonPoints = {
// num2: 19.19, // num2: 19.19,
} }
// Utilities for writing tests that depend on test values test.afterEach(async ({ context, page }, testInfo) => {
if (testInfo.status === 'skipped') return
if (testInfo.status === 'failed') return
const u = await getUtils(page)
// Kill the network so shutdown happens properly
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// It seems it's best to give the browser about 3s to close things
// It's not super reliable but we have no real other choice for now
await page.waitForTimeout(3000)
})
test.beforeEach(async ({ context, page }) => { test.beforeEach(async ({ context, page }) => {
// wait for Vite preview server to be up // wait for Vite preview server to be up
@ -78,7 +95,7 @@ test.beforeEach(async ({ context, page }) => {
await page.emulateMedia({ reducedMotion: 'reduce' }) await page.emulateMedia({ reducedMotion: 'reduce' })
}) })
test.setTimeout(60000) test.setTimeout(120000)
async function doBasicSketch(page: Page, openPanes: string[]) { async function doBasicSketch(page: Page, openPanes: string[]) {
const u = await getUtils(page) const u = await getUtils(page)
@ -543,6 +560,50 @@ test.describe('Testing Camera Movement', () => {
}) })
test.describe('Editor tests', () => { test.describe('Editor tests', () => {
test('can comment out code with ctrl+/', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
const CtrlKey = process.platform === 'darwin' ? 'Meta' : 'Control'
// check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await u.codeLocator.click()
await page.keyboard.type(`const sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
await page.keyboard.down(CtrlKey)
await page.keyboard.press('/')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
// |> close(%)`)
// uncomment the code
await page.keyboard.down(CtrlKey)
await page.keyboard.press('/')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
})
test('if you click the format button it formats your code', async ({ test('if you click the format button it formats your code', async ({
page, page,
}) => { }) => {
@ -1204,7 +1265,9 @@ test.describe('Editor tests', () => {
|> close(%)`) |> close(%)`)
}) })
test('Can undo a sketch modification with ctrl+z', async ({ page }) => { // failing for the same reason as "Can edit a sketch that has been extruded in the same pipe"
// please fix together
test.fixme('Can undo a sketch modification with ctrl+z', async ({ page }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
@ -4053,108 +4116,111 @@ test.describe('Sketch tests', () => {
}) })
}) })
test('Can edit a sketch that has been extruded in the same pipe', async ({ // failing for the same reason as "Can undo a sketch modification with ctrl+z"
page, // please fix together
}) => { test.fixme(
const u = await getUtils(page) 'Can edit a sketch that has been extruded in the same pipe',
await page.addInitScript(async () => { async ({ page }) => {
localStorage.setItem( const u = await getUtils(page)
'persistCode', await page.addInitScript(async () => {
`const sketch001 = startSketchOn('XZ') localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], %)
|> close(%) |> close(%)
|> extrude(5, %)` |> extrude(5, %)`
) )
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await u.waitForAuthSkipAppStart()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.openAndClearDebugPanel() await u.openAndClearDebugPanel()
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 }, vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 }, center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
const startPX = [665, 458] const startPX = [665, 458]
const dragPX = 40 const dragPX = 40
await page.getByText('startProfileAt([4.61, -14.01], %)').click() await page.getByText('startProfileAt([4.61, -14.01], %)').click()
await expect( await expect(
page.getByRole('button', { name: 'Edit Sketch' }) page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible() ).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click() await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400) await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText() let prevContent = await page.locator('.cm-content').innerText()
await expect(page.getByTestId('segment-overlay')).toHaveCount(2) await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
// drag startProfieAt handle // drag startProfieAt handle
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0], y: startPX[1] }, sourcePosition: { x: startPX[0], y: startPX[1] },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX }, targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// drag line handle // drag line handle
await page.waitForTimeout(100) await page.waitForTimeout(100)
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]') const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y }, sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX }, targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
}) })
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// drag tangentialArcTo handle // drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]') const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 }, sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
targetPosition: { targetPosition: {
x: tangentEnd.x + dragPX, x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX, y: tangentEnd.y + dragPX,
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ') .toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -16.82], %) |> startProfileAt([7.12, -16.82], %)
|> line([15.4, -2.74], %) |> line([15.4, -2.74], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], %)
|> line([2.65, -2.69], %) |> line([2.65, -2.69], %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) }
)
test('Can edit a sketch that has been revolved in the same pipe', async ({ test('Can edit a sketch that has been revolved in the same pipe', async ({
page, page,
@ -6704,7 +6770,15 @@ ${extraLine ? 'const myVar = segLen(seg01, part001)' : ''}`
}) })
test.describe('Test network and connection issues', () => { test.describe('Test network and connection issues', () => {
test('simulate network down and network little widget', async ({ page }) => { test('simulate network down and network little widget', async ({
page,
browserName,
}) => {
// TODO: Don't skip Mac for these. After `window.tearDown` is working in Safari, these should work on webkit
test.skip(
browserName === 'webkit',
'Skip on Safari until `window.tearDown` is working there'
)
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
@ -6774,7 +6848,15 @@ test.describe('Test network and connection issues', () => {
await expect(page.getByText('Network Health (Connected)')).toBeVisible() await expect(page.getByText('Network Health (Connected)')).toBeVisible()
}) })
test('Engine disconnect & reconnect in sketch mode', async ({ page }) => { test('Engine disconnect & reconnect in sketch mode', async ({
page,
browserName,
}) => {
// TODO: Don't skip Mac for these. After `window.tearDown` is working in Safari, these should work on webkit
test.skip(
browserName === 'webkit',
'Skip on Safari until `window.tearDown` is working there'
)
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -7134,6 +7216,40 @@ test.describe('Testing Gizmo', () => {
}) })
}) })
test('Units menu', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
await u.waitForAuthSkipAppStart()
const unitsMenuButton = page.getByRole('button', {
name: 'Current Units',
exact: false,
})
await expect(unitsMenuButton).toBeVisible()
await expect(unitsMenuButton).toContainText('in')
await unitsMenuButton.click()
const millimetersButton = page.getByRole('button', { name: 'Millimeters' })
await expect(millimetersButton).toBeVisible()
await millimetersButton.click()
// Look out for the toast message
const toastMessage = page.getByText(
`Set default unit to "mm" for this project`
)
await expect(toastMessage).toBeVisible()
// Verify that the popover has closed
await expect(millimetersButton).not.toBeAttached()
// Verify that the button label has updated
await expect(unitsMenuButton).toContainText('mm')
})
test('Successful export shows a success toast', async ({ page }) => { test('Successful export shows a success toast', async ({ page }) => {
// FYI this test doesn't work with only engine running locally // FYI this test doesn't work with only engine running locally
// And you will need to have the KittyCAD CLI installed // And you will need to have the KittyCAD CLI installed

View File

@ -435,6 +435,8 @@ test('Draft segments should look right', async ({ page, context }) => {
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 }) await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
await page.waitForTimeout(300)
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
}) })

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -312,9 +312,9 @@ export async function getUtils(page: Page) {
fullPage: true, fullPage: true,
}) })
const screenshot = await PNG.sync.read(buffer) const screenshot = await PNG.sync.read(buffer)
// most likely related to pixel density but the screenshots for webkit are 2x the size const pixMultiplier: number = await page.evaluate(
// there might be a more robust way of doing this. 'window.devicePixelRatio'
const pixMultiplier = browserType === 'webkit' ? 2 : 1 )
const index = const index =
(screenshot.width * coords.y * pixMultiplier + (screenshot.width * coords.y * pixMultiplier +
coords.x * pixMultiplier) * coords.x * pixMultiplier) *
@ -377,11 +377,10 @@ export async function getUtils(page: Page) {
emulateNetworkConditions: async ( emulateNetworkConditions: async (
networkOptions: Protocol.Network.emulateNetworkConditionsParameters networkOptions: Protocol.Network.emulateNetworkConditionsParameters
) => { ) => {
// Skip on non-Chromium browsers, since we need to use the CDP. if (cdpSession === null) {
test.skip( // Use a fail safe if we can't simulate disconnect (on Safari)
cdpSession === null, return page.evaluate('window.tearDown()')
'Network emulation is only supported in Chromium' }
)
cdpSession?.send('Network.emulateNetworkConditions', networkOptions) cdpSession?.send('Network.emulateNetworkConditions', networkOptions)
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "untitled-app", "name": "untitled-app",
"version": "0.23.1", "version": "0.24.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.17.0", "@codemirror/autocomplete": "^6.17.0",
@ -17,7 +17,9 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.19", "@headlessui/react": "^1.7.19",
"@headlessui/tailwindcss": "^0.2.0", "@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.69", "@kittycad/lib": "^0.0.70",
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.4.1",
"@react-hook/resize-observer": "^2.0.1", "@react-hook/resize-observer": "^2.0.1",
"@replit/codemirror-interact": "^6.3.1", "@replit/codemirror-interact": "^6.3.1",
"@tauri-apps/api": "^2.0.0-beta.14", "@tauri-apps/api": "^2.0.0-beta.14",
@ -109,6 +111,7 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.24.3", "@babel/preset-env": "^7.24.3",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@lezer/generator": "^1.7.1",
"@playwright/test": "^1.45.1", "@playwright/test": "^1.45.1",
"@tauri-apps/cli": "==2.0.0-beta.13", "@tauri-apps/cli": "==2.0.0-beta.13",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",

View File

@ -71,6 +71,9 @@ export interface LanguageServerOptions {
) => void ) => void
changesDelay?: number changesDelay?: number
doSemanticTokens?: boolean
doFoldingRanges?: boolean
} }
export class LanguageServerPlugin implements PluginValue { export class LanguageServerPlugin implements PluginValue {
@ -87,6 +90,9 @@ export class LanguageServerPlugin implements PluginValue {
notification: LSP.NotificationMessage notification: LSP.NotificationMessage
) => void ) => void
private doSemanticTokens: boolean = false
private doFoldingRanges: boolean = false
private _defferer = deferExecution((code: string) => { private _defferer = deferExecution((code: string) => {
try { try {
// Update the state (not the editor) with the new code. // Update the state (not the editor) with the new code.
@ -109,6 +115,9 @@ export class LanguageServerPlugin implements PluginValue {
this.client = options.client this.client = options.client
this.documentVersion = 0 this.documentVersion = 0
this.doSemanticTokens = options.doSemanticTokens ?? false
this.doFoldingRanges = options.doFoldingRanges ?? false
if (options.changesDelay) { if (options.changesDelay) {
this.changesDelay = options.changesDelay this.changesDelay = options.changesDelay
} }
@ -220,6 +229,7 @@ export class LanguageServerPlugin implements PluginValue {
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> { async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
if ( if (
!this.doFoldingRanges ||
!this.client.ready || !this.client.ready ||
!this.client.getServerCapabilities().foldingRangeProvider !this.client.getServerCapabilities().foldingRangeProvider
) )
@ -445,6 +455,7 @@ export class LanguageServerPlugin implements PluginValue {
async requestSemanticTokens() { async requestSemanticTokens() {
if ( if (
!this.doSemanticTokens ||
!this.client.ready || !this.client.ready ||
!this.client.getServerCapabilities().semanticTokensProvider !this.client.getServerCapabilities().semanticTokensProvider
) { ) {

6
src-tauri/Cargo.lock generated
View File

@ -2571,7 +2571,7 @@ dependencies = [
[[package]] [[package]]
name = "kcl-lib" name = "kcl-lib"
version = "0.1.69" version = "0.1.70"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"approx", "approx",
@ -2628,9 +2628,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad" name = "kittycad"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3de9bb4b1441f198689a9f64a8163a518377e30b348a784680e738985b95eb" checksum = "e1777b503442fa4666564cc3ab237d456df853a09648a4b2bb09622d25d021a5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",

View File

@ -16,7 +16,7 @@ tauri-build = { version = "2.0.0-beta.18", features = [] }
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
kcl-lib = { version = "0.1.53", path = "../src/wasm-lib/kcl" } kcl-lib = { version = "0.1.53", path = "../src/wasm-lib/kcl" }
kittycad = "0.3.5" kittycad = "0.3.7"
log = "0.4.21" log = "0.4.21"
oauth2 = "4.4.2" oauth2 = "4.4.2"
serde_json = "1.0" serde_json = "1.0"

View File

@ -80,5 +80,5 @@
} }
}, },
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"version": "0.23.1" "version": "0.24.0"
} }

View File

@ -25,6 +25,7 @@ import ModalContainer from 'react-modal-promise'
import useHotkeyWrapper from 'lib/hotkeyWrapper' import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo' import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump' import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu'
export function App() { export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS') useRefreshSettings(paths.FILE + 'SETTINGS')
@ -127,6 +128,7 @@ export function App() {
<Stream /> <Stream />
{/* <CamToggle /> */} {/* <CamToggle /> */}
<LowerRightControls coreDumpManager={coreDumpManager}> <LowerRightControls coreDumpManager={coreDumpManager}>
<UnitsMenu />
<Gizmo /> <Gizmo />
</LowerRightControls> </LowerRightControls>
</div> </div>

View File

@ -529,7 +529,6 @@ export class CameraControls {
parameters: { parameters: {
fov_y: fov_y:
this.camera instanceof PerspectiveCamera ? this.camera.fov : 45, this.camera instanceof PerspectiveCamera ? this.camera.fov : 45,
...calculateNearFarFromFOV(this.lastPerspectiveFov),
}, },
}, },
}) })
@ -612,8 +611,6 @@ export class CameraControls {
type: 'default_camera_set_perspective', type: 'default_camera_set_perspective',
parameters: { parameters: {
fov_y: newFov, fov_y: newFov,
z_near: 0.01,
z_far: 1000,
}, },
}, },
}) })
@ -631,8 +628,6 @@ export class CameraControls {
target: this.target, target: this.target,
}), }),
fov_y: newFov, fov_y: newFov,
z_near: 0.01,
z_far: 1000,
}, },
}) })
} }

View File

@ -96,6 +96,7 @@ export const ClientSideScene = ({
if (!canvasRef.current) return if (!canvasRef.current) return
const canvas = canvasRef.current const canvas = canvasRef.current
canvas.appendChild(sceneInfra.renderer.domElement) canvas.appendChild(sceneInfra.renderer.domElement)
canvas.appendChild(sceneInfra.labelRenderer.domElement)
sceneInfra.animate() sceneInfra.animate()
canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false) canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false)
canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false) canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false)

View File

@ -29,6 +29,9 @@ import {
INTERSECTION_PLANE_LAYER, INTERSECTION_PLANE_LAYER,
OnMouseEnterLeaveArgs, OnMouseEnterLeaveArgs,
RAYCASTABLE_PLANE, RAYCASTABLE_PLANE,
SEGMENT_LENGTH_LABEL,
SEGMENT_LENGTH_LABEL_OFFSET_PX,
SEGMENT_LENGTH_LABEL_TEXT,
SKETCH_GROUP_SEGMENTS, SKETCH_GROUP_SEGMENTS,
SKETCH_LAYER, SKETCH_LAYER,
X_AXIS, X_AXIS,
@ -47,6 +50,7 @@ import {
programMemoryInit, programMemoryInit,
recast, recast,
SketchGroup, SketchGroup,
ExtrudeGroup,
VariableDeclaration, VariableDeclaration,
VariableDeclarator, VariableDeclarator,
} from 'lang/wasm' } from 'lang/wasm'
@ -102,6 +106,7 @@ import {
} from 'lib/rectangleTool' } from 'lib/rectangleTool'
import { getThemeColorForThreeJs } from 'lib/theme' import { getThemeColorForThreeJs } from 'lib/theme'
import { err, trap } from 'lib/trap' import { err, trap } from 'lib/trap'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
type DraftSegment = 'line' | 'tangentialArcTo' type DraftSegment = 'line' | 'tangentialArcTo'
@ -414,7 +419,7 @@ export class SceneEntities {
} }
) )
let seg let seg: Group
const _node1 = getNodeFromPath<CallExpression>( const _node1 = getNodeFromPath<CallExpression>(
maybeModdedAst, maybeModdedAst,
segPathToNode, segPathToNode,
@ -1075,9 +1080,16 @@ export class SceneEntities {
programMemoryOverride, programMemoryOverride,
}) })
this.sceneProgramMemory = programMemory this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.root[
variableDeclarationName const maybeSketchGroup = programMemory.root[variableDeclarationName]
] as SketchGroup let sketchGroup = undefined
if (maybeSketchGroup.type === 'SketchGroup') {
sketchGroup = maybeSketchGroup
} else if ((maybeSketchGroup as ExtrudeGroup).sketchGroup) {
sketchGroup = (maybeSketchGroup as ExtrudeGroup).sketchGroup
}
if (!sketchGroup) return
const sgPaths = sketchGroup.value const sgPaths = sketchGroup.value
const orthoFactor = orthoScale(sceneInfra.camControls.camera) const orthoFactor = orthoScale(sceneInfra.camControls.camera)
@ -1302,6 +1314,7 @@ export class SceneEntities {
shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale) // The width of the line in px (2.4px in this case) shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale) // The width of the line in px (2.4px in this case)
shape.lineTo(0, (SEGMENT_WIDTH_PX / 2) * scale) shape.lineTo(0, (SEGMENT_WIDTH_PX / 2) * scale)
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
const labelGroup = group.getObjectByName(SEGMENT_LENGTH_LABEL) as Group
const length = Math.sqrt( const length = Math.sqrt(
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2) Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
@ -1347,6 +1360,29 @@ export class SceneEntities {
extraSegmentGroup.visible = isHandlesVisible extraSegmentGroup.visible = isHandlesVisible
} }
if (labelGroup) {
const labelWrapper = labelGroup.getObjectByName(
SEGMENT_LENGTH_LABEL_TEXT
) as CSS2DObject
const labelWrapperElem = labelWrapper.element as HTMLDivElement
const label = labelWrapperElem.children[0] as HTMLParagraphElement
label.innerText = `${roundOff(length)}${sceneInfra._baseUnit}`
label.classList.add(SEGMENT_LENGTH_LABEL_TEXT)
const offsetFromMidpoint = new Vector2(to[0] - from[0], to[1] - from[1])
.normalize()
.rotateAround(new Vector2(0, 0), Math.PI / 2)
.multiplyScalar(SEGMENT_LENGTH_LABEL_OFFSET_PX * scale)
label.style.setProperty('--x', `${offsetFromMidpoint.x}px`)
label.style.setProperty('--y', `${offsetFromMidpoint.y}px`)
labelWrapper.position.set(
(from[0] + to[0]) / 2 + offsetFromMidpoint.x,
(from[1] + to[1]) / 2 + offsetFromMidpoint.y,
0
)
labelGroup.visible = isHandlesVisible
}
const straightSegmentBody = group.children.find( const straightSegmentBody = group.children.find(
(child) => child.userData.type === STRAIGHT_SEGMENT_BODY (child) => child.userData.type === STRAIGHT_SEGMENT_BODY
) as Mesh ) as Mesh
@ -1397,6 +1433,14 @@ export class SceneEntities {
) )
let shouldResolve = false let shouldResolve = false
if (sketchSegments) { if (sketchSegments) {
// We have to manually remove the CSS2DObjects
// as they don't get removed when the group is removed
sketchSegments.traverse((object) => {
if (object instanceof CSS2DObject) {
object.element.remove()
object.remove()
}
})
this.scene.remove(sketchSegments) this.scene.remove(sketchSegments)
shouldResolve = true shouldResolve = true
} else { } else {

View File

@ -31,6 +31,7 @@ import { EngineCommandManager } from 'lang/std/engineConnection'
import { MouseState, SegmentOverlayPayload } from 'machines/modelingMachine' import { MouseState, SegmentOverlayPayload } from 'machines/modelingMachine'
import { getAngle, throttle } from 'lib/utils' import { getAngle, throttle } from 'lib/utils'
import { Themes } from 'lib/theme' import { Themes } from 'lib/theme'
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
type SendType = ReturnType<typeof useModelingContext>['send'] type SendType = ReturnType<typeof useModelingContext>['send']
@ -54,6 +55,9 @@ export const Y_AXIS = 'yAxis'
export const AXIS_GROUP = 'axisGroup' export const AXIS_GROUP = 'axisGroup'
export const SKETCH_GROUP_SEGMENTS = 'sketch-group-segments' export const SKETCH_GROUP_SEGMENTS = 'sketch-group-segments'
export const ARROWHEAD = 'arrowhead' export const ARROWHEAD = 'arrowhead'
export const SEGMENT_LENGTH_LABEL = 'segment-length-label'
export const SEGMENT_LENGTH_LABEL_TEXT = 'segment-length-label-text'
export const SEGMENT_LENGTH_LABEL_OFFSET_PX = 30
export interface OnMouseEnterLeaveArgs { export interface OnMouseEnterLeaveArgs {
selected: Object3D<Object3DEventMap> selected: Object3D<Object3DEventMap>
@ -95,6 +99,7 @@ export class SceneInfra {
static instance: SceneInfra static instance: SceneInfra
scene: Scene scene: Scene
renderer: WebGLRenderer renderer: WebGLRenderer
labelRenderer: CSS2DRenderer
camControls: CameraControls camControls: CameraControls
isPerspective = true isPerspective = true
fov = 45 fov = 45
@ -264,6 +269,13 @@ export class SceneInfra {
this.renderer = new WebGLRenderer({ antialias: true, alpha: true }) // Enable transparency this.renderer = new WebGLRenderer({ antialias: true, alpha: true }) // Enable transparency
this.renderer.setSize(window.innerWidth, window.innerHeight) this.renderer.setSize(window.innerWidth, window.innerHeight)
this.renderer.setClearColor(0x000000, 0) // Set clear color to black with 0 alpha (fully transparent) this.renderer.setClearColor(0x000000, 0) // Set clear color to black with 0 alpha (fully transparent)
// LABEL RENDERER
this.labelRenderer = new CSS2DRenderer()
this.labelRenderer.setSize(window.innerWidth, window.innerHeight)
this.labelRenderer.domElement.style.position = 'absolute'
this.labelRenderer.domElement.style.top = '0px'
this.labelRenderer.domElement.style.pointerEvents = 'none'
window.addEventListener('resize', this.onWindowResize) window.addEventListener('resize', this.onWindowResize)
this.camControls = new CameraControls( this.camControls = new CameraControls(
@ -328,6 +340,7 @@ export class SceneInfra {
onWindowResize = () => { onWindowResize = () => {
this.renderer.setSize(window.innerWidth, window.innerHeight) this.renderer.setSize(window.innerWidth, window.innerHeight)
this.labelRenderer.setSize(window.innerWidth, window.innerHeight)
} }
animate = () => { animate = () => {
@ -337,6 +350,7 @@ export class SceneInfra {
// console.log('animation frame', this.cameraControls.camera) // console.log('animation frame', this.cameraControls.camera)
this.camControls.update() this.camControls.update()
this.renderer.render(this.scene, this.camControls.camera) this.renderer.render(this.scene, this.camControls.camera)
this.labelRenderer.render(this.scene, this.camControls.camera)
} }
} }

View File

@ -21,6 +21,7 @@ import {
Vector3, Vector3,
} from 'three' } from 'three'
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js' import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { PathToNode, SketchGroup, getTangentialArcToInfo } from 'lang/wasm' import { PathToNode, SketchGroup, getTangentialArcToInfo } from 'lang/wasm'
import { import {
EXTRA_SEGMENT_HANDLE, EXTRA_SEGMENT_HANDLE,
@ -36,8 +37,14 @@ import {
TANGENTIAL_ARC_TO__SEGMENT_DASH, TANGENTIAL_ARC_TO__SEGMENT_DASH,
} from './sceneEntities' } from './sceneEntities'
import { getTangentPointFromPreviousArc } from 'lib/utils2d' import { getTangentPointFromPreviousArc } from 'lib/utils2d'
import { ARROWHEAD } from './sceneInfra' import {
ARROWHEAD,
SEGMENT_LENGTH_LABEL,
SEGMENT_LENGTH_LABEL_OFFSET_PX,
SEGMENT_LENGTH_LABEL_TEXT,
} from './sceneInfra'
import { Themes, getThemeColorForThreeJs } from 'lib/theme' import { Themes, getThemeColorForThreeJs } from 'lib/theme'
import { roundOff } from 'lib/utils'
export function profileStart({ export function profileStart({
from, from,
@ -101,7 +108,7 @@ export function straightSegment({
theme: Themes theme: Themes
isSelected?: boolean isSelected?: boolean
}): Group { }): Group {
const group = new Group() const segmentGroup = new Group()
const shape = new Shape() const shape = new Shape()
shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale) shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale)
@ -133,7 +140,7 @@ export function straightSegment({
: STRAIGHT_SEGMENT_BODY : STRAIGHT_SEGMENT_BODY
mesh.name = STRAIGHT_SEGMENT_BODY mesh.name = STRAIGHT_SEGMENT_BODY
group.userData = { segmentGroup.userData = {
type: STRAIGHT_SEGMENT, type: STRAIGHT_SEGMENT,
id, id,
from, from,
@ -143,37 +150,60 @@ export function straightSegment({
callExpName, callExpName,
baseColor, baseColor,
} }
group.name = STRAIGHT_SEGMENT segmentGroup.name = STRAIGHT_SEGMENT
segmentGroup.add(mesh)
const length = Math.sqrt( const length = Math.sqrt(
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2) Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
) )
const arrowGroup = createArrowhead(scale, theme, color)
arrowGroup.position.set(to[0], to[1], 0)
const dir = new Vector3()
.subVectors(new Vector3(to[0], to[1], 0), new Vector3(from[0], from[1], 0))
.normalize()
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
const pxLength = length / scale const pxLength = length / scale
const shouldHide = pxLength < HIDE_SEGMENT_LENGTH const shouldHide = pxLength < HIDE_SEGMENT_LENGTH
arrowGroup.visible = !shouldHide
group.add(mesh)
if (callExpName !== 'close') group.add(arrowGroup)
// All segment types get an extra segment handle,
// Which is a little plus sign that appears at the origin of the segment
// and can be dragged to insert a new segment
const extraSegmentGroup = createExtraSegmentHandle(scale, texture, theme) const extraSegmentGroup = createExtraSegmentHandle(scale, texture, theme)
const offsetFromBase = new Vector2(to[0] - from[0], to[1] - from[1]) const directionVector = new Vector2(
.normalize() to[0] - from[0],
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale) to[1] - from[1]
).normalize()
const offsetFromBase = directionVector.multiplyScalar(
EXTRA_SEGMENT_OFFSET_PX * scale
)
extraSegmentGroup.position.set( extraSegmentGroup.position.set(
from[0] + offsetFromBase.x, from[0] + offsetFromBase.x,
from[1] + offsetFromBase.y, from[1] + offsetFromBase.y,
0 0
) )
extraSegmentGroup.visible = !shouldHide extraSegmentGroup.visible = !shouldHide
group.add(extraSegmentGroup) segmentGroup.add(extraSegmentGroup)
return group // Segment decorators that only apply to non-close segments
if (callExpName !== 'close') {
// an arrowhead that appears at the end of the segment
const arrowGroup = createArrowhead(scale, theme, color)
arrowGroup.position.set(to[0], to[1], 0)
const dir = new Vector3()
.subVectors(
new Vector3(to[0], to[1], 0),
new Vector3(from[0], from[1], 0)
)
.normalize()
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
arrowGroup.visible = !shouldHide
segmentGroup.add(arrowGroup)
// A length indicator that appears at the midpoint of the segment
const lengthIndicatorGroup = createLengthIndicator({
from,
to,
scale,
length,
})
segmentGroup.add(lengthIndicatorGroup)
}
return segmentGroup
} }
function createArrowhead(scale = 1, theme: Themes, color?: number): Group { function createArrowhead(scale = 1, theme: Themes, color?: number): Group {
@ -230,6 +260,46 @@ function createExtraSegmentHandle(
return extraSegmentGroup return extraSegmentGroup
} }
/**
* Creates a group containing a CSS2DObject with the length of the segment
*/
function createLengthIndicator({
from,
to,
scale,
length,
}: {
from: Coords2d
to: Coords2d
scale: number
length: number
}) {
const lengthIndicatorGroup = new Group()
lengthIndicatorGroup.name = SEGMENT_LENGTH_LABEL
// Make the elements
const lengthIndicatorText = document.createElement('p')
lengthIndicatorText.classList.add(SEGMENT_LENGTH_LABEL_TEXT)
lengthIndicatorText.innerText = roundOff(length).toString()
const lengthIndicatorWrapper = document.createElement('div')
// Style the elements
lengthIndicatorWrapper.style.position = 'absolute'
lengthIndicatorWrapper.appendChild(lengthIndicatorText)
const cssObject = new CSS2DObject(lengthIndicatorWrapper)
cssObject.name = SEGMENT_LENGTH_LABEL_TEXT
// Position the elements based on the line's heading
const offsetFromMidpoint = new Vector2(to[0] - from[0], to[1] - from[1])
.normalize()
.rotateAround(new Vector2(0, 0), -Math.PI / 2)
.multiplyScalar(SEGMENT_LENGTH_LABEL_OFFSET_PX * scale)
lengthIndicatorText.style.setProperty('--x', `${offsetFromMidpoint.x}px`)
lengthIndicatorText.style.setProperty('--y', `${offsetFromMidpoint.y}px`)
lengthIndicatorGroup.add(cssObject)
return lengthIndicatorGroup
}
export function tangentialArcToSegment({ export function tangentialArcToSegment({
prevSegment, prevSegment,
from, from,

View File

@ -119,7 +119,7 @@ export default function Gizmo() {
<div <div
ref={wrapperRef} ref={wrapperRef}
aria-label="View orientation gizmo" aria-label="View orientation gizmo"
className="grid place-content-center rounded-full overflow-hidden border border-solid border-primary/50 pointer-events-auto" className="grid place-content-center rounded-full overflow-hidden border border-solid border-primary/50 pointer-events-auto bg-chalkboard-10/70 dark:bg-chalkboard-100/80 backdrop-blur-sm"
> >
<canvas ref={canvasRef} /> <canvas ref={canvasRef} />
<ContextMenu <ContextMenu

View File

@ -8,7 +8,7 @@ import {
LanguageServerPlugin, LanguageServerPlugin,
} from '@kittycad/codemirror-lsp-client' } from '@kittycad/codemirror-lsp-client'
import { TEST, VITE_KC_API_BASE_URL } from 'env' import { TEST, VITE_KC_API_BASE_URL } from 'env'
import KclLanguageSupport from 'editor/plugins/lsp/kcl/language' import { kcl } from 'editor/plugins/lsp/kcl/language'
import { copilotPlugin } from 'editor/plugins/lsp/copilot' import { copilotPlugin } from 'editor/plugins/lsp/copilot'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Extension } from '@codemirror/state' import { Extension } from '@codemirror/state'
@ -146,7 +146,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
let plugin = null let plugin = null
if (isKclLspReady && !TEST && kclLspClient) { if (isKclLspReady && !TEST && kclLspClient) {
// Set up the lsp plugin. // Set up the lsp plugin.
const lsp = new KclLanguageSupport({ const lsp = kcl({
documentUri: `file:///${PROJECT_ENTRYPOINT}`, documentUri: `file:///${PROJECT_ENTRYPOINT}`,
workspaceFolders: getWorkspaceFolders(), workspaceFolders: getWorkspaceFolders(),
client: kclLspClient, client: kclLspClient,

View File

@ -53,9 +53,8 @@ import {
sketchOnExtrudedFace, sketchOnExtrudedFace,
startSketchOnDefault, startSketchOnDefault,
} from 'lang/modifyAst' } from 'lang/modifyAst'
import { Program, VariableDeclaration, parse, recast } from 'lang/wasm' import { Program, parse, recast } from 'lang/wasm'
import { import {
getNodeFromPath,
getNodePathFromSourceRange, getNodePathFromSourceRange,
hasExtrudableGeometry, hasExtrudableGeometry,
isSingleCursorInPipe, isSingleCursorInPipe,
@ -164,6 +163,8 @@ export const ModelingMachineProvider = ({
store.videoElement?.pause() store.videoElement?.pause()
kclManager.executeCode(true).then(() => { kclManager.executeCode(true).then(() => {
if (engineCommandManager.engineConnection?.freezeFrame) return
store.videoElement?.play() store.videoElement?.play()
}) })
})() })()

View File

@ -8,7 +8,7 @@ import { NetworkHealthState } from 'hooks/useNetworkStatus'
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp' import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
import { butName } from 'lib/cameraControls' import { butName } from 'lib/cameraControls'
import { sendSelectEventToEngine } from 'lib/selections' import { sendSelectEventToEngine } from 'lib/selections'
import { kclManager } from 'lib/singletons' import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
export const Stream = () => { export const Stream = () => {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -18,6 +18,7 @@ export const Stream = () => {
const { settings } = useSettingsAuthContext() const { settings } = useSettingsAuthContext()
const { state, send, context } = useModelingContext() const { state, send, context } = useModelingContext()
const { overallState } = useNetworkContext() const { overallState } = useNetworkContext()
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
const isNetworkOkay = const isNetworkOkay =
overallState === NetworkHealthState.Ok || overallState === NetworkHealthState.Ok ||
@ -49,14 +50,71 @@ export const Stream = () => {
globalThis?.window?.document?.addEventListener('paste', handlePaste, { globalThis?.window?.document?.addEventListener('paste', handlePaste, {
capture: true, capture: true,
}) })
return () =>
const IDLE_TIME_MS = 1000 * 20
let timeoutIdIdleA: ReturnType<typeof setTimeout> | undefined = undefined
const teardown = () => {
videoRef.current?.pause()
setIsFreezeFrame(true)
sceneInfra.modelingSend({ type: 'Cancel' })
// Give video time to pause
window.requestAnimationFrame(() => {
engineCommandManager.engineConnection?.tearDown({ freeze: true })
})
}
// Teardown everything if we go hidden or reconnect
if (globalThis?.window?.document) {
globalThis.window.document.onvisibilitychange = () => {
if (globalThis.window.document.visibilityState === 'hidden') {
clearTimeout(timeoutIdIdleA)
timeoutIdIdleA = setTimeout(teardown, IDLE_TIME_MS)
} else if (!engineCommandManager.engineConnection?.isReady()) {
clearTimeout(timeoutIdIdleA)
engineCommandManager.engineConnection?.connect(true)
}
}
}
let timeoutIdIdleB: ReturnType<typeof setTimeout> | undefined = undefined
const onAnyInput = () => {
if (!engineCommandManager.engineConnection?.isReady()) {
engineCommandManager.engineConnection?.connect(true)
}
// Clear both timers
clearTimeout(timeoutIdIdleA)
clearTimeout(timeoutIdIdleB)
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
}
globalThis?.window?.document?.addEventListener('keydown', onAnyInput)
globalThis?.window?.document?.addEventListener('mousemove', onAnyInput)
globalThis?.window?.document?.addEventListener('mousedown', onAnyInput)
globalThis?.window?.document?.addEventListener('scroll', onAnyInput)
globalThis?.window?.document?.addEventListener('touchstart', onAnyInput)
timeoutIdIdleB = setTimeout(teardown, IDLE_TIME_MS)
return () => {
globalThis?.window?.document?.removeEventListener('paste', handlePaste, { globalThis?.window?.document?.removeEventListener('paste', handlePaste, {
capture: true, capture: true,
}) })
globalThis?.window?.document?.removeEventListener('keydown', onAnyInput)
globalThis?.window?.document?.removeEventListener('mousemove', onAnyInput)
globalThis?.window?.document?.removeEventListener('mousedown', onAnyInput)
globalThis?.window?.document?.removeEventListener('scroll', onAnyInput)
globalThis?.window?.document?.removeEventListener(
'touchstart',
onAnyInput
)
}
}, []) }, [])
useEffect(() => { useEffect(() => {
setIsFirstRender(kclManager.isFirstRender) setIsFirstRender(kclManager.isFirstRender)
if (!kclManager.isFirstRender) videoRef.current?.play()
}, [kclManager.isFirstRender]) }, [kclManager.isFirstRender])
useEffect(() => { useEffect(() => {
@ -67,7 +125,10 @@ export const Stream = () => {
return return
if (!videoRef.current) return if (!videoRef.current) return
if (!context.store?.mediaStream) return if (!context.store?.mediaStream) return
// Do not immediately play the stream!
videoRef.current.srcObject = context.store.mediaStream videoRef.current.srcObject = context.store.mediaStream
videoRef.current.pause()
send({ send({
type: 'Set context', type: 'Set context',
@ -172,17 +233,12 @@ export const Stream = () => {
<ClientSideScene <ClientSideScene
cameraControls={settings.context.modeling.mouseControls.current} cameraControls={settings.context.modeling.mouseControls.current}
/> />
{!isNetworkOkay && !isLoading && ( {(!isNetworkOkay || isLoading || isFirstRender) && !isFreezeFrame && (
<div className="text-center absolute inset-0"> <div className="text-center absolute inset-0">
<Loading> <Loading>
<span data-testid="loading-stream">Stream disconnected...</span> {!isNetworkOkay && !isLoading ? (
</Loading> <span data-testid="loading-stream">Stream disconnected...</span>
</div> ) : !isLoading && isFirstRender ? (
)}
{(isLoading || isFirstRender) && (
<div className="text-center absolute inset-0">
<Loading>
{!isLoading && isFirstRender ? (
<span data-testid="loading-stream">Building scene...</span> <span data-testid="loading-stream">Building scene...</span>
) : ( ) : (
<span data-testid="loading-stream">Loading stream...</span> <span data-testid="loading-stream">Loading stream...</span>

View File

@ -0,0 +1,54 @@
import { Popover } from '@headlessui/react'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { baseUnitLabels, baseUnitsUnion } from 'lib/settings/settingsTypes'
export function UnitsMenu() {
const { settings } = useSettingsAuthContext()
return (
<Popover className="relative pointer-events-auto">
{({ close }) => (
<>
<Popover.Button
className={`flex items-center gap-2 px-3 py-1
text-xs text-primary bg-chalkboard-10/70 dark:bg-chalkboard-100/80 backdrop-blur-sm
border !border-primary/50 rounded-full`}
>
<div className="w-4 h-[1px] bg-primary relative">
<div className="absolute w-[1px] h-[1em] bg-primary left-0 top-1/2 -translate-y-1/2"></div>
<div className="absolute w-[1px] h-[1em] bg-primary right-0 top-1/2 -translate-y-1/2"></div>
</div>
<span className="sr-only">Current units are:&nbsp;</span>
{settings.context.modeling.defaultUnit.current}
</Popover.Button>
<Popover.Panel
className={`absolute bottom-full right-0 mb-2 w-48 bg-chalkboard-10 dark:bg-chalkboard-90
border border-solid border-chalkboard-10 dark:border-chalkboard-90 rounded
shadow-lg`}
>
<ul className="relative flex flex-col gap-0.5 items-stretch content-stretch">
{baseUnitsUnion.map((unit) => (
<li key={unit} className="contents">
<button
className="flex items-center gap-2 py-1 px-2 cursor-pointer hover:bg-chalkboard-20 dark:hover:bg-chalkboard-80 border-none text-left"
onClick={() => {
settings.send({
type: 'set.modeling.defaultUnit',
data: {
level: 'project',
value: unit,
},
})
close()
}}
>
{baseUnitLabels[unit]}
</button>
</li>
))}
</ul>
</Popover.Panel>
</>
)}
</Popover>
)
}

View File

@ -12,14 +12,14 @@ import {
setDiagnosticsEffect, setDiagnosticsEffect,
} from '@codemirror/lint' } from '@codemirror/lint'
const updateOutsideEditorAnnotation = Annotation.define<null>() const updateOutsideEditorAnnotation = Annotation.define<boolean>()
export const updateOutsideEditorEvent = updateOutsideEditorAnnotation.of(null) export const updateOutsideEditorEvent = updateOutsideEditorAnnotation.of(true)
const modelingMachineAnnotation = Annotation.define<null>() const modelingMachineAnnotation = Annotation.define<boolean>()
export const modelingMachineEvent = modelingMachineAnnotation.of(null) export const modelingMachineEvent = modelingMachineAnnotation.of(true)
const setDiagnosticsAnnotation = Annotation.define<null>() const setDiagnosticsAnnotation = Annotation.define<boolean>()
export const setDiagnosticsEvent = setDiagnosticsAnnotation.of(null) export const setDiagnosticsEvent = setDiagnosticsAnnotation.of(true)
function diagnosticIsEqual(d1: Diagnostic, d2: Diagnostic): boolean { function diagnosticIsEqual(d1: Diagnostic, d2: Diagnostic): boolean {
return d1.from === d2.from && d1.to === d2.to && d1.message === d2.message return d1.from === d2.from && d1.to === d2.to && d1.message === d2.message
@ -123,7 +123,11 @@ export default class EditorManager {
this._editorView.dispatch({ this._editorView.dispatch({
effects: [setDiagnosticsEffect.of(diagnostics)], effects: [setDiagnosticsEffect.of(diagnostics)],
annotations: [setDiagnosticsEvent, Transaction.addToHistory.of(false)], annotations: [
setDiagnosticsEvent,
updateOutsideEditorEvent,
Transaction.addToHistory.of(false),
],
}) })
} }

View File

@ -37,11 +37,11 @@ import { CopilotAcceptCompletionParams } from 'wasm-lib/kcl/bindings/CopilotAcce
import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams' import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams'
import { editorManager } from 'lib/singletons' import { editorManager } from 'lib/singletons'
const copilotPluginAnnotation = Annotation.define<null>() const copilotPluginAnnotation = Annotation.define<boolean>()
export const copilotPluginEvent = copilotPluginAnnotation.of(null) export const copilotPluginEvent = copilotPluginAnnotation.of(true)
const rejectSuggestionAnnotation = Annotation.define<null>() const rejectSuggestionAnnotation = Annotation.define<boolean>()
export const rejectSuggestionCommand = rejectSuggestionAnnotation.of(null) export const rejectSuggestionCommand = rejectSuggestionAnnotation.of(true)
// Effects to tell StateEffect what to do with GhostText // Effects to tell StateEffect what to do with GhostText
const addSuggestion = StateEffect.define<Suggestion>() const addSuggestion = StateEffect.define<Suggestion>()
@ -229,7 +229,7 @@ export class CompletionRequester implements PluginValue {
isRelevant = true isRelevant = true
} else if (tr.isUserEvent('move')) { } else if (tr.isUserEvent('move')) {
isRelevant = true isRelevant = true
} else if (tr.annotation(copilotPluginEvent.type) !== undefined) { } else if (tr.annotation(copilotPluginEvent.type)) {
isRelevant = true isRelevant = true
} }
} }
@ -457,6 +457,7 @@ export class CompletionRequester implements PluginValue {
effects: clearSuggestion.of(null), effects: clearSuggestion.of(null),
annotations: [ annotations: [
rejectSuggestionCommand, rejectSuggestionCommand,
copilotPluginEvent,
Transaction.addToHistory.of(false), Transaction.addToHistory.of(false),
], ],
}) })

View File

@ -0,0 +1,26 @@
import { styleTags, tags as t } from '@lezer/highlight'
export const klcHighlight = styleTags({
'fn var let const': t.definitionKeyword,
return: t.controlKeyword,
'true false': t.bool,
nil: t.null,
'AddOp MultOp ExpOp': t.arithmeticOperator,
CompOp: t.logicOperator,
'Equals Arrow': t.definitionOperator,
PipeOperator: t.controlOperator,
String: t.string,
Number: t.number,
LineComment: t.lineComment,
BlockComment: t.blockComment,
Shebang: t.meta,
PipeSubstitution: t.atom,
VariableDefinition: t.definition(t.variableName),
VariableName: t.variableName,
PropertyName: t.propertyName,
TagDeclarator: t.tagName,
'( )': t.paren,
'{ }': t.brace,
'[ ]': t.bracket,
', . : ? ..': t.punctuation,
})

View File

@ -12,6 +12,9 @@ import { UpdateUnitsParams } from 'wasm-lib/kcl/bindings/UpdateUnitsParams'
import { UpdateCanExecuteParams } from 'wasm-lib/kcl/bindings/UpdateCanExecuteParams' import { UpdateCanExecuteParams } from 'wasm-lib/kcl/bindings/UpdateCanExecuteParams'
import { UpdateUnitsResponse } from 'wasm-lib/kcl/bindings/UpdateUnitsResponse' import { UpdateUnitsResponse } from 'wasm-lib/kcl/bindings/UpdateUnitsResponse'
import { UpdateCanExecuteResponse } from 'wasm-lib/kcl/bindings/UpdateCanExecuteResponse' import { UpdateCanExecuteResponse } from 'wasm-lib/kcl/bindings/UpdateCanExecuteResponse'
import { codeManagerUpdateEvent } from 'lang/codeManager'
import { copilotPluginEvent } from '../copilot'
import { updateOutsideEditorEvent } from 'editor/manager'
const changesDelay = 600 const changesDelay = 600
@ -45,11 +48,10 @@ export class KclPlugin implements PluginValue {
editorManager.setEditorView(viewUpdate.view) editorManager.setEditorView(viewUpdate.view)
let isUserSelect = false let isUserSelect = false
let isRelevant = false let isRelevant = viewUpdate.docChanged
for (const tr of viewUpdate.transactions) { for (const tr of viewUpdate.transactions) {
if (tr.isUserEvent('select')) { if (tr.isUserEvent('select')) {
isUserSelect = true isUserSelect = true
break
} else if (tr.isUserEvent('input')) { } else if (tr.isUserEvent('input')) {
isRelevant = true isRelevant = true
} else if (tr.isUserEvent('delete')) { } else if (tr.isUserEvent('delete')) {
@ -63,6 +65,21 @@ export class KclPlugin implements PluginValue {
} else if (tr.annotation(lspFormatCodeEvent.type)) { } else if (tr.annotation(lspFormatCodeEvent.type)) {
isRelevant = true isRelevant = true
} }
// Don't make this an else.
if (tr.annotation(codeManagerUpdateEvent.type)) {
// We want to ignore when we are forcing the editor to update.
isRelevant = false
break
} else if (tr.annotation(copilotPluginEvent.type)) {
// We want to ignore when copilot is doing stuff.
isRelevant = false
break
} else if (tr.annotation(updateOutsideEditorEvent.type)) {
// We want to ignore other events outside the editor.
isRelevant = false
break
}
} }
// If we have a user select event, we want to update what parts are // If we have a user select event, we want to update what parts are

View File

@ -0,0 +1,113 @@
@precedence {
member
call
exp @left
mult @left
add @left
comp @left
pipe @left
range
}
@top Program {
Shebang?
statement*
}
statement[@isGroup=Statement] {
FunctionDeclaration { kw<"fn"> VariableDefinition Equals ParamList Arrow Body } |
VariableDeclaration { (kw<"var"> | kw<"let"> | kw<"const">) VariableDefinition Equals expression } |
ReturnStatement { kw<"return"> expression } |
ExpressionStatement { expression }
}
ParamList { "(" commaSep<Parameter { VariableDefinition "?"? (":" type)? }> ")" }
Body { "{" statement* "}" }
expression[@isGroup=Expression] {
String |
Number |
VariableName |
TagDeclarator |
kw<"true"> | kw<"false"> | kw<"nil"> |
PipeSubstitution |
BinaryExpression {
expression !add AddOp expression |
expression !mult MultOp expression |
expression !exp ExpOp expression |
expression !comp CompOp expression
} |
UnaryExpression { AddOp expression } |
ParenthesizedExpression { "(" expression ")" } |
CallExpression { expression !call ArgumentList } |
ArrayExpression { "[" commaSep<expression | IntegerRange { expression !range ".." expression }> "]" } |
ObjectExpression { "{" commaSep<ObjectProperty> "}" } |
MemberExpression { expression !member "." PropertyName } |
SubscriptExpression { expression !member "[" expression "]" } |
PipeExpression { expression (!pipe PipeOperator expression)+ }
}
ObjectProperty { PropertyName ":" expression }
ArgumentList { "(" commaSep<expression> ")" }
type[@isGroup=Type] {
@specialize[@name=PrimitiveType]<
identifier,
"string" | "number" | "bool" | "sketch_group" | "sketch_surface" | "extrude_group"
> |
ArrayType { type !member "[" "]" } |
ObjectType { "{" commaSep<ObjectProperty { PropertyName ":" type }> "}" }
}
VariableDefinition { identifier }
VariableName { identifier }
@skip { whitespace | LineComment | BlockComment }
kw<term> { @specialize[@name={term}]<identifier, term> }
commaSep<term> { (term ("," term)*)? ","? }
@tokens {
String[isolate] { "'" ("\\" _ | !['\\])* "'" | '"' ("\\" _ | !["\\])* '"' }
Number { "." @digit+ | @digit+ ("." @digit*)? }
@precedence { Number, "." }
AddOp { "+" | "-" }
MultOp { "/" | "*" | "\\" }
ExpOp { "^" }
CompOp { $[<>] "="? | "!=" | "==" }
Equals { "=" }
Arrow { "=>" }
PipeOperator { "|>" }
PipeSubstitution { "%" }
identifier { (@asciiLetter | "_") (@asciiLetter | @digit | "_")* }
PropertyName { identifier }
TagDeclarator { "$" identifier }
whitespace { @whitespace+ }
LineComment[isolate] { "//" ![\n]* }
BlockComment[isolate] { "/*" blockCommentRest }
blockCommentRest { @eof | ![*] blockCommentRest | "*" blockCommentStar }
blockCommentStar { @eof | "/" | ![/] blockCommentRest | "*" blockCommentStar }
@precedence { LineComment, BlockComment, MultOp }
Shebang { "#!" ![\n]* }
"(" ")"
"{" "}"
"[" "]"
"," "?" ":" "." ".."
}
@external propSource klcHighlight from "./highlight"
@detectDelim

View File

@ -1,9 +1,13 @@
// Code mirror language implementation for kcl. // Code mirror language implementation for kcl.
import { import {
Language, LRLanguage,
defineLanguageFacet,
LanguageSupport, LanguageSupport,
indentNodeProp,
continuedIndent,
delimitedIndent,
foldNodeProp,
foldInside,
} from '@codemirror/language' } from '@codemirror/language'
import { import {
LanguageServerClient, LanguageServerClient,
@ -11,18 +15,8 @@ import {
} from '@kittycad/codemirror-lsp-client' } from '@kittycad/codemirror-lsp-client'
import { kclPlugin } from '.' import { kclPlugin } from '.'
import type * as LSP from 'vscode-languageserver-protocol' import type * as LSP from 'vscode-languageserver-protocol'
import KclParser from './parser' // @ts-ignore: No types available
import { parser } from './kcl.grammar'
const data = defineLanguageFacet({
// https://codemirror.net/docs/ref/#commands.CommentTokens
commentTokens: {
line: '//',
block: {
open: '/*',
close: '*/',
},
},
})
export interface LanguageOptions { export interface LanguageOptions {
workspaceFolders: LSP.WorkspaceFolder[] workspaceFolders: LSP.WorkspaceFolder[]
@ -34,26 +28,40 @@ export interface LanguageOptions {
) => void ) => void
} }
class KclLanguage extends Language { export const KclLanguage = LRLanguage.define({
constructor(options: LanguageOptions) { name: 'klc',
const plugin = kclPlugin({ parser: parser.configure({
props: [
indentNodeProp.add({
Body: delimitedIndent({ closing: '}' }),
BlockComment: () => null,
'Statement Property': continuedIndent({ except: /^{/ }),
}),
foldNodeProp.add({
'Body ArrayExpression ObjectExpression': foldInside,
BlockComment(tree) {
return { from: tree.from + 2, to: tree.to - 2 }
},
PipeExpression(tree) {
return { from: tree.firstChild!.to, to: tree.to }
},
}),
],
}),
languageData: {
commentTokens: { line: '//', block: { open: '/*', close: '*/' } },
},
})
export function kcl(options: LanguageOptions) {
return new LanguageSupport(
KclLanguage,
kclPlugin({
documentUri: options.documentUri, documentUri: options.documentUri,
workspaceFolders: options.workspaceFolders, workspaceFolders: options.workspaceFolders,
allowHTMLContent: true, allowHTMLContent: true,
client: options.client, client: options.client,
processLspNotification: options.processLspNotification, processLspNotification: options.processLspNotification,
}) })
)
const parser = new KclParser()
super(data, parser, [plugin], 'kcl')
}
}
export default class KclLanguageSupport extends LanguageSupport {
constructor(options: LanguageOptions) {
const lang = new KclLanguage(options)
super(lang)
}
} }

View File

@ -1,47 +0,0 @@
// Extends the codemirror Parser for kcl.
// This is really just a no-op parser since we use semantic tokens from the LSP
// server.
import {
Parser,
Input,
TreeFragment,
PartialParse,
Tree,
NodeType,
} from '@lezer/common'
import { DocInput } from '@codemirror/language'
export default class KclParser extends Parser {
createParse(
input: Input,
fragments: readonly TreeFragment[],
ranges: readonly { from: number; to: number }[]
): PartialParse {
let parse: PartialParse = new Context(input)
return parse
}
}
class Context implements PartialParse {
private input: DocInput
stoppedAt: number = 0
constructor(input: Input) {
this.input = input as DocInput
}
get parsedPos(): number {
return 0
}
advance(): Tree | null {
this.stoppedAt = this.input.doc.length
return new Tree(NodeType.none, [], [], this.input.doc.length)
}
stopAt(pos: number) {
this.stoppedAt = pos
}
}

View File

@ -254,6 +254,10 @@ code {
color: rgb(120, 120, 120, 0.8) !important; color: rgb(120, 120, 120, 0.8) !important;
} }
.segment-length-label-text {
transform: translate(var(--x, 0), var(--y, 0));
}
@layer components { @layer components {
kbd.hotkey { kbd.hotkey {
@apply font-mono text-xs inline-block px-1 py-0.5 rounded-sm; @apply font-mono text-xs inline-block px-1 py-0.5 rounded-sm;

View File

@ -185,6 +185,17 @@ const sk2 = startSketchOn('XY')
on: expect.any(Object), on: expect.any(Object),
start: expect.any(Object), start: expect.any(Object),
type: 'SketchGroup', type: 'SketchGroup',
tags: {
p: {
__meta: [
{
sourceRange: [114, 116],
},
],
type: 'TagIdentifier',
value: 'p',
},
},
value: [ value: [
{ {
type: 'ToPoint', type: 'ToPoint',
@ -265,6 +276,17 @@ const sk2 = startSketchOn('XY')
on: expect.any(Object), on: expect.any(Object),
start: expect.any(Object), start: expect.any(Object),
type: 'SketchGroup', type: 'SketchGroup',
tags: {
o: {
__meta: [
{
sourceRange: [417, 419],
},
],
type: 'TagIdentifier',
value: 'o',
},
},
value: [ value: [
{ {
type: 'ToPoint', type: 'ToPoint',

View File

@ -11,8 +11,8 @@ import { KeyBinding } from '@codemirror/view'
const PERSIST_CODE_KEY = 'persistCode' const PERSIST_CODE_KEY = 'persistCode'
const codeManagerUpdateAnnotation = Annotation.define<null>() const codeManagerUpdateAnnotation = Annotation.define<boolean>()
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null) export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(true)
export default class CodeManager { export default class CodeManager {
private _code: string = bracket private _code: string = bracket

View File

@ -155,6 +155,17 @@ const newVar = myVar + 1`
sourceRange: [39, 63], sourceRange: [39, 63],
}, },
}, },
tags: {
myPath: {
__meta: [
{
sourceRange: [109, 117],
},
],
type: 'TagIdentifier',
value: 'myPath',
},
},
value: [ value: [
{ {
type: 'ToPoint', type: 'ToPoint',

View File

@ -300,6 +300,7 @@ class EngineConnection extends EventTarget {
pc?: RTCPeerConnection pc?: RTCPeerConnection
unreliableDataChannel?: RTCDataChannel unreliableDataChannel?: RTCDataChannel
mediaStream?: MediaStream mediaStream?: MediaStream
freezeFrame: boolean = false
private _state: EngineConnectionState = { private _state: EngineConnectionState = {
type: EngineConnectionStateType.Fresh, type: EngineConnectionStateType.Fresh,
@ -365,7 +366,11 @@ class EngineConnection extends EventTarget {
this.pingPongSpan = { ping: undefined, pong: undefined } this.pingPongSpan = { ping: undefined, pong: undefined }
// Without an interval ping, our connection will timeout. // Without an interval ping, our connection will timeout.
// If this.freezeFrame is true we skip this logic so only reconnect
// happens on mouse move
setInterval(() => { setInterval(() => {
if (this.freezeFrame) return
switch (this.state.type as EngineConnectionStateType) { switch (this.state.type as EngineConnectionStateType) {
case EngineConnectionStateType.ConnectionEstablished: case EngineConnectionStateType.ConnectionEstablished:
// If there was no reply to the last ping, report a timeout. // If there was no reply to the last ping, report a timeout.
@ -426,7 +431,8 @@ class EngineConnection extends EventTarget {
return this.state.type === EngineConnectionStateType.ConnectionEstablished return this.state.type === EngineConnectionStateType.ConnectionEstablished
} }
tearDown() { tearDown(opts?: { freeze: boolean }) {
this.freezeFrame = opts?.freeze ?? false
this.disconnectAll() this.disconnectAll()
this.state = { this.state = {
type: EngineConnectionStateType.Disconnecting, type: EngineConnectionStateType.Disconnecting,
@ -996,6 +1002,9 @@ class EngineConnection extends EventTarget {
this.pc?.connectionState === 'closed' && this.pc?.connectionState === 'closed' &&
this.unreliableDataChannel?.readyState === 'closed' this.unreliableDataChannel?.readyState === 'closed'
if (allClosed) { if (allClosed) {
// Do not notify the rest of the program that we have cut off anything.
if (this.freezeFrame) return
this.state = { type: EngineConnectionStateType.Disconnected } this.state = { type: EngineConnectionStateType.Disconnected }
} }
} }
@ -1619,7 +1628,15 @@ export class EngineCommandManager extends EventTarget {
} }
} }
tearDown() { tearDown() {
this.engineConnection?.tearDown() if (this.engineConnection) {
this.engineConnection?.tearDown()
// Our window.tearDown assignment causes this case to happen which is
// only really for tests.
// @ts-ignore
} else if (this.engineCommandManager?.engineConnection) {
// @ts-ignore
this.engineCommandManager?.engineConnection?.tearDown()
}
} }
async startNewSession() { async startNewSession() {
this.lastArtifactMap = this.artifactMap this.lastArtifactMap = this.artifactMap

View File

@ -157,7 +157,7 @@ export function createSettings() {
), ),
}), }),
enableSSAO: new Setting<boolean>({ enableSSAO: new Setting<boolean>({
defaultValue: false, defaultValue: true,
description: description:
'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled', 'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled',
validate: (v) => typeof v === 'boolean', validate: (v) => typeof v === 'boolean',

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