Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
2f51763df9 | |||
7c4bf8d793 | |||
4747cdcab6 | |||
de73f335fe | |||
a62004da82 | |||
92e0da1f8d | |||
a111473658 | |||
7cfed9bff4 | |||
a30bd185d8 | |||
e8cae630a1 | |||
74ec749560 | |||
ebdaf59d1c | |||
cd68414d54 | |||
c8238ff04a | |||
8089369108 | |||
8ebe78c664 | |||
a85c1a9375 | |||
5701616f3e | |||
846acaba2f | |||
0a524d42f6 | |||
fe28527ef9 |
@ -121,6 +121,9 @@ const extrusion = extrude(5, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -282,6 +285,9 @@ const extrusion = extrude(5, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -125,6 +125,9 @@ const extrusion = extrude(5, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -286,6 +289,9 @@ const extrusion = extrude(5, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -126,6 +126,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -287,6 +290,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -476,6 +482,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -637,6 +646,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -125,6 +125,9 @@ const extrusion = extrude(10, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -286,6 +289,9 @@ const extrusion = extrude(10, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -475,6 +481,9 @@ const extrusion = extrude(10, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -636,6 +645,9 @@ const extrusion = extrude(10, sketch001)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -133,6 +133,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -294,6 +297,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -483,6 +489,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -644,6 +653,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -124,6 +124,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -285,6 +288,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -474,6 +480,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -635,6 +644,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -124,6 +124,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -285,6 +288,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -474,6 +480,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -635,6 +644,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -135,6 +135,9 @@ const exampleSketch = startSketchOn('XZ')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -296,6 +299,9 @@ const exampleSketch = startSketchOn('XZ')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -485,6 +491,9 @@ const exampleSketch = startSketchOn('XZ')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -646,6 +655,9 @@ const exampleSketch = startSketchOn('XZ')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -130,6 +130,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -291,6 +294,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -480,6 +486,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -641,6 +650,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -225,6 +225,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -532,6 +535,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -123,6 +123,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -410,6 +413,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -599,6 +605,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -760,6 +769,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -125,6 +125,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -286,6 +289,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -475,6 +481,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -636,6 +645,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -150,6 +150,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -311,6 +314,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
@ -580,6 +586,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -225,6 +225,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -524,6 +527,9 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -215,6 +215,9 @@ const revolution = startSketchOn(box, "revolveAxis")
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -211,6 +211,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -211,6 +211,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -213,6 +213,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -213,6 +213,9 @@ const part001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -512,6 +515,9 @@ const part001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -136,6 +136,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -297,6 +300,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
@ -479,6 +485,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -640,6 +649,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -821,6 +833,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -982,6 +997,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -129,6 +129,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -290,6 +293,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -479,6 +485,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -640,6 +649,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -116,6 +116,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -277,6 +280,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -466,6 +472,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -627,6 +636,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -134,6 +134,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -295,6 +298,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
|
@ -217,6 +217,9 @@ const example = extrude(-5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -127,6 +127,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -288,6 +291,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
|
@ -215,6 +215,9 @@ const example = extrude(1, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -217,6 +217,9 @@ let vase = layer()
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -117,6 +117,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -278,6 +281,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -112,6 +112,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -273,6 +276,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -111,6 +111,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -272,6 +275,9 @@ const sketch001 = startSketchOn('XY')
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -247,6 +247,9 @@ uuid |
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -408,6 +411,9 @@ uuid |
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -673,6 +679,9 @@ uuid |
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -124,6 +124,9 @@ const example = extrude(4, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -285,6 +288,9 @@ const example = extrude(4, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -122,6 +122,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -283,6 +286,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -123,6 +123,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -284,6 +287,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -121,6 +121,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -282,6 +285,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -213,6 +213,9 @@ shell({ faces: ['end'], thickness: 0.25 }, firstSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -512,6 +515,9 @@ shell({ faces: ['end'], thickness: 0.25 }, firstSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -195,6 +195,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -442,6 +445,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -603,6 +609,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -142,6 +142,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -303,6 +306,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -264,6 +264,9 @@ const a1 = startSketchOn({
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -539,6 +542,9 @@ const a1 = startSketchOn({
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
5655
docs/kcl/std.json
@ -125,6 +125,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -286,6 +289,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -475,6 +481,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -636,6 +645,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -116,6 +116,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -277,6 +280,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -466,6 +472,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -627,6 +636,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -74,6 +74,107 @@ You can nest expressions in parenthesis as well:
|
||||
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
|
||||
repo](https://github.com/KittyCAD/modeling-app/issues/new).
|
||||
|
@ -119,6 +119,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -280,6 +283,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -469,6 +475,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -630,6 +639,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -119,6 +119,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -280,6 +283,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -469,6 +475,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -630,6 +639,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -117,6 +117,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -278,6 +281,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -467,6 +473,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -628,6 +637,9 @@ const example = extrude(10, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -115,6 +115,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -276,6 +279,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -465,6 +471,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
@ -626,6 +635,9 @@ const example = extrude(5, exampleSketch)
|
||||
},
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
// Tag identifiers that have been declared in this sketch group.
|
||||
tags: {
|
||||
},
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
|
@ -52,7 +52,24 @@ const commonPoints = {
|
||||
// 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 }) => {
|
||||
// wait for Vite preview server to be up
|
||||
@ -78,7 +95,7 @@ test.beforeEach(async ({ context, page }) => {
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' })
|
||||
})
|
||||
|
||||
test.setTimeout(60000)
|
||||
test.setTimeout(120000)
|
||||
|
||||
async function doBasicSketch(page: Page, openPanes: string[]) {
|
||||
const u = await getUtils(page)
|
||||
@ -543,6 +560,50 @@ test.describe('Testing Camera Movement', () => {
|
||||
})
|
||||
|
||||
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 ({
|
||||
page,
|
||||
}) => {
|
||||
@ -1204,7 +1265,9 @@ test.describe('Editor tests', () => {
|
||||
|> 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)
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
@ -4053,108 +4116,111 @@ test.describe('Sketch tests', () => {
|
||||
})
|
||||
})
|
||||
|
||||
test('Can edit a sketch that has been extruded in the same pipe', async ({
|
||||
page,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const sketch001 = startSketchOn('XZ')
|
||||
// failing for the same reason as "Can undo a sketch modification with ctrl+z"
|
||||
// please fix together
|
||||
test.fixme(
|
||||
'Can edit a sketch that has been extruded in the same pipe',
|
||||
async ({ page }) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([4.61, -14.01], %)
|
||||
|> line([12.73, -0.09], %)
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> close(%)
|
||||
|> extrude(5, %)`
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
await u.waitForAuthSkipAppStart()
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
|
||||
await page.waitForTimeout(100)
|
||||
await u.openAndClearDebugPanel()
|
||||
await u.sendCustomCmd({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'default_camera_look_at',
|
||||
vantage: { x: 0, y: -1250, z: 580 },
|
||||
center: { x: 0, y: 0, z: 0 },
|
||||
up: { x: 0, y: 0, z: 1 },
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await u.sendCustomCmd({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'default_camera_get_settings',
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await page.waitForTimeout(100)
|
||||
await u.openAndClearDebugPanel()
|
||||
await u.sendCustomCmd({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'default_camera_look_at',
|
||||
vantage: { x: 0, y: -1250, z: 580 },
|
||||
center: { x: 0, y: 0, z: 0 },
|
||||
up: { x: 0, y: 0, z: 1 },
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await u.sendCustomCmd({
|
||||
type: 'modeling_cmd_req',
|
||||
cmd_id: uuidv4(),
|
||||
cmd: {
|
||||
type: 'default_camera_get_settings',
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
const startPX = [665, 458]
|
||||
const startPX = [665, 458]
|
||||
|
||||
const dragPX = 40
|
||||
const dragPX = 40
|
||||
|
||||
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Edit Sketch' })
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
await page.waitForTimeout(400)
|
||||
let prevContent = await page.locator('.cm-content').innerText()
|
||||
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Edit Sketch' })
|
||||
).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
await page.waitForTimeout(400)
|
||||
let prevContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
|
||||
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
|
||||
|
||||
// drag startProfieAt handle
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: startPX[0], y: startPX[1] },
|
||||
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
// drag startProfieAt handle
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: startPX[0], y: startPX[1] },
|
||||
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
// drag line handle
|
||||
await page.waitForTimeout(100)
|
||||
// drag line handle
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
|
||||
await page.waitForTimeout(100)
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
|
||||
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
|
||||
})
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
|
||||
await page.waitForTimeout(100)
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
|
||||
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
|
||||
})
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
prevContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
// drag tangentialArcTo handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
|
||||
targetPosition: {
|
||||
x: tangentEnd.x + dragPX,
|
||||
y: tangentEnd.y + dragPX,
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
// drag tangentialArcTo handle
|
||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
||||
await page.dragAndDrop('#stream', '#stream', {
|
||||
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
|
||||
targetPosition: {
|
||||
x: tangentEnd.x + dragPX,
|
||||
y: tangentEnd.y + dragPX,
|
||||
},
|
||||
})
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
||||
|
||||
// expect the code to have changed
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||
// expect the code to have changed
|
||||
await expect(page.locator('.cm-content'))
|
||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([7.12, -16.82], %)
|
||||
|> line([15.4, -2.74], %)
|
||||
|> tangentialArcTo([24.95, -5.38], %)
|
||||
|> line([2.65, -2.69], %)
|
||||
|> close(%)
|
||||
|> extrude(5, %)`)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test('Can edit a sketch that has been revolved in the same pipe', async ({
|
||||
page,
|
||||
@ -6704,7 +6770,15 @@ ${extraLine ? 'const myVar = segLen(seg01, part001)' : ''}`
|
||||
})
|
||||
|
||||
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)
|
||||
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()
|
||||
})
|
||||
|
||||
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)
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
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 }) => {
|
||||
// FYI this test doesn't work with only engine running locally
|
||||
// And you will need to have the KittyCAD CLI installed
|
||||
|
@ -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.waitForTimeout(300)
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
maxDiffPixels: 100,
|
||||
})
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
@ -312,9 +312,9 @@ export async function getUtils(page: Page) {
|
||||
fullPage: true,
|
||||
})
|
||||
const screenshot = await PNG.sync.read(buffer)
|
||||
// most likely related to pixel density but the screenshots for webkit are 2x the size
|
||||
// there might be a more robust way of doing this.
|
||||
const pixMultiplier = browserType === 'webkit' ? 2 : 1
|
||||
const pixMultiplier: number = await page.evaluate(
|
||||
'window.devicePixelRatio'
|
||||
)
|
||||
const index =
|
||||
(screenshot.width * coords.y * pixMultiplier +
|
||||
coords.x * pixMultiplier) *
|
||||
@ -377,11 +377,10 @@ export async function getUtils(page: Page) {
|
||||
emulateNetworkConditions: async (
|
||||
networkOptions: Protocol.Network.emulateNetworkConditionsParameters
|
||||
) => {
|
||||
// Skip on non-Chromium browsers, since we need to use the CDP.
|
||||
test.skip(
|
||||
cdpSession === null,
|
||||
'Network emulation is only supported in Chromium'
|
||||
)
|
||||
if (cdpSession === null) {
|
||||
// Use a fail safe if we can't simulate disconnect (on Safari)
|
||||
return page.evaluate('window.tearDown()')
|
||||
}
|
||||
|
||||
cdpSession?.send('Network.emulateNetworkConditions', networkOptions)
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.23.1",
|
||||
"version": "0.24.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.17.0",
|
||||
@ -17,7 +17,9 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@headlessui/react": "^1.7.19",
|
||||
"@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",
|
||||
"@replit/codemirror-interact": "^6.3.1",
|
||||
"@tauri-apps/api": "^2.0.0-beta.14",
|
||||
@ -109,6 +111,7 @@
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/preset-env": "^7.24.3",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@lezer/generator": "^1.7.1",
|
||||
"@playwright/test": "^1.45.1",
|
||||
"@tauri-apps/cli": "==2.0.0-beta.13",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
|
@ -71,6 +71,9 @@ export interface LanguageServerOptions {
|
||||
) => void
|
||||
|
||||
changesDelay?: number
|
||||
|
||||
doSemanticTokens?: boolean
|
||||
doFoldingRanges?: boolean
|
||||
}
|
||||
|
||||
export class LanguageServerPlugin implements PluginValue {
|
||||
@ -87,6 +90,9 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
notification: LSP.NotificationMessage
|
||||
) => void
|
||||
|
||||
private doSemanticTokens: boolean = false
|
||||
private doFoldingRanges: boolean = false
|
||||
|
||||
private _defferer = deferExecution((code: string) => {
|
||||
try {
|
||||
// Update the state (not the editor) with the new code.
|
||||
@ -109,6 +115,9 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
this.client = options.client
|
||||
this.documentVersion = 0
|
||||
|
||||
this.doSemanticTokens = options.doSemanticTokens ?? false
|
||||
this.doFoldingRanges = options.doFoldingRanges ?? false
|
||||
|
||||
if (options.changesDelay) {
|
||||
this.changesDelay = options.changesDelay
|
||||
}
|
||||
@ -220,6 +229,7 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
|
||||
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
|
||||
if (
|
||||
!this.doFoldingRanges ||
|
||||
!this.client.ready ||
|
||||
!this.client.getServerCapabilities().foldingRangeProvider
|
||||
)
|
||||
@ -445,6 +455,7 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
|
||||
async requestSemanticTokens() {
|
||||
if (
|
||||
!this.doSemanticTokens ||
|
||||
!this.client.ready ||
|
||||
!this.client.getServerCapabilities().semanticTokensProvider
|
||||
) {
|
||||
|
6
src-tauri/Cargo.lock
generated
@ -2571,7 +2571,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
@ -2628,9 +2628,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af3de9bb4b1441f198689a9f64a8163a518377e30b348a784680e738985b95eb"
|
||||
checksum = "e1777b503442fa4666564cc3ab237d456df853a09648a4b2bb09622d25d021a5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -16,7 +16,7 @@ tauri-build = { version = "2.0.0-beta.18", features = [] }
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
kcl-lib = { version = "0.1.53", path = "../src/wasm-lib/kcl" }
|
||||
kittycad = "0.3.5"
|
||||
kittycad = "0.3.7"
|
||||
log = "0.4.21"
|
||||
oauth2 = "4.4.2"
|
||||
serde_json = "1.0"
|
||||
|
@ -80,5 +80,5 @@
|
||||
}
|
||||
},
|
||||
"productName": "Zoo Modeling App",
|
||||
"version": "0.23.1"
|
||||
"version": "0.24.0"
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import ModalContainer from 'react-modal-promise'
|
||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||
import Gizmo from 'components/Gizmo'
|
||||
import { CoreDumpManager } from 'lib/coredump'
|
||||
import { UnitsMenu } from 'components/UnitsMenu'
|
||||
|
||||
export function App() {
|
||||
useRefreshSettings(paths.FILE + 'SETTINGS')
|
||||
@ -127,6 +128,7 @@ export function App() {
|
||||
<Stream />
|
||||
{/* <CamToggle /> */}
|
||||
<LowerRightControls coreDumpManager={coreDumpManager}>
|
||||
<UnitsMenu />
|
||||
<Gizmo />
|
||||
</LowerRightControls>
|
||||
</div>
|
||||
|
@ -529,7 +529,6 @@ export class CameraControls {
|
||||
parameters: {
|
||||
fov_y:
|
||||
this.camera instanceof PerspectiveCamera ? this.camera.fov : 45,
|
||||
...calculateNearFarFromFOV(this.lastPerspectiveFov),
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -612,8 +611,6 @@ export class CameraControls {
|
||||
type: 'default_camera_set_perspective',
|
||||
parameters: {
|
||||
fov_y: newFov,
|
||||
z_near: 0.01,
|
||||
z_far: 1000,
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -631,8 +628,6 @@ export class CameraControls {
|
||||
target: this.target,
|
||||
}),
|
||||
fov_y: newFov,
|
||||
z_near: 0.01,
|
||||
z_far: 1000,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ export const ClientSideScene = ({
|
||||
if (!canvasRef.current) return
|
||||
const canvas = canvasRef.current
|
||||
canvas.appendChild(sceneInfra.renderer.domElement)
|
||||
canvas.appendChild(sceneInfra.labelRenderer.domElement)
|
||||
sceneInfra.animate()
|
||||
canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false)
|
||||
canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false)
|
||||
|
@ -29,6 +29,9 @@ import {
|
||||
INTERSECTION_PLANE_LAYER,
|
||||
OnMouseEnterLeaveArgs,
|
||||
RAYCASTABLE_PLANE,
|
||||
SEGMENT_LENGTH_LABEL,
|
||||
SEGMENT_LENGTH_LABEL_OFFSET_PX,
|
||||
SEGMENT_LENGTH_LABEL_TEXT,
|
||||
SKETCH_GROUP_SEGMENTS,
|
||||
SKETCH_LAYER,
|
||||
X_AXIS,
|
||||
@ -47,6 +50,7 @@ import {
|
||||
programMemoryInit,
|
||||
recast,
|
||||
SketchGroup,
|
||||
ExtrudeGroup,
|
||||
VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
} from 'lang/wasm'
|
||||
@ -102,6 +106,7 @@ import {
|
||||
} from 'lib/rectangleTool'
|
||||
import { getThemeColorForThreeJs } from 'lib/theme'
|
||||
import { err, trap } from 'lib/trap'
|
||||
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
|
||||
|
||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||
|
||||
@ -414,7 +419,7 @@ export class SceneEntities {
|
||||
}
|
||||
)
|
||||
|
||||
let seg
|
||||
let seg: Group
|
||||
const _node1 = getNodeFromPath<CallExpression>(
|
||||
maybeModdedAst,
|
||||
segPathToNode,
|
||||
@ -1075,9 +1080,16 @@ export class SceneEntities {
|
||||
programMemoryOverride,
|
||||
})
|
||||
this.sceneProgramMemory = programMemory
|
||||
const sketchGroup = programMemory.root[
|
||||
variableDeclarationName
|
||||
] as SketchGroup
|
||||
|
||||
const maybeSketchGroup = programMemory.root[variableDeclarationName]
|
||||
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 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.lineTo(0, (SEGMENT_WIDTH_PX / 2) * scale)
|
||||
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
|
||||
const labelGroup = group.getObjectByName(SEGMENT_LENGTH_LABEL) as Group
|
||||
|
||||
const length = Math.sqrt(
|
||||
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
|
||||
@ -1347,6 +1360,29 @@ export class SceneEntities {
|
||||
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(
|
||||
(child) => child.userData.type === STRAIGHT_SEGMENT_BODY
|
||||
) as Mesh
|
||||
@ -1397,6 +1433,14 @@ export class SceneEntities {
|
||||
)
|
||||
let shouldResolve = false
|
||||
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)
|
||||
shouldResolve = true
|
||||
} else {
|
||||
|
@ -31,6 +31,7 @@ import { EngineCommandManager } from 'lang/std/engineConnection'
|
||||
import { MouseState, SegmentOverlayPayload } from 'machines/modelingMachine'
|
||||
import { getAngle, throttle } from 'lib/utils'
|
||||
import { Themes } from 'lib/theme'
|
||||
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
|
||||
|
||||
type SendType = ReturnType<typeof useModelingContext>['send']
|
||||
|
||||
@ -54,6 +55,9 @@ export const Y_AXIS = 'yAxis'
|
||||
export const AXIS_GROUP = 'axisGroup'
|
||||
export const SKETCH_GROUP_SEGMENTS = 'sketch-group-segments'
|
||||
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 {
|
||||
selected: Object3D<Object3DEventMap>
|
||||
@ -95,6 +99,7 @@ export class SceneInfra {
|
||||
static instance: SceneInfra
|
||||
scene: Scene
|
||||
renderer: WebGLRenderer
|
||||
labelRenderer: CSS2DRenderer
|
||||
camControls: CameraControls
|
||||
isPerspective = true
|
||||
fov = 45
|
||||
@ -264,6 +269,13 @@ export class SceneInfra {
|
||||
this.renderer = new WebGLRenderer({ antialias: true, alpha: true }) // Enable transparency
|
||||
this.renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
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)
|
||||
|
||||
this.camControls = new CameraControls(
|
||||
@ -328,6 +340,7 @@ export class SceneInfra {
|
||||
|
||||
onWindowResize = () => {
|
||||
this.renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
this.labelRenderer.setSize(window.innerWidth, window.innerHeight)
|
||||
}
|
||||
|
||||
animate = () => {
|
||||
@ -337,6 +350,7 @@ export class SceneInfra {
|
||||
// console.log('animation frame', this.cameraControls.camera)
|
||||
this.camControls.update()
|
||||
this.renderer.render(this.scene, this.camControls.camera)
|
||||
this.labelRenderer.render(this.scene, this.camControls.camera)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
Vector3,
|
||||
} from 'three'
|
||||
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 {
|
||||
EXTRA_SEGMENT_HANDLE,
|
||||
@ -36,8 +37,14 @@ import {
|
||||
TANGENTIAL_ARC_TO__SEGMENT_DASH,
|
||||
} from './sceneEntities'
|
||||
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 { roundOff } from 'lib/utils'
|
||||
|
||||
export function profileStart({
|
||||
from,
|
||||
@ -101,7 +108,7 @@ export function straightSegment({
|
||||
theme: Themes
|
||||
isSelected?: boolean
|
||||
}): Group {
|
||||
const group = new Group()
|
||||
const segmentGroup = new Group()
|
||||
|
||||
const shape = new Shape()
|
||||
shape.moveTo(0, (-SEGMENT_WIDTH_PX / 2) * scale)
|
||||
@ -133,7 +140,7 @@ export function straightSegment({
|
||||
: STRAIGHT_SEGMENT_BODY
|
||||
mesh.name = STRAIGHT_SEGMENT_BODY
|
||||
|
||||
group.userData = {
|
||||
segmentGroup.userData = {
|
||||
type: STRAIGHT_SEGMENT,
|
||||
id,
|
||||
from,
|
||||
@ -143,37 +150,60 @@ export function straightSegment({
|
||||
callExpName,
|
||||
baseColor,
|
||||
}
|
||||
group.name = STRAIGHT_SEGMENT
|
||||
segmentGroup.name = STRAIGHT_SEGMENT
|
||||
segmentGroup.add(mesh)
|
||||
|
||||
const length = Math.sqrt(
|
||||
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 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 offsetFromBase = new Vector2(to[0] - from[0], to[1] - from[1])
|
||||
.normalize()
|
||||
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale)
|
||||
const directionVector = new Vector2(
|
||||
to[0] - from[0],
|
||||
to[1] - from[1]
|
||||
).normalize()
|
||||
const offsetFromBase = directionVector.multiplyScalar(
|
||||
EXTRA_SEGMENT_OFFSET_PX * scale
|
||||
)
|
||||
extraSegmentGroup.position.set(
|
||||
from[0] + offsetFromBase.x,
|
||||
from[1] + offsetFromBase.y,
|
||||
0
|
||||
)
|
||||
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 {
|
||||
@ -230,6 +260,46 @@ function createExtraSegmentHandle(
|
||||
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({
|
||||
prevSegment,
|
||||
from,
|
||||
|
@ -119,7 +119,7 @@ export default function Gizmo() {
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
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} />
|
||||
<ContextMenu
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
LanguageServerPlugin,
|
||||
} from '@kittycad/codemirror-lsp-client'
|
||||
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 { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
import { Extension } from '@codemirror/state'
|
||||
@ -146,7 +146,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
let plugin = null
|
||||
if (isKclLspReady && !TEST && kclLspClient) {
|
||||
// Set up the lsp plugin.
|
||||
const lsp = new KclLanguageSupport({
|
||||
const lsp = kcl({
|
||||
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
||||
workspaceFolders: getWorkspaceFolders(),
|
||||
client: kclLspClient,
|
||||
|
@ -53,9 +53,8 @@ import {
|
||||
sketchOnExtrudedFace,
|
||||
startSketchOnDefault,
|
||||
} from 'lang/modifyAst'
|
||||
import { Program, VariableDeclaration, parse, recast } from 'lang/wasm'
|
||||
import { Program, parse, recast } from 'lang/wasm'
|
||||
import {
|
||||
getNodeFromPath,
|
||||
getNodePathFromSourceRange,
|
||||
hasExtrudableGeometry,
|
||||
isSingleCursorInPipe,
|
||||
@ -164,6 +163,8 @@ export const ModelingMachineProvider = ({
|
||||
|
||||
store.videoElement?.pause()
|
||||
kclManager.executeCode(true).then(() => {
|
||||
if (engineCommandManager.engineConnection?.freezeFrame) return
|
||||
|
||||
store.videoElement?.play()
|
||||
})
|
||||
})()
|
||||
|
@ -8,7 +8,7 @@ import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
||||
import { butName } from 'lib/cameraControls'
|
||||
import { sendSelectEventToEngine } from 'lib/selections'
|
||||
import { kclManager } from 'lib/singletons'
|
||||
import { kclManager, engineCommandManager, sceneInfra } from 'lib/singletons'
|
||||
|
||||
export const Stream = () => {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
@ -18,6 +18,7 @@ export const Stream = () => {
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const { state, send, context } = useModelingContext()
|
||||
const { overallState } = useNetworkContext()
|
||||
const [isFreezeFrame, setIsFreezeFrame] = useState(false)
|
||||
|
||||
const isNetworkOkay =
|
||||
overallState === NetworkHealthState.Ok ||
|
||||
@ -49,14 +50,71 @@ export const Stream = () => {
|
||||
globalThis?.window?.document?.addEventListener('paste', handlePaste, {
|
||||
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, {
|
||||
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(() => {
|
||||
setIsFirstRender(kclManager.isFirstRender)
|
||||
if (!kclManager.isFirstRender) videoRef.current?.play()
|
||||
}, [kclManager.isFirstRender])
|
||||
|
||||
useEffect(() => {
|
||||
@ -67,7 +125,10 @@ export const Stream = () => {
|
||||
return
|
||||
if (!videoRef.current) return
|
||||
if (!context.store?.mediaStream) return
|
||||
|
||||
// Do not immediately play the stream!
|
||||
videoRef.current.srcObject = context.store.mediaStream
|
||||
videoRef.current.pause()
|
||||
|
||||
send({
|
||||
type: 'Set context',
|
||||
@ -172,17 +233,12 @@ export const Stream = () => {
|
||||
<ClientSideScene
|
||||
cameraControls={settings.context.modeling.mouseControls.current}
|
||||
/>
|
||||
{!isNetworkOkay && !isLoading && (
|
||||
{(!isNetworkOkay || isLoading || isFirstRender) && !isFreezeFrame && (
|
||||
<div className="text-center absolute inset-0">
|
||||
<Loading>
|
||||
<span data-testid="loading-stream">Stream disconnected...</span>
|
||||
</Loading>
|
||||
</div>
|
||||
)}
|
||||
{(isLoading || isFirstRender) && (
|
||||
<div className="text-center absolute inset-0">
|
||||
<Loading>
|
||||
{!isLoading && isFirstRender ? (
|
||||
{!isNetworkOkay && !isLoading ? (
|
||||
<span data-testid="loading-stream">Stream disconnected...</span>
|
||||
) : !isLoading && isFirstRender ? (
|
||||
<span data-testid="loading-stream">Building scene...</span>
|
||||
) : (
|
||||
<span data-testid="loading-stream">Loading stream...</span>
|
||||
|
54
src/components/UnitsMenu.tsx
Normal 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: </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>
|
||||
)
|
||||
}
|
@ -12,14 +12,14 @@ import {
|
||||
setDiagnosticsEffect,
|
||||
} from '@codemirror/lint'
|
||||
|
||||
const updateOutsideEditorAnnotation = Annotation.define<null>()
|
||||
export const updateOutsideEditorEvent = updateOutsideEditorAnnotation.of(null)
|
||||
const updateOutsideEditorAnnotation = Annotation.define<boolean>()
|
||||
export const updateOutsideEditorEvent = updateOutsideEditorAnnotation.of(true)
|
||||
|
||||
const modelingMachineAnnotation = Annotation.define<null>()
|
||||
export const modelingMachineEvent = modelingMachineAnnotation.of(null)
|
||||
const modelingMachineAnnotation = Annotation.define<boolean>()
|
||||
export const modelingMachineEvent = modelingMachineAnnotation.of(true)
|
||||
|
||||
const setDiagnosticsAnnotation = Annotation.define<null>()
|
||||
export const setDiagnosticsEvent = setDiagnosticsAnnotation.of(null)
|
||||
const setDiagnosticsAnnotation = Annotation.define<boolean>()
|
||||
export const setDiagnosticsEvent = setDiagnosticsAnnotation.of(true)
|
||||
|
||||
function diagnosticIsEqual(d1: Diagnostic, d2: Diagnostic): boolean {
|
||||
return d1.from === d2.from && d1.to === d2.to && d1.message === d2.message
|
||||
@ -123,7 +123,11 @@ export default class EditorManager {
|
||||
|
||||
this._editorView.dispatch({
|
||||
effects: [setDiagnosticsEffect.of(diagnostics)],
|
||||
annotations: [setDiagnosticsEvent, Transaction.addToHistory.of(false)],
|
||||
annotations: [
|
||||
setDiagnosticsEvent,
|
||||
updateOutsideEditorEvent,
|
||||
Transaction.addToHistory.of(false),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,11 @@ import { CopilotAcceptCompletionParams } from 'wasm-lib/kcl/bindings/CopilotAcce
|
||||
import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams'
|
||||
import { editorManager } from 'lib/singletons'
|
||||
|
||||
const copilotPluginAnnotation = Annotation.define<null>()
|
||||
export const copilotPluginEvent = copilotPluginAnnotation.of(null)
|
||||
const copilotPluginAnnotation = Annotation.define<boolean>()
|
||||
export const copilotPluginEvent = copilotPluginAnnotation.of(true)
|
||||
|
||||
const rejectSuggestionAnnotation = Annotation.define<null>()
|
||||
export const rejectSuggestionCommand = rejectSuggestionAnnotation.of(null)
|
||||
const rejectSuggestionAnnotation = Annotation.define<boolean>()
|
||||
export const rejectSuggestionCommand = rejectSuggestionAnnotation.of(true)
|
||||
|
||||
// Effects to tell StateEffect what to do with GhostText
|
||||
const addSuggestion = StateEffect.define<Suggestion>()
|
||||
@ -229,7 +229,7 @@ export class CompletionRequester implements PluginValue {
|
||||
isRelevant = true
|
||||
} else if (tr.isUserEvent('move')) {
|
||||
isRelevant = true
|
||||
} else if (tr.annotation(copilotPluginEvent.type) !== undefined) {
|
||||
} else if (tr.annotation(copilotPluginEvent.type)) {
|
||||
isRelevant = true
|
||||
}
|
||||
}
|
||||
@ -457,6 +457,7 @@ export class CompletionRequester implements PluginValue {
|
||||
effects: clearSuggestion.of(null),
|
||||
annotations: [
|
||||
rejectSuggestionCommand,
|
||||
copilotPluginEvent,
|
||||
Transaction.addToHistory.of(false),
|
||||
],
|
||||
})
|
||||
|
26
src/editor/plugins/lsp/kcl/highlight.ts
Normal 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,
|
||||
})
|
@ -12,6 +12,9 @@ import { UpdateUnitsParams } from 'wasm-lib/kcl/bindings/UpdateUnitsParams'
|
||||
import { UpdateCanExecuteParams } from 'wasm-lib/kcl/bindings/UpdateCanExecuteParams'
|
||||
import { UpdateUnitsResponse } from 'wasm-lib/kcl/bindings/UpdateUnitsResponse'
|
||||
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
|
||||
|
||||
@ -45,11 +48,10 @@ export class KclPlugin implements PluginValue {
|
||||
editorManager.setEditorView(viewUpdate.view)
|
||||
|
||||
let isUserSelect = false
|
||||
let isRelevant = false
|
||||
let isRelevant = viewUpdate.docChanged
|
||||
for (const tr of viewUpdate.transactions) {
|
||||
if (tr.isUserEvent('select')) {
|
||||
isUserSelect = true
|
||||
break
|
||||
} else if (tr.isUserEvent('input')) {
|
||||
isRelevant = true
|
||||
} else if (tr.isUserEvent('delete')) {
|
||||
@ -63,6 +65,21 @@ export class KclPlugin implements PluginValue {
|
||||
} else if (tr.annotation(lspFormatCodeEvent.type)) {
|
||||
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
|
||||
|
113
src/editor/plugins/lsp/kcl/kcl.grammar
Normal 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
|
@ -1,9 +1,13 @@
|
||||
// Code mirror language implementation for kcl.
|
||||
|
||||
import {
|
||||
Language,
|
||||
defineLanguageFacet,
|
||||
LRLanguage,
|
||||
LanguageSupport,
|
||||
indentNodeProp,
|
||||
continuedIndent,
|
||||
delimitedIndent,
|
||||
foldNodeProp,
|
||||
foldInside,
|
||||
} from '@codemirror/language'
|
||||
import {
|
||||
LanguageServerClient,
|
||||
@ -11,18 +15,8 @@ import {
|
||||
} from '@kittycad/codemirror-lsp-client'
|
||||
import { kclPlugin } from '.'
|
||||
import type * as LSP from 'vscode-languageserver-protocol'
|
||||
import KclParser from './parser'
|
||||
|
||||
const data = defineLanguageFacet({
|
||||
// https://codemirror.net/docs/ref/#commands.CommentTokens
|
||||
commentTokens: {
|
||||
line: '//',
|
||||
block: {
|
||||
open: '/*',
|
||||
close: '*/',
|
||||
},
|
||||
},
|
||||
})
|
||||
// @ts-ignore: No types available
|
||||
import { parser } from './kcl.grammar'
|
||||
|
||||
export interface LanguageOptions {
|
||||
workspaceFolders: LSP.WorkspaceFolder[]
|
||||
@ -34,26 +28,40 @@ export interface LanguageOptions {
|
||||
) => void
|
||||
}
|
||||
|
||||
class KclLanguage extends Language {
|
||||
constructor(options: LanguageOptions) {
|
||||
const plugin = kclPlugin({
|
||||
export const KclLanguage = LRLanguage.define({
|
||||
name: 'klc',
|
||||
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,
|
||||
workspaceFolders: options.workspaceFolders,
|
||||
allowHTMLContent: true,
|
||||
client: options.client,
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -254,6 +254,10 @@ code {
|
||||
color: rgb(120, 120, 120, 0.8) !important;
|
||||
}
|
||||
|
||||
.segment-length-label-text {
|
||||
transform: translate(var(--x, 0), var(--y, 0));
|
||||
}
|
||||
|
||||
@layer components {
|
||||
kbd.hotkey {
|
||||
@apply font-mono text-xs inline-block px-1 py-0.5 rounded-sm;
|
||||
|
@ -185,6 +185,17 @@ const sk2 = startSketchOn('XY')
|
||||
on: expect.any(Object),
|
||||
start: expect.any(Object),
|
||||
type: 'SketchGroup',
|
||||
tags: {
|
||||
p: {
|
||||
__meta: [
|
||||
{
|
||||
sourceRange: [114, 116],
|
||||
},
|
||||
],
|
||||
type: 'TagIdentifier',
|
||||
value: 'p',
|
||||
},
|
||||
},
|
||||
value: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
@ -265,6 +276,17 @@ const sk2 = startSketchOn('XY')
|
||||
on: expect.any(Object),
|
||||
start: expect.any(Object),
|
||||
type: 'SketchGroup',
|
||||
tags: {
|
||||
o: {
|
||||
__meta: [
|
||||
{
|
||||
sourceRange: [417, 419],
|
||||
},
|
||||
],
|
||||
type: 'TagIdentifier',
|
||||
value: 'o',
|
||||
},
|
||||
},
|
||||
value: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
|
@ -11,8 +11,8 @@ import { KeyBinding } from '@codemirror/view'
|
||||
|
||||
const PERSIST_CODE_KEY = 'persistCode'
|
||||
|
||||
const codeManagerUpdateAnnotation = Annotation.define<null>()
|
||||
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
|
||||
const codeManagerUpdateAnnotation = Annotation.define<boolean>()
|
||||
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(true)
|
||||
|
||||
export default class CodeManager {
|
||||
private _code: string = bracket
|
||||
|
@ -155,6 +155,17 @@ const newVar = myVar + 1`
|
||||
sourceRange: [39, 63],
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
myPath: {
|
||||
__meta: [
|
||||
{
|
||||
sourceRange: [109, 117],
|
||||
},
|
||||
],
|
||||
type: 'TagIdentifier',
|
||||
value: 'myPath',
|
||||
},
|
||||
},
|
||||
value: [
|
||||
{
|
||||
type: 'ToPoint',
|
||||
|
@ -300,6 +300,7 @@ class EngineConnection extends EventTarget {
|
||||
pc?: RTCPeerConnection
|
||||
unreliableDataChannel?: RTCDataChannel
|
||||
mediaStream?: MediaStream
|
||||
freezeFrame: boolean = false
|
||||
|
||||
private _state: EngineConnectionState = {
|
||||
type: EngineConnectionStateType.Fresh,
|
||||
@ -365,7 +366,11 @@ class EngineConnection extends EventTarget {
|
||||
this.pingPongSpan = { ping: undefined, pong: undefined }
|
||||
|
||||
// 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(() => {
|
||||
if (this.freezeFrame) return
|
||||
|
||||
switch (this.state.type as EngineConnectionStateType) {
|
||||
case EngineConnectionStateType.ConnectionEstablished:
|
||||
// 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
|
||||
}
|
||||
|
||||
tearDown() {
|
||||
tearDown(opts?: { freeze: boolean }) {
|
||||
this.freezeFrame = opts?.freeze ?? false
|
||||
this.disconnectAll()
|
||||
this.state = {
|
||||
type: EngineConnectionStateType.Disconnecting,
|
||||
@ -996,6 +1002,9 @@ class EngineConnection extends EventTarget {
|
||||
this.pc?.connectionState === 'closed' &&
|
||||
this.unreliableDataChannel?.readyState === 'closed'
|
||||
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 }
|
||||
}
|
||||
}
|
||||
@ -1619,7 +1628,15 @@ export class EngineCommandManager extends EventTarget {
|
||||
}
|
||||
}
|
||||
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() {
|
||||
this.lastArtifactMap = this.artifactMap
|
||||
|
@ -157,7 +157,7 @@ export function createSettings() {
|
||||
),
|
||||
}),
|
||||
enableSSAO: new Setting<boolean>({
|
||||
defaultValue: false,
|
||||
defaultValue: true,
|
||||
description:
|
||||
'Whether or not Screen Space Ambient Occlusion (SSAO) is enabled',
|
||||
validate: (v) => typeof v === 'boolean',
|
||||
|