Compare commits
	
		
			109 Commits
		
	
	
		
			batch-take
			...
			achalmers/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 74b09f3ef6 | |||
| 76480f1a43 | |||
| f850f80de1 | |||
| 15ebbe6947 | |||
| 01beba42da | |||
| 509e372ed2 | |||
| b0417114af | |||
| 0360a4021b | |||
| 6f36371e6d | |||
| ebcc19e757 | |||
| 84cbcddff1 | |||
| e758c6cab0 | |||
| c63ea8e445 | |||
| 7e0e0e1ee1 | |||
| db3e2879bd | |||
| 7804079d8c | |||
| 571406fca3 | |||
| a9e41a616d | |||
| 9a0b086e07 | |||
| 358184c634 | |||
| 85ac8bf7a3 | |||
| 544a327ee9 | |||
| 868a560e1a | |||
| 32a2835d0e | |||
| 4c93346f48 | |||
| bfa8b8aca4 | |||
| b1fe2dddb6 | |||
| 6d3f6c784e | |||
| 4904785bbd | |||
| ca30fd44bd | |||
| 5d69a62324 | |||
| 0e04e20b97 | |||
| 1dac62067a | |||
| 86de039dc4 | |||
| dce5833d79 | |||
| f714c19890 | |||
| f52128c41a | |||
| 39566174e7 | |||
| 3688c8a05e | |||
| 0025349e9a | |||
| d8cc57b843 | |||
| e76db4a621 | |||
| 027e947bd5 | |||
| 0983dcca22 | |||
| 846fc99bbc | |||
| c258ede25c | |||
| 4cc1b3d5ed | |||
| be0dd1512d | |||
| a5156c3f5d | |||
| 8038b5d7a3 | |||
| 54b234360e | |||
| 465d933d53 | |||
| ccd0c619a6 | |||
| 7b570bf525 | |||
| 44d1c29801 | |||
| 0e916cfd5b | |||
| e773e932b0 | |||
| 2d39fd32ce | |||
| 5a585a6c2d | |||
| c09d6ee6bd | |||
| 09b55259ab | |||
| 68b61c9832 | |||
| 469ca94437 | |||
| 1d3850b46a | |||
| 0358343285 | |||
| 38b0603fa2 | |||
| e48a8b6c5d | |||
| 73e573b251 | |||
| 793409d53d | |||
| 3e9ab16c4b | |||
| ab226bc86f | |||
| 97677e4474 | |||
| 37fbc8c9ab | |||
| 29d61da552 | |||
| ad2f669ec6 | |||
| d66aad8b5d | |||
| d8b8710a0d | |||
| 8f8ba2dca5 | |||
| 970b0abb54 | |||
| 06b464816f | |||
| 08f7bb2811 | |||
| 197df9f25d | |||
| 4d387dfaf7 | |||
| 912b97bea5 | |||
| 3e4ce44dc9 | |||
| c2058a05fa | |||
| 7a57965690 | |||
| c5b115ba97 | |||
| 90057c2dda | |||
| f3e59690d6 | |||
| 9642a44a02 | |||
| 252c7651ac | |||
| 79edcf3826 | |||
| b05ac3a05f | |||
| 1d01ba454b | |||
| bf1d6963fe | |||
| 176ee63cb9 | |||
| 1ae8059c2b | |||
| 93f406d005 | |||
| e97833f0ed | |||
| 35417dd8a6 | |||
| cf0560dcfb | |||
| 3659946653 | |||
| 156c51484a | |||
| dc8dd4bc72 | |||
| 335add67bd | |||
| 231794a69d | |||
| 8e5a6bc6fc | |||
| 4f82121105 | 
| @ -1,3 +1,3 @@ | ||||
| [codespell] | ||||
| ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey | ||||
| skip: **/target,node_modules,build,**/Cargo.lock | ||||
| skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md | ||||
|  | ||||
							
								
								
									
										4
									
								
								.github/workflows/check-exampleKcl.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -16,10 +16,10 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Comment on PR | ||||
|         uses: actions/github-script@v6 | ||||
|         uses: actions/github-script@v7 | ||||
|         with: | ||||
|           script: | | ||||
|             const message = '`src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.'; | ||||
|  | ||||
							
								
								
									
										4
									
								
								.github/workflows/playwright.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -9,6 +9,10 @@ concurrency: | ||||
