diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..54f07af58b4cd9fb7d7e5e11909310ce21eeabcf --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..cd89b14cf669d9c4bb3c83859e5b1f51aa4b199d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,20 @@ +# This file is a template, and might need editing before it works on your project. +# To contribute improvements to CI/CD templates, please follow the Development guide at: +# https://docs.gitlab.com/ee/development/cicd/templates.html +# This specific template is located at: +# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Pages/HTML.gitlab-ci.yml + +# Full project: https://gitlab.com/pages/plain-html +pages: + stage: deploy + script: + - echo "The site will be deployed to $CI_PAGES_URL" + - mkdir .public + - cp -r ./dist .public + - rm -rf public + - mv .public public + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..51e2d4f30687b878ca8a9e79fe667b43f62109e3 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2023, Developed by Jake Read and Quentin Bolsée at the Center for Bits and Atoms, MIT + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/index.html b/index.html new file mode 100644 index 0000000000000000000000000000000000000000..5553c88a0f87c2a463e3b3339edba364ae6d0352 --- /dev/null +++ b/index.html @@ -0,0 +1,81 @@ +<!-- Quentin Bolsee and Jake Read, MIT Center for Bits and Atoms, 2023 --> +<!DOCTYPE html> +<html> +<head> + <link rel="icon" type="image/x-icon" href="images/logo.png"> + <link rel="stylesheet" href="src/style.css"> + <meta charset="utf-8"> + <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> + <meta http-equiv="Pragma" content="no-cache" /> + <meta http-equiv="Expires" content="-1" /> +</head> +<body style="background-color: rgb(255, 255, 255);"> + <h1>gerber2png</h1> + <div id="dropZone"><p id="dropText">↑</p></div> + <input type="file" id="fileInput" multiple hidden></input> + <canvas id="canvas" hidden></canvas> + <div class="container"> + <div class="panel"> + <h2>Viewer</h2> + <div class="preview"> + <svg id="previewSVG"></svg> + </div> + <div> + <!-- <button class="interface" id="loadButton">Load file(s)...</button></input> --> + <button class="interface" id="downloadRenderButton">Download render</button> + <button class="interface" id="downloadlayersButton">Download layers</button> + </div> + </div> + <div class="panel"> + <h2>Settings</h2> + <div class="settings"> + <h3>Rendering</h3> + + <div> + <input type="checkbox" id="settingsFill" checked=checked> + <label for="settingsFill">Fill edge cut</label> + </div> + + <div> + <input type="checkbox" id="settingsAsSVG" checked=unchecked> + <label for="settingsAsSVG">Download as SVG</label> + </div> + + <h3>Resolution [DPI]</h3> + + <div> + <input id="settingsDPI" step=1 min=1 type="number" value="1000"> + </div> + + <h3>Origin [mm]</h3> + <div> + <label for="settingsOrigX">x:</label> + <input id="settingsOrigX" step=0.1 type="number"> + <label for="settingsOrigY">y:</label> + <input id="settingsOrigY" step=0.1 type="number"> + <button class="lock" id="settingsLockOrig">🔓</button> + </div> + + <h3>Dimensions [mm]</h3> + <div> + <label for="settingsDimX">x:</label> + <input id="settingsDimX" step=0.1 type="number"> + <label for="settingsDimY">y:</label> + <input id="settingsDimY" step=0.1 type="number"> + <button class="lock" id="settingsLockDim">🔓</button> + </div> + + <h3>Margins [mm]</h3> + <div> + <label for="settingsMarginX">x:</label> + <input id="settingsMarginX" step=0.1 min=0 type="number" value=3> + <label for="settingsMarginY">y:</label> + <input id="settingsMarginY" step=0.1 min=0 type="number" value=3> + </div> + </div> + </div> + </div> + <script src="/src/interface.js" type="module"></script> + <script src="/src/interface.js" type="module"></script> +</body> +</html> diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..1a0b4ab77aeac0deaac67c80a1884fc1f4156918 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1625 @@ +{ + "name": "gerber2png", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "gerber2png", + "version": "0.0.0", + "dependencies": { + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.0", + "events": "^3.3.0", + "gerber-to-svg": "^4.2.8", + "process": "^0.11.10", + "save-svg-as-png": "^1.4.0", + "stream-browserify": "^3.0.0", + "util": "^0.12.5" + }, + "devDependencies": { + "typescript": "^5.0.2", + "vite": "^4.4.11" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@tracespace/xml-id": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@tracespace/xml-id/-/xml-id-4.2.7.tgz", + "integrity": "sha512-4T7uAx5HB6qwKNH7jQDiij4EDe+uP+zlFcccMpZageZA5S2V2GFxm3g5lThJdTaQhp8Or4FLsmu8C/BRdYS7hg==" + }, + "node_modules/@types/node": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", + "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~5.25.1" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gerber-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/gerber-parser/-/gerber-parser-4.2.7.tgz", + "integrity": "sha512-Docb3egdLPjqYu/oH9Zhhc25kb2Ub9qkVFXu3seg13nDNW+KxbglqvyDcC0CGxkXxCaTqP3iyWNBG38fssmGKw==", + "dependencies": { + "@types/node": "^13.1.6", + "inherits": "^2.0.4", + "lodash.isfinite": "^3.3.2", + "lodash.padend": "^4.6.1", + "lodash.padstart": "^4.6.1", + "readable-stream": "^3.4.0" + } + }, + "node_modules/gerber-parser/node_modules/@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + }, + "node_modules/gerber-plotter": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/gerber-plotter/-/gerber-plotter-4.2.8.tgz", + "integrity": "sha512-n+Kg4HJQzCVBvgh73Rit8xCrQOJFhnnIBV7psboURjlcIwuYum4eAEOTd6S3GyXXvxGGay3aOmp6HwQ373ciuQ==", + "dependencies": { + "@types/node": "^13.1.6", + "inherits": "^2.0.4", + "lodash.fill": "^3.4.0", + "lodash.isfinite": "^3.3.2", + "lodash.isfunction": "^3.0.9", + "readable-stream": "^3.4.0" + }, + "peerDependencies": { + "gerber-parser": "^4.0.0" + } + }, + "node_modules/gerber-plotter/node_modules/@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + }, + "node_modules/gerber-to-svg": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/gerber-to-svg/-/gerber-to-svg-4.2.8.tgz", + "integrity": "sha512-EgUR5cJu5s1UgB2jy+we9UBGH5c2ecmcsBsv2AOEjeYRUijMx7jg7mCsHAuGoF8ogmBWmh6/ahDxDJe7d7zzIw==", + "dependencies": { + "@tracespace/xml-id": "^4.2.7", + "@types/node": "^13.1.6", + "escape-html": "^1.0.3", + "gerber-parser": "^4.2.7", + "gerber-plotter": "^4.2.8", + "inherits": "^2.0.4", + "lodash.isfinite": "^3.3.2", + "readable-stream": "^3.4.0", + "xml-element-string": "^1.0.0" + } + }, + "node_modules/gerber-to-svg/node_modules/@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/lodash.fill": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/lodash.fill/-/lodash.fill-3.4.0.tgz", + "integrity": "sha512-YgunwHKIxPWOe3VnM65J3oi6oShakIxdLMeIZ9xxcsMxc8X/FQC2VlA4eJzMv+7GlC5gebQLn+U+qcNoG18iLA==" + }, + "node_modules/lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==" + }, + "node_modules/lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==" + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/save-svg-as-png": { + "version": "1.4.17", + "resolved": "https://registry.npmjs.org/save-svg-as-png/-/save-svg-as-png-1.4.17.tgz", + "integrity": "sha512-7QDaqJsVhdFPwviCxkgHiGm9omeaMBe1VKbHySWU6oFB2LtnGCcYS13eVoslUgq6VZC6Tjq/HddBd1K6p2PGpA==" + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/vite": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/xml-element-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-element-string/-/xml-element-string-1.0.0.tgz", + "integrity": "sha512-JhO/ZCCwce8c9rLVXEA/KAy3Kg5340Ey4QBglQ+9ScQrQdroothAXblTRtyGkJZRRqQkkJSMZx8Kd7DGPMBsAw==", + "dependencies": { + "escape-html": "^1.0.3" + } + } + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "dev": true, + "optional": true + }, + "@tracespace/xml-id": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@tracespace/xml-id/-/xml-id-4.2.7.tgz", + "integrity": "sha512-4T7uAx5HB6qwKNH7jQDiij4EDe+uP+zlFcccMpZageZA5S2V2GFxm3g5lThJdTaQhp8Or4FLsmu8C/BRdYS7hg==" + }, + "@types/node": { + "version": "20.8.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", + "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "undici-types": "~5.25.1" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gerber-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/gerber-parser/-/gerber-parser-4.2.7.tgz", + "integrity": "sha512-Docb3egdLPjqYu/oH9Zhhc25kb2Ub9qkVFXu3seg13nDNW+KxbglqvyDcC0CGxkXxCaTqP3iyWNBG38fssmGKw==", + "requires": { + "@types/node": "^13.1.6", + "inherits": "^2.0.4", + "lodash.isfinite": "^3.3.2", + "lodash.padend": "^4.6.1", + "lodash.padstart": "^4.6.1", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + } + } + }, + "gerber-plotter": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/gerber-plotter/-/gerber-plotter-4.2.8.tgz", + "integrity": "sha512-n+Kg4HJQzCVBvgh73Rit8xCrQOJFhnnIBV7psboURjlcIwuYum4eAEOTd6S3GyXXvxGGay3aOmp6HwQ373ciuQ==", + "requires": { + "@types/node": "^13.1.6", + "inherits": "^2.0.4", + "lodash.fill": "^3.4.0", + "lodash.isfinite": "^3.3.2", + "lodash.isfunction": "^3.0.9", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + } + } + }, + "gerber-to-svg": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/gerber-to-svg/-/gerber-to-svg-4.2.8.tgz", + "integrity": "sha512-EgUR5cJu5s1UgB2jy+we9UBGH5c2ecmcsBsv2AOEjeYRUijMx7jg7mCsHAuGoF8ogmBWmh6/ahDxDJe7d7zzIw==", + "requires": { + "@tracespace/xml-id": "^4.2.7", + "@types/node": "^13.1.6", + "escape-html": "^1.0.3", + "gerber-parser": "^4.2.7", + "gerber-plotter": "^4.2.8", + "inherits": "^2.0.4", + "lodash.isfinite": "^3.3.2", + "readable-stream": "^3.4.0", + "xml-element-string": "^1.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.52", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + } + } + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==" + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "lodash.fill": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/lodash.fill/-/lodash.fill-3.4.0.tgz", + "integrity": "sha512-YgunwHKIxPWOe3VnM65J3oi6oShakIxdLMeIZ9xxcsMxc8X/FQC2VlA4eJzMv+7GlC5gebQLn+U+qcNoG18iLA==" + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==" + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==" + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "save-svg-as-png": { + "version": "1.4.17", + "resolved": "https://registry.npmjs.org/save-svg-as-png/-/save-svg-as-png-1.4.17.tgz", + "integrity": "sha512-7QDaqJsVhdFPwviCxkgHiGm9omeaMBe1VKbHySWU6oFB2LtnGCcYS13eVoslUgq6VZC6Tjq/HddBd1K6p2PGpA==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true + }, + "undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true, + "optional": true, + "peer": true + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "vite": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", + "dev": true, + "requires": { + "esbuild": "^0.18.10", + "fsevents": "~2.3.2", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + } + }, + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "xml-element-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-element-string/-/xml-element-string-1.0.0.tgz", + "integrity": "sha512-JhO/ZCCwce8c9rLVXEA/KAy3Kg5340Ey4QBglQ+9ScQrQdroothAXblTRtyGkJZRRqQkkJSMZx8Kd7DGPMBsAw==", + "requires": { + "escape-html": "^1.0.3" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..956a3bdb4b7d0dc894c5dea53453ff116cc0fccf --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "gerber2png", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "buffer": "^6.0.0", + "events": "^3.0.0", + "gerber-to-svg": "^4.2.8", + "save-svg-as-png": "^1.4.0", + "browserify-zlib": "^0.2.0", + "process": "^0.11.10", + "stream-browserify": "^3.0.0", + "util": "^0.12.5" + }, + "devDependencies": { + "typescript": "^5.0.2", + "vite": "^4.4.11" + } +} diff --git a/src/interface.js b/src/interface.js new file mode 100644 index 0000000000000000000000000000000000000000..452fad7e89993895713240d9aec039328d55864d --- /dev/null +++ b/src/interface.js @@ -0,0 +1,464 @@ +// Quentin Bolsee and Jake Read, MIT Center for Bits and Atoms, 2023 +// import * as saveSvgAsPng from 'save-svg-as-png' +// import * as downloadAsPng from 'save-svg-as-png' +// require('save-svg-as-png') +// require('process'); +import process from "process"; +// import { util } from "util"; +import { Buffer } from "buffer"; +import EventEmitter from "events"; + +window.Buffer = Buffer; +window.process = process; +window.EventEmitter = EventEmitter; + +import gerberToSvg from 'gerber-to-svg' +import * as saveSvg from 'save-svg-as-png' + +let sourceElem = document.getElementById("body"); +let svgElem = document.getElementById("previewSVG"); + +// order of known layers, KiCAD and EAGLE namings +const lookupOrder = [ + "Edge_Cuts", // KiCAD + "profile", // EAGLE + "B_Cu", + "copper_bottom", + "F_Cu", + "copper_top", + "B_Mask", + "soldermask_bottom", + "F_Mask", + "soldermask_top", + "B_Paste", + "solderpaste_bottom", + "F_Paste", + "solderpaste_top", + "drill", + "B_Silkscreen", + "B_Silks", + "silkscreen_bottom", + "F_Silkscreen", + "F_Silks", + "silkscreen_top", +]; + +const lookupColor = { + "Edge_Cuts": [70,105,58,1.0], + "profile": [70,105,58,1.0], + "B_Cu": [30,130,220,0.8], + "copper_bottom": [30,130,220,0.8], + "F_Cu": [89,165,82,0.8], + "copper_top": [89,165,82,0.8], + "B_Mask": [200,177,170,0.6], + "soldermask_bottom": [200,177,170,0.6], + "F_Mask": [239,177,58,1.0], + "soldermask_top": [239,177,58,1.0], + "B_Paste": [200,20,230,0.2], + "solderpaste_bottom": [200,20,230,0.2], + "F_Paste": [200,20,230,0.3], + "solderpaste_top": [200,20,230,0.3], + "drill": [120,120,120,1.0], + "B_Silkscreen": [255,255,255,0.6], + "B_Silks": [255,255,255,0.6], + "silkscreen_bottom": [255,255,255,0.6], + "F_Silkscreen": [255,255,255,1.0], + "F_Silks": [255,255,255,1.0], + "silkscreen_top": [255,255,255,1.0], +}; + +let globalLayers = []; + +let globalXML = null; + +// units in mm +let globalSettings = { + fillEdge : true, + asSVG: false, + dpi: 1000, + svgOrig : [NaN, NaN], + lockOrig : false, + svgDim : [NaN, NaN], + lockDim : false, + svgMargin : [0, 0], +}; + +function renderSVG() { + if (globalXML === null) { + svgElem.outerHTML = '<svg id="previewSVG"></svg>'; + } else { + let serializer = new XMLSerializer(); + svgElem.outerHTML = serializer.serializeToString(globalXML); + } + // update reference + svgElem = document.getElementById("previewSVG"); +} + +function updateSVG(fromSettingsChange=false) { + let parser = new DOMParser(); + globalXML = parser.parseFromString('<svg id="previewSVG" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>', "text/xml"); + + if (globalLayers.length == 0) { + renderSVG(); + return; + } + + let layersSorted = globalLayers.toSorted((a, b) => { + return lookupOrder.indexOf(a[0]) - lookupOrder.indexOf(b[0]); + }); + + let layerName, layerTxt; + + let xMin = Number.MAX_VALUE; + let xMax = -Number.MAX_VALUE; + let yMin = Number.MAX_VALUE; + let yMax = -Number.MAX_VALUE; + + let deltaY = []; + + // reset XML + let globalXMLRoot = globalXML.childNodes[0]; + globalXMLRoot.setAttribute("stroke-linecap", "round"); + globalXMLRoot.setAttribute("stroke-linejoin", "round"); + globalXMLRoot.setAttribute("stroke-width", "0"); + // globalXMLRoot.setAttribute("background-color", "rgb(255,255,255)"); + globalXMLRoot.setAttribute("fill-rule", "evenodd"); + + let layerVB, layerXML, layerXMLRoot; + + // compute viewBox + for ([layerName, layerTxt] of layersSorted) { + layerXML = parser.parseFromString(layerTxt, "text/xml"); + layerXMLRoot = layerXML.childNodes[0]; + layerVB = layerXMLRoot.getAttribute("viewBox").split(" ").map((x) => Number(x)); + if (layerXMLRoot.childNodes.length == 0) { + continue; + } + xMin = Math.min(xMin, layerVB[0]); + xMax = Math.max(xMax, layerVB[0]+layerVB[2]); + yMin = Math.min(yMin, layerVB[1]); + yMax = Math.max(yMax, layerVB[1]+layerVB[3]); + } + // sync settings + if (!fromSettingsChange) { + if (!globalSettings.lockOrig || isNaN(globalSettings.svgOrig[0])) { + globalSettings.svgOrig[0] = xMin / 1000.0; + globalSettings.svgOrig[1] = yMin / 1000.0; + } + if (!globalSettings.lockDim || isNaN(globalSettings.svgDim[0])) { + globalSettings.svgDim[0] = (xMax - xMin) / 1000.0; + globalSettings.svgDim[1] = (yMax - yMin) / 1000.0; + } + } + writeSettings(); + let vb = [ + (globalSettings.svgOrig[0]-globalSettings.svgMargin[0]), + (globalSettings.svgOrig[1]-globalSettings.svgMargin[1]), + (globalSettings.svgDim[0]+2*globalSettings.svgMargin[0]), + (globalSettings.svgDim[1]+2*globalSettings.svgMargin[1]) + ].map((x) => x * 1000); + + globalXMLRoot.setAttribute("viewBox", vb.join(' ')); + globalXMLRoot.setAttribute("width", `${(vb[2]/1000).toFixed(3)}mm`); + globalXMLRoot.setAttribute("height", `${(vb[3]/1000).toFixed(3)}mm`); + + for ([layerName, layerTxt] of layersSorted) { + layerXML = parser.parseFromString(layerTxt, "text/xml"); + layerXMLRoot = layerXML.childNodes[0]; + layerVB = layerXMLRoot.getAttribute("viewBox").split(" ").map((x) => Number(x)); + + let layerRGB = 'rgb('+lookupColor[layerName].slice(0, 3).join(',')+')'; + let layerOpacity = lookupColor[layerName][3]; + + for (let g of layerXMLRoot.childNodes) { + if (g.tagName == "g") { + const regex_translate = /translate\([-.\d]+,\s*([-.\d]+)\)/; + const m = g.getAttribute("transform").match(regex_translate); + // fix vertical alignment (none of this makes sense) + let ty = Number(m[1]); + ty += ((vb[1] + vb[3]) - (layerVB[1] + layerVB[3])); + ty += (vb[1] - layerVB[1]); + g.setAttribute("transform", `translate(0, ${ty}) scale(1, -1)`); + + // let ty = Number(m[1]) + (layerVB[3]-(yMax-yMin))/2; + g.setAttribute("opacity", layerOpacity); + g.setAttribute("fill", layerRGB); + g.setAttribute("stroke", layerRGB); + g.childNodes.forEach((p) => { + if (["profile", "Edge_Cuts"].includes(layerName) && globalSettings.fillEdge) { + // fill mode + p.removeAttribute("fill"); + p.setAttribute("stroke", "none"); + } + }); + } + globalXMLRoot.appendChild(g.cloneNode(true)); + } + } + + renderSVG(); +} + +function setDPI(canvas, dpi) { + // Set up CSS size. + canvas.style.width = canvas.style.width || canvas.width + 'px'; + canvas.style.height = canvas.style.height || canvas.height + 'px'; + + // Resize canvas and scale future draws. + var scaleFactor = dpi / 96; + canvas.width = Math.ceil(canvas.width * scaleFactor); + canvas.height = Math.ceil(canvas.height * scaleFactor); + var ctx = canvas.getContext('2d'); + ctx.scale(scaleFactor, scaleFactor); +} + +function downloadImage(separateLayers=false) { + if (separateLayers) { + return; + } + + saveSvg.saveSvgAsPng(svgElem, "diagram.png"); + // if (isNaN(globalSettings.svgDim[0])) { + // return; + // } + // let svg = svgElem.closest('svg'); + // let svgWidth = svg.attributes['width'].value; + // let svgHeight = svg.attributes['height'].value; + // + // let mmWidth = (globalSettings.svgDim[0]+2*globalSettings.svgMargin[0]); + // let mmHeight = (globalSettings.svgDim[1]+2*globalSettings.svgMargin[1]); + // let pxWidth = Math.round(globalSettings.dpi * mmWidth / 25.4); + // let pxHeight = Math.round(globalSettings.dpi * mmHeight / 25.4); + // + // let image = new Image(); + // let canvas = document.getElementById('canvas'); + // setDPI(canvas, globalSettings.dpi); + // // canvas.width = pxWidth; + // // canvas.height = pxHeight; + // let ctx = canvas.getContext('2d'); + // + // image.addEventListener('load', (e) => { + // console.log(e.target.width) + // console.log(e.target.height) + // ctx.drawImage(e.target, 0, 0, e.target.width, e.target.height); + // const a = document.createElement('a'); + // a.style.display = 'none'; + // a.href = canvas.toDataURL("image/png"); + // a.download = 'render.png'; + // document.body.appendChild(a); + // a.click(); + // }); + // let svgURL = new XMLSerializer().serializeToString(svgElem); + // image.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL); + // let txt = JSON.stringify(layers); + // var txtBlob = new Blob([txt], { + // type: 'text/plain' + // }); + // const url = window.URL.createObjectURL(txtBlob); + // // the filename you want + // window.URL.revokeObjectURL(url); + // + // console.log(JSON.parse(txt)) +} + +var dropZone = document.getElementById('dropZone'); + +function showDropZone() { + dropZone.style.visibility = "visible"; +} + +function hideDropZone() { + dropZone.style.visibility = "hidden"; +} + +window.addEventListener('dragenter', (e) => { + showDropZone(); +}); + +function allowDrag(e) { + if (true) { // Test that the item being dragged is a valid one + e.dataTransfer.dropEffect = 'copy'; + e.preventDefault(); + } +} + +dropZone.addEventListener('dragenter', allowDrag); +dropZone.addEventListener('dragover', allowDrag); + +dropZone.addEventListener('dragleave', (e) => { + hideDropZone(); +}); + +dropZone.addEventListener('drop', (e) => { + e.preventDefault(); + hideDropZone(); + if (!e.dataTransfer.items) { + return; + } + + // layerName: SVG + let promiseAllSVG = []; + + for (let file of e.dataTransfer.files) { + let layerName; + if (file.name.endsWith('.xln') || file.name.endsWith('.drl')) { + layerName = "drill"; + } else { + if (!file.name.endsWith('.gbr')) { + continue; + } + let filename = file.name.replace('.gbr', ''); + let layerNum = -1; + + for (let j in lookupOrder) { + layerName = lookupOrder[j]; + if (filename.endsWith(layerName)) { + layerNum = j; + break; + } + } + if (layerNum == -1) { + continue; + } + } + + let promiseSVG = new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (event) => { + const options = { + encoding: 'utf8', + optimizePaths: true + }; + gerberToSvg(reader.result, options, (err, svg) => { + if (err) { + resolve(null); + } else { + resolve([layerName, svg]); + } + }); + } + reader.onerror = reject; + reader.readAsText(file); + }); + promiseAllSVG.push(promiseSVG); + } + Promise.all(promiseAllSVG).then((values) => { + globalLayers = values; + updateSVG(); + }) +}); + +function readSettings() { + let settingsFill = document.getElementById("settingsFill"); + let settingsAsSVG = document.getElementById("settingsAsSVG"); + let settingsDPI = document.getElementById("settingsDPI"); + let settingsOrigX = document.getElementById("settingsOrigX"); + let settingsOrigY = document.getElementById("settingsOrigY"); + let settingsDimX = document.getElementById("settingsDimX"); + let settingsDimY = document.getElementById("settingsDimY"); + let settingsMarginX = document.getElementById("settingsMarginX"); + let settingsMarginY = document.getElementById("settingsMarginY"); + + globalSettings.fillEdge = settingsFill.checked; + globalSettings.asSVG = settingsAsSVG.checked; + globalSettings.dpi = Number(settingsDPI.value); + globalSettings.svgMargin = [ + Number(settingsMarginX.value), + Number(settingsMarginY.value) + ] + globalSettings.svgOrig = [ + Number(settingsOrigX.value), + Number(settingsOrigY.value) + ]; + globalSettings.svgDim = [ + Number(settingsDimX.value), + Number(settingsDimY.value) + ]; +} + +function writeSettings() { + let settingsOrigX = document.getElementById("settingsOrigX"); + let settingsOrigY = document.getElementById("settingsOrigY"); + let settingsDimX = document.getElementById("settingsDimX"); + let settingsDimY = document.getElementById("settingsDimY"); + + settingsOrigX.value = globalSettings.svgOrig[0]; + settingsOrigY.value = globalSettings.svgOrig[1]; + settingsDimX.value = globalSettings.svgDim[0]; + settingsDimY.value = globalSettings.svgDim[1]; +} + +/* buttons */ +function initListeners() { + // document.getElementById("loadButton").addEventListener("click", () => { + // document.getElementById("fileInput").click(); + // }); + + for (let elementId of [ + 'settingsFill', + 'settingsAsSVG', + 'settingsDPI', + 'settingsOrigX', + 'settingsOrigY', + 'settingsDimX', + 'settingsDimY', + 'settingsMarginX', + 'settingsMarginY']) { + document.getElementById(elementId).addEventListener("change", () => { + readSettings(); + updateSVG(true); + }) + } +} + +let lockOrigElem = document.getElementById("settingsLockOrig"); +let lockDimElem = document.getElementById("settingsLockDim"); + +lockOrigElem.addEventListener("click", () => { + let settingsOrigX = document.getElementById("settingsOrigX"); + let settingsOrigY = document.getElementById("settingsOrigY"); + if (globalSettings.lockOrig) { + settingsOrigX.disabled = false; + settingsOrigY.disabled = false; + globalSettings.lockOrig = false; + lockOrigElem.innerHTML = "🔓"; + } else { + settingsOrigX.disabled = true; + settingsOrigY.disabled = true; + globalSettings.lockOrig = true; + lockOrigElem.innerHTML = "🔒"; + } + updateSVG(); +}); + +lockDimElem.addEventListener("click", () => { + let settingsDimX = document.getElementById("settingsDimX"); + let settingsDimY = document.getElementById("settingsDimY"); + if (globalSettings.lockDim) { + settingsDimX.disabled = false; + settingsDimY.disabled = false; + globalSettings.lockDim = false; + lockDimElem.innerHTML = "🔓"; + } else { + settingsDimX.disabled = true; + settingsDimY.disabled = true; + globalSettings.lockDim = true; + lockDimElem.innerHTML = "🔒"; + } + updateSVG(); +}); + +document.getElementById("downloadRenderButton").addEventListener("click", () => { + downloadImage(false); +}); + +document.getElementById("downloadlayersButton").addEventListener("click", () => { + downloadImage(true); +}); + +readSettings(); +initListeners(); + +globalLayers = JSON.parse('[["F_Cu","<svg version=\\"1.1\\" xmlns=\\"http://www.w3.org/2000/svg\\" xmlns:xlink=\\"http://www.w3.org/1999/xlink\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"0\\" fill-rule=\\"evenodd\\" width=\\"32.531mm\\" height=\\"34.7mm\\" viewBox=\\"53775 -68780 32531 34700\\"><defs><rect x=\\"-635\\" y=\\"-1270\\" width=\\"1270\\" height=\\"2540\\" id=\\"M7zzQZkyObU1_pad-10\\"/><rect x=\\"-850\\" y=\\"-1000\\" width=\\"1700\\" height=\\"2000\\" id=\\"M7zzQZkyObU1_pad-11\\"/><rect x=\\"-1000\\" y=\\"-850\\" width=\\"2000\\" height=\\"1700\\" id=\\"M7zzQZkyObU1_pad-12\\"/><rect x=\\"-1500\\" y=\\"-800\\" width=\\"3000\\" height=\\"1600\\" id=\\"M7zzQZkyObU1_pad-13\\"/><rect x=\\"-600\\" y=\\"-1200\\" width=\\"1200\\" height=\\"2400\\" id=\\"M7zzQZkyObU1_pad-14\\"/><circle cx=\\"0\\" cy=\\"0\\" r=\\"600\\" id=\\"M7zzQZkyObU1_pad-15\\"/><rect x=\\"-370\\" y=\\"-1200\\" width=\\"740\\" height=\\"2400\\" id=\\"M7zzQZkyObU1_pad-16\\"/></defs><g transform=\\"translate(0,-102860) scale(1,-1)\\" fill=\\"currentColor\\" stroke=\\"currentColor\\"><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"67970\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"65430\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"62890\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"60350\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"57810\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-10\\" x=\\"55270\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-11\\" x=\\"82550\\" y=\\"-48800\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-11\\" x=\\"82550\\" y=\\"-52800\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"81375\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"77375\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"63595\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"59595\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"71215\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-12\\" x=\\"67215\\" y=\\"-55880\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-35560\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-38100\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-40640\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-43180\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-45720\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-48260\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"61235\\" y=\\"-50800\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-50800\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-48260\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-45720\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-43180\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-40640\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-38100\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-13\\" x=\\"78470\\" y=\\"-35560\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-14\\" x=\\"71125\\" y=\\"-52070\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-14\\" x=\\"68585\\" y=\\"-52070\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-15\\" x=\\"68580\\" y=\\"-34680\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-15\\" x=\\"68580\\" y=\\"-37220\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-15\\" x=\\"71120\\" y=\\"-37220\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-15\\" x=\\"71120\\" y=\\"-34680\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-11\\" x=\\"57785\\" y=\\"-47720\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-11\\" x=\\"57785\\" y=\\"-43720\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"81915\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"81915\\" y=\\"-65450\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"80645\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"80645\\" y=\\"-65450\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"79375\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"79375\\" y=\\"-65450\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"78105\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"78105\\" y=\\"-65450\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"76835\\" y=\\"-61550\\"/><use xlink:href=\\"#M7zzQZkyObU1_pad-16\\" x=\\"76835\\" y=\\"-65450\\"/><path d=\\"M 77765 -67310 78105 -66970 78105 -65450 79375 -65450 79375 -67050 79375 -66720 M 79375 -67050 79635 -67310 81280 -67310 81915 -66675 81915 -65450 83140 -65450 85090 -63500 85090 -48895 84995 -48800 82550 -48800 M 85090 -48895 85090 -42545 80645 -38100 77470 -38100 79450 -38100 M 56515 -67310 71120 -67310 77765 -67310 M 71215 -67215 71120 -67310 M 55270 -60915 55270 -61550 55270 -66065 56515 -67310 M 71215 -55880 71215 -67215 M 81915 -68580 86106 -64389 86106 -41910 79756 -35560 77470 -35560 79450 -35560 M 60039.002 -59404.002 54260.998 -59404.002 53975 -59690 53975 -66675 55880 -68580 81915 -68580 M 60350 -59715 60039.002 -59404.002 M 60350 -61550 60350 -59715 M 81915 -59690 81915 -61550 M 77470 -48260 74930 -50800 74930 -56504.295 76845.206 -58419.501 80644.501 -58419.501 81915 -59690 M 74120.499 -49069.501 74120.499 -56839.602 76509.9 -59229.002 77384.002 -59229.002 78105 -59950 78105 -61550 M 77470 -45720 74120.499 -49069.501 M 76835 -60960 73310.998 -57435.998 73310.998 -47339.002 77470 -43180 M 76835 -61550 76835 -60960 M 56515 -56385.488 57914.512 -57785 62300 -57785 65430 -60915 M 56515 -48990 56515 -56385.488 M 57785 -47720 56515 -48990 M 57229.704 -58245 57229 -58245 55372 -56388 55372 -43053 57785 -40640 62235 -40640 M 61769.501 -58594.501 57579.205 -58594.501 57229.704 -58245 M 62890 -59715 61769.501 -58594.501 M 62890 -60915 62890 -59715 M 62235 -48392 62235 -48260 M 58325 -43180 57785 -43720 M 62235 -43180 58325 -43180 M 59595 -51530 59595 -55880 M 60325 -50800 59595 -51530 M 62235 -50800 60325 -50800 M 63595 -55880 67215 -55880 M 77375 -50895 77375 -55880 M 79375 -50800 77470 -50800 77375 -50895 M 81375 -55880 81915 -55880 82550 -55245 82550 -52800\\" fill=\\"none\\" stroke-width=\\"400\\"/></g></svg>"],["Edge_Cuts","<svg version=\\"1.1\\" xmlns=\\"http://www.w3.org/2000/svg\\" xmlns:xlink=\\"http://www.w3.org/1999/xlink\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" stroke-width=\\"0\\" fill-rule=\\"evenodd\\" width=\\"34.39mm\\" height=\\"38.835mm\\" viewBox=\\"52655 -71170 34390 38835\\"><g transform=\\"translate(0,-103505) scale(1,-1)\\" fill=\\"currentColor\\" stroke=\\"currentColor\\"><path d=\\"M 86995 -34925 A 2540 2540 0 0 1 84455 -32385 L 55245 -32385 A 2540 2540 0 0 1 52705 -34925 L 52705 -68580 A 2540 2540 0 0 1 55245 -71120 L 84455 -71120 A 2540 2540 0 0 1 86995 -68580 L 86995 -34925\\" fill=\\"none\\" stroke-width=\\"100\\"/></g></svg>"]]'); + +updateSVG(); diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000000000000000000000000000000000000..c7b8476a826ae060d9b4fc9fcc860e71b884107c --- /dev/null +++ b/src/style.css @@ -0,0 +1,136 @@ +body { + font-family: Arial, Helvetica, sans-serif; +} + +input { + max-width: 30%; +} + +p { + color: rgba(0, 0, 0, 1); +} + +h3 { + margin-left: 4px; + margin-top: 20px; + margin-bottom: 4px; +} + +p.lock { + cursor: default; + margin: 0; +} + +p#dropText { + font-size: 100px; +} + +/* #paper and #controls should be inline with each other in a 60 40 ratio*/ +.container { + display: flex; +} + +/* input { + border-radius: 2px; +} */ + +button { + border: none; +} + +button.interface { + background-color: rgb(200, 200, 200); + padding: 4px; + border-radius: 6px; + margin: 4px; + width: 28%; + min-width: 80px; + /* font-size: 10px; */ +} + +button.interface:hover { + background-color: rgb(160, 160, 160); + cursor: pointer; +} + +button.lock { + background: none; + border: none; + margin: 0; + padding: 0; + cursor: pointer; +} + +div { + margin: 4px; +} + +h2 { + margin: 4px; +} + +/* button.settingsButton { + width: 30%; +} */ + + +.info { + background-color: rgb(221, 221, 221); + padding: 5px; + border-radius: 8px; +} + +.full-flex { + flex: 1; +} + +.panel { + display: flex; + flex-direction: column; + padding: 4px; +} + +.settings { + width: 35vh; + height: 65vh; + margin: 4px; + display: flex; + border-radius: 6px; + border: 1px solid rgb(0, 0, 0); + flex-direction: column; +} + +#previewSVG { + width: 100%; + height: 100%; +} + +div.SVGbox { + border: 1px solid rgb(0, 0, 0); +} + +div.preview { + width: 65vh; + height: 65vh; + margin: 4px; + border-radius: 6px; + background-color: rgb(255, 255, 255); + border: 1px solid rgb(0, 0, 0); + display: flex; + align-items: center; + justify-content: center; +} + +div#dropZone { + background-color: rgba(180, 180, 180, 0.6); + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; + visibility: hidden; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..11f02fe2a0061d6e6e1f271b21da95423b448b32 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// <reference types="vite/client" /> diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..75abdef26594460f62f904bf54b54377573c9209 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000000000000000000000000000000000000..161206c05abdbcb94a1ef103358e0c5954848af6 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,21 @@ +import { resolve } from 'path' +import { defineConfig } from 'vite' + +export default defineConfig({ + resolve: { + alias: { + process: "process/browser", + stream: "stream-browserify", + zlib: "browserify-zlib", + util: 'util' + } + }, + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + // nested: resolve(__dirname, 'nested/index.html'), + }, + }, + }, +})