|   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||||
|   cancel-in-progress: true | ||||
|  | ||||
| permissions: | ||||
|   contents: write | ||||
|   pull-requests: write | ||||
|  | ||||
| jobs: | ||||
|   playwright-ubuntu: | ||||
|     timeout-minutes: 60 | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the absolute value of a number. | ||||
| abs(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the arccosine of a number (in radians). | ||||
| acos(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the arcsine of a number (in radians). | ||||
| asin(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the arctangent of a number (in radians). | ||||
| atan(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the smallest integer greater than or equal to a number. | ||||
| ceil(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| --- | ||||
| title: "cos" | ||||
| excerpt: "Computes the sine of a number (in radians)." | ||||
| excerpt: "Computes the cosine of a number (in radians)." | ||||
| layout: manual | ||||
| --- | ||||
|  | ||||
| Computes the sine of a number (in radians). | ||||
| Computes the cosine of a number (in radians). | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the sine of a number (in radians). | ||||
| cos(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Return the value of Euler’s number `e`. | ||||
| e() -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the largest integer less than or equal to a number. | ||||
| floor(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
							
								
								
									
										180
									
								
								docs/kcl/getEdge.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										308
									
								
								docs/kcl/helix.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -30,10 +30,12 @@ layout: manual | ||||
| * [`extrude`](kcl/extrude) | ||||
| * [`fillet`](kcl/fillet) | ||||
| * [`floor`](kcl/floor) | ||||
| * [`getEdge`](kcl/getEdge) | ||||
| * [`getExtrudeWallTransform`](kcl/getExtrudeWallTransform) | ||||
| * [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge) | ||||
| * [`getOppositeEdge`](kcl/getOppositeEdge) | ||||
| * [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge) | ||||
| * [`helix`](kcl/helix) | ||||
| * [`hole`](kcl/hole) | ||||
| * [`import`](kcl/import) | ||||
| * [`lastSegX`](kcl/lastSegX) | ||||
| @ -55,6 +57,7 @@ layout: manual | ||||
| * [`patternLinear3d`](kcl/patternLinear3d) | ||||
| * [`pi`](kcl/pi) | ||||
| * [`pow`](kcl/pow) | ||||
| * [`revolve`](kcl/revolve) | ||||
| * [`segAng`](kcl/segAng) | ||||
| * [`segEndX`](kcl/segEndX) | ||||
| * [`segEndY`](kcl/segEndY) | ||||
|  | ||||
| @ -12,6 +12,10 @@ Returns the angle of the given leg for x. | ||||
| legAngX(hypotenuse: number, leg: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `utilities` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Returns the angle of the given leg for y. | ||||
| legAngY(hypotenuse: number, leg: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `utilities` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Returns the length of the given leg. | ||||
| legLen(hypotenuse: number, leg: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `utilities` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the natural logarithm of the number. | ||||
| ln(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ The result might not be correctly rounded owing to implementation details; `log2 | ||||
| log(num: number, base: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the base 10 logarithm of the number. | ||||
| log10(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the base 2 logarithm of the number. | ||||
| log2(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the maximum of the given arguments. | ||||
| max(args: [number]) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the minimum of the given arguments. | ||||
| min(args: [number]) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Return the value of `pi`. Archimedes’ constant (π). | ||||
| pi() -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the number to a power. | ||||
| pow(num: number, pow: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
							
								
								
									
										444
									
								
								docs/kcl/revolve.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -12,6 +12,10 @@ Computes the sine of a number (in radians). | ||||
| sin(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Computes the square root of a number. | ||||
| sqrt(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
							
								
								
									
										4675
									
								
								docs/kcl/std.json
									
									
									
									
									
								
							
							
						
						| @ -12,6 +12,10 @@ Computes the tangent of a number (in radians). | ||||
| tan(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Return the value of `tau`. The full circle constant (τ). Equal to 2π. | ||||
| tau() -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Converts a number from radians to degrees. | ||||
| toDegrees(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| @ -12,6 +12,10 @@ Converts a number from degrees to radians. | ||||
| toRadians(num: number) -> number | ||||
| ``` | ||||
|  | ||||
| ### Tags | ||||
|  | ||||
| * `math` | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| ```js | ||||
|  | ||||
| Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 224 KiB | 
| Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 224 KiB | 
| Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 224 KiB | 
| Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 165 KiB | 
| Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 165 KiB | 
| Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 165 KiB | 
| Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 165 KiB | 
| Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 224 KiB | 
| Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 165 KiB | 
| Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 165 KiB | 
| @ -20,6 +20,8 @@ const commonPoints = { | ||||
|   startAt: '[9.06, -12.22]', | ||||
|   num1: 9.14, | ||||
|   num2: 18.2, | ||||
|   // num1: 9.64, | ||||
|   // num2: 19.19, | ||||
| } | ||||
|  | ||||
| test.beforeEach(async ({ context, page }) => { | ||||
| @ -76,6 +78,7 @@ test('Basic sketch', async ({ page }) => { | ||||
|   await expect(page.locator('.cm-content')).toHaveText( | ||||
|     `const part001 = startSketchOn('-XZ')` | ||||
|   ) | ||||
|   await u.closeDebugPanel() | ||||
|  | ||||
|   await page.waitForTimeout(300) // TODO detect animation ending, or disable animation | ||||
|  | ||||
| @ -86,7 +89,6 @@ test('Basic sketch', async ({ page }) => { | ||||
|   |> startProfileAt(${commonPoints.startAt}, %)`) | ||||
|   await page.waitForTimeout(100) | ||||
|  | ||||
|   await u.closeDebugPanel() | ||||
|   await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) | ||||
|   await page.waitForTimeout(100) | ||||
|  | ||||
| @ -472,8 +474,18 @@ test('Auto complete works', async ({ page }) => { | ||||
|   const u = getUtils(page) | ||||
|   // const PUR = 400 / 37.5 //pixeltoUnitRatio | ||||
|   await page.setViewportSize({ width: 1200, height: 500 }) | ||||
|   const lspStartPromise = page.waitForEvent('console', async (message) => { | ||||
|     // it would be better to wait for a message that the kcl lsp has started by looking for the message  message.text().includes('[lsp] [window/logMessage]') | ||||
|     // but that doesn't seem to make it to the console for macos/safari :( | ||||
|     if (message.text().includes('start kcl lsp')) { | ||||
|       await new Promise((resolve) => setTimeout(resolve, 200)) | ||||
|       return true | ||||
|     } | ||||
|     return false | ||||
|   }) | ||||
|   await page.goto('/') | ||||
|   await u.waitForAuthSkipAppStart() | ||||
|   await lspStartPromise | ||||
|  | ||||
|   // this test might be brittle as we add and remove functions | ||||
|   // but should also be easy to update. | ||||
| @ -625,7 +637,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => { | ||||
|   const emptySpaceClick = () => | ||||
|     page.mouse.click(728, 343).then(() => page.waitForTimeout(100)) | ||||
|   const topHorzSegmentClick = () => | ||||
|     page.mouse.click(709, 289).then(() => page.waitForTimeout(100)) | ||||
|     page.mouse.click(709, 290).then(() => page.waitForTimeout(100)) | ||||
|   const bottomHorzSegmentClick = () => | ||||
|     page.mouse.click(767, 396).then(() => page.waitForTimeout(100)) | ||||
|  | ||||
| @ -640,13 +652,12 @@ test('Selections work on fresh and edited sketch', async ({ page }) => { | ||||
|   await page.waitForTimeout(700) // wait for animation | ||||
|  | ||||
|   const startXPx = 600 | ||||
|   await u.closeDebugPanel() | ||||
|   await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toHaveText(`const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt(${commonPoints.startAt}, %)`) | ||||
|  | ||||
|   await u.closeDebugPanel() | ||||
|  | ||||
|   await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
| @ -727,13 +738,18 @@ test('Selections work on fresh and edited sketch', async ({ page }) => { | ||||
|     await emptySpaceClick() | ||||
|  | ||||
|     // select segment in editor than another segment in scene and check there are two cursors | ||||
|     await page.getByText(`  |> line([-${commonPoints.num2}, 0], %)`).click() | ||||
|     await page.waitForTimeout(300) | ||||
|     await page.keyboard.down('Shift') | ||||
|     await expect(page.locator('.cm-cursor')).toHaveCount(1) | ||||
|     // TODO change this back to shift click in the scene, not cmd click in the editor | ||||
|     await bottomHorzSegmentClick() | ||||
|     await page.keyboard.up('Shift') | ||||
|  | ||||
|     await expect(page.locator('.cm-cursor')).toHaveCount(1) | ||||
|  | ||||
|     await page.keyboard.down(process.platform === 'linux' ? 'Control' : 'Meta') | ||||
|     await page.waitForTimeout(100) | ||||
|     await page.getByText(`  |> line([-${commonPoints.num2}, 0], %)`).click() | ||||
|  | ||||
|     await expect(page.locator('.cm-cursor')).toHaveCount(2) | ||||
|     await page.waitForTimeout(500) | ||||
|     await page.keyboard.up(process.platform === 'linux' ? 'Control' : 'Meta') | ||||
|  | ||||
|     // clear selection by clicking on nothing | ||||
|     await emptySpaceClick() | ||||
| @ -918,13 +934,13 @@ test('Can add multiple sketches', async ({ page }) => { | ||||
|   await page.waitForTimeout(500) // TODO detect animation ending, or disable animation | ||||
|  | ||||
|   const startXPx = 600 | ||||
|   await u.closeDebugPanel() | ||||
|   await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toHaveText(`const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt(${commonPoints.startAt}, %)`) | ||||
|   await page.waitForTimeout(100) | ||||
|  | ||||
|   await u.closeDebugPanel() | ||||
|   await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) | ||||
|   await page.waitForTimeout(100) | ||||
|  | ||||
| @ -1372,10 +1388,129 @@ test('Snap to close works (at any scale)', async ({ page }) => { | ||||
|   ) => `const part001 = startSketchOn('XZ') | ||||
| |> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %) | ||||
| |> line([${roundOff(scale * 175.36)}, 0], %) | ||||
| |> line([0, -${roundOff(scale * 175.37) + fudge}], %) | ||||
| |> line([0, -${roundOff(scale * 175.36) + fudge}], %) | ||||
| |> close(%)` | ||||
|  | ||||
|   await doSnapAtDifferentScales([0, 100, 100], codeTemplate(0.01, 0.01)) | ||||
|  | ||||
|   await doSnapAtDifferentScales([0, 10000, 10000], codeTemplate()) | ||||
| }) | ||||
|  | ||||
| test('Sketch on face', async ({ page, context }) => { | ||||
|   const u = getUtils(page) | ||||
|   await context.addInitScript(async () => { | ||||
|     localStorage.setItem( | ||||
|       'persistCode', | ||||
|       `const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt([3.29, 7.86], %) | ||||
|   |> line([2.48, 2.44], %) | ||||
|   |> line([2.66, 1.17], %) | ||||
|   |> line([3.75, 0.46], %) | ||||
|   |> line([4.99, -0.46], %) | ||||
|   |> line([3.3, -2.12], %) | ||||
|   |> line([2.16, -3.33], %) | ||||
|   |> line([0.85, -3.08], %) | ||||
|   |> line([-0.18, -3.36], %) | ||||
|   |> line([-3.86, -2.73], %) | ||||
|   |> line([-17.67, 0.85], %) | ||||
|   |> close(%) | ||||
|   |> extrude(5 + 7, %)` | ||||
|     ) | ||||
|   }) | ||||
|  | ||||
|   await page.setViewportSize({ width: 1200, height: 500 }) | ||||
|   await page.goto('/') | ||||
|   await u.waitForAuthSkipAppStart() | ||||
|   await expect( | ||||
|     page.getByRole('button', { name: 'Start Sketch' }) | ||||
|   ).not.toBeDisabled() | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Start Sketch' }).click() | ||||
|  | ||||
|   let previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await page.mouse.click(793, 133) | ||||
|  | ||||
|   const firstClickPosition = [612, 238] | ||||
|   const secondClickPosition = [661, 242] | ||||
|   const thirdClickPosition = [609, 267] | ||||
|  | ||||
|   await page.waitForTimeout(300) | ||||
|  | ||||
|   await page.mouse.click(firstClickPosition[0], firstClickPosition[1]) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await page.mouse.click(secondClickPosition[0], secondClickPosition[1]) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await page.mouse.click(thirdClickPosition[0], thirdClickPosition[1]) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await page.mouse.click(firstClickPosition[0], firstClickPosition[1]) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toContainText(`const part002 = startSketchOn(part001, 'seg01') | ||||
|   |> startProfileAt([1.03, 1.03], %) | ||||
|   |> line([4.18, -0.35], %) | ||||
|   |> line([-4.44, -2.13], %) | ||||
|   |> close(%)`) | ||||
|  | ||||
|   await u.openAndClearDebugPanel() | ||||
|   await page.getByRole('button', { name: 'Exit Sketch' }).click() | ||||
|   await u.expectCmdLog('[data-message-type="execution-done"]') | ||||
|  | ||||
|   await u.updateCamPosition([1049, 239, 686]) | ||||
|   await u.closeDebugPanel() | ||||
|  | ||||
|   await page.getByText('startProfileAt([1.03, 1.03], %)').click() | ||||
|   await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeVisible() | ||||
|   await page.getByRole('button', { name: 'Edit Sketch' }).click() | ||||
|   await page.waitForTimeout(200) | ||||
|  | ||||
|   const pointToDragFirst = [691, 237] | ||||
|   await page.mouse.move(pointToDragFirst[0], pointToDragFirst[1]) | ||||
|   await page.mouse.down() | ||||
|   await page.mouse.move(pointToDragFirst[0] - 20, pointToDragFirst[1], { | ||||
|     steps: 5, | ||||
|   }) | ||||
|   await page.mouse.up() | ||||
|   await page.waitForTimeout(100) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toContainText(`const part002 = startSketchOn(part001, 'seg01') | ||||
| |> startProfileAt([1.03, 1.03], %) | ||||
| |> line([2.81, -0.33], %) | ||||
| |> line([-4.44, -2.13], %) | ||||
| |> close(%)`) | ||||
|  | ||||
|   // exit sketch | ||||
|   await u.openAndClearDebugPanel() | ||||
|   await page.getByRole('button', { name: 'Exit Sketch' }).click() | ||||
|   await u.expectCmdLog('[data-message-type="execution-done"]') | ||||
|  | ||||
|   await page.getByText('startProfileAt([1.03, 1.03], %)').click() | ||||
|  | ||||
|   await expect(page.getByRole('button', { name: 'Extrude' })).not.toBeDisabled() | ||||
|   await page.getByRole('button', { name: 'Extrude' }).click() | ||||
|  | ||||
|   await expect(page.getByTestId('command-bar')).toBeVisible() | ||||
|  | ||||
|   await page.keyboard.press('Enter') | ||||
|   await expect(page.getByText('Confirm Extrude')).toBeVisible() | ||||
|   await page.keyboard.press('Enter') | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toContainText(`const part002 = startSketchOn(part001, 'seg01') | ||||
| |> startProfileAt([1.03, 1.03], %) | ||||
| |> line([2.81, -0.33], %) | ||||
| |> line([-4.44, -2.13], %) | ||||
| |> close(%) | ||||
| |> extrude(5 + 7, %)`) | ||||
| }) | ||||
|  | ||||
| @ -22,7 +22,7 @@ test.beforeEach(async ({ context, page }) => { | ||||
|         onboardingStatus: 'dismissed', | ||||
|         showDebugPanel: true, | ||||
|         textWrapping: 'On', | ||||
|         theme: 'system', | ||||
|         theme: 'dark', | ||||
|         unitSystem: 'imperial', | ||||
|       }) | ||||
|     ) | ||||
| @ -397,7 +397,7 @@ test('Draft segments should look right', async ({ page, context }) => { | ||||
|         onboardingStatus: 'dismissed', | ||||
|         showDebugPanel: true, | ||||
|         textWrapping: 'On', | ||||
|         theme: 'system', | ||||
|         theme: 'dark', | ||||
|         unitSystem: 'imperial', | ||||
|       }) | ||||
|     ) | ||||
| @ -475,7 +475,7 @@ test('Client side scene scale should match engine scale inch', async ({ | ||||
|         onboardingStatus: 'dismissed', | ||||
|         showDebugPanel: true, | ||||
|         textWrapping: 'On', | ||||
|         theme: 'system', | ||||
|         theme: 'dark', | ||||
|         unitSystem: 'imperial', | ||||
|       }) | ||||
|     ) | ||||
| @ -575,7 +575,7 @@ test('Client side scene scale should match engine scale mm', async ({ | ||||
|         onboardingStatus: 'dismissed', | ||||
|         showDebugPanel: true, | ||||
|         textWrapping: 'On', | ||||
|         theme: 'system', | ||||
|         theme: 'dark', | ||||
|         unitSystem: 'metric', | ||||
|       }) | ||||
|     ) | ||||
| @ -612,7 +612,7 @@ test('Client side scene scale should match engine scale mm', async ({ | ||||
|   await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toHaveText(`const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt([230.03, -310.33], %)`) | ||||
|   |> startProfileAt([230.03, -310.32], %)`) | ||||
|   await page.waitForTimeout(100) | ||||
|  | ||||
|   await u.closeDebugPanel() | ||||
| @ -622,7 +622,7 @@ test('Client side scene scale should match engine scale mm', async ({ | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toHaveText(`const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt([230.03, -310.33], %) | ||||
|   |> startProfileAt([230.03, -310.32], %) | ||||
|   |> line([232.2, 0], %)`) | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Tangential Arc' }).click() | ||||
| @ -632,7 +632,7 @@ test('Client side scene scale should match engine scale mm', async ({ | ||||
|  | ||||
|   await expect(page.locator('.cm-content')) | ||||
|     .toHaveText(`const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt([230.03, -310.33], %) | ||||
|   |> startProfileAt([230.03, -310.32], %) | ||||
|   |> line([232.2, 0], %) | ||||
|   |> tangentialArcTo([694.43, -78.12], %)`) | ||||
|  | ||||
| @ -658,3 +658,48 @@ test('Client side scene scale should match engine scale mm', async ({ | ||||
|     maxDiffPixels: 100, | ||||
|   }) | ||||
| }) | ||||
|  | ||||
| test('Sketch on face with none z-up', async ({ page, context }) => { | ||||
|   const u = getUtils(page) | ||||
|   await context.addInitScript(async () => { | ||||
|     localStorage.setItem( | ||||
|       'persistCode', | ||||
|       `const part001 = startSketchOn('-XZ') | ||||
|   |> startProfileAt([1.4, 2.47], %) | ||||
|   |> line({ to: [9.31, 10.55], tag: 'seg01' }, %) | ||||
|   |> line([11.91, -10.42], %) | ||||
|   |> close(%) | ||||
|   |> extrude(5 + 7, %) | ||||
| const part002 = startSketchOn(part001, 'seg01') | ||||
|   |> startProfileAt([-2.89, 1.82], %) | ||||
|   |> line([4.68, 3.05], %) | ||||
|   |> line({ to: [0, -7.79], tag: 'seg02' }, %) | ||||
|   |> close(%) | ||||
|   |> extrude(5 + 7, %) | ||||
| ` | ||||
|     ) | ||||
|   }) | ||||
|  | ||||
|   await page.setViewportSize({ width: 1200, height: 500 }) | ||||
|   await page.goto('/') | ||||
|   await u.waitForAuthSkipAppStart() | ||||
|   await expect( | ||||
|     page.getByRole('button', { name: 'Start Sketch' }) | ||||
|   ).not.toBeDisabled() | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Start Sketch' }).click() | ||||
|   let previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   // click at 641, 135 | ||||
|   await page.mouse.click(641, 135) | ||||
|   await expect(page.locator('.cm-content')).not.toHaveText(previousCodeContent) | ||||
|   previousCodeContent = await page.locator('.cm-content').innerText() | ||||
|  | ||||
|   await page.waitForTimeout(300) | ||||
|  | ||||
|   await expect(page).toHaveScreenshot({ | ||||
|     maxDiffPixels: 100, | ||||
|   }) | ||||
|  | ||||
|   await page.waitForTimeout(200) | ||||
| }) | ||||
|  | ||||
| Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB | 
| Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 48 KiB | 
| Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 47 KiB | 
| Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 49 KiB | 
| Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB | 
| Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB | 
| After Width: | Height: | Size: 65 KiB | 
| Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB | 
| Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 52 KiB | 
| Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB | 
| Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 54 KiB | 
| Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB | 
| Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 50 KiB | 
| @ -67,3 +67,12 @@ echo "Versions has been bumped in relevant json files, a branch has been created | ||||
| echo "" | ||||
| echo "What's left for you to do is, push the branch and make the release PR." | ||||
| echo "" | ||||
|  | ||||
| echo "Suggested changelog:" | ||||
| echo "\`\`\`" | ||||
| echo "## What's Changed" | ||||
| git log $(git describe --tags --abbrev=0)..HEAD --oneline --pretty=format:%s | grep -v Bump | grep -v 'Cut release v' | awk '{print "* "toupper(substr($0,0,1))substr($0,2)}' | ||||
| echo "" | ||||
| echo "**Full Changelog**: https://github.com/KittyCAD/modeling-app/compare/${latest_tag}...${new_version}" | ||||
| echo "\`\`\`" | ||||
| echo "and would recommend removing ones that aren't related to the product (eg. CI changes)" | ||||
|  | ||||
							
								
								
									
										64
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @ -1,30 +1,30 @@ | ||||
| { | ||||
|   "name": "untitled-app", | ||||
|   "version": "0.16.0", | ||||
|   "version": "0.17.1", | ||||
|   "private": true, | ||||
|   "dependencies": { | ||||
|     "@codemirror/autocomplete": "^6.10.2", | ||||
|     "@codemirror/autocomplete": "^6.15.0", | ||||
|     "@fortawesome/fontawesome-svg-core": "^6.4.2", | ||||
|     "@fortawesome/free-brands-svg-icons": "^6.4.2", | ||||
|     "@fortawesome/free-solid-svg-icons": "^6.4.2", | ||||
|     "@fortawesome/react-fontawesome": "^0.2.0", | ||||
|     "@headlessui/react": "^1.7.17", | ||||
|     "@headlessui/react": "^1.7.18", | ||||
|     "@headlessui/tailwindcss": "^0.2.0", | ||||
|     "@kittycad/lib": "^0.0.55", | ||||
|     "@kittycad/lib": "^0.0.56", | ||||
|     "@lezer/javascript": "^1.4.9", | ||||
|     "@open-rpc/client-js": "^1.8.1", | ||||
|     "@react-hook/resize-observer": "^1.2.6", | ||||
|     "@replit/codemirror-interact": "^6.3.0", | ||||
|     "@tauri-apps/api": "^1.5.1", | ||||
|     "@tauri-apps/api": "^1.5.3", | ||||
|     "@testing-library/jest-dom": "^5.14.1", | ||||
|     "@testing-library/react": "^14.0.0", | ||||
|     "@testing-library/user-event": "^14.5.1", | ||||
|     "@testing-library/user-event": "^14.5.2", | ||||
|     "@ts-stack/markdown": "^1.5.0", | ||||
|     "@tweenjs/tween.js": "^23.1.1", | ||||
|     "@types/node": "^16.7.13", | ||||
|     "@types/react": "^18.2.41", | ||||
|     "@types/react-dom": "^18.0.0", | ||||
|     "@uiw/react-codemirror": "^4.21.20", | ||||
|     "@types/node": "^18.19.26", | ||||
|     "@types/react": "^18.2.73", | ||||
|     "@types/react-dom": "^18.2.22", | ||||
|     "@uiw/react-codemirror": "^4.21.24", | ||||
|     "@xstate/inspect": "^0.8.0", | ||||
|     "@xstate/react": "^3.2.2", | ||||
|     "crypto-js": "^4.2.0", | ||||
| @ -39,27 +39,27 @@ | ||||
|     "react": "^18.2.0", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-hot-toast": "^2.4.1", | ||||
|     "react-hotkeys-hook": "^4.4.1", | ||||
|     "react-hotkeys-hook": "^4.5.0", | ||||
|     "react-json-view": "^1.21.3", | ||||
|     "react-modal": "^3.16.1", | ||||
|     "react-modal-promise": "^1.0.2", | ||||
|     "react-router-dom": "^6.14.2", | ||||
|     "react-router-dom": "^6.22.3", | ||||
|     "sketch-helpers": "^0.0.4", | ||||
|     "swr": "^2.2.2", | ||||
|     "tauri-plugin-fs-extra-api": "https://github.com/tauri-apps/tauri-plugin-fs-extra#v1", | ||||
|     "three": "^0.160.0", | ||||
|     "toml": "^3.0.0", | ||||
|     "ts-node": "^10.9.1", | ||||
|     "typescript": "^5.2.2", | ||||
|     "ts-node": "^10.9.2", | ||||
|     "typescript": "^5.4.3", | ||||
|     "uuid": "^9.0.1", | ||||
|     "vitest": "^1.3.1", | ||||
|     "vitest": "^1.4.0", | ||||
|     "vscode-jsonrpc": "^8.1.0", | ||||
|     "vscode-languageserver-protocol": "^3.17.5", | ||||
|     "wasm-pack": "^0.12.1", | ||||
|     "web-vitals": "^3.5.0", | ||||
|     "web-vitals": "^3.5.2", | ||||
|     "ws": "^8.13.0", | ||||
|     "xstate": "^4.38.2", | ||||
|     "zustand": "^4.4.5" | ||||
|     "zustand": "^4.5.2" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "start": "vite", | ||||
| @ -110,41 +110,41 @@ | ||||
|     "@babel/plugin-proposal-private-property-in-object": "^7.21.11", | ||||
|     "@babel/preset-env": "^7.23.3", | ||||
|     "@playwright/test": "^1.39.0", | ||||
|     "@tauri-apps/cli": "^1.5.6", | ||||
|     "@types/crypto-js": "^4.1.1", | ||||
|     "@types/debounce-promise": "^3.1.8", | ||||
|     "@tauri-apps/cli": "^1.5.11", | ||||
|     "@types/crypto-js": "^4.2.2", | ||||
|     "@types/debounce-promise": "^3.1.9", | ||||
|     "@types/pixelmatch": "^5.2.6", | ||||
|     "@types/pngjs": "^6.0.4", | ||||
|     "@types/react-modal": "^3.16.3", | ||||
|     "@types/three": "^0.160.0", | ||||
|     "@types/uuid": "^9.0.4", | ||||
|     "@types/uuid": "^9.0.8", | ||||
|     "@types/wait-on": "^5.3.4", | ||||
|     "@types/wicg-file-system-access": "^2020.9.6", | ||||
|     "@types/wicg-file-system-access": "^2023.10.5", | ||||
|     "@types/ws": "^8.5.5", | ||||
|     "@vitejs/plugin-react": "^4.2.1", | ||||
|     "@wdio/cli": "^8.24.3", | ||||
|     "@wdio/globals": "^8.24.3", | ||||
|     "@wdio/local-runner": "^8.24.3", | ||||
|     "@wdio/mocha-framework": "^8.24.3", | ||||
|     "@wdio/spec-reporter": "^8.24.2", | ||||
|     "@wdio/local-runner": "^8.35.1", | ||||
|     "@wdio/mocha-framework": "^8.35.0", | ||||
|     "@wdio/spec-reporter": "^8.32.4", | ||||
|     "@xstate/cli": "^0.5.17", | ||||
|     "autoprefixer": "^10.4.13", | ||||
|     "eslint": "^8.53.0", | ||||
|     "autoprefixer": "^10.4.19", | ||||
|     "eslint": "^8.57.0", | ||||
|     "eslint-config-react-app": "^7.0.1", | ||||
|     "eslint-plugin-css-modules": "^2.12.0", | ||||
|     "happy-dom": "^10.8.0", | ||||
|     "husky": "^8.0.3", | ||||
|     "happy-dom": "^14.3.1", | ||||
|     "husky": "^9.0.11", | ||||
|     "pixelmatch": "^5.3.0", | ||||
|     "pngjs": "^7.0.0", | ||||
|     "postcss": "^8.4.31", | ||||
|     "postinstall-postinstall": "^2.1.0", | ||||
|     "prettier": "^2.8.0", | ||||
|     "setimmediate": "^1.0.5", | ||||
|     "tailwindcss": "^3.3.6", | ||||
|     "vite": "^5.1.3", | ||||
|     "tailwindcss": "^3.4.1", | ||||
|     "vite": "^5.2.2", | ||||
|     "vite-plugin-eslint": "^1.8.1", | ||||
|     "vite-plugin-package-version": "^1.1.0", | ||||
|     "vite-tsconfig-paths": "^4.3.1", | ||||
|     "vite-tsconfig-paths": "^4.3.2", | ||||
|     "vitest-webgl-canvas-mock": "^1.1.0", | ||||
|     "wait-on": "^7.2.0", | ||||
|     "yarn": "^1.22.19" | ||||
|  | ||||
